Handle trade interruption

This commit is contained in:
Manfred Karrer 2015-03-28 14:18:56 +01:00
parent 846cb1869a
commit fa1fdc3f12
66 changed files with 1660 additions and 1060 deletions

View file

@ -398,7 +398,7 @@ public class TradeWalletService {
Futures.addCallback(broadcastComplete, callback); Futures.addCallback(broadcastComplete, callback);
} }
// Returns local transaction which has a different state as the serialized publishedDepositTx we get from the offerer // Commits the tx to the wallet and returns that
public Transaction commitsDepositTx(Transaction publishedDepositTx) throws VerificationException { public Transaction commitsDepositTx(Transaction publishedDepositTx) throws VerificationException {
log.trace("takerCommitsDepositTx called"); log.trace("takerCommitsDepositTx called");
log.trace("publishedDepositTx " + publishedDepositTx.toString()); log.trace("publishedDepositTx " + publishedDepositTx.toString());
@ -411,6 +411,14 @@ public class TradeWalletService {
return depositTx; return depositTx;
} }
// Returns local existing wallet transaction
public Transaction getWalletTx(Transaction tx) throws VerificationException {
log.trace("getWalleTx called");
log.trace("tx " + tx.toString());
return wallet.getTransaction(tx.getHash());
}
public byte[] offererCreatesAndSignsPayoutTx(Transaction depositTx, public byte[] offererCreatesAndSignsPayoutTx(Transaction depositTx,
Coin offererPayoutAmount, Coin offererPayoutAmount,
Coin takerPayoutAmount, Coin takerPayoutAmount,

View file

@ -30,7 +30,7 @@ import org.slf4j.LoggerFactory;
public class TaskRunner<T extends Model> { public class TaskRunner<T extends Model> {
private static final Logger log = LoggerFactory.getLogger(TaskRunner.class); private static final Logger log = LoggerFactory.getLogger(TaskRunner.class);
private final Queue<Class> tasks = new LinkedBlockingQueue<>(); private final Queue<Class<? extends Task>> tasks = new LinkedBlockingQueue<>();
protected final T sharedModel; protected final T sharedModel;
private final ResultHandler resultHandler; private final ResultHandler resultHandler;
private final ErrorMessageHandler errorMessageHandler; private final ErrorMessageHandler errorMessageHandler;
@ -45,7 +45,7 @@ public class TaskRunner<T extends Model> {
this.errorMessageHandler = errorMessageHandler; this.errorMessageHandler = errorMessageHandler;
} }
public void addTasks(Class<? extends Task>... items) { public final void addTasks(Class<? extends Task>... items) {
tasks.addAll(Arrays.asList(items)); tasks.addAll(Arrays.asList(items));
} }

View file

@ -128,7 +128,6 @@ public class Offer implements Serializable {
setState(State.UNKNOWN); setState(State.UNKNOWN);
} }
// Serialized object does not create our transient objects
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); in.defaultReadObject();
stateProperty = new SimpleObjectProperty<>(state); stateProperty = new SimpleObjectProperty<>(state);
@ -282,6 +281,7 @@ public class Offer implements Serializable {
", fiatPrice=" + fiatPrice + ", fiatPrice=" + fiatPrice +
", amount=" + amount + ", amount=" + amount +
", minAmount=" + minAmount + ", minAmount=" + minAmount +
", p2pSigPubKey=" + p2pSigPubKey +
", fiatAccountType=" + fiatAccountType + ", fiatAccountType=" + fiatAccountType +
", bankAccountCountry=" + bankAccountCountry + ", bankAccountCountry=" + bankAccountCountry +
", securityDeposit=" + securityDeposit + ", securityDeposit=" + securityDeposit +
@ -291,7 +291,6 @@ public class Offer implements Serializable {
", arbitratorIds=" + arbitratorIds + ", arbitratorIds=" + arbitratorIds +
", offerFeePaymentTxID='" + offerFeePaymentTxID + '\'' + ", offerFeePaymentTxID='" + offerFeePaymentTxID + '\'' +
", state=" + state + ", state=" + state +
", stateProperty=" + stateProperty +
'}'; '}';
} }
} }

View file

@ -173,8 +173,13 @@ public class TomP2PAddressService extends TomP2PDHTService implements AddressSer
} }
private void removeAddress() { private void removeAddress() {
try {
boolean success = removeDataFromMyProtectedDomain(locationKey).awaitUninterruptibly(1000); boolean success = removeDataFromMyProtectedDomain(locationKey).awaitUninterruptibly(1000);
log.debug("removeDataFromMyProtectedDomain success=" + success); log.debug("removeDataFromMyProtectedDomain success=" + success);
} catch (Throwable t) {
t.printStackTrace();
log.error(t.getMessage());
}
} }
} }

View file

@ -122,6 +122,7 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic
private void sendMailboxMessage(PublicKey p2pSigPubKey, PublicKey p2pEncryptPubKey, MailboxMessage message, SendMessageListener listener) { private void sendMailboxMessage(PublicKey p2pSigPubKey, PublicKey p2pEncryptPubKey, MailboxMessage message, SendMessageListener listener) {
Bucket bucket = null; Bucket bucket = null;
log.info("sendMailboxMessage called");
try { try {
bucket = encryptionService.encryptObject(p2pEncryptPubKey, message); bucket = encryptionService.encryptObject(p2pEncryptPubKey, message);
} catch (Throwable t) { } catch (Throwable t) {

View file

@ -29,6 +29,7 @@ import java.security.PublicKey;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@SuppressWarnings("WeakerAccess")
@Immutable @Immutable
public class Contract implements Serializable { public class Contract implements Serializable {
// That object is sent over the wire, so we need to take care of version compatibility. // That object is sent over the wire, so we need to take care of version compatibility.

View file

@ -20,9 +20,9 @@ package io.bitsquare.trade;
import io.bitsquare.offer.Offer; import io.bitsquare.offer.Offer;
import io.bitsquare.p2p.Peer; import io.bitsquare.p2p.Peer;
import io.bitsquare.storage.Storage; import io.bitsquare.storage.Storage;
import io.bitsquare.trade.protocol.trade.TradeProcessModel; import io.bitsquare.trade.protocol.trade.ProcessModel;
import io.bitsquare.trade.protocol.trade.offerer.OffererProtocol; import io.bitsquare.trade.protocol.trade.offerer.OffererProtocol;
import io.bitsquare.trade.protocol.trade.offerer.models.OffererTradeProcessModel; import io.bitsquare.trade.protocol.trade.offerer.models.OffererProcessModel;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.core.TransactionConfidence; import org.bitcoinj.core.TransactionConfidence;
@ -34,6 +34,7 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable; import java.io.Serializable;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -50,6 +51,7 @@ import org.slf4j.LoggerFactory;
public class OffererTrade extends Trade implements Serializable { public class OffererTrade extends Trade implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization. // That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
transient private static final Logger log = LoggerFactory.getLogger(OffererTrade.class); transient private static final Logger log = LoggerFactory.getLogger(OffererTrade.class);
@ -84,48 +86,61 @@ public class OffererTrade extends Trade implements Serializable {
// Fields // Fields
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Nullable private Coin tradeAmount; // Transient/Immutable
@Nullable private Peer tradingPeer; transient private ObjectProperty<OffererProcessState> processStateProperty;
@NotNull private OffererProcessState processState = OffererProcessState.UNDEFINED; transient private ObjectProperty<OffererLifeCycleState> lifeCycleStateProperty;
@NotNull private OffererLifeCycleState lifeCycleState = OffererLifeCycleState.OFFER_OPEN;
@NotNull transient private ObjectProperty<OffererProcessState> processStateProperty = new SimpleObjectProperty<>(processState); // Mutable
@NotNull transient private ObjectProperty<OffererLifeCycleState> lifeCycleStateProperty = new SimpleObjectProperty<>(lifeCycleState); private Coin tradeAmount;
private Peer tradingPeer;
private OffererProcessState processState;
private OffererLifeCycleState lifeCycleState;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor // Constructor, initialization
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public OffererTrade(@NotNull Offer offer, @NotNull Storage<? extends TradeProcessModel> storage) { public OffererTrade(Offer offer, Storage<? extends TradeList> storage) {
super(offer, storage); super(offer, storage);
} log.trace("Created by constructor");
@Override processState = OffererProcessState.UNDEFINED;
protected TradeProcessModel createProcessModel() { lifeCycleState = OffererLifeCycleState.OFFER_OPEN;
return new OffererTradeProcessModel();
}
@Override
public void createProtocol() {
protocol = new OffererProtocol(this);
}
// Serialized object does not create our transient objects
private void readObject(@NotNull java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
processStateProperty = new SimpleObjectProperty<>(processState); processStateProperty = new SimpleObjectProperty<>(processState);
lifeCycleStateProperty = new SimpleObjectProperty<>(lifeCycleState); lifeCycleStateProperty = new SimpleObjectProperty<>(lifeCycleState);
tradeAmountProperty = new SimpleObjectProperty<>(); tradeAmountProperty = new SimpleObjectProperty<>();
tradeVolumeProperty = new SimpleObjectProperty<>(); tradeVolumeProperty = new SimpleObjectProperty<>();
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
log.trace("Created from serialized form.");
processStateProperty = new SimpleObjectProperty<>(processState);
lifeCycleStateProperty = new SimpleObjectProperty<>(lifeCycleState);
tradeAmountProperty = new SimpleObjectProperty<>();
tradeVolumeProperty = new SimpleObjectProperty<>();
if (tradeAmount != null) { if (tradeAmount != null) {
tradeAmountProperty.set(tradeAmount); tradeAmountProperty.set(tradeAmount);
tradeVolumeProperty.set(getTradeVolume()); tradeVolumeProperty.set(getTradeVolume());
} }
} }
@Override
protected ProcessModel createProcessModel() {
return new OffererProcessModel();
}
@Override
public void createProtocol() {
protocol = new OffererProtocol(this);
}
public void onFiatPaymentStarted() { public void onFiatPaymentStarted() {
assert protocol != null; assert protocol != null;
((OffererProtocol) protocol).onFiatPaymentStarted(); ((OffererProtocol) protocol).onFiatPaymentStarted();
@ -133,10 +148,29 @@ public class OffererTrade extends Trade implements Serializable {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Setters // Getter only
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void setProcessState(@NotNull OffererProcessState processState) { @Override
public ReadOnlyObjectProperty<OffererProcessState> processStateProperty() {
return processStateProperty;
}
@Override
public ReadOnlyObjectProperty<OffererLifeCycleState> lifeCycleStateProperty() {
return lifeCycleStateProperty;
}
public OffererProcessModel getProcessModel() {
return (OffererProcessModel) processModel;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setter for Mutable objects
///////////////////////////////////////////////////////////////////////////////////////////
public void setProcessState(OffererProcessState processState) {
this.processState = processState; this.processState = processState;
processStateProperty.set(processState); processStateProperty.set(processState);
@ -148,7 +182,7 @@ public class OffererTrade extends Trade implements Serializable {
} }
} }
public void setLifeCycleState(@NotNull OffererLifeCycleState lifeCycleState) { public void setLifeCycleState(OffererLifeCycleState lifeCycleState) {
switch (lifeCycleState) { switch (lifeCycleState) {
case FAILED: case FAILED:
disposeProtocol(); disposeProtocol();
@ -161,36 +195,24 @@ public class OffererTrade extends Trade implements Serializable {
lifeCycleStateProperty.set(lifeCycleState); lifeCycleStateProperty.set(lifeCycleState);
} }
public void setTradeAmount(@NotNull Coin tradeAmount) {
this.tradeAmount = tradeAmount;
tradeAmountProperty.set(tradeAmount);
tradeVolumeProperty.set(getTradeVolume());
}
public void setTradingPeer(@NotNull Peer tradingPeer) { ///////////////////////////////////////////////////////////////////////////////////////////
// Getter/Setter for Mutable objects
///////////////////////////////////////////////////////////////////////////////////////////
public void setTradingPeer(Peer tradingPeer) {
this.tradingPeer = tradingPeer; this.tradingPeer = tradingPeer;
} }
@Nullable
/////////////////////////////////////////////////////////////////////////////////////////// public Peer getTradingPeer() {
// Getters return tradingPeer;
///////////////////////////////////////////////////////////////////////////////////////////
@NotNull
public OffererTradeProcessModel getProcessModel() {
return (OffererTradeProcessModel) processModel;
} }
@NotNull public void setTradeAmount(Coin tradeAmount) {
@Override this.tradeAmount = tradeAmount;
public ReadOnlyObjectProperty<OffererProcessState> processStateProperty() { tradeAmountProperty.set(tradeAmount);
return processStateProperty; tradeVolumeProperty.set(getTradeVolume());
}
@NotNull
@Override
public ReadOnlyObjectProperty<OffererLifeCycleState> lifeCycleStateProperty() {
return lifeCycleStateProperty;
} }
@Nullable @Nullable
@ -202,22 +224,19 @@ public class OffererTrade extends Trade implements Serializable {
@Nullable @Nullable
@Override @Override
public Fiat getTradeVolume() { public Fiat getTradeVolume() {
if (tradeAmount != null)
return offer.getVolumeByAmount(tradeAmount); return offer.getVolumeByAmount(tradeAmount);
} else
return null;
@Nullable
@Override
public Peer getTradingPeer() {
return tradingPeer;
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Private // Protected
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Override @Override
protected void setConfidenceListener() { protected void setupConfidenceListener() {
assert depositTx != null; assert depositTx != null;
TransactionConfidence transactionConfidence = depositTx.getConfidence(); TransactionConfidence transactionConfidence = depositTx.getConfidence();
ListenableFuture<TransactionConfidence> future = transactionConfidence.getDepthFuture(1); ListenableFuture<TransactionConfidence> future = transactionConfidence.getDepthFuture(1);
@ -236,4 +255,14 @@ public class OffererTrade extends Trade implements Serializable {
} }
}); });
} }
@Override
public String toString() {
return "OffererTrade{" +
"tradeAmount=" + tradeAmount +
", tradingPeer=" + tradingPeer +
", processState=" + processState +
", lifeCycleState=" + lifeCycleState +
'}';
}
} }

View file

@ -20,9 +20,9 @@ package io.bitsquare.trade;
import io.bitsquare.offer.Offer; import io.bitsquare.offer.Offer;
import io.bitsquare.p2p.Peer; import io.bitsquare.p2p.Peer;
import io.bitsquare.storage.Storage; import io.bitsquare.storage.Storage;
import io.bitsquare.trade.protocol.trade.TradeProcessModel; import io.bitsquare.trade.protocol.trade.ProcessModel;
import io.bitsquare.trade.protocol.trade.taker.TakerProtocol; import io.bitsquare.trade.protocol.trade.taker.TakerProtocol;
import io.bitsquare.trade.protocol.trade.taker.models.TakerTradeProcessModel; import io.bitsquare.trade.protocol.trade.taker.models.TakerProcessModel;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.core.TransactionConfidence; import org.bitcoinj.core.TransactionConfidence;
@ -48,6 +48,7 @@ import org.slf4j.LoggerFactory;
public class TakerTrade extends Trade implements Serializable { public class TakerTrade extends Trade implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization. // That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
transient private static final Logger log = LoggerFactory.getLogger(TakerTrade.class); transient private static final Logger log = LoggerFactory.getLogger(TakerTrade.class);
@ -84,33 +85,55 @@ public class TakerTrade extends Trade implements Serializable {
// Fields // Fields
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@NotNull private final Coin tradeAmount; // Transient/Immutable
@NotNull private final Peer tradingPeer; transient private ObjectProperty<TakerProcessState> processStateProperty;
transient private ObjectProperty<TakerLifeCycleState> lifeCycleStateProperty;
@NotNull private TakerProcessState processState = TakerProcessState.UNDEFINED; // Immutable
@NotNull private TakerLifeCycleState lifeCycleState = TakerLifeCycleState.PENDING; private final Coin tradeAmount;
private final Peer tradingPeer;
@NotNull transient private ObjectProperty<TakerProcessState> processStateProperty = new SimpleObjectProperty<>(processState); // Mutable
@NotNull transient private ObjectProperty<TakerLifeCycleState> lifeCycleStateProperty = new SimpleObjectProperty<>(lifeCycleState); private TakerProcessState processState;
private TakerLifeCycleState lifeCycleState;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor // Constructor, initialization
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public TakerTrade(@NotNull Offer offer, @NotNull Coin tradeAmount, @NotNull Peer peer, public TakerTrade(Offer offer, Coin tradeAmount, Peer tradingPeer,
@NotNull Storage<? extends TradeProcessModel> storage) { Storage<? extends TradeList> storage) {
super(offer, storage); super(offer, storage);
log.trace("Created by constructor");
this.tradeAmount = tradeAmount; this.tradeAmount = tradeAmount;
this.tradingPeer = peer; this.tradingPeer = tradingPeer;
processState = TakerProcessState.UNDEFINED;
lifeCycleState = TakerLifeCycleState.PENDING;
processStateProperty = new SimpleObjectProperty<>(processState);
lifeCycleStateProperty = new SimpleObjectProperty<>(lifeCycleState);
tradeAmountProperty = new SimpleObjectProperty<>(tradeAmount); tradeAmountProperty = new SimpleObjectProperty<>(tradeAmount);
tradeVolumeProperty = new SimpleObjectProperty<>(getTradeVolume()); // cannot be set before offer is set tradeVolumeProperty = new SimpleObjectProperty<>(getTradeVolume());
} }
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
log.trace("Created from serialized form.");
processStateProperty = new SimpleObjectProperty<>(processState);
lifeCycleStateProperty = new SimpleObjectProperty<>(lifeCycleState);
tradeAmountProperty = new SimpleObjectProperty<>(tradeAmount);
tradeVolumeProperty = new SimpleObjectProperty<>(getTradeVolume());
}
@Override @Override
protected TradeProcessModel createProcessModel() { protected ProcessModel createProcessModel() {
return new TakerTradeProcessModel(); return new TakerProcessModel();
} }
@Override @Override
@ -118,21 +141,16 @@ public class TakerTrade extends Trade implements Serializable {
protocol = new TakerProtocol(this); protocol = new TakerProtocol(this);
} }
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
public void takeAvailableOffer() { public void takeAvailableOffer() {
assert processModel != null; assert processModel != null;
((TakerProtocol) protocol).takeAvailableOffer(); ((TakerProtocol) protocol).takeAvailableOffer();
} }
// Serialized object does not create our transient objects
private void readObject(@NotNull java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
processStateProperty = new SimpleObjectProperty<>(processState);
lifeCycleStateProperty = new SimpleObjectProperty<>(lifeCycleState);
tradeAmountProperty = new SimpleObjectProperty<>(tradeAmount);
tradeVolumeProperty = new SimpleObjectProperty<>(getTradeVolume());
}
public void onFiatPaymentReceived() { public void onFiatPaymentReceived() {
assert protocol != null; assert protocol != null;
((TakerProtocol) protocol).onFiatPaymentReceived(); ((TakerProtocol) protocol).onFiatPaymentReceived();
@ -140,53 +158,9 @@ public class TakerTrade extends Trade implements Serializable {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Setters // Getter only
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void setLifeCycleState(@NotNull TakerLifeCycleState lifeCycleState) {
this.lifeCycleState = lifeCycleState;
lifeCycleStateProperty.set(lifeCycleState);
}
public void setProcessState(@NotNull TakerProcessState processState) {
this.processState = processState;
processStateProperty.set(processState);
if (processState == TakerProcessState.EXCEPTION) {
setLifeCycleState(TakerLifeCycleState.FAILED);
disposeProtocol();
}
}
@Override
public void setThrowable(@NotNull Throwable throwable) {
super.setThrowable(throwable);
setProcessState(TakerTrade.TakerProcessState.EXCEPTION);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
@NotNull
public TakerTradeProcessModel getProcessModel() {
return (TakerTradeProcessModel) processModel;
}
@NotNull
@Override
public ReadOnlyObjectProperty<TakerProcessState> processStateProperty() {
return processStateProperty;
}
@NotNull
@Override
public ReadOnlyObjectProperty<TakerLifeCycleState> lifeCycleStateProperty() {
return lifeCycleStateProperty;
}
@NotNull
@Override @Override
public Coin getTradeAmount() { public Coin getTradeAmount() {
return tradeAmount; return tradeAmount;
@ -197,21 +171,57 @@ public class TakerTrade extends Trade implements Serializable {
return offer.getVolumeByAmount(tradeAmount); return offer.getVolumeByAmount(tradeAmount);
} }
@NotNull
@Override
public Peer getTradingPeer() { public Peer getTradingPeer() {
return tradingPeer; return tradingPeer;
} }
@Override
/////////////////////////////////////////////////////////////////////////////////////////// public ReadOnlyObjectProperty<TakerProcessState> processStateProperty() {
// Private return processStateProperty;
/////////////////////////////////////////////////////////////////////////////////////////// }
@Override @Override
protected void setConfidenceListener() { public ReadOnlyObjectProperty<TakerLifeCycleState> lifeCycleStateProperty() {
return lifeCycleStateProperty;
}
public TakerProcessModel getProcessModel() {
return (TakerProcessModel) processModel;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setter for Mutable objects
///////////////////////////////////////////////////////////////////////////////////////////
public void setLifeCycleState(TakerLifeCycleState lifeCycleState) {
this.lifeCycleState = lifeCycleState;
lifeCycleStateProperty.set(lifeCycleState);
}
public void setProcessState(TakerProcessState processState) {
this.processState = processState;
processStateProperty.set(processState);
if (processState == TakerProcessState.EXCEPTION) {
setLifeCycleState(TakerLifeCycleState.FAILED);
disposeProtocol();
}
}
@Override
public void setThrowable(Throwable throwable) {
super.setThrowable(throwable);
setProcessState(TakerTrade.TakerProcessState.EXCEPTION);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Protected
///////////////////////////////////////////////////////////////////////////////////////////
@Override
protected void setupConfidenceListener() {
assert depositTx != null; assert depositTx != null;
TransactionConfidence transactionConfidence = depositTx.getConfidence(); TransactionConfidence transactionConfidence = depositTx.getConfidence();
ListenableFuture<TransactionConfidence> future = transactionConfidence.getDepthFuture(1); ListenableFuture<TransactionConfidence> future = transactionConfidence.getDepthFuture(1);
@ -230,4 +240,14 @@ public class TakerTrade extends Trade implements Serializable {
} }
}); });
} }
@Override
public String toString() {
return "TakerTrade{" +
"tradeAmount=" + tradeAmount +
", tradingPeer=" + tradingPeer +
", processState=" + processState +
", lifeCycleState=" + lifeCycleState +
'}';
}
} }

View file

@ -25,18 +25,18 @@ import io.bitsquare.common.taskrunner.Model;
import io.bitsquare.crypto.SignatureService; import io.bitsquare.crypto.SignatureService;
import io.bitsquare.offer.Offer; import io.bitsquare.offer.Offer;
import io.bitsquare.p2p.MailboxMessage; import io.bitsquare.p2p.MailboxMessage;
import io.bitsquare.p2p.MailboxService;
import io.bitsquare.p2p.MessageService; import io.bitsquare.p2p.MessageService;
import io.bitsquare.p2p.Peer;
import io.bitsquare.storage.Storage; import io.bitsquare.storage.Storage;
import io.bitsquare.trade.protocol.Protocol; import io.bitsquare.trade.protocol.Protocol;
import io.bitsquare.trade.protocol.trade.TradeProcessModel; import io.bitsquare.trade.protocol.trade.ProcessModel;
import io.bitsquare.user.User; import io.bitsquare.user.User;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
import org.bitcoinj.utils.Fiat; import org.bitcoinj.utils.Fiat;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date; import java.util.Date;
@ -45,9 +45,6 @@ import javax.annotation.Nullable;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -60,7 +57,7 @@ abstract public class Trade extends Model implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization. // That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
transient protected static final Logger log = LoggerFactory.getLogger(Trade.class); private transient static final Logger log = LoggerFactory.getLogger(Trade.class);
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -78,53 +75,59 @@ abstract public class Trade extends Model implements Serializable {
// Fields // Fields
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Transient/Immutable
transient private Storage<? extends TradeList> storage;
transient protected Protocol protocol;
// Immutable
protected final Offer offer; protected final Offer offer;
@NotNull private final Date date; private final Date date;
@NotNull protected TradeProcessModel processModel = createProcessModel(); protected final ProcessModel processModel;
protected abstract TradeProcessModel createProcessModel(); // Mutable
private MailboxMessage mailboxMessage;
protected Transaction depositTx;
private Contract contract;
private String contractAsJson;
private String takerContractSignature;
private String offererContractSignature;
private Transaction payoutTx;
@NotNull transient protected Protocol protocol; // Transient/Mutable
transient private String errorMessage;
@Nullable MailboxMessage mailboxMessage; transient private Throwable throwable;
@Nullable Transaction depositTx; transient protected ObjectProperty<Coin> tradeAmountProperty;
@Nullable private Transaction payoutTx; transient protected ObjectProperty<Fiat> tradeVolumeProperty;
@Nullable private Contract contract;
@Nullable private String contractAsJson;
@Nullable private String takerContractSignature;
@Nullable private String offererContractSignature;
@NotNull transient private Storage<? extends TradeProcessModel> storage;
@Nullable private transient String errorMessage;
@Nullable private transient Throwable throwable;
@NotNull transient ObjectProperty<Coin> tradeAmountProperty = new SimpleObjectProperty<>();
@NotNull transient ObjectProperty<Fiat> tradeVolumeProperty = new SimpleObjectProperty<>();
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor // Constructor, initialization
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
Trade(Offer offer, @NotNull Storage<? extends TradeProcessModel> storage) { Trade(Offer offer, Storage<? extends TradeList> storage) {
log.trace("Created by constructor");
this.offer = offer; this.offer = offer;
this.storage = storage; this.storage = storage;
date = new Date(); date = new Date();
processModel = createProcessModel();
} }
public void initProcessModel(@NotNull MessageService messageService, private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
@NotNull MailboxService mailboxService, in.defaultReadObject();
@NotNull WalletService walletService, log.trace("Created from serialized form.");
@NotNull TradeWalletService tradeWalletService, }
@NotNull BlockChainService blockChainService,
@NotNull SignatureService signatureService,
@NotNull ArbitrationRepository arbitrationRepository,
@NotNull User user) {
processModel.init(offer, public void init(MessageService messageService,
WalletService walletService,
TradeWalletService tradeWalletService,
BlockChainService blockChainService,
SignatureService signatureService,
ArbitrationRepository arbitrationRepository,
User user) {
processModel.onAllServicesInitialized(offer,
messageService, messageService,
mailboxService,
walletService, walletService,
tradeWalletService, tradeWalletService,
blockChainService, blockChainService,
@ -138,20 +141,28 @@ abstract public class Trade extends Model implements Serializable {
protocol.setMailboxMessage(mailboxMessage); protocol.setMailboxMessage(mailboxMessage);
} }
public void setStorage(Storage<? extends TradeList> storage) {
this.storage = storage;
}
abstract protected ProcessModel createProcessModel();
abstract protected void createProtocol();
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// API // API
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// The deserialized tx has not actual confidence data, so we need to get the fresh one from the wallet. // The deserialized tx has not actual confidence data, so we need to get the fresh one from the wallet.
public void syncDepositTxWithWallet(@NotNull TradeWalletService tradeWalletService) { public void updateDepositTxFromWallet(TradeWalletService tradeWalletService) {
if (depositTx != null) if (depositTx != null)
setDepositTx(tradeWalletService.commitsDepositTx(depositTx)); setDepositTx(tradeWalletService.getWalletTx(depositTx));
} }
public void setDepositTx(@NotNull Transaction tx) { public void setDepositTx(Transaction tx) {
this.depositTx = tx; this.depositTx = tx;
setConfidenceListener(); setupConfidenceListener();
} }
public void disposeProtocol() { public void disposeProtocol() {
@ -161,15 +172,15 @@ abstract public class Trade extends Model implements Serializable {
} }
} }
public void setMailboxMessage(@NotNull MailboxMessage mailboxMessage) { public void setMailboxMessage(MailboxMessage mailboxMessage) {
this.mailboxMessage = mailboxMessage; this.mailboxMessage = mailboxMessage;
assert protocol != null; if (protocol != null)
protocol.setMailboxMessage(mailboxMessage); protocol.setMailboxMessage(mailboxMessage);
storage.queueUpForSave();
} }
public void setStorage(@NotNull Storage<? extends TradeProcessModel> storage) { protected abstract void setupConfidenceListener();
this.storage = storage;
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -187,72 +198,13 @@ abstract public class Trade extends Model implements Serializable {
storage.queueUpForSave(); storage.queueUpForSave();
} }
///////////////////////////////////////////////////////////////////////////////////////////
// Setters
///////////////////////////////////////////////////////////////////////////////////////////
protected abstract void setConfidenceListener();
public void setTakerContractSignature(@NotNull String takerSignature) {
this.takerContractSignature = takerSignature;
}
public void setOffererContractSignature(@NotNull String offererContractSignature) {
this.offererContractSignature = offererContractSignature;
}
public void setContractAsJson(@NotNull String contractAsJson) {
this.contractAsJson = contractAsJson;
}
public void setContract(@NotNull Contract contract) {
this.contract = contract;
}
public void setPayoutTx(@NotNull Transaction tx) {
this.payoutTx = tx;
}
public void setErrorMessage(@NotNull String errorMessage) {
this.errorMessage = errorMessage;
}
public void setThrowable(@NotNull Throwable throwable) {
this.throwable = throwable;
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Getters // Getter only
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Nullable public Date getDate() {
public String getTakerContractSignature() { return date;
return takerContractSignature;
}
@Nullable
public String getOffererContractSignature() {
return offererContractSignature;
}
@Nullable
public Transaction getDepositTx() {
return depositTx;
}
@Nullable
public Transaction getPayoutTx() {
return payoutTx;
}
@Nullable
public Contract getContract() {
return contract;
}
public Coin getSecurityDeposit() {
return offer.getSecurityDeposit();
} }
public String getId() { public String getId() {
@ -263,14 +215,86 @@ abstract public class Trade extends Model implements Serializable {
return offer; return offer;
} }
@Nullable
public Transaction getDepositTx() {
return depositTx;
}
public Coin getSecurityDeposit() {
return offer.getSecurityDeposit();
}
public ReadOnlyObjectProperty<Coin> tradeAmountProperty() {
return tradeAmountProperty;
}
public ReadOnlyObjectProperty<Fiat> tradeVolumeProperty() {
return tradeVolumeProperty;
}
@Nullable
abstract public Coin getTradeAmount();
@Nullable
abstract public Fiat getTradeVolume();
abstract public ReadOnlyObjectProperty<? extends ProcessState> processStateProperty();
abstract public ReadOnlyObjectProperty<? extends LifeCycleState> lifeCycleStateProperty();
///////////////////////////////////////////////////////////////////////////////////////////
// Getter/Setter for Mutable objects
///////////////////////////////////////////////////////////////////////////////////////////
public void setTakerContractSignature(String takerSignature) {
this.takerContractSignature = takerSignature;
}
@Nullable
public String getTakerContractSignature() {
return takerContractSignature;
}
public void setOffererContractSignature(String offererContractSignature) {
this.offererContractSignature = offererContractSignature;
}
@Nullable
public String getOffererContractSignature() {
return offererContractSignature;
}
public void setContractAsJson(String contractAsJson) {
this.contractAsJson = contractAsJson;
}
@Nullable @Nullable
public String getContractAsJson() { public String getContractAsJson() {
return contractAsJson; return contractAsJson;
} }
@NotNull public void setContract(Contract contract) {
public Date getDate() { this.contract = contract;
return date; }
@Nullable
public Contract getContract() {
return contract;
}
public void setPayoutTx(Transaction payoutTx) {
this.payoutTx = payoutTx;
}
// Not used now, but will be used in some reporting UI
public Transaction getPayoutTx() {
return payoutTx;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
} }
@Nullable @Nullable
@ -278,53 +302,30 @@ abstract public class Trade extends Model implements Serializable {
return errorMessage; return errorMessage;
} }
public void setThrowable(Throwable throwable) {
this.throwable = throwable;
}
@Nullable @Nullable
public Throwable getThrowable() { public Throwable getThrowable() {
return throwable; return throwable;
} }
@NotNull
public ReadOnlyObjectProperty<Coin> tradeAmountProperty() {
return tradeAmountProperty;
}
@NotNull
public ReadOnlyObjectProperty<Fiat> tradeVolumeProperty() {
return tradeVolumeProperty;
}
abstract void createProtocol();
@NotNull
public abstract ReadOnlyObjectProperty<? extends ProcessState> processStateProperty();
@NotNull
public abstract ReadOnlyObjectProperty<? extends LifeCycleState> lifeCycleStateProperty();
@org.jetbrains.annotations.Nullable
public abstract Coin getTradeAmount();
@org.jetbrains.annotations.Nullable
public abstract Fiat getTradeVolume();
@org.jetbrains.annotations.Nullable
public abstract Peer getTradingPeer();
@NotNull
@Override @Override
public String toString() { public String toString() {
return "Trade{" + return "Trade{" +
"protocol=" + protocol + "throwable=" + throwable +
", mailboxMessage=" + mailboxMessage +
", offer=" + offer + ", offer=" + offer +
", date=" + date + ", date=" + date +
", mailboxMessage=" + mailboxMessage +
", depositTx=" + depositTx +
", contract=" + contract + ", contract=" + contract +
", contractAsJson='" + contractAsJson + '\'' + ", contractAsJson='" + contractAsJson + '\'' +
", takerContractSignature='" + takerContractSignature + '\'' + ", takerContractSignature='" + takerContractSignature + '\'' +
", offererContractSignature='" + offererContractSignature + '\'' + ", offererContractSignature='" + offererContractSignature + '\'' +
", depositTx=" + depositTx + ", errorMessage='" + errorMessage + '\'' +
", payoutTx=" + payoutTx + ", processModel=" + processModel +
'}'; '}';
} }
} }

View file

@ -19,6 +19,8 @@ package io.bitsquare.trade;
import io.bitsquare.storage.Storage; import io.bitsquare.storage.Storage;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
@ -36,6 +38,7 @@ public class TradeList<T> extends ArrayList<T> implements Serializable {
transient private static final Logger log = LoggerFactory.getLogger(TradeList.class); transient private static final Logger log = LoggerFactory.getLogger(TradeList.class);
transient final private Storage<TradeList> storage; transient final private Storage<TradeList> storage;
// Use getObservableList() also class locally, to be sure that object exists in case we use the object as deserialized form
transient private ObservableList<T> observableList; transient private ObservableList<T> observableList;
// Superclass is ArrayList, which will be persisted // Superclass is ArrayList, which will be persisted
@ -45,6 +48,7 @@ public class TradeList<T> extends ArrayList<T> implements Serializable {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public TradeList(Storage<TradeList> storage, String fileName) { public TradeList(Storage<TradeList> storage, String fileName) {
log.trace("Created by constructor");
this.storage = storage; this.storage = storage;
TradeList persisted = storage.initAndGetPersisted(this, fileName); TradeList persisted = storage.initAndGetPersisted(this, fileName);
@ -54,10 +58,15 @@ public class TradeList<T> extends ArrayList<T> implements Serializable {
observableList = FXCollections.observableArrayList(this); observableList = FXCollections.observableArrayList(this);
} }
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
log.trace("Created from serialized form.");
}
@Override @Override
public boolean add(T trade) { public boolean add(T trade) {
boolean result = super.add(trade); boolean result = super.add(trade);
observableList.add(trade); getObservableList().add(trade);
storage.queueUpForSave(); storage.queueUpForSave();
return result; return result;
} }
@ -65,12 +74,14 @@ public class TradeList<T> extends ArrayList<T> implements Serializable {
@Override @Override
public boolean remove(Object trade) { public boolean remove(Object trade) {
boolean result = super.remove(trade); boolean result = super.remove(trade);
observableList.remove(trade); getObservableList().remove(trade);
storage.queueUpForSave(); storage.queueUpForSave();
return result; return result;
} }
public ObservableList<T> getObservableList() { public ObservableList<T> getObservableList() {
if (observableList == null)
observableList = FXCollections.observableArrayList(this);
return observableList; return observableList;
} }

View file

@ -35,7 +35,6 @@ import io.bitsquare.p2p.EncryptedMailboxMessage;
import io.bitsquare.p2p.MailboxMessage; import io.bitsquare.p2p.MailboxMessage;
import io.bitsquare.p2p.MailboxService; import io.bitsquare.p2p.MailboxService;
import io.bitsquare.p2p.MessageService; import io.bitsquare.p2p.MessageService;
import io.bitsquare.p2p.Peer;
import io.bitsquare.storage.Storage; import io.bitsquare.storage.Storage;
import io.bitsquare.trade.handlers.TakeOfferResultHandler; import io.bitsquare.trade.handlers.TakeOfferResultHandler;
import io.bitsquare.trade.handlers.TransactionResultHandler; import io.bitsquare.trade.handlers.TransactionResultHandler;
@ -89,8 +88,8 @@ public class TradeManager {
private final ArbitrationRepository arbitrationRepository; private final ArbitrationRepository arbitrationRepository;
private final Map<String, CheckOfferAvailabilityProtocol> checkOfferAvailabilityProtocolMap = new HashMap<>(); private final Map<String, CheckOfferAvailabilityProtocol> checkOfferAvailabilityProtocolMap = new HashMap<>();
private final Storage pendingTradesStorage; private final Storage<TradeList> pendingTradesStorage;
private final Storage openOfferTradesStorage; private final Storage<TradeList> openOfferTradesStorage;
private final TradeList<OffererTrade> openOfferTrades; private final TradeList<OffererTrade> openOfferTrades;
private final TradeList<Trade> pendingTrades; private final TradeList<Trade> pendingTrades;
private final TradeList<Trade> closedTrades; private final TradeList<Trade> closedTrades;
@ -129,12 +128,12 @@ public class TradeManager {
this.offerBookService = offerBookService; this.offerBookService = offerBookService;
this.arbitrationRepository = arbitrationRepository; this.arbitrationRepository = arbitrationRepository;
openOfferTradesStorage = new Storage(storageDir); openOfferTradesStorage = new Storage<>(storageDir);
pendingTradesStorage = new Storage(storageDir); pendingTradesStorage = new Storage<>(storageDir);
this.openOfferTrades = new TradeList<>(openOfferTradesStorage, "OpenOfferTrades"); this.openOfferTrades = new TradeList<>(openOfferTradesStorage, "OpenOfferTrades");
this.pendingTrades = new TradeList<>(pendingTradesStorage, "PendingTrades"); this.pendingTrades = new TradeList<>(pendingTradesStorage, "PendingTrades");
this.closedTrades = new TradeList<>(new Storage(storageDir), "ClosedTrades"); this.closedTrades = new TradeList<>(new Storage<>(storageDir), "ClosedTrades");
// In case the app did get killed the shutDown from the modules is not called, so we use a shutdown hook // In case the app did get killed the shutDown from the modules is not called, so we use a shutdown hook
@ -144,9 +143,66 @@ public class TradeManager {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Public API // Lifecycle
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// When all services are initialized we create the protocols for our open offers and persisted pendingTrades
// OffererAsBuyerProtocol listens for take offer requests, so we need to instantiate it early.
public void onAllServicesInitialized() {
for (OffererTrade offererTrade : openOfferTrades) {
Offer offer = offererTrade.getOffer();
// We add own offers to offerbook when we go online again
offerBookService.addOffer(offer,
() -> log.debug("Successful removed open offer from DHT"),
(message, throwable) -> log.error("Remove open offer from DHT failed. " + message));
offererTrade.setStorage(openOfferTradesStorage);
initTrade(offererTrade);
}
for (Trade trade : pendingTrades) {
// We continue an interrupted trade.
// TODO if the peer has changed its IP address, we need to make another findPeer request. At the moment we use the peer stored in trade to
// continue the trade, but that might fail.
initTrade(trade);
trade.updateDepositTxFromWallet(tradeWalletService);
trade.setStorage(pendingTradesStorage);
}
// if there are messages in our mailbox we apply it and remove them from the DHT
mailboxService.getAllMessages(user.getP2PSigPubKey(),
(encryptedMailboxMessages) -> {
setMailboxMessagesToTrades(encryptedMailboxMessages);
emptyMailbox();
});
}
private void setMailboxMessagesToTrades(List<EncryptedMailboxMessage> encryptedMailboxMessages) {
log.trace("applyMailboxMessage encryptedMailboxMessage.size=" + encryptedMailboxMessages.size());
for (EncryptedMailboxMessage encrypted : encryptedMailboxMessages) {
try {
MailboxMessage mailboxMessage = encryptionService.decryptToObject(user.getP2pEncryptPrivateKey(), encrypted.getBucket());
if (mailboxMessage instanceof TradeMessage) {
String tradeId = ((TradeMessage) mailboxMessage).tradeId;
Optional<Trade> tradeOptional = pendingTrades.stream().filter(e -> e.getId().equals(tradeId)).findAny();
if (tradeOptional.isPresent())
tradeOptional.get().setMailboxMessage(mailboxMessage);
}
} catch (Throwable e) {
e.printStackTrace();
log.error(e.getMessage());
}
}
}
private void emptyMailbox() {
mailboxService.removeAllMessages(user.getP2PSigPubKey(),
() -> log.debug("All mailbox entries removed"),
(errorMessage, fault) -> {
log.error(errorMessage);
log.error(fault.getMessage());
});
}
public void shutDown() { public void shutDown() {
if (!shutDownRequested) { if (!shutDownRequested) {
@ -160,50 +216,6 @@ public class TradeManager {
} }
} }
// When all services are initialized we create the protocols for our open offers and persisted not completed pendingTrades
// OffererAsBuyerProtocol listens for take offer requests, so we need to instantiate it early.
public void onAllServicesInitialized() {
for (OffererTrade offererTrade : openOfferTrades) {
Offer offer = offererTrade.getOffer();
// we add own offers to offerbook when we go online again
offerBookService.addOffer(offer,
() -> log.debug("Successful removed open offer from DHT"),
(message, throwable) -> log.error("Remove open offer from DHT failed. " + message));
offererTrade.setStorage(openOfferTradesStorage);
offererTrade.initProcessModel(messageService,
mailboxService,
walletService,
tradeWalletService,
blockChainService,
signatureService,
arbitrationRepository,
user);
}
for (Trade trade : pendingTrades) {
// We continue an interrupted trade.
// TODO if the peer has changed its IP address, we need to make another findPeer request. At the moment we use the peer stored in trade to
// continue the trade, but that might fail.
trade.initProcessModel(messageService,
mailboxService,
walletService,
tradeWalletService,
blockChainService,
signatureService,
arbitrationRepository,
user);
trade.syncDepositTxWithWallet(tradeWalletService);
trade.setStorage(pendingTradesStorage);
}
mailboxService.getAllMessages(user.getP2PSigPubKey(),
(encryptedMailboxMessages) -> {
decryptMailboxMessages(encryptedMailboxMessages);
emptyMailbox();
});
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Offer // Offer
@ -217,17 +229,17 @@ public class TradeManager {
TransactionResultHandler resultHandler, TransactionResultHandler resultHandler,
ErrorMessageHandler errorMessageHandler) { ErrorMessageHandler errorMessageHandler) {
FiatAccount currentFiatAccount = user.currentFiatAccountProperty().get(); FiatAccount fiatAccount = user.currentFiatAccountProperty().get();
Offer offer = new Offer(id, Offer offer = new Offer(id,
user.getP2PSigPubKey(), user.getP2PSigPubKey(),
direction, direction,
price.getValue(), price.getValue(),
amount, amount,
minAmount, minAmount,
currentFiatAccount.type, fiatAccount.type,
currentFiatAccount.currencyCode, fiatAccount.currencyCode,
currentFiatAccount.country, fiatAccount.country,
currentFiatAccount.id, fiatAccount.id,
accountSettings.getAcceptedArbitratorIds(), accountSettings.getAcceptedArbitratorIds(),
accountSettings.getSecurityDeposit(), accountSettings.getSecurityDeposit(),
accountSettings.getAcceptedCountries(), accountSettings.getAcceptedCountries(),
@ -237,24 +249,24 @@ public class TradeManager {
PlaceOfferProtocol placeOfferProtocol = new PlaceOfferProtocol( PlaceOfferProtocol placeOfferProtocol = new PlaceOfferProtocol(
model, model,
(transaction) -> { transaction -> handlePlaceOfferResult(transaction, offer, resultHandler),
errorMessageHandler::handleErrorMessage
);
placeOfferProtocol.placeOffer();
}
private void handlePlaceOfferResult(Transaction transaction, Offer offer, TransactionResultHandler resultHandler) {
OffererTrade offererTrade = new OffererTrade(offer, openOfferTradesStorage); OffererTrade offererTrade = new OffererTrade(offer, openOfferTradesStorage);
openOfferTrades.add(offererTrade); openOfferTrades.add(offererTrade);
offererTrade.initProcessModel(messageService, initTrade(offererTrade);
mailboxService,
walletService,
tradeWalletService,
blockChainService,
signatureService,
arbitrationRepository,
user);
offererTrade.processStateProperty().addListener((ov, oldValue, newValue) -> { offererTrade.processStateProperty().addListener((ov, oldValue, newValue) -> {
log.debug("offererTrade state = " + newValue); log.debug("offererTrade state = " + newValue);
if (newValue == OffererTrade.OffererProcessState.DEPOSIT_PUBLISHED) { if (newValue == OffererTrade.OffererProcessState.DEPOSIT_PUBLISHED) {
removeOpenOffer(offererTrade.getOffer(), removeOpenOffer(offererTrade.getOffer(),
() -> log.debug("remove offer was successful"), () -> log.debug("remove offer was successful"),
(message) -> log.error(message), log::error,
false); false);
pendingTrades.add(offererTrade); pendingTrades.add(offererTrade);
offererTrade.setStorage(pendingTradesStorage); offererTrade.setStorage(pendingTradesStorage);
@ -262,17 +274,38 @@ public class TradeManager {
}); });
resultHandler.handleResult(transaction); resultHandler.handleResult(transaction);
},
(message) -> errorMessageHandler.handleErrorMessage(message)
);
placeOfferProtocol.placeOffer();
} }
public void cancelOpenOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { public void cancelOpenOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
removeOpenOffer(offer, resultHandler, errorMessageHandler, true); removeOpenOffer(offer, resultHandler, errorMessageHandler, true);
} }
private void removeOpenOffer(Offer offer,
ResultHandler resultHandler,
ErrorMessageHandler errorMessageHandler,
boolean isCancelRequest) {
offerBookService.removeOffer(offer,
() -> {
offer.setState(Offer.State.REMOVED);
Optional<OffererTrade> offererTradeOptional = openOfferTrades.stream().filter(e -> e.getId().equals(offer.getId())).findAny();
if (offererTradeOptional.isPresent()) {
OffererTrade offererTrade = offererTradeOptional.get();
openOfferTrades.remove(offererTrade);
if (isCancelRequest) {
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.OFFER_CANCELED);
closedTrades.add(offererTrade);
offererTrade.disposeProtocol();
}
}
disposeCheckOfferAvailabilityRequest(offer);
resultHandler.handleResult();
},
(message, throwable) -> errorMessageHandler.handleErrorMessage(message));
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Take offer // Take offer
@ -305,18 +338,24 @@ public class TradeManager {
public void requestTakeOffer(Coin amount, Offer offer, TakeOfferResultHandler takeOfferResultHandler) { public void requestTakeOffer(Coin amount, Offer offer, TakeOfferResultHandler takeOfferResultHandler) {
CheckOfferAvailabilityModel model = new CheckOfferAvailabilityModel(offer, messageService, addressService); CheckOfferAvailabilityModel model = new CheckOfferAvailabilityModel(offer, messageService, addressService);
CheckOfferAvailabilityProtocol availabilityProtocol = new CheckOfferAvailabilityProtocol(model, CheckOfferAvailabilityProtocol availabilityProtocol = new CheckOfferAvailabilityProtocol(model,
() -> { () -> handleCheckOfferAvailabilityResult(amount, offer, model, takeOfferResultHandler),
disposeCheckOfferAvailabilityRequest(offer);
if (offer.getState() == Offer.State.AVAILABLE) {
TakerTrade trade = takeAvailableOffer(amount, offer, model.getPeer());
takeOfferResultHandler.handleResult(trade);
}
},
(errorMessage) -> disposeCheckOfferAvailabilityRequest(offer)); (errorMessage) -> disposeCheckOfferAvailabilityRequest(offer));
checkOfferAvailabilityProtocolMap.put(offer.getId(), availabilityProtocol); checkOfferAvailabilityProtocolMap.put(offer.getId(), availabilityProtocol);
availabilityProtocol.checkOfferAvailability(); availabilityProtocol.checkOfferAvailability();
} }
private void handleCheckOfferAvailabilityResult(Coin amount, Offer offer, CheckOfferAvailabilityModel model, TakeOfferResultHandler
takeOfferResultHandler) {
disposeCheckOfferAvailabilityRequest(offer);
if (offer.getState() == Offer.State.AVAILABLE) {
TakerTrade takerTrade = new TakerTrade(offer, amount, model.getPeer(), pendingTradesStorage);
initTrade(takerTrade);
pendingTrades.add(takerTrade);
takerTrade.takeAvailableOffer();
takeOfferResultHandler.handleResult(takerTrade);
}
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Trade // Trade
@ -328,8 +367,9 @@ public class TradeManager {
// TODO handle overpaid securityDeposit // TODO handle overpaid securityDeposit
Coin amountToWithdraw = trade.getSecurityDeposit(); Coin amountToWithdraw = trade.getSecurityDeposit();
assert trade.getTradeAmount() != null;
if (trade instanceof OffererTrade) if (trade instanceof OffererTrade)
amountToWithdraw = amountToWithdraw.add(((OffererTrade) trade).getTradeAmount()); amountToWithdraw = amountToWithdraw.add(trade.getTradeAmount());
FutureCallback<Transaction> callback = new FutureCallback<Transaction>() { FutureCallback<Transaction> callback = new FutureCallback<Transaction>() {
@Override @Override
@ -392,35 +432,9 @@ public class TradeManager {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Private methods // Misc
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private void removeOpenOffer(Offer offer,
ResultHandler resultHandler,
ErrorMessageHandler errorMessageHandler,
boolean isCancelRequest) {
offerBookService.removeOffer(offer,
() -> {
offer.setState(Offer.State.REMOVED);
Optional<OffererTrade> offererTradeOptional = openOfferTrades.stream().filter(e -> e.getId().equals(offer.getId())).findAny();
if (offererTradeOptional.isPresent()) {
OffererTrade offererTrade = offererTradeOptional.get();
openOfferTrades.remove(offererTrade);
if (isCancelRequest) {
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.OFFER_CANCELED);
closedTrades.add(offererTrade);
offererTrade.disposeProtocol();
}
}
disposeCheckOfferAvailabilityRequest(offer);
resultHandler.handleResult();
},
(message, throwable) -> errorMessageHandler.handleErrorMessage(message));
}
private void disposeCheckOfferAvailabilityRequest(Offer offer) { private void disposeCheckOfferAvailabilityRequest(Offer offer) {
if (checkOfferAvailabilityProtocolMap.containsKey(offer.getId())) { if (checkOfferAvailabilityProtocolMap.containsKey(offer.getId())) {
CheckOfferAvailabilityProtocol protocol = checkOfferAvailabilityProtocolMap.get(offer.getId()); CheckOfferAvailabilityProtocol protocol = checkOfferAvailabilityProtocolMap.get(offer.getId());
@ -429,57 +443,14 @@ public class TradeManager {
} }
} }
private void initTrade(Trade trade) {
/////////////////////////////////////////////////////////////////////////////////////////// trade.init(messageService,
// Trade
///////////////////////////////////////////////////////////////////////////////////////////
private TakerTrade takeAvailableOffer(Coin amount, Offer offer, Peer peer) {
TakerTrade takerTrade = new TakerTrade(offer, amount, peer, pendingTradesStorage);
takerTrade.initProcessModel(messageService,
mailboxService,
walletService, walletService,
tradeWalletService, tradeWalletService,
blockChainService, blockChainService,
signatureService, signatureService,
arbitrationRepository, arbitrationRepository,
user); user);
pendingTrades.add(takerTrade);
takerTrade.takeAvailableOffer();
return takerTrade;
} }
///////////////////////////////////////////////////////////////////////////////////////////
// Mailbox
///////////////////////////////////////////////////////////////////////////////////////////
private void decryptMailboxMessages(List<EncryptedMailboxMessage> encryptedMailboxMessages) {
log.trace("applyMailboxMessage encryptedMailboxMessage.size=" + encryptedMailboxMessages.size());
for (EncryptedMailboxMessage encrypted : encryptedMailboxMessages) {
try {
MailboxMessage mailboxMessage = encryptionService.decryptToObject(user.getP2pEncryptPrivateKey(), encrypted.getBucket());
if (mailboxMessage instanceof TradeMessage) {
String tradeId = ((TradeMessage) mailboxMessage).tradeId;
Optional<Trade> tradeOptional = pendingTrades.stream().filter(e -> e.getId().equals(tradeId)).findAny();
if (tradeOptional.isPresent())
tradeOptional.get().setMailboxMessage(mailboxMessage);
}
} catch (Throwable e) {
e.printStackTrace();
log.error(e.getMessage());
}
}
}
private void emptyMailbox() {
mailboxService.removeAllMessages(user.getP2PSigPubKey(),
() -> {
log.debug("All mailbox entries removed");
},
(errorMessage, fault) -> {
log.error(errorMessage);
log.error(fault.getMessage());
});
}
} }

View file

@ -42,7 +42,6 @@ public class TradeModule extends BitsquareModule {
@Override @Override
protected void doClose(Injector injector) { protected void doClose(Injector injector) {
log.trace("doClose " + getClass().getSimpleName()); log.trace("doClose " + getClass().getSimpleName());
// First shut down AddressService to remove address from DHT
injector.getInstance(TradeManager.class).shutDown(); injector.getInstance(TradeManager.class).shutDown();
} }
} }

View file

@ -1,25 +0,0 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.handlers;
import io.bitsquare.offer.Offer;
public interface OfferStateResultHandler {
void handleStateResult(Offer.State state);
}

View file

@ -55,7 +55,7 @@ public class CheckOfferAvailabilityProtocol {
messageHandler = this::handleMessage; messageHandler = this::handleMessage;
} }
public void cleanup() { private void cleanup() {
model.messageService.removeMessageHandler(messageHandler); model.messageService.removeMessageHandler(messageHandler);
} }
@ -71,12 +71,8 @@ public class CheckOfferAvailabilityProtocol {
model.messageService.addMessageHandler(messageHandler); model.messageService.addMessageHandler(messageHandler);
taskRunner = new TaskRunner<>(model, taskRunner = new TaskRunner<>(model,
() -> { () -> log.debug("sequence at onCheckOfferAvailability completed"),
log.debug("sequence at onCheckOfferAvailability completed"); log::error
},
(errorMessage) -> {
log.error(errorMessage);
}
); );
taskRunner.addTasks( taskRunner.addTasks(
GetPeerAddress.class, GetPeerAddress.class,
@ -96,7 +92,7 @@ public class CheckOfferAvailabilityProtocol {
// Incoming message handling // Incoming message handling
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private void handleMessage(Message message, Peer sender) { private void handleMessage(Message message, @SuppressWarnings("UnusedParameters") Peer sender) {
if (!isCanceled) { if (!isCanceled) {
if (message instanceof ReportOfferAvailabilityMessage && model.offer.getId().equals(((ReportOfferAvailabilityMessage) message).offerId)) if (message instanceof ReportOfferAvailabilityMessage && model.offer.getId().equals(((ReportOfferAvailabilityMessage) message).offerId))
handleReportOfferAvailabilityMessage((ReportOfferAvailabilityMessage) message); handleReportOfferAvailabilityMessage((ReportOfferAvailabilityMessage) message);

View file

@ -33,7 +33,7 @@ public class PlaceOfferModel extends Model {
public final Offer offer; public final Offer offer;
public final WalletService walletService; public final WalletService walletService;
public TradeWalletService tradeWalletService; public final TradeWalletService tradeWalletService;
public final OfferBookService offerBookService; public final OfferBookService offerBookService;
private Transaction transaction; private Transaction transaction;

View file

@ -35,11 +35,7 @@ public class AddOfferToRemoteOfferBook extends Task<PlaceOfferModel> {
@Override @Override
protected void doRun() { protected void doRun() {
model.offerBookService.addOffer(model.offer, model.offerBookService.addOffer(model.offer,
() -> { this::complete,
complete(); (message, throwable) -> failed(throwable));
},
(message, throwable) -> {
failed(throwable);
});
} }
} }

View file

@ -72,9 +72,7 @@ public class BroadcastCreateOfferFeeTx extends Task<PlaceOfferModel> {
// We store now the changed txID to the offer and add that again. // We store now the changed txID to the offer and add that again.
model.offer.setOfferFeePaymentTxID(transaction.getHashAsString()); model.offer.setOfferFeePaymentTxID(transaction.getHashAsString());
model.offerBookService.addOffer(model.offer, model.offerBookService.addOffer(model.offer,
() -> { BroadcastCreateOfferFeeTx.this::complete,
complete();
},
(message, throwable) -> { (message, throwable) -> {
log.error("addOffer failed"); log.error("addOffer failed");
addOfferFailed = true; addOfferFailed = true;
@ -108,9 +106,7 @@ public class BroadcastCreateOfferFeeTx extends Task<PlaceOfferModel> {
if (!removeOfferFailed && !addOfferFailed) { if (!removeOfferFailed && !addOfferFailed) {
// If broadcast fails we need to remove offer from offerbook // If broadcast fails we need to remove offer from offerbook
model.offerBookService.removeOffer(model.offer, model.offerBookService.removeOffer(model.offer,
() -> { () -> log.info("Offer removed from offerbook because broadcast failed."),
log.info("Offer removed from offerbook because broadcast failed.");
},
(message, throwable) -> { (message, throwable) -> {
log.error("removeOffer failed"); log.error("removeOffer failed");
failed(throwable); failed(throwable);

View file

@ -0,0 +1,154 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade;
import io.bitsquare.arbitration.ArbitrationRepository;
import io.bitsquare.btc.BlockChainService;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.common.taskrunner.Model;
import io.bitsquare.crypto.SignatureService;
import io.bitsquare.offer.Offer;
import io.bitsquare.p2p.MailboxMessage;
import io.bitsquare.p2p.MessageService;
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
import io.bitsquare.user.User;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ProcessModel extends Model implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = 1L;
private static final Logger log = LoggerFactory.getLogger(ProcessModel.class);
// Transient/Immutable
transient private MessageService messageService;
transient private WalletService walletService;
transient private TradeWalletService tradeWalletService;
transient private BlockChainService blockChainService;
transient private SignatureService signatureService;
transient private ArbitrationRepository arbitrationRepository;
transient private Offer offer;
// Mutable
transient private MailboxMessage mailboxMessage;
transient private TradeMessage tradeMessage;
protected ProcessModel() {
log.trace("Created by constructor");
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
log.trace("Created from serialized form.");
}
public void onAllServicesInitialized(Offer offer,
MessageService messageService,
WalletService walletService,
TradeWalletService tradeWalletService,
BlockChainService blockChainService,
SignatureService signatureService,
ArbitrationRepository arbitrationRepository,
User user) {
this.offer = offer;
this.messageService = messageService;
this.walletService = walletService;
this.tradeWalletService = tradeWalletService;
this.blockChainService = blockChainService;
this.signatureService = signatureService;
this.arbitrationRepository = arbitrationRepository;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getter only
///////////////////////////////////////////////////////////////////////////////////////////
public MessageService getMessageService() {
return messageService;
}
public WalletService getWalletService() {
return walletService;
}
public TradeWalletService getTradeWalletService() {
return tradeWalletService;
}
public BlockChainService getBlockChainService() {
return blockChainService;
}
public SignatureService getSignatureService() {
return signatureService;
}
public byte[] getArbitratorPubKey() {
return arbitrationRepository.getDefaultArbitrator().getPubKey();
}
public Offer getOffer() {
return offer;
}
public String getId() {
return offer.getId();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getter/Setter for Mutable objects
///////////////////////////////////////////////////////////////////////////////////////////
public void setTradeMessage(TradeMessage tradeMessage) {
this.tradeMessage = tradeMessage;
}
@Nullable
public TradeMessage getTradeMessage() {
return tradeMessage;
}
public void setMailboxMessage(MailboxMessage mailboxMessage) {
this.mailboxMessage = mailboxMessage;
}
@Nullable
public MailboxMessage getMailboxMessage() {
return mailboxMessage;
}
@Override
public String toString() {
return "ProcessModel{" +
"offer=" + offer +
'}';
}
}

View file

@ -1,106 +0,0 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade;
import io.bitsquare.arbitration.ArbitrationRepository;
import io.bitsquare.btc.BlockChainService;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.common.taskrunner.Model;
import io.bitsquare.crypto.SignatureService;
import io.bitsquare.offer.Offer;
import io.bitsquare.p2p.MailboxMessage;
import io.bitsquare.p2p.MailboxService;
import io.bitsquare.p2p.MessageService;
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
import io.bitsquare.user.User;
import java.io.Serializable;
import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TradeProcessModel extends Model implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = 1L;
protected static final Logger log = LoggerFactory.getLogger(TradeProcessModel.class);
// those fields are re-assigned in case of deserialized object after backend is ready.
// Therefore they are not final but annotated with @NotNull
@NotNull transient public MessageService messageService;
@NotNull transient public MailboxService mailboxService;
@NotNull transient public WalletService walletService;
@NotNull transient public TradeWalletService tradeWalletService;
@NotNull transient public BlockChainService blockChainService;
@NotNull transient public SignatureService signatureService;
@NotNull public Offer offer;
@NotNull public String id;
@NotNull public byte[] arbitratorPubKey;
@Nullable private transient MailboxMessage mailboxMessage;
@Nullable transient private TradeMessage tradeMessage;
protected TradeProcessModel() {
}
public void init(@NotNull Offer offer,
@NotNull MessageService messageService,
@NotNull MailboxService mailboxService,
@NotNull WalletService walletService,
@NotNull TradeWalletService tradeWalletService,
@NotNull BlockChainService blockChainService,
@NotNull SignatureService signatureService,
@NotNull ArbitrationRepository arbitrationRepository,
@NotNull User user) {
this.offer = offer;
this.messageService = messageService;
this.mailboxService = mailboxService;
this.walletService = walletService;
this.tradeWalletService = tradeWalletService;
this.blockChainService = blockChainService;
this.signatureService = signatureService;
id = offer.getId();
arbitratorPubKey = arbitrationRepository.getDefaultArbitrator().getPubKey();
assert arbitratorPubKey != null;
}
public void setTradeMessage(@NotNull TradeMessage tradeMessage) {
this.tradeMessage = tradeMessage;
}
public void setMailboxMessage(@NotNull MailboxMessage mailboxMessage) {
this.mailboxMessage = mailboxMessage;
}
@Nullable
public TradeMessage getTradeMessage() {
return tradeMessage;
}
@Nullable
public MailboxMessage getMailboxMessage() {
return mailboxMessage;
}
}

View file

@ -30,7 +30,7 @@ public abstract class OfferMessage implements Message, Serializable {
public final String offerId; public final String offerId;
public OfferMessage(String offerId) { protected OfferMessage(String offerId) {
this.offerId = offerId; this.offerId = offerId;
} }
} }

View file

@ -44,7 +44,6 @@ public class RequestOffererPublishDepositTxMessage extends TradeMessage implemen
public final String takerPayoutAddressString; public final String takerPayoutAddressString;
public final Transaction takersPreparedDepositTx; public final Transaction takersPreparedDepositTx;
public final List<TransactionOutput> takerConnectedOutputsForAllInputs; public final List<TransactionOutput> takerConnectedOutputsForAllInputs;
public final List<TransactionOutput> takerOutputs;
public RequestOffererPublishDepositTxMessage(String tradeId, public RequestOffererPublishDepositTxMessage(String tradeId,
FiatAccount takerFiatAccount, FiatAccount takerFiatAccount,
@ -55,8 +54,7 @@ public class RequestOffererPublishDepositTxMessage extends TradeMessage implemen
String takerContractSignature, String takerContractSignature,
String takerPayoutAddressString, String takerPayoutAddressString,
Transaction takersPreparedDepositTx, Transaction takersPreparedDepositTx,
List<TransactionOutput> takerConnectedOutputsForAllInputs, List<TransactionOutput> takerConnectedOutputsForAllInputs) {
List<TransactionOutput> takerOutputs) {
super(tradeId); super(tradeId);
this.takerFiatAccount = takerFiatAccount; this.takerFiatAccount = takerFiatAccount;
this.takerAccountId = takerAccountId; this.takerAccountId = takerAccountId;
@ -67,6 +65,5 @@ public class RequestOffererPublishDepositTxMessage extends TradeMessage implemen
this.takerPayoutAddressString = takerPayoutAddressString; this.takerPayoutAddressString = takerPayoutAddressString;
this.takersPreparedDepositTx = takersPreparedDepositTx; this.takersPreparedDepositTx = takersPreparedDepositTx;
this.takerConnectedOutputsForAllInputs = takerConnectedOutputsForAllInputs; this.takerConnectedOutputsForAllInputs = takerConnectedOutputsForAllInputs;
this.takerOutputs = takerOutputs;
} }
} }

View file

@ -30,7 +30,7 @@ public abstract class TradeMessage implements Message, Serializable {
public final String tradeId; public final String tradeId;
public TradeMessage(String tradeId) { protected TradeMessage(String tradeId) {
this.tradeId = tradeId; this.tradeId = tradeId;
} }
} }

View file

@ -31,7 +31,7 @@ import io.bitsquare.trade.protocol.trade.messages.PayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.messages.RequestDepositTxInputsMessage; import io.bitsquare.trade.protocol.trade.messages.RequestDepositTxInputsMessage;
import io.bitsquare.trade.protocol.trade.messages.RequestOffererPublishDepositTxMessage; import io.bitsquare.trade.protocol.trade.messages.RequestOffererPublishDepositTxMessage;
import io.bitsquare.trade.protocol.trade.messages.TradeMessage; import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
import io.bitsquare.trade.protocol.trade.offerer.models.OffererTradeProcessModel; import io.bitsquare.trade.protocol.trade.offerer.models.OffererProcessModel;
import io.bitsquare.trade.protocol.trade.offerer.tasks.CreateAndSignPayoutTx; import io.bitsquare.trade.protocol.trade.offerer.tasks.CreateAndSignPayoutTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.CreateOffererDepositTxInputs; import io.bitsquare.trade.protocol.trade.offerer.tasks.CreateOffererDepositTxInputs;
import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessPayoutTxPublishedMessage; import io.bitsquare.trade.protocol.trade.offerer.tasks.ProcessPayoutTxPublishedMessage;
@ -55,7 +55,7 @@ public class OffererProtocol implements Protocol {
private final MessageHandler messageHandler; private final MessageHandler messageHandler;
private final OffererTrade offererTrade; private final OffererTrade offererTrade;
private final OffererTradeProcessModel offererTradeProcessModel; private final OffererProcessModel offererTradeProcessModel;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor // Constructor
@ -67,7 +67,7 @@ public class OffererProtocol implements Protocol {
offererTradeProcessModel = offererTrade.getProcessModel(); offererTradeProcessModel = offererTrade.getProcessModel();
messageHandler = this::handleMessage; messageHandler = this::handleMessage;
offererTradeProcessModel.messageService.addMessageHandler(messageHandler); offererTradeProcessModel.getMessageService().addMessageHandler(messageHandler);
} }
@ -89,7 +89,7 @@ public class OffererProtocol implements Protocol {
public void cleanup() { public void cleanup() {
log.debug("cleanup " + this); log.debug("cleanup " + this);
offererTradeProcessModel.messageService.removeMessageHandler(messageHandler); offererTradeProcessModel.getMessageService().removeMessageHandler(messageHandler);
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -99,15 +99,15 @@ public class OffererProtocol implements Protocol {
// OpenOffer requests // OpenOffer requests
private void handleRequestIsOfferAvailableMessage(RequestIsOfferAvailableMessage tradeMessage, Peer sender) { private void handleRequestIsOfferAvailableMessage(RequestIsOfferAvailableMessage tradeMessage, Peer sender) {
try { try {
checkTradeId(offererTradeProcessModel.id, tradeMessage); checkTradeId(offererTradeProcessModel.getId(), tradeMessage);
// We don't store anything in the offererTradeProcessModel as we might be in a trade process and receive that request from another peer who wants // We don't store anything in the offererTradeProcessModel as we might be in a trade process and receive that request from another peer who wants
// to take the // to take the
// offer // offer
// at the same time // at the same time
boolean isOfferOpen = offererTrade.lifeCycleStateProperty().get() == OffererTrade.OffererLifeCycleState.OFFER_OPEN; boolean isOfferOpen = offererTrade.lifeCycleStateProperty().get() == OffererTrade.OffererLifeCycleState.OFFER_OPEN;
ReportOfferAvailabilityMessage reportOfferAvailabilityMessage = new ReportOfferAvailabilityMessage(offererTradeProcessModel.id, isOfferOpen); ReportOfferAvailabilityMessage reportOfferAvailabilityMessage = new ReportOfferAvailabilityMessage(offererTradeProcessModel.getId(), isOfferOpen);
offererTradeProcessModel.messageService.sendMessage(sender, reportOfferAvailabilityMessage, new SendMessageListener() { offererTradeProcessModel.getMessageService().sendMessage(sender, reportOfferAvailabilityMessage, new SendMessageListener() {
@Override @Override
public void handleResult() { public void handleResult() {
// Offerer does not do anything at that moment. Peer might only watch the offer and does not start a trade. // Offerer does not do anything at that moment. Peer might only watch the offer and does not start a trade.
@ -128,14 +128,14 @@ public class OffererProtocol implements Protocol {
// Trade started. We reserve the offer for that taker. If anything goes wrong we reset the offer as open. // Trade started. We reserve the offer for that taker. If anything goes wrong we reset the offer as open.
private void handleRequestDepositTxInputsMessage(RequestDepositTxInputsMessage tradeMessage, Peer taker) { private void handleRequestDepositTxInputsMessage(RequestDepositTxInputsMessage tradeMessage, Peer taker) {
checkTradeId(offererTradeProcessModel.id, tradeMessage); checkTradeId(offererTradeProcessModel.getId(), tradeMessage);
offererTradeProcessModel.setTradeMessage(tradeMessage); offererTradeProcessModel.setTradeMessage(tradeMessage);
offererTrade.setTradingPeer(taker); offererTrade.setTradingPeer(taker);
offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.OFFER_RESERVED); offererTrade.setLifeCycleState(OffererTrade.OffererLifeCycleState.OFFER_RESERVED);
TaskRunner<OffererTrade> taskRunner = new TaskRunner<>(offererTrade, TaskRunner<OffererTrade> taskRunner = new TaskRunner<>(offererTrade,
() -> log.debug("taskRunner at handleTakeOfferFeePayedMessage completed"), () -> log.debug("taskRunner at handleTakeOfferFeePayedMessage completed"),
(errorMessage) -> handleTaskRunnerFault(errorMessage)); this::handleTaskRunnerFault);
taskRunner.addTasks( taskRunner.addTasks(
ProcessRequestDepositTxInputsMessage.class, ProcessRequestDepositTxInputsMessage.class,
CreateOffererDepositTxInputs.class, CreateOffererDepositTxInputs.class,
@ -149,7 +149,7 @@ public class OffererProtocol implements Protocol {
TaskRunner<OffererTrade> taskRunner = new TaskRunner<>(offererTrade, TaskRunner<OffererTrade> taskRunner = new TaskRunner<>(offererTrade,
() -> log.debug("taskRunner at handleRequestOffererPublishDepositTxMessage completed"), () -> log.debug("taskRunner at handleRequestOffererPublishDepositTxMessage completed"),
(errorMessage) -> handleTaskRunnerFault(errorMessage)); this::handleTaskRunnerFault);
taskRunner.addTasks( taskRunner.addTasks(
ProcessRequestOffererPublishDepositTxMessage.class, ProcessRequestOffererPublishDepositTxMessage.class,
VerifyTakerAccount.class, VerifyTakerAccount.class,
@ -169,7 +169,7 @@ public class OffererProtocol implements Protocol {
public void onFiatPaymentStarted() { public void onFiatPaymentStarted() {
TaskRunner<OffererTrade> taskRunner = new TaskRunner<>(offererTrade, TaskRunner<OffererTrade> taskRunner = new TaskRunner<>(offererTrade,
() -> log.debug("taskRunner at handleBankTransferStartedUIEvent completed"), () -> log.debug("taskRunner at handleBankTransferStartedUIEvent completed"),
(errorMessage) -> handleTaskRunnerFault(errorMessage)); this::handleTaskRunnerFault);
taskRunner.addTasks( taskRunner.addTasks(
CreateAndSignPayoutTx.class, CreateAndSignPayoutTx.class,
VerifyTakeOfferFeePayment.class, VerifyTakeOfferFeePayment.class,
@ -192,7 +192,7 @@ public class OffererProtocol implements Protocol {
// we are done! // we are done!
offererTradeProcessModel.onComplete(); offererTradeProcessModel.onComplete();
}, },
(errorMessage) -> handleTaskRunnerFault(errorMessage)); this::handleTaskRunnerFault);
taskRunner.addTasks(ProcessPayoutTxPublishedMessage.class); taskRunner.addTasks(ProcessPayoutTxPublishedMessage.class);
taskRunner.run(); taskRunner.run();
@ -230,6 +230,7 @@ public class OffererProtocol implements Protocol {
} }
private void handleTaskRunnerFault(String errorMessage) { private void handleTaskRunnerFault(String errorMessage) {
log.error(errorMessage);
cleanup(); cleanup();
} }
} }

View file

@ -18,34 +18,158 @@
package io.bitsquare.trade.protocol.trade.offerer.models; package io.bitsquare.trade.protocol.trade.offerer.models;
import io.bitsquare.btc.AddressEntry; import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.WalletService;
import io.bitsquare.fiat.FiatAccount; import io.bitsquare.fiat.FiatAccount;
import io.bitsquare.offer.Offer;
import io.bitsquare.user.User;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.core.TransactionOutput; import org.bitcoinj.core.TransactionOutput;
import org.bitcoinj.crypto.DeterministicKey; import org.bitcoinj.crypto.DeterministicKey;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable; import java.io.Serializable;
import java.security.PublicKey; import java.security.PublicKey;
import java.util.Arrays;
import java.util.List; import java.util.List;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Offerer implements Serializable { public class Offerer implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization. // That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public FiatAccount fiatAccount; transient private static final Logger log = LoggerFactory.getLogger(Offerer.class);
public String accountId;
public PublicKey p2pSigPubKey;
public PublicKey p2pEncryptPubKey;
public byte[] registrationPubKey;
transient public DeterministicKey registrationKeyPair;
public AddressEntry addressEntry;
public byte[] tradeWalletPubKey;
// written by tasks // Transient/Immutable
public byte[] payoutTxSignature; private transient Offer offer;
public Coin payoutAmount; private transient WalletService walletService;
public List<TransactionOutput> connectedOutputsForAllInputs; private transient User user;
public List<TransactionOutput> outputs; // used to verify amounts with change outputs
// Mutable
private byte[] payoutTxSignature;
private Coin payoutAmount;
private List<TransactionOutput> connectedOutputsForAllInputs;
private List<TransactionOutput> outputs; // used to verify amounts with change outputs
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization
///////////////////////////////////////////////////////////////////////////////////////////
public Offerer() {
log.trace("Created by constructor");
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
log.trace("Created from serialized form.");
}
// We need to wait until backend services are ready to set the required dependencies
public void onAllServicesInitialized(Offer offer,
WalletService walletService,
User user) {
log.trace("onBackendReady");
this.offer = offer;
this.walletService = walletService;
this.user = user;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getter only
///////////////////////////////////////////////////////////////////////////////////////////
public FiatAccount getFiatAccount() {
return user.getFiatAccount(offer.getBankAccountId());
}
public String getAccountId() {
return user.getAccountId();
}
public PublicKey getP2pSigPubKey() {
return user.getP2PSigPubKey();
}
public PublicKey getP2pEncryptPubKey() {
return user.getP2PEncryptPubKey();
}
public byte[] getRegistrationPubKey() {
return walletService.getRegistrationAddressEntry().getPubKey();
}
public DeterministicKey getRegistrationKeyPair() {
return walletService.getRegistrationAddressEntry().getKeyPair();
}
public AddressEntry getAddressEntry() {
return walletService.getAddressEntry(offer.getId());
}
public byte[] getTradeWalletPubKey() {
return getAddressEntry().getPubKey();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getter/Setter for Mutable objects
///////////////////////////////////////////////////////////////////////////////////////////
@Nullable
public List<TransactionOutput> getOutputs() {
return outputs;
}
public void setOutputs(List<TransactionOutput> outputs) {
this.outputs = outputs;
}
@Nullable
public byte[] getPayoutTxSignature() {
return payoutTxSignature;
}
public void setPayoutTxSignature(byte[] payoutTxSignature) {
this.payoutTxSignature = payoutTxSignature;
}
@Nullable
public Coin getPayoutAmount() {
return payoutAmount;
}
public void setPayoutAmount(Coin payoutAmount) {
this.payoutAmount = payoutAmount;
}
@Nullable
public List<TransactionOutput> getConnectedOutputsForAllInputs() {
return connectedOutputsForAllInputs;
}
public void setConnectedOutputsForAllInputs(List<TransactionOutput> connectedOutputsForAllInputs) {
this.connectedOutputsForAllInputs = connectedOutputsForAllInputs;
}
@Override
public String toString() {
return "Offerer{" +
"offer=" + offer +
", walletService=" + walletService +
", user=" + user +
", payoutTxSignature=" + Arrays.toString(payoutTxSignature) +
", payoutAmount=" + payoutAmount +
", connectedOutputsForAllInputs=" + connectedOutputsForAllInputs +
", outputs=" + outputs +
'}';
}
} }

View file

@ -0,0 +1,111 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.offerer.models;
import io.bitsquare.arbitration.ArbitrationRepository;
import io.bitsquare.btc.BlockChainService;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.crypto.SignatureService;
import io.bitsquare.offer.Offer;
import io.bitsquare.p2p.MessageService;
import io.bitsquare.trade.protocol.trade.ProcessModel;
import io.bitsquare.user.User;
import java.io.IOException;
import java.io.Serializable;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OffererProcessModel extends ProcessModel implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = 1L;
transient private static final Logger log = LoggerFactory.getLogger(OffererProcessModel.class);
// Immutable
public final Taker taker;
public final Offerer offerer;
// Mutable
private String takeOfferFeeTxId;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization
///////////////////////////////////////////////////////////////////////////////////////////
public OffererProcessModel() {
log.trace("Created by constructor");
taker = new Taker();
offerer = new Offerer();
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
log.trace("Created from serialized form.");
}
public void onAllServicesInitialized(Offer offer,
MessageService messageService,
WalletService walletService,
TradeWalletService tradeWalletService,
BlockChainService blockChainService,
SignatureService signatureService,
ArbitrationRepository arbitrationRepository,
User user) {
log.trace("onAllServicesInitialized");
super.onAllServicesInitialized(offer,
messageService,
walletService,
tradeWalletService,
blockChainService,
signatureService,
arbitrationRepository,
user);
offerer.onAllServicesInitialized(offer, walletService, user);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getter/Setter for Mutable objects
///////////////////////////////////////////////////////////////////////////////////////////
@Nullable
public String getTakeOfferFeeTxId() {
return takeOfferFeeTxId;
}
public void setTakeOfferFeeTxId(String takeOfferFeeTxId) {
this.takeOfferFeeTxId = takeOfferFeeTxId;
}
@Override
public String toString() {
return "OffererProcessModel{" +
"taker=" + taker +
", offerer=" + offerer +
", takeOfferFeeTxId='" + takeOfferFeeTxId + '\'' +
'}';
}
}

View file

@ -1,90 +0,0 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.offerer.models;
import io.bitsquare.arbitration.ArbitrationRepository;
import io.bitsquare.btc.BlockChainService;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.crypto.SignatureService;
import io.bitsquare.offer.Offer;
import io.bitsquare.p2p.MailboxService;
import io.bitsquare.p2p.MessageService;
import io.bitsquare.trade.protocol.trade.TradeProcessModel;
import io.bitsquare.user.User;
import java.io.Serializable;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OffererTradeProcessModel extends TradeProcessModel implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = 1L;
transient private static final Logger log = LoggerFactory.getLogger(OffererTradeProcessModel.class);
public final Taker taker = new Taker();
public final Offerer offerer = new Offerer();
// written by tasks
private String takeOfferFeeTxId;
public OffererTradeProcessModel() {
}
public void init(@NotNull Offer offer,
@NotNull MessageService messageService,
@NotNull MailboxService mailboxService,
@NotNull WalletService walletService,
@NotNull TradeWalletService tradeWalletService,
@NotNull BlockChainService blockChainService,
@NotNull SignatureService signatureService,
@NotNull ArbitrationRepository arbitrationRepository,
@NotNull User user) {
super.init(offer,
messageService,
mailboxService,
walletService,
tradeWalletService,
blockChainService,
signatureService,
arbitrationRepository,
user);
offerer.registrationPubKey = walletService.getRegistrationAddressEntry().getPubKey();
offerer.registrationKeyPair = walletService.getRegistrationAddressEntry().getKeyPair();
offerer.addressEntry = walletService.getAddressEntry(id);
offerer.fiatAccount = user.getFiatAccount(offer.getBankAccountId());
offerer.accountId = user.getAccountId();
offerer.p2pSigPubKey = user.getP2PSigPubKey();
offerer.p2pEncryptPubKey = user.getP2PEncryptPubKey();
offerer.tradeWalletPubKey = offerer.addressEntry.getPubKey();
log.debug("BuyerAsOffererModel addressEntry " + offerer.addressEntry);
}
public String getTakeOfferFeeTxId() {
return takeOfferFeeTxId;
}
public void setTakeOfferFeeTxId(String takeOfferFeeTxId) {
this.takeOfferFeeTxId = takeOfferFeeTxId;
}
}

View file

@ -23,26 +23,159 @@ import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionOutput; import org.bitcoinj.core.TransactionOutput;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable; import java.io.Serializable;
import java.security.PublicKey; import java.security.PublicKey;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Taker implements Serializable { public class Taker implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization. // That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
// written by tasks transient private static final Logger log = LoggerFactory.getLogger(Taker.class);
public String accountId;
public FiatAccount fiatAccount; // Mutable
public PublicKey p2pSigPublicKey; private String accountId;
public PublicKey p2pEncryptPubKey; private FiatAccount fiatAccount;
public String contractAsJson;//TODO only write access now, missing impl. private PublicKey p2pSigPublicKey;
public String contractSignature; private PublicKey p2pEncryptPubKey;
public Coin payoutAmount; private String contractAsJson;
public Transaction preparedDepositTx; private String contractSignature;
public List<TransactionOutput> connectedOutputsForAllInputs; private Coin payoutAmount;
public String payoutAddressString; private Transaction preparedDepositTx;
public byte[] tradeWalletPubKey; private List<TransactionOutput> connectedOutputsForAllInputs;
private String payoutAddressString;
private byte[] tradeWalletPubKey;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization
///////////////////////////////////////////////////////////////////////////////////////////
public Taker() {
log.trace("Created by constructor");
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
log.trace("Created from serialized form.");
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getter/Setter for Mutable objects
///////////////////////////////////////////////////////////////////////////////////////////
public String getAccountId() {
return accountId;
}
public void setAccountId(String accountId) {
this.accountId = accountId;
}
public FiatAccount getFiatAccount() {
return fiatAccount;
}
public void setFiatAccount(FiatAccount fiatAccount) {
this.fiatAccount = fiatAccount;
}
public PublicKey getP2pSigPublicKey() {
return p2pSigPublicKey;
}
public void setP2pSigPublicKey(PublicKey p2pSigPublicKey) {
this.p2pSigPublicKey = p2pSigPublicKey;
}
public PublicKey getP2pEncryptPubKey() {
return p2pEncryptPubKey;
}
public void setP2pEncryptPubKey(PublicKey p2pEncryptPubKey) {
this.p2pEncryptPubKey = p2pEncryptPubKey;
}
public String getContractAsJson() {
return contractAsJson;
}
public void setContractAsJson(String contractAsJson) {
this.contractAsJson = contractAsJson;
}
public String getContractSignature() {
return contractSignature;
}
public void setContractSignature(String contractSignature) {
this.contractSignature = contractSignature;
}
public Coin getPayoutAmount() {
return payoutAmount;
}
public void setPayoutAmount(Coin payoutAmount) {
this.payoutAmount = payoutAmount;
}
public Transaction getPreparedDepositTx() {
return preparedDepositTx;
}
public void setPreparedDepositTx(Transaction preparedDepositTx) {
this.preparedDepositTx = preparedDepositTx;
}
public List<TransactionOutput> getConnectedOutputsForAllInputs() {
return connectedOutputsForAllInputs;
}
public void setConnectedOutputsForAllInputs(List<TransactionOutput> connectedOutputsForAllInputs) {
this.connectedOutputsForAllInputs = connectedOutputsForAllInputs;
}
public String getPayoutAddressString() {
return payoutAddressString;
}
public void setPayoutAddressString(String payoutAddressString) {
this.payoutAddressString = payoutAddressString;
}
public byte[] getTradeWalletPubKey() {
return tradeWalletPubKey;
}
public void setTradeWalletPubKey(byte[] tradeWalletPubKey) {
this.tradeWalletPubKey = tradeWalletPubKey;
}
@Override
public String toString() {
return "Taker{" +
"accountId='" + accountId + '\'' +
", fiatAccount=" + fiatAccount +
", p2pSigPublicKey=" + p2pSigPublicKey +
", p2pEncryptPubKey=" + p2pEncryptPubKey +
", contractAsJson='" + contractAsJson + '\'' +
", contractSignature='" + contractSignature + '\'' +
", payoutAmount=" + payoutAmount +
", preparedDepositTx=" + preparedDepositTx +
", connectedOutputsForAllInputs=" + connectedOutputsForAllInputs +
", payoutAddressString='" + payoutAddressString + '\'' +
", tradeWalletPubKey=" + Arrays.toString(tradeWalletPubKey) +
'}';
}
} }

View file

@ -35,23 +35,24 @@ public class CreateAndSignPayoutTx extends OffererTradeTask {
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
assert offererTrade.getTradeAmount() != null;
Coin securityDeposit = offererTrade.getSecurityDeposit(); Coin securityDeposit = offererTrade.getSecurityDeposit();
Coin offererPayoutAmount = offererTrade.getTradeAmount().add(securityDeposit); Coin offererPayoutAmount = offererTrade.getTradeAmount().add(securityDeposit);
@SuppressWarnings("UnnecessaryLocalVariable") Coin takerPayoutAmount = securityDeposit; @SuppressWarnings("UnnecessaryLocalVariable") Coin takerPayoutAmount = securityDeposit;
byte[] offererPayoutTxSignature = offererTradeProcessModel.tradeWalletService.offererCreatesAndSignsPayoutTx( byte[] offererPayoutTxSignature = offererTradeProcessModel.getTradeWalletService().offererCreatesAndSignsPayoutTx(
offererTrade.getDepositTx(), offererTrade.getDepositTx(),
offererPayoutAmount, offererPayoutAmount,
takerPayoutAmount, takerPayoutAmount,
offererTradeProcessModel.offerer.addressEntry, offererTradeProcessModel.offerer.getAddressEntry(),
offererTradeProcessModel.taker.payoutAddressString, offererTradeProcessModel.taker.getPayoutAddressString(),
offererTradeProcessModel.offerer.tradeWalletPubKey, offererTradeProcessModel.offerer.getTradeWalletPubKey(),
offererTradeProcessModel.taker.tradeWalletPubKey, offererTradeProcessModel.taker.getTradeWalletPubKey(),
offererTradeProcessModel.arbitratorPubKey); offererTradeProcessModel.getArbitratorPubKey());
offererTradeProcessModel.offerer.payoutTxSignature = offererPayoutTxSignature; offererTradeProcessModel.offerer.setPayoutTxSignature(offererPayoutTxSignature);
offererTradeProcessModel.offerer.payoutAmount = offererPayoutAmount; offererTradeProcessModel.offerer.setPayoutAmount(offererPayoutAmount);
offererTradeProcessModel.taker.payoutAmount = takerPayoutAmount; offererTradeProcessModel.taker.setPayoutAmount(takerPayoutAmount);
complete(); complete();
} catch (Throwable t) { } catch (Throwable t) {

View file

@ -39,11 +39,11 @@ public class CreateOffererDepositTxInputs extends OffererTradeTask {
try { try {
log.debug("offererTrade.id" + offererTrade.getId()); log.debug("offererTrade.id" + offererTrade.getId());
Coin offererInputAmount = offererTrade.getSecurityDeposit().add(FeePolicy.TX_FEE); Coin offererInputAmount = offererTrade.getSecurityDeposit().add(FeePolicy.TX_FEE);
TradeWalletService.Result result = offererTradeProcessModel.tradeWalletService.createOffererDepositTxInputs(offererInputAmount, TradeWalletService.Result result = offererTradeProcessModel.getTradeWalletService().createOffererDepositTxInputs(offererInputAmount,
offererTradeProcessModel.offerer.addressEntry); offererTradeProcessModel.offerer.getAddressEntry());
offererTradeProcessModel.offerer.connectedOutputsForAllInputs = result.getConnectedOutputsForAllInputs(); offererTradeProcessModel.offerer.setConnectedOutputsForAllInputs(result.getConnectedOutputsForAllInputs());
offererTradeProcessModel.offerer.outputs = result.getOutputs(); offererTradeProcessModel.offerer.setOutputs(result.getOutputs());
complete(); complete();
} catch (Throwable t) { } catch (Throwable t) {

View file

@ -23,17 +23,17 @@ import io.bitsquare.btc.exceptions.WalletException;
import io.bitsquare.common.taskrunner.Task; import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.OffererTrade; import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.protocol.trade.offerer.models.OffererTradeProcessModel; import io.bitsquare.trade.protocol.trade.offerer.models.OffererProcessModel;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class OffererTradeTask extends Task<OffererTrade> { class OffererTradeTask extends Task<OffererTrade> {
private static final Logger log = LoggerFactory.getLogger(OffererTradeTask.class); private static final Logger log = LoggerFactory.getLogger(OffererTradeTask.class);
protected final OffererTradeProcessModel offererTradeProcessModel; protected final OffererProcessModel offererTradeProcessModel;
protected final OffererTrade offererTrade; protected final OffererTrade offererTrade;
public OffererTradeTask(TaskRunner taskHandler, OffererTrade model) { OffererTradeTask(TaskRunner taskHandler, OffererTrade model) {
super(taskHandler, model); super(taskHandler, model);
offererTrade = model; offererTrade = model;

View file

@ -37,9 +37,11 @@ public class ProcessPayoutTxPublishedMessage extends OffererTradeTask {
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
checkTradeId(offererTradeProcessModel.id, offererTradeProcessModel.getTradeMessage()); PayoutTxPublishedMessage message = (PayoutTxPublishedMessage) offererTradeProcessModel.getTradeMessage();
checkTradeId(offererTradeProcessModel.getId(), message);
checkNotNull(message);
offererTrade.setPayoutTx(checkNotNull(((PayoutTxPublishedMessage) offererTradeProcessModel.getTradeMessage()).payoutTx)); offererTrade.setPayoutTx(checkNotNull(message.payoutTx));
offererTrade.setProcessState(OffererTrade.OffererProcessState.PAYOUT_PUBLISHED); offererTrade.setProcessState(OffererTrade.OffererProcessState.PAYOUT_PUBLISHED);

View file

@ -37,12 +37,13 @@ public class ProcessRequestDepositTxInputsMessage extends OffererTradeTask {
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
checkTradeId(offererTradeProcessModel.id, offererTradeProcessModel.getTradeMessage()); RequestDepositTxInputsMessage message = (RequestDepositTxInputsMessage) offererTradeProcessModel.getTradeMessage();
RequestDepositTxInputsMessage requestDepositTxInputsMessage = (RequestDepositTxInputsMessage) offererTradeProcessModel.getTradeMessage(); checkTradeId(offererTradeProcessModel.getId(), message);
checkNotNull(message);
offererTrade.setTradeAmount(positiveCoinOf(nonZeroCoinOf(requestDepositTxInputsMessage.tradeAmount))); offererTrade.setTradeAmount(positiveCoinOf(nonZeroCoinOf(message.tradeAmount)));
offererTradeProcessModel.setTakeOfferFeeTxId(nonEmptyStringOf(requestDepositTxInputsMessage.takeOfferFeeTxId)); offererTradeProcessModel.setTakeOfferFeeTxId(nonEmptyStringOf(message.takeOfferFeeTxId));
offererTradeProcessModel.taker.tradeWalletPubKey = checkNotNull(requestDepositTxInputsMessage.takerTradeWalletPubKey); offererTradeProcessModel.taker.setTradeWalletPubKey(checkNotNull(message.takerTradeWalletPubKey));
complete(); complete();
} catch (Throwable t) { } catch (Throwable t) {

View file

@ -37,18 +37,19 @@ public class ProcessRequestOffererPublishDepositTxMessage extends OffererTradeTa
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
checkTradeId(offererTradeProcessModel.id, offererTradeProcessModel.getTradeMessage());
RequestOffererPublishDepositTxMessage message = (RequestOffererPublishDepositTxMessage) offererTradeProcessModel.getTradeMessage(); RequestOffererPublishDepositTxMessage message = (RequestOffererPublishDepositTxMessage) offererTradeProcessModel.getTradeMessage();
checkTradeId(offererTradeProcessModel.getId(), message);
checkNotNull(message);
offererTradeProcessModel.taker.fiatAccount = checkNotNull(message.takerFiatAccount); offererTradeProcessModel.taker.setFiatAccount(checkNotNull(message.takerFiatAccount));
offererTradeProcessModel.taker.accountId = nonEmptyStringOf(message.takerAccountId); offererTradeProcessModel.taker.setAccountId(nonEmptyStringOf(message.takerAccountId));
offererTradeProcessModel.taker.p2pSigPublicKey = checkNotNull(message.takerP2PSigPublicKey); offererTradeProcessModel.taker.setP2pSigPublicKey(checkNotNull(message.takerP2PSigPublicKey));
offererTradeProcessModel.taker.p2pEncryptPubKey = checkNotNull(message.takerP2PEncryptPublicKey); offererTradeProcessModel.taker.setP2pEncryptPubKey(checkNotNull(message.takerP2PEncryptPublicKey));
offererTradeProcessModel.taker.contractAsJson = nonEmptyStringOf(message.takerContractAsJson); offererTradeProcessModel.taker.setContractAsJson(nonEmptyStringOf(message.takerContractAsJson));
offererTradeProcessModel.taker.contractSignature = nonEmptyStringOf(message.takerContractSignature); offererTradeProcessModel.taker.setContractSignature(nonEmptyStringOf(message.takerContractSignature));
offererTradeProcessModel.taker.payoutAddressString = nonEmptyStringOf(message.takerPayoutAddressString); offererTradeProcessModel.taker.setPayoutAddressString(nonEmptyStringOf(message.takerPayoutAddressString));
offererTradeProcessModel.taker.preparedDepositTx = checkNotNull(message.takersPreparedDepositTx); offererTradeProcessModel.taker.setPreparedDepositTx(checkNotNull(message.takersPreparedDepositTx));
offererTradeProcessModel.taker.connectedOutputsForAllInputs = checkNotNull(message.takerConnectedOutputsForAllInputs); offererTradeProcessModel.taker.setConnectedOutputsForAllInputs(checkNotNull(message.takerConnectedOutputsForAllInputs));
checkArgument(message.takerConnectedOutputsForAllInputs.size() > 0); checkArgument(message.takerConnectedOutputsForAllInputs.size() > 0);
complete(); complete();

View file

@ -36,16 +36,16 @@ public class RequestTakerDepositPayment extends OffererTradeTask {
protected void doRun() { protected void doRun() {
try { try {
RequestTakerDepositPaymentMessage tradeMessage = new RequestTakerDepositPaymentMessage( RequestTakerDepositPaymentMessage tradeMessage = new RequestTakerDepositPaymentMessage(
offererTradeProcessModel.id, offererTradeProcessModel.getId(),
offererTradeProcessModel.offerer.connectedOutputsForAllInputs, offererTradeProcessModel.offerer.getConnectedOutputsForAllInputs(),
offererTradeProcessModel.offerer.outputs, offererTradeProcessModel.offerer.getOutputs(),
offererTradeProcessModel.offerer.tradeWalletPubKey, offererTradeProcessModel.offerer.getTradeWalletPubKey(),
offererTradeProcessModel.offerer.p2pSigPubKey, offererTradeProcessModel.offerer.getP2pSigPubKey(),
offererTradeProcessModel.offerer.p2pEncryptPubKey, offererTradeProcessModel.offerer.getP2pEncryptPubKey(),
offererTradeProcessModel.offerer.fiatAccount, offererTradeProcessModel.offerer.getFiatAccount(),
offererTradeProcessModel.offerer.accountId); offererTradeProcessModel.offerer.getAccountId());
offererTradeProcessModel.messageService.sendMessage(offererTrade.getTradingPeer(), tradeMessage, new SendMessageListener() { offererTradeProcessModel.getMessageService().sendMessage(offererTrade.getTradingPeer(), tradeMessage, new SendMessageListener() {
@Override @Override
public void handleResult() { public void handleResult() {
log.trace("RequestTakerDepositPaymentMessage successfully arrived at peer"); log.trace("RequestTakerDepositPaymentMessage successfully arrived at peer");

View file

@ -35,15 +35,15 @@ public class SendBankTransferStartedMessage extends OffererTradeTask {
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
FiatTransferStartedMessage tradeMessage = new FiatTransferStartedMessage(offererTradeProcessModel.id, FiatTransferStartedMessage tradeMessage = new FiatTransferStartedMessage(offererTradeProcessModel.getId(),
offererTradeProcessModel.offerer.payoutTxSignature, offererTradeProcessModel.offerer.getPayoutTxSignature(),
offererTradeProcessModel.offerer.payoutAmount, offererTradeProcessModel.offerer.getPayoutAmount(),
offererTradeProcessModel.taker.payoutAmount, offererTradeProcessModel.taker.getPayoutAmount(),
offererTradeProcessModel.offerer.addressEntry.getAddressString()); offererTradeProcessModel.offerer.getAddressEntry().getAddressString());
offererTradeProcessModel.messageService.sendMessage(offererTrade.getTradingPeer(), tradeMessage, offererTradeProcessModel.getMessageService().sendMessage(offererTrade.getTradingPeer(), tradeMessage,
offererTradeProcessModel.taker.p2pSigPublicKey, offererTradeProcessModel.taker.getP2pSigPublicKey(),
offererTradeProcessModel.taker.p2pEncryptPubKey, offererTradeProcessModel.taker.getP2pEncryptPubKey(),
new SendMessageListener() { new SendMessageListener() {
@Override @Override
public void handleResult() { public void handleResult() {

View file

@ -35,9 +35,9 @@ public class SendDepositTxToTaker extends OffererTradeTask {
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
DepositTxPublishedMessage tradeMessage = new DepositTxPublishedMessage(offererTradeProcessModel.id, offererTrade.getDepositTx()); DepositTxPublishedMessage tradeMessage = new DepositTxPublishedMessage(offererTradeProcessModel.getId(), offererTrade.getDepositTx());
offererTradeProcessModel.messageService.sendMessage(offererTrade.getTradingPeer(), tradeMessage, new SendMessageListener() { offererTradeProcessModel.getMessageService().sendMessage(offererTrade.getTradingPeer(), tradeMessage, new SendMessageListener() {
@Override @Override
public void handleResult() { public void handleResult() {
log.trace("DepositTxPublishedMessage successfully arrived at peer"); log.trace("DepositTxPublishedMessage successfully arrived at peer");

View file

@ -42,15 +42,15 @@ public class SignAndPublishDepositTx extends OffererTradeTask {
protected void doRun() { protected void doRun() {
try { try {
Coin offererInputAmount = offererTrade.getSecurityDeposit().add(FeePolicy.TX_FEE); Coin offererInputAmount = offererTrade.getSecurityDeposit().add(FeePolicy.TX_FEE);
offererTradeProcessModel.tradeWalletService.offererSignsAndPublishDepositTx( offererTradeProcessModel.getTradeWalletService().offererSignsAndPublishDepositTx(
offererTradeProcessModel.taker.preparedDepositTx, offererTradeProcessModel.taker.getPreparedDepositTx(),
offererTradeProcessModel.offerer.connectedOutputsForAllInputs, offererTradeProcessModel.offerer.getConnectedOutputsForAllInputs(),
offererTradeProcessModel.taker.connectedOutputsForAllInputs, offererTradeProcessModel.taker.getConnectedOutputsForAllInputs(),
offererTradeProcessModel.offerer.outputs, offererTradeProcessModel.offerer.getOutputs(),
offererInputAmount, offererInputAmount,
offererTradeProcessModel.offerer.tradeWalletPubKey, offererTradeProcessModel.offerer.getTradeWalletPubKey(),
offererTradeProcessModel.taker.tradeWalletPubKey, offererTradeProcessModel.taker.getTradeWalletPubKey(),
offererTradeProcessModel.arbitratorPubKey, offererTradeProcessModel.getArbitratorPubKey(),
new FutureCallback<Transaction>() { new FutureCallback<Transaction>() {
@Override @Override
public void onSuccess(Transaction transaction) { public void onSuccess(Transaction transaction) {

View file

@ -36,22 +36,23 @@ public class VerifyAndSignContract extends OffererTradeTask {
protected void doRun() { protected void doRun() {
try { try {
Contract contract = new Contract( Contract contract = new Contract(
offererTradeProcessModel.offer, offererTradeProcessModel.getOffer(),
offererTrade.getTradeAmount(), offererTrade.getTradeAmount(),
offererTradeProcessModel.getTakeOfferFeeTxId(), offererTradeProcessModel.getTakeOfferFeeTxId(),
offererTradeProcessModel.offerer.accountId, offererTradeProcessModel.offerer.getAccountId(),
offererTradeProcessModel.taker.accountId, offererTradeProcessModel.taker.getAccountId(),
offererTradeProcessModel.offerer.fiatAccount, offererTradeProcessModel.offerer.getFiatAccount(),
offererTradeProcessModel.taker.fiatAccount, offererTradeProcessModel.taker.getFiatAccount(),
offererTradeProcessModel.offerer.p2pSigPubKey, offererTradeProcessModel.offerer.getP2pSigPubKey(),
offererTradeProcessModel.taker.p2pSigPublicKey); offererTradeProcessModel.taker.getP2pSigPublicKey());
String contractAsJson = Utilities.objectToJson(contract); String contractAsJson = Utilities.objectToJson(contract);
String signature = offererTradeProcessModel.signatureService.signMessage(offererTradeProcessModel.offerer.registrationKeyPair, contractAsJson); String signature = offererTradeProcessModel.getSignatureService().signMessage(offererTradeProcessModel.offerer.getRegistrationKeyPair(),
contractAsJson);
offererTrade.setContract(contract); offererTrade.setContract(contract);
offererTrade.setContractAsJson(contractAsJson); offererTrade.setContractAsJson(contractAsJson);
offererTrade.setOffererContractSignature(signature); offererTrade.setOffererContractSignature(signature);
offererTrade.setTakerContractSignature(offererTradeProcessModel.taker.contractSignature); offererTrade.setTakerContractSignature(offererTradeProcessModel.taker.getContractSignature());
complete(); complete();
} catch (Throwable t) { } catch (Throwable t) {

View file

@ -34,7 +34,7 @@ public class VerifyTakeOfferFeePayment extends OffererTradeTask {
protected void doRun() { protected void doRun() {
try { try {
//TODO mocked yet, need a confidence listeners //TODO mocked yet, need a confidence listeners
int numOfPeersSeenTx = offererTradeProcessModel.walletService.getNumOfPeersSeenTx(offererTradeProcessModel.getTakeOfferFeeTxId()); int numOfPeersSeenTx = offererTradeProcessModel.getWalletService().getNumOfPeersSeenTx(offererTradeProcessModel.getTakeOfferFeeTxId());
/* if (numOfPeersSeenTx > 2) { /* if (numOfPeersSeenTx > 2) {
resultHandler.handleResult(); resultHandler.handleResult();
}*/ }*/

View file

@ -34,9 +34,10 @@ public class VerifyTakerAccount extends OffererTradeTask {
protected void doRun() { protected void doRun() {
try { try {
//TODO mocked yet //TODO mocked yet
if (offererTradeProcessModel.blockChainService.verifyAccountRegistration()) { if (offererTradeProcessModel.getBlockChainService().verifyAccountRegistration()) {
if (offererTradeProcessModel.blockChainService.isAccountBlackListed(offererTradeProcessModel.taker.accountId, offererTradeProcessModel.taker if (offererTradeProcessModel.getBlockChainService().isAccountBlackListed(offererTradeProcessModel.taker.getAccountId(), offererTradeProcessModel
.fiatAccount)) { .taker
.getFiatAccount())) {
log.error("Taker is blacklisted"); log.error("Taker is blacklisted");
failed("Taker is blacklisted"); failed("Taker is blacklisted");
} }

View file

@ -28,7 +28,7 @@ import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.messages.FiatTransferStartedMessage; import io.bitsquare.trade.protocol.trade.messages.FiatTransferStartedMessage;
import io.bitsquare.trade.protocol.trade.messages.RequestTakerDepositPaymentMessage; import io.bitsquare.trade.protocol.trade.messages.RequestTakerDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.messages.TradeMessage; import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
import io.bitsquare.trade.protocol.trade.taker.models.TakerTradeProcessModel; import io.bitsquare.trade.protocol.trade.taker.models.TakerProcessModel;
import io.bitsquare.trade.protocol.trade.taker.tasks.BroadcastTakeOfferFeeTx; import io.bitsquare.trade.protocol.trade.taker.tasks.BroadcastTakeOfferFeeTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateAndSignContract; import io.bitsquare.trade.protocol.trade.taker.tasks.CreateAndSignContract;
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateTakeOfferFeeTx; import io.bitsquare.trade.protocol.trade.taker.tasks.CreateTakeOfferFeeTx;
@ -53,7 +53,7 @@ public class TakerProtocol implements Protocol {
private static final Logger log = LoggerFactory.getLogger(TakerProtocol.class); private static final Logger log = LoggerFactory.getLogger(TakerProtocol.class);
private final TakerTrade takerTrade; private final TakerTrade takerTrade;
private final TakerTradeProcessModel takerTradeProcessModel; private final TakerProcessModel takerTradeProcessModel;
private final MessageHandler messageHandler; private final MessageHandler messageHandler;
@ -67,7 +67,7 @@ public class TakerProtocol implements Protocol {
takerTradeProcessModel = takerTrade.getProcessModel(); takerTradeProcessModel = takerTrade.getProcessModel();
messageHandler = this::handleMessage; messageHandler = this::handleMessage;
takerTradeProcessModel.messageService.addMessageHandler(messageHandler); takerTradeProcessModel.getMessageService().addMessageHandler(messageHandler);
} }
@ -77,7 +77,7 @@ public class TakerProtocol implements Protocol {
public void cleanup() { public void cleanup() {
log.debug("cleanup " + this); log.debug("cleanup " + this);
takerTradeProcessModel.messageService.removeMessageHandler(messageHandler); takerTradeProcessModel.getMessageService().removeMessageHandler(messageHandler);
} }
public void setMailboxMessage(MailboxMessage mailboxMessage) { public void setMailboxMessage(MailboxMessage mailboxMessage) {
@ -96,10 +96,8 @@ public class TakerProtocol implements Protocol {
public void takeAvailableOffer() { public void takeAvailableOffer() {
TaskRunner<TakerTrade> taskRunner = new TaskRunner<>(takerTrade, TaskRunner<TakerTrade> taskRunner = new TaskRunner<>(takerTrade,
() -> { () -> log.debug("taskRunner at takeAvailableOffer completed"),
log.debug("taskRunner at takeAvailableOffer completed"); this::handleTaskRunnerFault);
},
(errorMessage) -> handleTaskRunnerFault(errorMessage));
taskRunner.addTasks( taskRunner.addTasks(
CreateTakeOfferFeeTx.class, CreateTakeOfferFeeTx.class,
@ -118,10 +116,8 @@ public class TakerProtocol implements Protocol {
takerTradeProcessModel.setTradeMessage(tradeMessage); takerTradeProcessModel.setTradeMessage(tradeMessage);
TaskRunner<TakerTrade> taskRunner = new TaskRunner<>(takerTrade, TaskRunner<TakerTrade> taskRunner = new TaskRunner<>(takerTrade,
() -> { () -> log.debug("taskRunner at handleTakerDepositPaymentRequestMessage completed"),
log.debug("taskRunner at handleTakerDepositPaymentRequestMessage completed"); this::handleTaskRunnerFault);
},
(errorMessage) -> handleTaskRunnerFault(errorMessage));
taskRunner.addTasks( taskRunner.addTasks(
ProcessRequestTakerDepositPaymentMessage.class, ProcessRequestTakerDepositPaymentMessage.class,
@ -137,10 +133,8 @@ public class TakerProtocol implements Protocol {
takerTradeProcessModel.setTradeMessage(tradeMessage); takerTradeProcessModel.setTradeMessage(tradeMessage);
TaskRunner<TakerTrade> taskRunner = new TaskRunner<>(takerTrade, TaskRunner<TakerTrade> taskRunner = new TaskRunner<>(takerTrade,
() -> { () -> log.debug("taskRunner at handleDepositTxPublishedMessage completed"),
log.debug("taskRunner at handleDepositTxPublishedMessage completed"); this::handleTaskRunnerFault);
},
(errorMessage) -> handleTaskRunnerFault(errorMessage));
taskRunner.addTasks( taskRunner.addTasks(
ProcessDepositTxPublishedMessage.class, ProcessDepositTxPublishedMessage.class,
@ -153,10 +147,8 @@ public class TakerProtocol implements Protocol {
takerTradeProcessModel.setTradeMessage(tradeMessage); takerTradeProcessModel.setTradeMessage(tradeMessage);
TaskRunner<TakerTrade> taskRunner = new TaskRunner<>(takerTrade, TaskRunner<TakerTrade> taskRunner = new TaskRunner<>(takerTrade,
() -> { () -> log.debug("taskRunner at handleFiatTransferStartedMessage completed"),
log.debug("taskRunner at handleFiatTransferStartedMessage completed"); this::handleTaskRunnerFault);
},
(errorMessage) -> handleTaskRunnerFault(errorMessage));
taskRunner.addTasks(ProcessFiatTransferStartedMessage.class); taskRunner.addTasks(ProcessFiatTransferStartedMessage.class);
taskRunner.run(); taskRunner.run();
@ -178,7 +170,7 @@ public class TakerProtocol implements Protocol {
// we are done! // we are done!
takerTradeProcessModel.onComplete(); takerTradeProcessModel.onComplete();
}, },
(errorMessage) -> handleTaskRunnerFault(errorMessage)); this::handleTaskRunnerFault);
taskRunner.addTasks( taskRunner.addTasks(
SignAndPublishPayoutTx.class, SignAndPublishPayoutTx.class,
@ -198,7 +190,7 @@ public class TakerProtocol implements Protocol {
TradeMessage tradeMessage = (TradeMessage) message; TradeMessage tradeMessage = (TradeMessage) message;
nonEmptyStringOf(tradeMessage.tradeId); nonEmptyStringOf(tradeMessage.tradeId);
if (tradeMessage.tradeId.equals(takerTradeProcessModel.id)) { if (tradeMessage.tradeId.equals(takerTradeProcessModel.getId())) {
if (tradeMessage instanceof RequestTakerDepositPaymentMessage) { if (tradeMessage instanceof RequestTakerDepositPaymentMessage) {
handleRequestTakerDepositPaymentMessage((RequestTakerDepositPaymentMessage) tradeMessage); handleRequestTakerDepositPaymentMessage((RequestTakerDepositPaymentMessage) tradeMessage);
} }
@ -216,6 +208,7 @@ public class TakerProtocol implements Protocol {
} }
private void handleTaskRunnerFault(String errorMessage) { private void handleTaskRunnerFault(String errorMessage) {
log.error(errorMessage);
cleanup(); cleanup();
} }

View file

@ -22,29 +22,164 @@ import io.bitsquare.fiat.FiatAccount;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.core.TransactionOutput; import org.bitcoinj.core.TransactionOutput;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable; import java.io.Serializable;
import java.security.PublicKey; import java.security.PublicKey;
import java.util.Arrays;
import java.util.List; import java.util.List;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Fully serializable, no transient fields
*/
public class Offerer implements Serializable { public class Offerer implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization. // That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
transient private static final Logger log = LoggerFactory.getLogger(Offerer.class);
// Mutable
private byte[] tradeWalletPubKey;
private Coin payoutAmount;
private String payoutAddressString;
private List<TransactionOutput> connectedOutputsForAllInputs;
private List<TransactionOutput> outputs;
private byte[] signature;
private FiatAccount fiatAccount;
private String accountId;
private PublicKey p2pSigPublicKey;
private PublicKey p2pEncryptPubKey;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization
///////////////////////////////////////////////////////////////////////////////////////////
public Offerer() { public Offerer() {
log.trace("Created by constructor");
} }
// written by tasks private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
public byte[] tradeWalletPubKey; in.defaultReadObject();
public Coin payoutAmount; log.trace("Created from serialized form.");
public String payoutAddressString; }
public List<TransactionOutput> connectedOutputsForAllInputs;
public List<TransactionOutput> outputs;
public byte[] signature; ///////////////////////////////////////////////////////////////////////////////////////////
public FiatAccount fiatAccount; // Getter/Setter for Mutable objects
public String accountId; ///////////////////////////////////////////////////////////////////////////////////////////
public PublicKey p2pSigPublicKey;
public PublicKey p2pEncryptPubKey; @Nullable
public byte[] getTradeWalletPubKey() {
return tradeWalletPubKey;
}
public void setTradeWalletPubKey(byte[] tradeWalletPubKey) {
this.tradeWalletPubKey = tradeWalletPubKey;
}
@Nullable
public Coin getPayoutAmount() {
return payoutAmount;
}
public void setPayoutAmount(Coin payoutAmount) {
this.payoutAmount = payoutAmount;
}
@Nullable
public String getPayoutAddressString() {
return payoutAddressString;
}
public void setPayoutAddressString(String payoutAddressString) {
this.payoutAddressString = payoutAddressString;
}
@Nullable
public List<TransactionOutput> getConnectedOutputsForAllInputs() {
return connectedOutputsForAllInputs;
}
public void setConnectedOutputsForAllInputs(List<TransactionOutput> connectedOutputsForAllInputs) {
this.connectedOutputsForAllInputs = connectedOutputsForAllInputs;
}
@Nullable
public List<TransactionOutput> getOutputs() {
return outputs;
}
public void setOutputs(List<TransactionOutput> outputs) {
this.outputs = outputs;
}
@Nullable
public byte[] getSignature() {
return signature;
}
public void setSignature(byte[] signature) {
this.signature = signature;
}
@Nullable
public FiatAccount getFiatAccount() {
return fiatAccount;
}
public void setFiatAccount(FiatAccount fiatAccount) {
this.fiatAccount = fiatAccount;
}
@Nullable
public String getAccountId() {
return accountId;
}
public void setAccountId(String accountId) {
this.accountId = accountId;
}
@Nullable
public PublicKey getP2pSigPublicKey() {
return p2pSigPublicKey;
}
public void setP2pSigPublicKey(PublicKey p2pSigPublicKey) {
this.p2pSigPublicKey = p2pSigPublicKey;
}
@Nullable
public PublicKey getP2pEncryptPubKey() {
return p2pEncryptPubKey;
}
public void setP2pEncryptPubKey(PublicKey p2pEncryptPubKey) {
this.p2pEncryptPubKey = p2pEncryptPubKey;
}
@Override
public String toString() {
return "Offerer{" +
"tradeWalletPubKey=" + Arrays.toString(tradeWalletPubKey) +
", payoutAmount=" + payoutAmount +
", payoutAddressString='" + payoutAddressString + '\'' +
", connectedOutputsForAllInputs=" + connectedOutputsForAllInputs +
", outputs=" + outputs +
", signature=" + Arrays.toString(signature) +
", fiatAccount=" + fiatAccount +
", accountId='" + accountId + '\'' +
", p2pSigPublicKey=" + p2pSigPublicKey +
", p2pEncryptPubKey=" + p2pEncryptPubKey +
'}';
}
} }

View file

@ -18,39 +18,147 @@
package io.bitsquare.trade.protocol.trade.taker.models; package io.bitsquare.trade.protocol.trade.taker.models;
import io.bitsquare.btc.AddressEntry; import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.WalletService;
import io.bitsquare.fiat.FiatAccount; import io.bitsquare.fiat.FiatAccount;
import io.bitsquare.offer.Offer;
import io.bitsquare.user.User;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionOutput; import org.bitcoinj.core.TransactionOutput;
import org.bitcoinj.crypto.DeterministicKey; import org.bitcoinj.crypto.DeterministicKey;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable; import java.io.Serializable;
import java.security.PublicKey; import java.security.PublicKey;
import java.util.List; import java.util.List;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Taker implements Serializable { public class Taker implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization. // That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
transient private static final Logger log = LoggerFactory.getLogger(Taker.class);
// Transient/Immutable
transient private Offer offer;
transient private WalletService walletService;
transient private User user;
// Mutable
private List<TransactionOutput> connectedOutputsForAllInputs;
private Coin payoutAmount;
private Transaction preparedDepositTx;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization
///////////////////////////////////////////////////////////////////////////////////////////
public Taker() { public Taker() {
log.trace("Created by constructor");
} }
public FiatAccount fiatAccount; private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
public String accountId; in.defaultReadObject();
public PublicKey p2pSigPubKey; log.trace("Created from serialized form.");
public PublicKey p2pEncryptPublicKey; }
public byte[] registrationPubKey; // TODO not read yet, missing impl.
transient public DeterministicKey registrationKeyPair; // We need to wait until backend services are ready to set the required dependencies
public AddressEntry addressEntry; public void onAllServicesInitialized(Offer offer,
public byte[] tradeWalletPubKey; WalletService walletService,
User user) {
// written by tasks log.trace("onBackendReady");
public List<TransactionOutput> connectedOutputsForAllInputs; this.offer = offer;
public List<TransactionOutput> outputs; this.walletService = walletService;
public Coin payoutAmount; this.user = user;
public Transaction preparedDepositTx; }
///////////////////////////////////////////////////////////////////////////////////////////
// Getter only
///////////////////////////////////////////////////////////////////////////////////////////
public FiatAccount getFiatAccount() {
return user.getFiatAccount(offer.getBankAccountId());
}
public DeterministicKey getRegistrationKeyPair() {
return walletService.getRegistrationAddressEntry().getKeyPair();
}
public String getAccountId() {
return user.getAccountId();
}
public PublicKey getP2pSigPubKey() {
return user.getP2PSigPubKey();
}
public PublicKey getP2pEncryptPublicKey() {
return user.getP2PEncryptPubKey();
}
public byte[] getRegistrationPubKey() {
return walletService.getRegistrationAddressEntry().getPubKey();
}
public AddressEntry getAddressEntry() {
return walletService.getAddressEntry(offer.getId());
}
public byte[] getTradeWalletPubKey() {
return getAddressEntry().getPubKey();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getter/Setter for Mutable objects
///////////////////////////////////////////////////////////////////////////////////////////
@Nullable
public List<TransactionOutput> getConnectedOutputsForAllInputs() {
return connectedOutputsForAllInputs;
}
public void setConnectedOutputsForAllInputs(List<TransactionOutput> connectedOutputsForAllInputs) {
this.connectedOutputsForAllInputs = connectedOutputsForAllInputs;
}
@Nullable
public Coin getPayoutAmount() {
return payoutAmount;
}
public void setPayoutAmount(Coin payoutAmount) {
this.payoutAmount = payoutAmount;
}
@Nullable
public Transaction getPreparedDepositTx() {
return preparedDepositTx;
}
public void setPreparedDepositTx(Transaction preparedDepositTx) {
this.preparedDepositTx = preparedDepositTx;
}
@Override
public String toString() {
return "Taker{" +
"offer=" + offer +
", walletService=" + walletService +
", user=" + user +
", connectedOutputsForAllInputs=" + connectedOutputsForAllInputs +
", payoutAmount=" + payoutAmount +
", preparedDepositTx=" + preparedDepositTx +
'}';
}
} }

View file

@ -0,0 +1,130 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.taker.models;
import io.bitsquare.arbitration.ArbitrationRepository;
import io.bitsquare.btc.BlockChainService;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.crypto.SignatureService;
import io.bitsquare.offer.Offer;
import io.bitsquare.p2p.MessageService;
import io.bitsquare.trade.protocol.trade.ProcessModel;
import io.bitsquare.user.User;
import org.bitcoinj.core.Transaction;
import java.io.IOException;
import java.io.Serializable;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Fully serializable, no transient fields
* <p/>
* Holds all data which are needed between tasks. All relevant data for the trade itself are stored in Trade.
*/
public class TakerProcessModel extends ProcessModel implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = 1L;
transient private static final Logger log = LoggerFactory.getLogger(TakerProcessModel.class);
// Immutable
public final Taker taker;
public final Offerer offerer;
// Mutable
private Transaction takeOfferFeeTx;
private Transaction payoutTx;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization
///////////////////////////////////////////////////////////////////////////////////////////
public TakerProcessModel() {
log.trace("Created by constructor");
taker = new Taker();
offerer = new Offerer();
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
log.trace("Created from serialized form.");
}
@Override
public void onAllServicesInitialized(Offer offer,
MessageService messageService,
WalletService walletService,
TradeWalletService tradeWalletService,
BlockChainService blockChainService,
SignatureService signatureService,
ArbitrationRepository arbitrationRepository,
User user) {
log.trace("onAllServicesInitialized");
super.onAllServicesInitialized(offer,
messageService,
walletService,
tradeWalletService,
blockChainService,
signatureService,
arbitrationRepository,
user);
taker.onAllServicesInitialized(offer, walletService, user);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getter/Setter for Mutable objects
///////////////////////////////////////////////////////////////////////////////////////////
@Nullable
public Transaction getPayoutTx() {
return payoutTx;
}
public void setPayoutTx(Transaction payoutTx) {
this.payoutTx = payoutTx;
}
@Nullable
public Transaction getTakeOfferFeeTx() {
return takeOfferFeeTx;
}
public void setTakeOfferFeeTx(Transaction takeOfferFeeTx) {
this.takeOfferFeeTx = takeOfferFeeTx;
}
@Override
public String toString() {
return "TakerProcessModel{" +
"taker=" + taker +
", offerer=" + offerer +
", takeOfferFeeTx=" + takeOfferFeeTx +
", payoutTx=" + payoutTx +
'}';
}
}

View file

@ -1,109 +0,0 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.taker.models;
import io.bitsquare.arbitration.ArbitrationRepository;
import io.bitsquare.btc.BlockChainService;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.crypto.SignatureService;
import io.bitsquare.offer.Offer;
import io.bitsquare.p2p.MailboxService;
import io.bitsquare.p2p.MessageService;
import io.bitsquare.trade.protocol.trade.TradeProcessModel;
import io.bitsquare.user.User;
import org.bitcoinj.core.Transaction;
import java.io.Serializable;
import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Holds all data which are needed between tasks. All relevant data for the trade itself are stored in Trade.
*/
public class TakerTradeProcessModel extends TradeProcessModel implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = 1L;
transient private static final Logger log = LoggerFactory.getLogger(TakerTradeProcessModel.class);
public final Taker taker = new Taker();
public final Offerer offerer = new Offerer();
// written by tasks
@Nullable private Transaction takeOfferFeeTx;
@Nullable private Transaction payoutTx;
public TakerTradeProcessModel(){
}
public void init(@NotNull Offer offer,
@NotNull MessageService messageService,
@NotNull MailboxService mailboxService,
@NotNull WalletService walletService,
@NotNull TradeWalletService tradeWalletService,
@NotNull BlockChainService blockChainService,
@NotNull SignatureService signatureService,
@NotNull ArbitrationRepository arbitrationRepository,
@NotNull User user) {
super.init(offer,
messageService,
mailboxService,
walletService,
tradeWalletService,
blockChainService,
signatureService,
arbitrationRepository,
user);
taker.registrationPubKey = walletService.getRegistrationAddressEntry().getPubKey();
taker.registrationKeyPair = walletService.getRegistrationAddressEntry().getKeyPair();
taker.addressEntry = walletService.getAddressEntry(id);
taker.fiatAccount = user.getFiatAccount(offer.getBankAccountId());
taker.accountId = user.getAccountId();
taker.p2pSigPubKey = user.getP2PSigPubKey();
taker.p2pEncryptPublicKey = user.getP2PEncryptPubKey();
taker.tradeWalletPubKey = taker.addressEntry.getPubKey();
}
public void setPayoutTx(@NotNull Transaction payoutTx) {
this.payoutTx = payoutTx;
}
public void setTakeOfferFeeTx(@NotNull Transaction takeOfferFeeTx) {
this.takeOfferFeeTx = takeOfferFeeTx;
}
@Nullable
public Transaction getTakeOfferFeeTx() {
return takeOfferFeeTx;
}
@Nullable
public Transaction getPayoutTx() {
return payoutTx;
}
}

View file

@ -39,7 +39,7 @@ public class BroadcastTakeOfferFeeTx extends TakerTradeTask {
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
takerTradeProcessModel.tradeWalletService.broadcastTakeOfferFeeTx(takerTradeProcessModel.getTakeOfferFeeTx(), takerTradeProcessModel.getTradeWalletService().broadcastTakeOfferFeeTx(takerTradeProcessModel.getTakeOfferFeeTx(),
new FutureCallback<Transaction>() { new FutureCallback<Transaction>() {
@Override @Override
public void onSuccess(Transaction transaction) { public void onSuccess(Transaction transaction) {

View file

@ -35,18 +35,19 @@ public class CreateAndSignContract extends TakerTradeTask {
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
assert takerTradeProcessModel.getTakeOfferFeeTx() != null;
Contract contract = new Contract( Contract contract = new Contract(
takerTradeProcessModel.offer, takerTradeProcessModel.getOffer(),
model.getTradeAmount(), model.getTradeAmount(),
takerTradeProcessModel.getTakeOfferFeeTx().getHashAsString(), takerTradeProcessModel.getTakeOfferFeeTx().getHashAsString(),
takerTradeProcessModel.offerer.accountId, takerTradeProcessModel.offerer.getAccountId(),
takerTradeProcessModel.taker.accountId, takerTradeProcessModel.taker.getAccountId(),
takerTradeProcessModel.offerer.fiatAccount, takerTradeProcessModel.offerer.getFiatAccount(),
takerTradeProcessModel.taker.fiatAccount, takerTradeProcessModel.taker.getFiatAccount(),
takerTradeProcessModel.offer.getP2PSigPubKey(), takerTradeProcessModel.getOffer().getP2PSigPubKey(),
takerTradeProcessModel.taker.p2pSigPubKey); takerTradeProcessModel.taker.getP2pSigPubKey());
String contractAsJson = Utilities.objectToJson(contract); String contractAsJson = Utilities.objectToJson(contract);
String signature = takerTradeProcessModel.signatureService.signMessage(takerTradeProcessModel.taker.registrationKeyPair, contractAsJson); String signature = takerTradeProcessModel.getSignatureService().signMessage(takerTradeProcessModel.taker.getRegistrationKeyPair(), contractAsJson);
model.setContract(contract); model.setContract(contract);
model.setContractAsJson(contractAsJson); model.setContractAsJson(contractAsJson);

View file

@ -35,7 +35,8 @@ public class CreateTakeOfferFeeTx extends TakerTradeTask {
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
Transaction createTakeOfferFeeTx = takerTradeProcessModel.tradeWalletService.createTakeOfferFeeTx(takerTradeProcessModel.taker.addressEntry); Transaction createTakeOfferFeeTx = takerTradeProcessModel.getTradeWalletService().createTakeOfferFeeTx(takerTradeProcessModel.taker
.getAddressEntry());
takerTradeProcessModel.setTakeOfferFeeTx(createTakeOfferFeeTx); takerTradeProcessModel.setTakeOfferFeeTx(createTakeOfferFeeTx);
takerTrade.setProcessState(TakerTrade.TakerProcessState.TAKE_OFFER_FEE_TX_CREATED); takerTrade.setProcessState(TakerTrade.TakerProcessState.TAKE_OFFER_FEE_TX_CREATED);

View file

@ -37,9 +37,10 @@ public class ProcessDepositTxPublishedMessage extends TakerTradeTask {
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
checkTradeId(takerTradeProcessModel.id, takerTradeProcessModel.getTradeMessage());
DepositTxPublishedMessage message = (DepositTxPublishedMessage) takerTradeProcessModel.getTradeMessage(); DepositTxPublishedMessage message = (DepositTxPublishedMessage) takerTradeProcessModel.getTradeMessage();
checkTradeId(takerTradeProcessModel.getId(), message);
checkNotNull(message);
takerTrade.setDepositTx(checkNotNull(message.depositTx)); takerTrade.setDepositTx(checkNotNull(message.depositTx));
takerTrade.setProcessState(TakerTrade.TakerProcessState.DEPOSIT_PUBLISHED); takerTrade.setProcessState(TakerTrade.TakerProcessState.DEPOSIT_PUBLISHED);

View file

@ -37,13 +37,14 @@ public class ProcessFiatTransferStartedMessage extends TakerTradeTask {
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
checkTradeId(takerTradeProcessModel.id, takerTradeProcessModel.getTradeMessage());
FiatTransferStartedMessage message = (FiatTransferStartedMessage) takerTradeProcessModel.getTradeMessage(); FiatTransferStartedMessage message = (FiatTransferStartedMessage) takerTradeProcessModel.getTradeMessage();
checkTradeId(takerTradeProcessModel.getId(), message);
checkNotNull(message);
takerTradeProcessModel.offerer.signature = checkNotNull(message.offererSignature); takerTradeProcessModel.offerer.setSignature(checkNotNull(message.offererSignature));
takerTradeProcessModel.offerer.payoutAmount = positiveCoinOf(nonZeroCoinOf(message.offererPayoutAmount)); takerTradeProcessModel.offerer.setPayoutAmount(positiveCoinOf(nonZeroCoinOf(message.offererPayoutAmount)));
takerTradeProcessModel.taker.payoutAmount = positiveCoinOf(nonZeroCoinOf(message.takerPayoutAmount)); takerTradeProcessModel.taker.setPayoutAmount(positiveCoinOf(nonZeroCoinOf(message.takerPayoutAmount)));
takerTradeProcessModel.offerer.payoutAddressString = nonEmptyStringOf(message.offererPayoutAddress); takerTradeProcessModel.offerer.setPayoutAddressString(nonEmptyStringOf(message.offererPayoutAddress));
takerTrade.setProcessState(TakerTrade.TakerProcessState.FIAT_PAYMENT_STARTED); takerTrade.setProcessState(TakerTrade.TakerProcessState.FIAT_PAYMENT_STARTED);
complete(); complete();

View file

@ -37,17 +37,18 @@ public class ProcessRequestTakerDepositPaymentMessage extends TakerTradeTask {
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
checkTradeId(takerTradeProcessModel.id, takerTradeProcessModel.getTradeMessage());
RequestTakerDepositPaymentMessage message = (RequestTakerDepositPaymentMessage) takerTradeProcessModel.getTradeMessage(); RequestTakerDepositPaymentMessage message = (RequestTakerDepositPaymentMessage) takerTradeProcessModel.getTradeMessage();
checkTradeId(takerTradeProcessModel.getId(), message);
checkNotNull(message);
takerTradeProcessModel.offerer.connectedOutputsForAllInputs = checkNotNull(message.offererConnectedOutputsForAllInputs); takerTradeProcessModel.offerer.setConnectedOutputsForAllInputs(checkNotNull(message.offererConnectedOutputsForAllInputs));
checkArgument(message.offererConnectedOutputsForAllInputs.size() > 0); checkArgument(message.offererConnectedOutputsForAllInputs.size() > 0);
takerTradeProcessModel.offerer.outputs = checkNotNull(message.offererOutputs); takerTradeProcessModel.offerer.setOutputs(checkNotNull(message.offererOutputs));
takerTradeProcessModel.offerer.tradeWalletPubKey = checkNotNull(message.offererTradeWalletPubKey); takerTradeProcessModel.offerer.setTradeWalletPubKey(checkNotNull(message.offererTradeWalletPubKey));
takerTradeProcessModel.offerer.p2pSigPublicKey = checkNotNull(message.offererP2PSigPublicKey); takerTradeProcessModel.offerer.setP2pSigPublicKey(checkNotNull(message.offererP2PSigPublicKey));
takerTradeProcessModel.offerer.p2pEncryptPubKey = checkNotNull(message.offererP2PEncryptPublicKey); takerTradeProcessModel.offerer.setP2pEncryptPubKey(checkNotNull(message.offererP2PEncryptPublicKey));
takerTradeProcessModel.offerer.fiatAccount = checkNotNull(message.offererFiatAccount); takerTradeProcessModel.offerer.setFiatAccount(checkNotNull(message.offererFiatAccount));
takerTradeProcessModel.offerer.accountId = nonEmptyStringOf(message.offererAccountId); takerTradeProcessModel.offerer.setAccountId(nonEmptyStringOf(message.offererAccountId));
complete(); complete();
} catch (Throwable t) { } catch (Throwable t) {

View file

@ -35,11 +35,11 @@ public class SendPayoutTxToOfferer extends TakerTradeTask {
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(takerTradeProcessModel.id, takerTradeProcessModel.getPayoutTx()); PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(takerTradeProcessModel.getId(), takerTradeProcessModel.getPayoutTx());
takerTradeProcessModel.messageService.sendMessage(takerTrade.getTradingPeer(), takerTradeProcessModel.getMessageService().sendMessage(takerTrade.getTradingPeer(),
tradeMessage, tradeMessage,
takerTradeProcessModel.offerer.p2pSigPublicKey, takerTradeProcessModel.offerer.getP2pSigPublicKey(),
takerTradeProcessModel.offerer.p2pEncryptPubKey, takerTradeProcessModel.offerer.getP2pEncryptPubKey(),
new SendMessageListener() { new SendMessageListener() {
@Override @Override
public void handleResult() { public void handleResult() {

View file

@ -39,13 +39,14 @@ public class SendRequestDepositTxInputsMessage extends TakerTradeTask {
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
assert takerTradeProcessModel.getTakeOfferFeeTx() != null;
RequestDepositTxInputsMessage msg = new RequestDepositTxInputsMessage( RequestDepositTxInputsMessage msg = new RequestDepositTxInputsMessage(
takerTradeProcessModel.id, takerTradeProcessModel.getId(),
takerTradeProcessModel.getTakeOfferFeeTx().getHashAsString(), takerTradeProcessModel.getTakeOfferFeeTx().getHashAsString(),
takerTrade.getTradeAmount(), takerTrade.getTradeAmount(),
takerTradeProcessModel.taker.tradeWalletPubKey); takerTradeProcessModel.taker.getTradeWalletPubKey());
takerTradeProcessModel.messageService.sendMessage(takerTrade.getTradingPeer(), msg, new SendMessageListener() { takerTradeProcessModel.getMessageService().sendMessage(takerTrade.getTradingPeer(), msg, new SendMessageListener() {
@Override @Override
public void handleResult() { public void handleResult() {
log.trace("Sending TakeOfferFeePayedMessage succeeded."); log.trace("Sending TakeOfferFeePayedMessage succeeded.");

View file

@ -36,20 +36,19 @@ public class SendSignedTakerDepositTx extends TakerTradeTask {
protected void doRun() { protected void doRun() {
try { try {
RequestOffererPublishDepositTxMessage tradeMessage = new RequestOffererPublishDepositTxMessage( RequestOffererPublishDepositTxMessage tradeMessage = new RequestOffererPublishDepositTxMessage(
takerTradeProcessModel.id, takerTradeProcessModel.getId(),
takerTradeProcessModel.taker.fiatAccount, takerTradeProcessModel.taker.getFiatAccount(),
takerTradeProcessModel.taker.accountId, takerTradeProcessModel.taker.getAccountId(),
takerTradeProcessModel.taker.p2pSigPubKey, takerTradeProcessModel.taker.getP2pSigPubKey(),
takerTradeProcessModel.taker.p2pEncryptPublicKey, takerTradeProcessModel.taker.getP2pEncryptPublicKey(),
takerTrade.getContractAsJson(), takerTrade.getContractAsJson(),
takerTrade.getTakerContractSignature(), takerTrade.getTakerContractSignature(),
takerTradeProcessModel.taker.addressEntry.getAddressString(), takerTradeProcessModel.taker.getAddressEntry().getAddressString(),
takerTradeProcessModel.taker.preparedDepositTx, takerTradeProcessModel.taker.getPreparedDepositTx(),
takerTradeProcessModel.taker.connectedOutputsForAllInputs, takerTradeProcessModel.taker.getConnectedOutputsForAllInputs()
takerTradeProcessModel.taker.outputs
); );
takerTradeProcessModel.messageService.sendMessage(takerTrade.getTradingPeer(), tradeMessage, new SendMessageListener() { takerTradeProcessModel.getMessageService().sendMessage(takerTrade.getTradingPeer(), tradeMessage, new SendMessageListener() {
@Override @Override
public void handleResult() { public void handleResult() {
complete(); complete();

View file

@ -39,16 +39,16 @@ public class SignAndPublishPayoutTx extends TakerTradeTask {
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
takerTradeProcessModel.tradeWalletService.takerSignsAndPublishPayoutTx( takerTradeProcessModel.getTradeWalletService().takerSignsAndPublishPayoutTx(
takerTrade.getDepositTx(), takerTrade.getDepositTx(),
takerTradeProcessModel.offerer.signature, takerTradeProcessModel.offerer.getSignature(),
takerTradeProcessModel.offerer.payoutAmount, takerTradeProcessModel.offerer.getPayoutAmount(),
takerTradeProcessModel.taker.payoutAmount, takerTradeProcessModel.taker.getPayoutAmount(),
takerTradeProcessModel.offerer.payoutAddressString, takerTradeProcessModel.offerer.getPayoutAddressString(),
takerTradeProcessModel.taker.addressEntry, takerTradeProcessModel.taker.getAddressEntry(),
takerTradeProcessModel.offerer.tradeWalletPubKey, takerTradeProcessModel.offerer.getTradeWalletPubKey(),
takerTradeProcessModel.taker.tradeWalletPubKey, takerTradeProcessModel.taker.getTradeWalletPubKey(),
takerTradeProcessModel.arbitratorPubKey, takerTradeProcessModel.getArbitratorPubKey(),
new FutureCallback<Transaction>() { new FutureCallback<Transaction>() {
@Override @Override
public void onSuccess(Transaction transaction) { public void onSuccess(Transaction transaction) {

View file

@ -36,7 +36,7 @@ public class TakerCommitDepositTx extends TakerTradeTask {
protected void doRun() { protected void doRun() {
try { try {
// To access tx confidence we need to add that tx into our wallet. // To access tx confidence we need to add that tx into our wallet.
Transaction depositTx = takerTradeProcessModel.tradeWalletService.commitsDepositTx(takerTrade.getDepositTx()); Transaction depositTx = takerTradeProcessModel.getTradeWalletService().commitsDepositTx(takerTrade.getDepositTx());
takerTrade.setDepositTx(depositTx); takerTrade.setDepositTx(depositTx);

View file

@ -37,23 +37,23 @@ public class TakerCreatesAndSignsDepositTx extends TakerTradeTask {
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
assert takerTrade.getTradeAmount() != null;
Coin takerInputAmount = takerTrade.getTradeAmount().add(takerTrade.getSecurityDeposit()).add(FeePolicy.TX_FEE); Coin takerInputAmount = takerTrade.getTradeAmount().add(takerTrade.getSecurityDeposit()).add(FeePolicy.TX_FEE);
Coin msOutputAmount = takerInputAmount.add(takerTrade.getSecurityDeposit()); Coin msOutputAmount = takerInputAmount.add(takerTrade.getSecurityDeposit());
TradeWalletService.Result result = takerTradeProcessModel.tradeWalletService.takerCreatesAndSignsDepositTx( TradeWalletService.Result result = takerTradeProcessModel.getTradeWalletService().takerCreatesAndSignsDepositTx(
takerInputAmount, takerInputAmount,
msOutputAmount, msOutputAmount,
takerTradeProcessModel.offerer.connectedOutputsForAllInputs, takerTradeProcessModel.offerer.getConnectedOutputsForAllInputs(),
takerTradeProcessModel.offerer.outputs, takerTradeProcessModel.offerer.getOutputs(),
takerTradeProcessModel.taker.addressEntry, takerTradeProcessModel.taker.getAddressEntry(),
takerTradeProcessModel.offerer.tradeWalletPubKey, takerTradeProcessModel.offerer.getTradeWalletPubKey(),
takerTradeProcessModel.taker.tradeWalletPubKey, takerTradeProcessModel.taker.getTradeWalletPubKey(),
takerTradeProcessModel.arbitratorPubKey); takerTradeProcessModel.getArbitratorPubKey());
takerTradeProcessModel.taker.connectedOutputsForAllInputs = result.getConnectedOutputsForAllInputs(); takerTradeProcessModel.taker.setConnectedOutputsForAllInputs(result.getConnectedOutputsForAllInputs());
takerTradeProcessModel.taker.outputs = result.getOutputs(); takerTradeProcessModel.taker.setPreparedDepositTx(result.getDepositTx());
takerTradeProcessModel.taker.preparedDepositTx = result.getDepositTx();
complete(); complete();
} catch (Throwable t) { } catch (Throwable t) {

View file

@ -23,17 +23,17 @@ import io.bitsquare.btc.exceptions.WalletException;
import io.bitsquare.common.taskrunner.Task; import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.TakerTrade; import io.bitsquare.trade.TakerTrade;
import io.bitsquare.trade.protocol.trade.taker.models.TakerTradeProcessModel; import io.bitsquare.trade.protocol.trade.taker.models.TakerProcessModel;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class TakerTradeTask extends Task<TakerTrade> { class TakerTradeTask extends Task<TakerTrade> {
private static final Logger log = LoggerFactory.getLogger(TakerTradeTask.class); private static final Logger log = LoggerFactory.getLogger(TakerTradeTask.class);
protected final TakerTradeProcessModel takerTradeProcessModel; protected final TakerProcessModel takerTradeProcessModel;
protected final TakerTrade takerTrade; protected final TakerTrade takerTrade;
public TakerTradeTask(TaskRunner taskHandler, TakerTrade model) { TakerTradeTask(TaskRunner taskHandler, TakerTrade model) {
super(taskHandler, model); super(taskHandler, model);
takerTrade = model; takerTrade = model;

View file

@ -34,7 +34,7 @@ public class VerifyOfferFeePayment extends TakerTradeTask {
protected void doRun() { protected void doRun() {
try { try {
//TODO impl. missing //TODO impl. missing
int numOfPeersSeenTx = takerTradeProcessModel.walletService.getNumOfPeersSeenTx(takerTradeProcessModel.getTakeOfferFeeTx().getHashAsString()); int numOfPeersSeenTx = takerTradeProcessModel.getWalletService().getNumOfPeersSeenTx(takerTradeProcessModel.getTakeOfferFeeTx().getHashAsString());
/* if (numOfPeersSeenTx > 2) { /* if (numOfPeersSeenTx > 2) {
resultHandler.handleResult(); resultHandler.handleResult();
}*/ }*/

View file

@ -33,9 +33,10 @@ public class VerifyOffererAccount extends TakerTradeTask {
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
if (takerTradeProcessModel.blockChainService.verifyAccountRegistration()) { if (takerTradeProcessModel.getBlockChainService().verifyAccountRegistration()) {
if (takerTradeProcessModel.blockChainService.isAccountBlackListed(takerTradeProcessModel.offerer.accountId, takerTradeProcessModel.offerer if (takerTradeProcessModel.getBlockChainService().isAccountBlackListed(takerTradeProcessModel.offerer.getAccountId(), takerTradeProcessModel
.fiatAccount)) { .offerer
.getFiatAccount())) {
failed("Taker is blacklisted."); failed("Taker is blacklisted.");
} }
else { else {

View file

@ -54,6 +54,4 @@ public class Validator {
public static void checkTradeId(String tradeId, TradeMessage tradeMessage) { public static void checkTradeId(String tradeId, TradeMessage tradeMessage) {
checkArgument(tradeId.equals(tradeMessage.tradeId)); checkArgument(tradeId.equals(tradeMessage.tradeId));
} }
} }