Refactor payment process

This commit is contained in:
Manfred Karrer 2015-03-10 16:53:25 +01:00
parent 397aedc099
commit aee5addacf
32 changed files with 472 additions and 462 deletions

View file

@ -39,7 +39,6 @@ import org.bitcoinj.core.TransactionInput;
import org.bitcoinj.core.TransactionOutPoint; import org.bitcoinj.core.TransactionOutPoint;
import org.bitcoinj.core.TransactionOutput; import org.bitcoinj.core.TransactionOutput;
import org.bitcoinj.core.Utils; import org.bitcoinj.core.Utils;
import org.bitcoinj.core.VerificationException;
import org.bitcoinj.core.Wallet; import org.bitcoinj.core.Wallet;
import org.bitcoinj.core.WalletEventListener; import org.bitcoinj.core.WalletEventListener;
import org.bitcoinj.crypto.DeterministicKey; import org.bitcoinj.crypto.DeterministicKey;
@ -624,11 +623,11 @@ public class WalletService {
log.trace("offererPubKey=" + offererPubKey); log.trace("offererPubKey=" + offererPubKey);
log.trace("takerPubKey=" + takerPubKey); log.trace("takerPubKey=" + takerPubKey);
log.trace("arbitratorPubKey=" + arbitratorPubKey); log.trace("arbitratorPubKey=" + arbitratorPubKey);
log.trace("offererInputAmount=" + offererInputAmount.toFriendlyString()); log.trace("tradeId=" + tradeId);
// we need to subtract the fee as it will go to the miners // We need to subtract the fee as it will go to the miners
Coin amountToPay = offererInputAmount.subtract(FeePolicy.TX_FEE); Coin offererInput = offererInputAmount.subtract(FeePolicy.TX_FEE);
log.trace("amountToPay=" + amountToPay.toFriendlyString()); log.trace("amountToPay=" + offererInput.toFriendlyString());
// We pay the offererInputAmount to a temporary MS output which will be changed later to the correct value. // We pay the offererInputAmount to a temporary MS output which will be changed later to the correct value.
// With the usage of completeTx() we get all the work done with fee calculation, validation and coin selection. // With the usage of completeTx() we get all the work done with fee calculation, validation and coin selection.
@ -638,7 +637,7 @@ public class WalletService {
// The btc tx fee will be included by the completeTx() call, so we don't need to add it manually. // The btc tx fee will be included by the completeTx() call, so we don't need to add it manually.
Transaction tx = new Transaction(params); Transaction tx = new Transaction(params);
Script multiSigOutputScript = getMultiSigScript(offererPubKey, takerPubKey, arbitratorPubKey); Script multiSigOutputScript = getMultiSigScript(offererPubKey, takerPubKey, arbitratorPubKey);
tx.addOutput(amountToPay, multiSigOutputScript); tx.addOutput(offererInput, multiSigOutputScript); // that output is just a dummy for input calculation
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx); Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx);
sendRequest.shuffleOutputs = false; sendRequest.shuffleOutputs = false;
@ -660,8 +659,7 @@ public class WalletService {
/* /*
IN[0] any input > offererInputAmount + fee (unsigned) IN[0] any input > offererInputAmount + fee (unsigned)
OUT[0] MS offererInputAmount OUT[0] MS offererInputAmount
OUT[1] Change = input - offererInputAmount - fee OUT[1] Optional Change = input - offererInputAmount - fee btc tx fee
btc tx fee
*/ */
log.trace("Check if wallet is consistent: result=" + wallet.isConsistent()); log.trace("Check if wallet is consistent: result=" + wallet.isConsistent());
@ -688,6 +686,7 @@ public class WalletService {
log.trace("takerPubKey=" + takerPubKey); log.trace("takerPubKey=" + takerPubKey);
log.trace("arbitratorPubKey=" + arbitratorPubKey); log.trace("arbitratorPubKey=" + arbitratorPubKey);
log.trace("offerersPartialDepositTxAsHex=" + offerersPartialDepositTxAsHex); log.trace("offerersPartialDepositTxAsHex=" + offerersPartialDepositTxAsHex);
log.trace("tradeId=" + tradeId);
// We pay the btc tx fee 2 times to the deposit tx: // We pay the btc tx fee 2 times to the deposit tx:
// 1. will be spent to miners when publishing the deposit tx // 1. will be spent to miners when publishing the deposit tx
@ -718,8 +717,7 @@ public class WalletService {
/* /*
IN[0] any input taker > takerInputAmount + fee (signed) IN[0] any input taker > takerInputAmount + fee (signed)
OUT[0] MS takerInputAmount OUT[0] MS takerInputAmount
OUT[1] Change = input taker - takerInputAmount - fee OUT[1] Optional change = input taker - takerInputAmount - fee btc tx fee
btc tx fee
*/ */
@ -736,7 +734,9 @@ public class WalletService {
*/ */
// Now we add the inputs and outputs from our temp tx and change the multiSig amount to the correct value // Now we add the inputs and outputs from our temp tx and change the multiSig amount to the correct value
// TODO multiple inputs not supported yet
tx.addInput(tempTx.getInput(0)); tx.addInput(tempTx.getInput(0));
// handle optional change output
if (tempTx.getOutputs().size() == 2) { if (tempTx.getOutputs().size() == 2) {
tx.addOutput(tempTx.getOutput(1)); tx.addOutput(tempTx.getOutput(1));
} }
@ -745,11 +745,10 @@ public class WalletService {
msOutputAmount = msOutputAmount.add(FeePolicy.TX_FEE); msOutputAmount = msOutputAmount.add(FeePolicy.TX_FEE);
tx.getOutput(0).setValue(msOutputAmount); tx.getOutput(0).setValue(msOutputAmount);
// Now we sign our input // Now we sign our input (index 1)
TransactionInput input = tx.getInput(1); TransactionInput input = tx.getInput(1);
if (input == null || input.getConnectedOutput() == null) { if (input == null || input.getConnectedOutput() == null)
log.error("input or input.getConnectedOutput() is null: " + input); log.error("Must not happen - input or input.getConnectedOutput() is null: " + input);
}
Script scriptPubKey = input.getConnectedOutput().getScriptPubKey(); Script scriptPubKey = input.getConnectedOutput().getScriptPubKey();
ECKey sigKey = input.getOutpoint().getConnectedKey(wallet); ECKey sigKey = input.getOutpoint().getConnectedKey(wallet);
@ -778,8 +777,7 @@ public class WalletService {
IN[1] any input taker > takerInputAmount + fee (signed) e.g.: 1.1001 IN[1] any input taker > takerInputAmount + fee (signed) e.g.: 1.1001
OUT[0] MS offererInputAmount e.g.: 1.2001 OUT[0] MS offererInputAmount e.g.: 1.2001
OUT[1] Change = input offerer - offererInputAmount - fee e.g.: 0 if input is matching correct value OUT[1] Change = input offerer - offererInputAmount - fee e.g.: 0 if input is matching correct value
OUT[2] Change = input taker - takerInputAmount - fee e.g.: 0 if input is matching correct value OUT[2] Change = input taker - takerInputAmount - fee e.g.: 0 if input is matching correct value btc tx fee e.g.: 0.1001
btc tx fee e.g.: 0.1001
*/ */
// We must not commit that tx to the wallet as we will get it over the network when the offerer // We must not commit that tx to the wallet as we will get it over the network when the offerer
@ -926,13 +924,9 @@ public class WalletService {
// boolean isAlreadyInWallet = wallet.maybeCommitTx(depositTx); // boolean isAlreadyInWallet = wallet.maybeCommitTx(depositTx);
//log.trace("isAlreadyInWallet=" + isAlreadyInWallet); //log.trace("isAlreadyInWallet=" + isAlreadyInWallet);
try { // Manually add the multisigContract to the wallet, overriding the isRelevant checks so we can track
// Manually add the multisigContract to the wallet, overriding the isRelevant checks so we can track // it and check for double-spends later
// it and check for double-spends later wallet.receivePending(depositTx, null, true);
wallet.receivePending(depositTx, null, true);
} catch (VerificationException e) {
throw new RuntimeException(e); // Cannot happen, we already called multisigContract.verify()
}
return depositTx; return depositTx;

View file

@ -548,7 +548,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
setGraphic(iconView); setGraphic(iconView);
} }
else { else {
if (stateProperty != null) { if (stateProperty != null && stateChangeListener != null) {
stateProperty.removeListener(stateChangeListener); stateProperty.removeListener(stateChangeListener);
stateChangeListener = null; stateChangeListener = null;
} }

View file

@ -142,9 +142,16 @@ class TakeOfferDataModel implements Activatable, DataModel {
trade.stateProperty().addListener((ov, oldValue, newValue) -> { trade.stateProperty().addListener((ov, oldValue, newValue) -> {
log.debug("trade state = " + newValue); log.debug("trade state = " + newValue);
switch (newValue) { switch (newValue) {
// TODO Check why DEPOSIT_CONFIRMED can happen, refactor state handling case OPEN:
break;
case OFFERER_ACCEPTED:
break;
case OFFERER_REJECTED:
requestTakeOfferErrorMessage.set("Take offer request got rejected. Maybe another trader has taken the offer in the meantime.");
break;
case DEPOSIT_PUBLISHED: case DEPOSIT_PUBLISHED:
case DEPOSIT_CONFIRMED: case DEPOSIT_CONFIRMED:
// TODO Check why DEPOSIT_CONFIRMED can happen, refactor state handling
// TODO null pointer happened here! // TODO null pointer happened here!
if (trade.getDepositTx() != null) { if (trade.getDepositTx() != null) {
transactionId.set(trade.getDepositTx().getHashAsString()); transactionId.set(trade.getDepositTx().getHashAsString());
@ -155,14 +162,15 @@ class TakeOfferDataModel implements Activatable, DataModel {
" That should not happen and needs more investigation why it can happen."); " That should not happen and needs more investigation why it can happen.");
} }
break; break;
case PAYMENT_STARTED:
break;
case FAILED: case FAILED:
requestTakeOfferErrorMessage.set("An error occurred. Error: " + trade.getFault().getMessage()); requestTakeOfferErrorMessage.set("An error occurred. Error: " + trade.getFault().getMessage());
break; break;
case OFFERER_REJECTED: case COMPLETED:
requestTakeOfferErrorMessage.set("Take offer request got rejected.");
break; break;
default: default:
log.warn("Unhandled trade state: " + newValue); log.error("Unhandled trade state: " + newValue);
break; break;
} }
}); });

View file

@ -163,13 +163,11 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
showPaymentInfoScreenButton.setVisible(true); showPaymentInfoScreenButton.setVisible(true);
} }
else if ((state == Offer.State.OFFER_NOT_AVAILABLE)) { else if ((state == Offer.State.OFFER_NOT_AVAILABLE)) {
Popups.openWarningPopup("You cannot take that offer", Popups.openWarningPopup("You cannot take that offer", "The offerer is either offline or the offer was already taken by another trader.");
"The offerer is either offline or the offer was already taken by another trader.");
close(); close();
} }
else if ((state == Offer.State.OFFER_REMOVED)) { else if ((state == Offer.State.OFFER_REMOVED)) {
Popups.openWarningPopup("You cannot take that offer", Popups.openWarningPopup("You cannot take that offer", "The offerer has been removed in the meantime.");
"The offerer has been removed in the meantime.");
close(); close();
} }
} }
@ -196,8 +194,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
} }
}); });
Popups.openInfoPopup("To ensure that both traders behave fair they need to pay a security deposit.", Popups.openInfoPopup("To ensure that both traders behave fair they need to pay a security deposit.",
"The deposit will stay in your local trading wallet until the offer gets accepted by " + "The deposit will stay in your local trading wallet until the offer gets accepted by another trader. " +
"another trader. " +
"\nIt will be refunded to you after the trade has successfully completed.", "\nIt will be refunded to you after the trade has successfully completed.",
actions); actions);

View file

@ -53,7 +53,7 @@ public class Trade implements Serializable {
private String takeOfferFeeTxID; private String takeOfferFeeTxID;
private Contract contract; private Contract contract;
private String contractAsJson; private String contractAsJson;
private String takerSignature; private String takerContractSignature;
private Transaction depositTx; private Transaction depositTx;
private Transaction payoutTx; private Transaction payoutTx;
@ -86,8 +86,8 @@ public class Trade implements Serializable {
// Setters // Setters
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void setContractTakerSignature(String takerSignature) { public void setTakerContractSignature(String takerSignature) {
this.takerSignature = takerSignature; this.takerContractSignature = takerSignature;
} }
public void setTakeOfferFeeTxID(String takeOfferFeeTxID) { public void setTakeOfferFeeTxID(String takeOfferFeeTxID) {
@ -143,8 +143,8 @@ public class Trade implements Serializable {
return offer.getVolumeByAmount(tradeAmount); return offer.getVolumeByAmount(tradeAmount);
} }
public String getTakerSignature() { public String getTakerContractSignature() {
return takerSignature; return takerContractSignature;
} }
public Transaction getDepositTx() { public Transaction getDepositTx() {

View file

@ -30,20 +30,20 @@ import io.bitsquare.offer.OfferBookService;
import io.bitsquare.offer.OpenOffer; import io.bitsquare.offer.OpenOffer;
import io.bitsquare.persistence.Persistence; import io.bitsquare.persistence.Persistence;
import io.bitsquare.trade.handlers.TransactionResultHandler; import io.bitsquare.trade.handlers.TransactionResultHandler;
import io.bitsquare.trade.listeners.BuyerAcceptsOfferProtocolListener;
import io.bitsquare.trade.listeners.SellerTakesOfferProtocolListener;
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferProtocol; import io.bitsquare.trade.protocol.placeoffer.PlaceOfferProtocol;
import io.bitsquare.trade.protocol.trade.OfferMessage; import io.bitsquare.trade.protocol.trade.OfferMessage;
import io.bitsquare.trade.protocol.trade.TradeMessage; import io.bitsquare.trade.protocol.trade.TradeMessage;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAcceptsOfferProtocol; import io.bitsquare.trade.protocol.trade.offerer.BuyerAcceptsOfferProtocol;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAcceptsOfferProtocolListener;
import io.bitsquare.trade.protocol.trade.offerer.messages.BankTransferInitedMessage; import io.bitsquare.trade.protocol.trade.offerer.messages.BankTransferInitedMessage;
import io.bitsquare.trade.protocol.trade.offerer.messages.DepositTxPublishedMessage; import io.bitsquare.trade.protocol.trade.offerer.messages.DepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.messages.IsOfferAvailableResponseMessage; import io.bitsquare.trade.protocol.trade.offerer.messages.IsOfferAvailableResponseMessage;
import io.bitsquare.trade.protocol.trade.offerer.messages.RequestTakerDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.offerer.messages.RespondToTakeOfferRequestMessage; import io.bitsquare.trade.protocol.trade.offerer.messages.RespondToTakeOfferRequestMessage;
import io.bitsquare.trade.protocol.trade.offerer.messages.TakerDepositPaymentRequestMessage;
import io.bitsquare.trade.protocol.trade.offerer.tasks.IsOfferAvailableResponse; import io.bitsquare.trade.protocol.trade.offerer.tasks.IsOfferAvailableResponse;
import io.bitsquare.trade.protocol.trade.taker.RequestIsOfferAvailableProtocol; import io.bitsquare.trade.protocol.trade.taker.RequestIsOfferAvailableProtocol;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferProtocol; import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferProtocol;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferProtocolListener;
import io.bitsquare.trade.protocol.trade.taker.messages.PayoutTxPublishedMessage; import io.bitsquare.trade.protocol.trade.taker.messages.PayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestIsOfferAvailableMessage; import io.bitsquare.trade.protocol.trade.taker.messages.RequestIsOfferAvailableMessage;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestOffererPublishDepositTxMessage; import io.bitsquare.trade.protocol.trade.taker.messages.RequestOffererPublishDepositTxMessage;
@ -227,6 +227,8 @@ public class TradeManager {
pendingTrades.put(offer.getId(), trade); pendingTrades.put(offer.getId(), trade);
persistPendingTrades(); persistPendingTrades();
currentPendingTrade = trade;
return trade; return trade;
} }
@ -241,6 +243,14 @@ public class TradeManager {
persistClosedTrades(); persistClosedTrades();
} }
private void removeFailedTrade(Trade trade) {
if (!pendingTrades.containsKey(trade.getId()))
log.error("trades does not contain the trade with the ID " + trade.getId());
pendingTrades.remove(trade.getId());
persistPendingTrades();
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Trading protocols // Trading protocols
@ -251,7 +261,6 @@ public class TradeManager {
if (openOffers.containsKey(offerId)) { if (openOffers.containsKey(offerId)) {
Offer offer = openOffers.get(offerId).getOffer(); Offer offer = openOffers.get(offerId).getOffer();
Trade trade = createTrade(offer); Trade trade = createTrade(offer);
currentPendingTrade = trade;
BuyerAcceptsOfferProtocol buyerAcceptsOfferProtocol = new BuyerAcceptsOfferProtocol(trade, BuyerAcceptsOfferProtocol buyerAcceptsOfferProtocol = new BuyerAcceptsOfferProtocol(trade,
sender, sender,
@ -263,10 +272,10 @@ public class TradeManager {
new BuyerAcceptsOfferProtocolListener() { new BuyerAcceptsOfferProtocolListener() {
@Override @Override
public void onOfferAccepted(Offer offer) { public void onOfferAccepted(Offer offer) {
trade.setState(Trade.State.OFFERER_ACCEPTED);
persistPendingTrades(); persistPendingTrades();
//TODO do that later
requestRemoveOpenOffer(offer.getId(), requestRemoveOpenOffer(offer.getId(),
() -> log.debug("remove was successful"), () -> log.debug("remove offer was successful"),
(message) -> log.error(message)); (message) -> log.error(message));
} }
@ -298,21 +307,11 @@ public class TradeManager {
@Override @Override
public void onFault(Throwable throwable, BuyerAcceptsOfferProtocol.State state) { public void onFault(Throwable throwable, BuyerAcceptsOfferProtocol.State state) {
log.error("Error while executing trade process at state: " + state + " / " + throwable); log.error("Error while executing trade process at state: " + state + " / " + throwable);
trade.setFault(throwable); switch (state) {
trade.setState(Trade.State.FAILED); case RespondToTakeOfferRequest:
persistPendingTrades(); removeFailedTrade(trade);
} break;
}
// probably not needed
@Override
public void onWaitingForPeerResponse(BuyerAcceptsOfferProtocol.State state) {
log.debug("Waiting for peers response at state " + state);
}
// probably not needed
@Override
public void onWaitingForUserInteraction(BuyerAcceptsOfferProtocol.State state) {
log.debug("Waiting for UI activity at state " + state);
} }
}); });
@ -336,18 +335,15 @@ public class TradeManager {
Trade trade = createTrade(offer); Trade trade = createTrade(offer);
trade.setTradeAmount(amount); trade.setTradeAmount(amount);
currentPendingTrade = trade;
SellerTakesOfferProtocolListener listener = new SellerTakesOfferProtocolListener() { SellerTakesOfferProtocolListener listener = new SellerTakesOfferProtocolListener() {
@Override @Override
public void onTakeOfferRequestAccepted(Trade trade) { public void onTakeOfferRequestAccepted() {
trade.setState(Trade.State.OFFERER_ACCEPTED);
persistPendingTrades(); persistPendingTrades();
} }
@Override @Override
public void onTakeOfferRequestRejected(Trade trade) { public void onTakeOfferRequestRejected() {
trade.setState(Trade.State.OFFERER_REJECTED); removeFailedTrade(trade);
persistPendingTrades();
} }
@Override @Override
@ -369,25 +365,28 @@ public class TradeManager {
trade.setState(Trade.State.COMPLETED); trade.setState(Trade.State.COMPLETED);
// We close the trade when the user has withdrawn his trade funds (see #283) // We close the trade when the user has withdrawn his trade funds (see #283)
//closeTrade(trade); //closeTrade(trade);
persistPendingTrades();
} }
@Override @Override
public void onFault(Throwable throwable, SellerTakesOfferProtocol.State state) { public void onFault(Throwable throwable, SellerTakesOfferProtocol.State state) {
log.error("onFault: " + throwable.getMessage() + " / " + state); log.error("Error while executing trade process at state: " + state + " / " + throwable);
switch (state) { switch (state) {
case GetPeerAddress: case GetPeerAddress:
// TODO add unreachable node to a local ignore list in case of repeated failures removeFailedTrade(trade);
break; break;
case RequestTakeOffer: case RequestTakeOffer:
// TODO add unreachable node to a local ignore list in case of repeated failures removeFailedTrade(trade);
break;
case PayTakeOfferFee:
removeFailedTrade(trade);
break;
case SendTakeOfferFeePayedMessage:
removeFailedTrade(trade);
break; break;
}
}
// probably not needed
@Override }
public void onWaitingForPeerResponse(SellerTakesOfferProtocol.State state) {
log.debug("onWaitingForPeerResponse");
} }
}; };
@ -411,7 +410,7 @@ public class TradeManager {
// Also we don't support yet offline messaging (mail box) // Also we don't support yet offline messaging (mail box)
public void fiatPaymentStarted(String tradeId) { public void fiatPaymentStarted(String tradeId) {
if (offererAsBuyerProtocolMap.get(tradeId) != null) { if (offererAsBuyerProtocolMap.get(tradeId) != null) {
offererAsBuyerProtocolMap.get(tradeId).onUIEventBankTransferInited(); offererAsBuyerProtocolMap.get(tradeId).handleUIEventBankTransferInited();
pendingTrades.get(tradeId).setState(Trade.State.PAYMENT_STARTED); pendingTrades.get(tradeId).setState(Trade.State.PAYMENT_STARTED);
persistPendingTrades(); persistPendingTrades();
} }
@ -423,7 +422,7 @@ public class TradeManager {
} }
public void fiatPaymentReceived(String tradeId) { public void fiatPaymentReceived(String tradeId) {
takerAsSellerProtocolMap.get(tradeId).onUIEventFiatReceived(); takerAsSellerProtocolMap.get(tradeId).handleUIEventFiatReceived();
} }
public void requestIsOfferAvailable(Offer offer) { public void requestIsOfferAvailable(Offer offer) {
@ -436,12 +435,12 @@ public class TradeManager {
log.warn("requestIsOfferAvailable already called for offer with ID:" + offer.getId()); log.warn("requestIsOfferAvailable already called for offer with ID:" + offer.getId());
} }
} }
// When closing take offer view, we are not interested in the requestIsOfferAvailable result anymore, so remove from the map // When closing take offer view, we are not interested in the requestIsOfferAvailable result anymore, so remove from the map
public void stopRequestIsOfferAvailableRequest(Offer offer) { public void stopRequestIsOfferAvailableRequest(Offer offer) {
requestIsOfferAvailableProtocolMap.remove(offer.getId()); requestIsOfferAvailableProtocolMap.remove(offer.getId());
} }
public void onOfferRemovedFromRemoteOfferBook(Offer offer) { public void onOfferRemovedFromRemoteOfferBook(Offer offer) {
requestIsOfferAvailableProtocolMap.remove(offer.getId()); requestIsOfferAvailableProtocolMap.remove(offer.getId());
} }
@ -488,23 +487,24 @@ public class TradeManager {
checkNotNull(tradeId); checkNotNull(tradeId);
if (tradeMessage instanceof RequestTakeOfferMessage) { if (tradeMessage instanceof RequestTakeOfferMessage) {
// Step 3. in trade protocol
createOffererAsBuyerProtocol(tradeId, sender); createOffererAsBuyerProtocol(tradeId, sender);
} }
else if (tradeMessage instanceof RespondToTakeOfferRequestMessage) { else if (tradeMessage instanceof RespondToTakeOfferRequestMessage) {
takerAsSellerProtocolMap.get(tradeId).onRespondToTakeOfferRequestMessage((RespondToTakeOfferRequestMessage) tradeMessage); takerAsSellerProtocolMap.get(tradeId).handleRespondToTakeOfferRequestMessage((RespondToTakeOfferRequestMessage) tradeMessage);
} }
else if (tradeMessage instanceof TakeOfferFeePayedMessage) { else if (tradeMessage instanceof TakeOfferFeePayedMessage) {
offererAsBuyerProtocolMap.get(tradeId).onTakeOfferFeePayedMessage((TakeOfferFeePayedMessage) tradeMessage); offererAsBuyerProtocolMap.get(tradeId).handleTakeOfferFeePayedMessage((TakeOfferFeePayedMessage) tradeMessage);
} }
else if (tradeMessage instanceof RequestTakerDepositPaymentMessage) { else if (tradeMessage instanceof TakerDepositPaymentRequestMessage) {
takerAsSellerProtocolMap.get(tradeId).onRequestTakerDepositPaymentMessage((RequestTakerDepositPaymentMessage) tradeMessage); takerAsSellerProtocolMap.get(tradeId).handleTakerDepositPaymentRequestMessage((TakerDepositPaymentRequestMessage) tradeMessage);
} }
else if (tradeMessage instanceof RequestOffererPublishDepositTxMessage) { else if (tradeMessage instanceof RequestOffererPublishDepositTxMessage) {
offererAsBuyerProtocolMap.get(tradeId).onRequestOffererPublishDepositTxMessage((RequestOffererPublishDepositTxMessage) tradeMessage); offererAsBuyerProtocolMap.get(tradeId).handleRequestOffererPublishDepositTxMessage((RequestOffererPublishDepositTxMessage) tradeMessage);
} }
else if (tradeMessage instanceof DepositTxPublishedMessage) { else if (tradeMessage instanceof DepositTxPublishedMessage) {
persistPendingTrades(); persistPendingTrades();
takerAsSellerProtocolMap.get(tradeId).onDepositTxPublishedMessage((DepositTxPublishedMessage) tradeMessage); takerAsSellerProtocolMap.get(tradeId).handleDepositTxPublishedMessage((DepositTxPublishedMessage) tradeMessage);
} }
else if (tradeMessage instanceof BankTransferInitedMessage) { else if (tradeMessage instanceof BankTransferInitedMessage) {
// Here happened a null pointer. I assume the only possible reason was that we got a null for the // Here happened a null pointer. I assume the only possible reason was that we got a null for the
@ -513,10 +513,10 @@ public class TradeManager {
// For getting better info we add a check. tradeId is checked above. // For getting better info we add a check. tradeId is checked above.
if (takerAsSellerProtocolMap.get(tradeId) == null) if (takerAsSellerProtocolMap.get(tradeId) == null)
log.error("takerAsSellerProtocolMap.get(tradeId) = null. That must not happen."); log.error("takerAsSellerProtocolMap.get(tradeId) = null. That must not happen.");
takerAsSellerProtocolMap.get(tradeId).onBankTransferInitedMessage((BankTransferInitedMessage) tradeMessage); takerAsSellerProtocolMap.get(tradeId).handleBankTransferInitedMessage((BankTransferInitedMessage) tradeMessage);
} }
else if (tradeMessage instanceof PayoutTxPublishedMessage) { else if (tradeMessage instanceof PayoutTxPublishedMessage) {
offererAsBuyerProtocolMap.get(tradeId).onPayoutTxPublishedMessage((PayoutTxPublishedMessage) tradeMessage); offererAsBuyerProtocolMap.get(tradeId).handlePayoutTxPublishedMessage((PayoutTxPublishedMessage) tradeMessage);
} }
else { else {
log.error("Incoming tradeMessage not supported. " + tradeMessage); log.error("Incoming tradeMessage not supported. " + tradeMessage);

View file

@ -15,9 +15,10 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>. * along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/ */
package io.bitsquare.trade.protocol.trade.offerer; package io.bitsquare.trade.listeners;
import io.bitsquare.offer.Offer; import io.bitsquare.offer.Offer;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAcceptsOfferProtocol;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
@ -31,8 +32,4 @@ public interface BuyerAcceptsOfferProtocolListener {
void onPayoutTxPublished(Transaction payoutTx); void onPayoutTxPublished(Transaction payoutTx);
void onFault(Throwable throwable, BuyerAcceptsOfferProtocol.State state); void onFault(Throwable throwable, BuyerAcceptsOfferProtocol.State state);
void onWaitingForPeerResponse(BuyerAcceptsOfferProtocol.State state);
void onWaitingForUserInteraction(BuyerAcceptsOfferProtocol.State state);
} }

View file

@ -15,9 +15,10 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>. * along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/ */
package io.bitsquare.trade.protocol.trade.taker; package io.bitsquare.trade.listeners;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferProtocol;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
@ -30,10 +31,8 @@ public interface SellerTakesOfferProtocolListener {
void onFault(Throwable throwable, SellerTakesOfferProtocol.State state); void onFault(Throwable throwable, SellerTakesOfferProtocol.State state);
void onWaitingForPeerResponse(SellerTakesOfferProtocol.State state); void onTakeOfferRequestAccepted();
void onTakeOfferRequestAccepted(Trade trade); void onTakeOfferRequestRejected();
void onTakeOfferRequestRejected(Trade trade);
} }

View file

@ -27,15 +27,15 @@ import io.bitsquare.offer.Offer;
import io.bitsquare.trade.Contract; import io.bitsquare.trade.Contract;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeMessageService; import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.listeners.BuyerAcceptsOfferProtocolListener;
import io.bitsquare.trade.protocol.trade.offerer.tasks.CreateDepositTx; import io.bitsquare.trade.protocol.trade.offerer.tasks.CreateDepositTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.HandleTakeOfferRequest; import io.bitsquare.trade.protocol.trade.offerer.tasks.RespondToTakeOfferRequest;
import io.bitsquare.trade.protocol.trade.offerer.tasks.RequestTakerDepositPayment;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendDepositTxIdToTaker; import io.bitsquare.trade.protocol.trade.offerer.tasks.SendDepositTxIdToTaker;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendSignedPayoutTx; import io.bitsquare.trade.protocol.trade.offerer.tasks.SendSignedPayoutTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendTakerDepositPaymentRequest;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SetupListenerForBlockChainConfirmation; import io.bitsquare.trade.protocol.trade.offerer.tasks.SetupListenerForBlockChainConfirmation;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SignAndPublishDepositTx; import io.bitsquare.trade.protocol.trade.offerer.tasks.SignAndPublishDepositTx;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyAndSignContract; import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyAndSignContract;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakeOfferFeePayment;
import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakerAccount; import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakerAccount;
import io.bitsquare.trade.protocol.trade.taker.messages.PayoutTxPublishedMessage; import io.bitsquare.trade.protocol.trade.taker.messages.PayoutTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestOffererPublishDepositTxMessage; import io.bitsquare.trade.protocol.trade.taker.messages.RequestOffererPublishDepositTxMessage;
@ -72,25 +72,24 @@ public class BuyerAcceptsOfferProtocol {
public enum State { public enum State {
Init, Init,
HandleTakeOfferRequest, RespondToTakeOfferRequest,
onTakeOfferFeePayedMessage, handleTakeOfferFeePayedMessage,
VerifyTakeOfferFeePayment, /* VerifyTakeOfferFeePayment,*/
CreateDepositTx, CreateDepositTx,
RequestTakerDepositPayment, RequestTakerDepositPayment,
onRequestOffererPublishDepositTxMessage, handleRequestOffererPublishDepositTxMessage,
VerifyTakerAccount, VerifyTakerAccount,
VerifyAndSignContract, VerifyAndSignContract,
SignAndPublishDepositTx, SignAndPublishDepositTx,
SendDepositTxIdToTaker, SendDepositTxIdToTaker,
SetupListenerForBlockChainConfirmation, SetupListenerForBlockChainConfirmation,
onResultSetupListenerForBlockChainConfirmation,
onUIEventBankTransferInited, handleUIEventBankTransferInited,
SendSignedPayoutTx, SendSignedPayoutTx,
onPayoutTxPublishedMessage handlePayoutTxPublishedMessage
} }
// provided // provided
@ -118,7 +117,7 @@ public class BuyerAcceptsOfferProtocol {
// data written by messages, read by tasks // data written by messages, read by tasks
private String takeOfferFeeTxId; private String takeOfferFeeTxId;
private String takerPubKey; private String tradePubKeyAsHex;
private String peersPayoutAddress; private String peersPayoutAddress;
private String peersAccountId; private String peersAccountId;
private BankAccount peersBankAccount; private BankAccount peersBankAccount;
@ -131,7 +130,7 @@ public class BuyerAcceptsOfferProtocol {
// state // state
private State state; private State state;
private int step = 0;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor // Constructor
@ -173,33 +172,28 @@ public class BuyerAcceptsOfferProtocol {
} }
public void start() { public void start() {
handleTakeOfferRequest(); respondToTakeOfferRequest();
} }
// 1. HandleTakeOfferRequest // 4. RespondToTakeOfferRequest
// Async private void respondToTakeOfferRequest() {
// In case of an error: Repeat once, then give up. No rollback activity needed log.debug("respondToTakeOfferRequest called: state = " + state);
private void handleTakeOfferRequest() { state = State.RespondToTakeOfferRequest;
log.debug("handleTakeOfferRequest called " + step++); RespondToTakeOfferRequest.run(this::handleRespondToTakeOfferRequestResult, this::handleErrorMessage, tradeMessageService, peer,
state = State.HandleTakeOfferRequest; trade.getState(), tradeId);
HandleTakeOfferRequest.run(this::onResultHandleTakeOfferRequest, this::onHandleTakeOfferRequestFault, peer, tradeMessageService, trade.getState(),
tradeId);
} }
private void onHandleTakeOfferRequestFault(Throwable throwable) { private void handleRespondToTakeOfferRequestResult() {
HandleTakeOfferRequest.run(this::onResultHandleTakeOfferRequest, this::onFault, peer, tradeMessageService, trade.getState(), tradeId); log.debug("handleRespondToTakeOfferRequestResult called: state = " + state);
}
public void onResultHandleTakeOfferRequest(boolean takeOfferRequestAccepted) { // Here we are not setting a state as that is not relevant for the trade process.
log.debug("onResultHandleTakeOfferRequest called " + step++); // In accept case we remove the offer from the offerbook, but that happens outside of the flow of the trade process
if (takeOfferRequestAccepted) { if (trade.getState() == Trade.State.OPEN) {
trade.setState(Trade.State.OFFERER_ACCEPTED); trade.setState(Trade.State.OFFERER_ACCEPTED);
listener.onOfferAccepted(offer); listener.onOfferAccepted(offer);
listener.onWaitingForPeerResponse(state);
} }
else { else {
// Don't use OFFERER_REJECTED as that trade might has been accepted to another taker. log.info("Ignore that request as we have already the offer accepted.");
log.info("Finish here as we have already the offer accepted.");
} }
} }
@ -208,48 +202,48 @@ public class BuyerAcceptsOfferProtocol {
// Incoming message from peer // Incoming message from peer
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void onTakeOfferFeePayedMessage(@NotNull TakeOfferFeePayedMessage message) { // 8. handleTakeOfferFeePayedMessage
log.debug("onTakeOfferFeePayedMessage called " + step++); public void handleTakeOfferFeePayedMessage(@NotNull TakeOfferFeePayedMessage message) {
log.debug("state " + state); log.debug("handleTakeOfferFeePayedMessage called: state = " + state);
// validation // validation
checkState(state == State.HandleTakeOfferRequest); checkState(state == State.RespondToTakeOfferRequest);
checkArgument(tradeId.equals(message.getTradeId())); checkTradeId(tradeId, message);
String takeOfferFeeTxId = nonEmptyStringOf(message.getTakeOfferFeeTxId()); String takeOfferFeeTxId = nonEmptyStringOf(message.getTakeOfferFeeTxId());
Coin tradeAmount = positiveCoinOf(nonZeroCoinOf(message.getTradeAmount())); Coin tradeAmount = positiveCoinOf(nonZeroCoinOf(message.getTradeAmount()));
String takerPubKey = nonEmptyStringOf(message.getTakerPubKey()); String tradePubKeyAsHex = nonEmptyStringOf(message.getTakerPubKeyAsHex());
// apply new state // apply new state
state = State.onTakeOfferFeePayedMessage; state = State.handleTakeOfferFeePayedMessage;
this.takeOfferFeeTxId = takeOfferFeeTxId; this.takeOfferFeeTxId = takeOfferFeeTxId;
this.takerPubKey = takerPubKey; this.tradePubKeyAsHex = tradePubKeyAsHex;
trade.setTakeOfferFeeTxID(takeOfferFeeTxId); trade.setTakeOfferFeeTxID(takeOfferFeeTxId);
trade.setTradeAmount(tradeAmount); trade.setTradeAmount(tradeAmount);
// next task // next task
state = State.VerifyTakeOfferFeePayment; createDepositTx();
VerifyTakeOfferFeePayment.run(this::onResultVerifyTakeOfferFeePayment, this::onFault, walletService,
this.takeOfferFeeTxId);
} }
public void onResultVerifyTakeOfferFeePayment() { // 9. CreateDepositTx
log.debug("onResultVerifyTakeOfferFeePayment called " + step++); private void createDepositTx() {
log.debug("handleVerifyTakeOfferFeePaymentResult called: state = " + state);
checkState(state == State.handleTakeOfferFeePayedMessage);
Coin offererInputAmount = trade.getSecurityDeposit().add(FeePolicy.TX_FEE); Coin offererInputAmount = trade.getSecurityDeposit().add(FeePolicy.TX_FEE);
state = State.CreateDepositTx; state = State.CreateDepositTx;
CreateDepositTx.run(this::onResultCreateDepositTx, this::onFault, walletService, tradeId, offererInputAmount, CreateDepositTx.run(this::handleCreateDepositTxResult, this::handleFault, walletService, tradeId, offererInputAmount,
takerPubKey, arbitratorPubKey); tradePubKeyAsHex, arbitratorPubKey);
} }
public void onResultCreateDepositTx(String offererPubKey, String preparedOffererDepositTxAsHex, // 4. RequestTakerDepositPayment
long offererTxOutIndex) { private void handleCreateDepositTxResult(String offererPubKey, String preparedOffererDepositTxAsHex, long offererTxOutIndex) {
log.debug("onResultCreateDepositTx called " + step++); log.debug("handleCreateDepositTxResult called: state = " + state);
checkState(state == State.CreateDepositTx);
this.preparedOffererDepositTxAsHex = preparedOffererDepositTxAsHex; this.preparedOffererDepositTxAsHex = preparedOffererDepositTxAsHex;
this.offererTxOutIndex = offererTxOutIndex; this.offererTxOutIndex = offererTxOutIndex;
state = State.RequestTakerDepositPayment; state = State.RequestTakerDepositPayment;
RequestTakerDepositPayment.run(this::onResultRequestTakerDepositPayment, SendTakerDepositPaymentRequest.run(this::handleErrorMessage,
this::onFault,
peer, peer,
tradeMessageService, tradeMessageService,
tradeId, tradeId,
@ -260,23 +254,19 @@ public class BuyerAcceptsOfferProtocol {
offererTxOutIndex); offererTxOutIndex);
} }
public void onResultRequestTakerDepositPayment() {
log.debug("onResultRequestTakerDepositPayment called " + step++);
listener.onWaitingForPeerResponse(state);
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer // Incoming message from peer
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void onRequestOffererPublishDepositTxMessage(RequestOffererPublishDepositTxMessage message) { // 5. VerifyTakerAccount
log.debug("onRequestOffererPublishDepositTxMessage called " + step++); public void handleRequestOffererPublishDepositTxMessage(RequestOffererPublishDepositTxMessage message) {
log.debug("handleRequestOffererPublishDepositTxMessage called: state = " + state);
log.debug("state " + state); log.debug("state " + state);
// validation // validation
checkState(state == State.RequestTakerDepositPayment); checkState(state == State.RequestTakerDepositPayment);
checkArgument(tradeId.equals(message.getTradeId())); checkTradeId(tradeId, message);
String peersPayoutAddress = nonEmptyStringOf(message.getTakerPayoutAddress()); String peersPayoutAddress = nonEmptyStringOf(message.getTakerPayoutAddress());
String peersAccountId = nonEmptyStringOf(message.getTakerAccountId()); String peersAccountId = nonEmptyStringOf(message.getTakerAccountId());
BankAccount peersBankAccount = checkNotNull(message.getTakerBankAccount()); BankAccount peersBankAccount = checkNotNull(message.getTakerBankAccount());
@ -288,7 +278,7 @@ public class BuyerAcceptsOfferProtocol {
long takerTxOutIndex = nonNegativeLongOf(message.getTakerTxOutIndex()); long takerTxOutIndex = nonNegativeLongOf(message.getTakerTxOutIndex());
// apply new state // apply new state
state = State.onRequestOffererPublishDepositTxMessage; state = State.handleRequestOffererPublishDepositTxMessage;
this.peersPayoutAddress = peersPayoutAddress; this.peersPayoutAddress = peersPayoutAddress;
this.peersAccountId = peersAccountId; this.peersAccountId = peersAccountId;
this.peersBankAccount = peersBankAccount; this.peersBankAccount = peersBankAccount;
@ -301,17 +291,18 @@ public class BuyerAcceptsOfferProtocol {
// next task // next task
state = State.VerifyTakerAccount; state = State.VerifyTakerAccount;
VerifyTakerAccount.run(this::onResultVerifyTakerAccount, this::onFault, blockChainService, VerifyTakerAccount.run(this::handleVerifyTakerAccountResult, this::handleFault, blockChainService,
this.peersAccountId, this.peersBankAccount); this.peersAccountId, this.peersBankAccount);
} }
public void onResultVerifyTakerAccount() { // 6. VerifyAndSignContract
log.debug("onResultVerifyTakerAccount called " + step++); private void handleVerifyTakerAccountResult() {
log.debug("handleVerifyTakerAccountResult called: state = " + state);
Coin tradeAmount = trade.getTradeAmount(); Coin tradeAmount = trade.getTradeAmount();
state = State.VerifyAndSignContract; state = State.VerifyAndSignContract;
VerifyAndSignContract.run(this::onResultVerifyAndSignContract, VerifyAndSignContract.run(this::handleVerifyAndSignContractResult,
this::onFault, this::handleFault,
signatureService, signatureService,
accountId, accountId,
tradeAmount, tradeAmount,
@ -326,15 +317,16 @@ public class BuyerAcceptsOfferProtocol {
accountKey); accountKey);
} }
public void onResultVerifyAndSignContract(Contract contract, String contractAsJson, String signature) { // 7. SignAndPublishDepositTx
log.debug("onResultVerifyAndSignContract called " + step++); private void handleVerifyAndSignContractResult(Contract contract, String contractAsJson, String signature) {
log.debug("handleVerifyAndSignContractResult called: state = " + state);
trade.setContract(contract); trade.setContract(contract);
trade.setContractAsJson(contractAsJson); trade.setContractAsJson(contractAsJson);
trade.setContractTakerSignature(signature); trade.setTakerContractSignature(signature);
state = State.SignAndPublishDepositTx; state = State.SignAndPublishDepositTx;
SignAndPublishDepositTx.run(this::onResultSignAndPublishDepositTx, SignAndPublishDepositTx.run(this::handleSignAndPublishDepositTxResult,
this::onFault, this::handleFault,
walletService, walletService,
preparedOffererDepositTxAsHex, preparedOffererDepositTxAsHex,
signedTakerDepositTxAsHex, signedTakerDepositTxAsHex,
@ -344,54 +336,64 @@ public class BuyerAcceptsOfferProtocol {
takerTxOutIndex); takerTxOutIndex);
} }
public void onResultSignAndPublishDepositTx(Transaction depositTransaction) { // 8. SendDepositTxIdToTaker
log.debug("onResultSignAndPublishDepositTx called " + step++); private void handleSignAndPublishDepositTxResult(Transaction depositTransaction) {
log.debug("handleSignAndPublishDepositTxResult called: state = " + state);
listener.onDepositTxPublished(depositTransaction); listener.onDepositTxPublished(depositTransaction);
state = State.SendDepositTxIdToTaker; state = State.SendDepositTxIdToTaker;
SendDepositTxIdToTaker.run(this::onResultSendDepositTxIdToTaker, this::onFault, peer, tradeMessageService, SendDepositTxIdToTaker.run(this::handleSendDepositTxIdToTakerResult, this::handleErrorMessage, peer, tradeMessageService,
tradeId, depositTransaction); tradeId, depositTransaction);
} }
public void onResultSendDepositTxIdToTaker() { private void handleSendDepositTxIdToTakerResult() {
log.debug("onResultSendDepositTxIdToTaker called " + step++); log.debug("handleSendDepositTxIdToTakerResult called: state = " + state);
state = State.SetupListenerForBlockChainConfirmation; state = State.SetupListenerForBlockChainConfirmation;
SetupListenerForBlockChainConfirmation.run(this::onResultSetupListenerForBlockChainConfirmation, SetupListenerForBlockChainConfirmation.run(trade.getDepositTx(), listener);
trade.getDepositTx(), listener);
} }
public void onResultSetupListenerForBlockChainConfirmation() { /*
log.debug("onResultSetupListenerForBlockChainConfirmation called " + step++); // 9. VerifyTakeOfferFeePayment
private void verifyTakeOfferFeePayment() {
state = State.onResultSetupListenerForBlockChainConfirmation; state = State.VerifyTakeOfferFeePayment;
listener.onWaitingForUserInteraction(state); VerifyTakeOfferFeePayment.run(this::handleVerifyTakeOfferFeePaymentResult, this::handleFault, walletService, this.takeOfferFeeTxId);
} }
// 10. CreateDepositTx
private void handleVerifyTakeOfferFeePaymentResult() {
log.debug("handleVerifyTakeOfferFeePaymentResult called: state = " + state);
checkState(state == State.VerifyTakeOfferFeePayment);
Coin offererInputAmount = trade.getSecurityDeposit().add(FeePolicy.TX_FEE);
state = State.CreateDepositTx;
CreateDepositTx.run(this::handleCreateDepositTxResult, this::handleFault, walletService, tradeId, offererInputAmount,
tradePubKeyAsHex, arbitratorPubKey);
}
*/
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Triggered UI event // Triggered UI event
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Triggered from UI event: Button click "Bank transfer inited" // Triggered from UI event: Button click "Bank transfer inited"
public void onUIEventBankTransferInited() { // 9. SendSignedPayoutTx
log.debug("onUIEventBankTransferInited called " + step++); public void handleUIEventBankTransferInited() {
log.debug("onUIEventBankTransferInited called: state = " + state);
log.debug("state " + state); log.debug("state " + state);
// validation // validation
checkState(state.ordinal() >= State.SignAndPublishDepositTx.ordinal() && checkState(state.ordinal() >= State.SignAndPublishDepositTx.ordinal() &&
state.ordinal() <= State.onResultSetupListenerForBlockChainConfirmation.ordinal()); state.ordinal() <= State.SetupListenerForBlockChainConfirmation.ordinal());
state = State.onUIEventBankTransferInited; state = State.handleUIEventBankTransferInited;
// next task // next task
String depositTransactionId = trade.getDepositTx().getHashAsString(); String depositTransactionId = trade.getDepositTx().getHashAsString();
Coin tradeAmount = trade.getTradeAmount(); Coin tradeAmount = trade.getTradeAmount();
Coin securityDeposit = trade.getSecurityDeposit(); Coin securityDeposit = trade.getSecurityDeposit();
state = State.SendSignedPayoutTx; state = State.SendSignedPayoutTx;
SendSignedPayoutTx.run(this::onResultSendSignedPayoutTx, SendSignedPayoutTx.run(this::handleFault,
this::onFault,
peer, peer,
tradeMessageService, tradeMessageService,
walletService, walletService,
@ -403,50 +405,40 @@ public class BuyerAcceptsOfferProtocol {
tradeAmount); tradeAmount);
} }
public void onResultSendSignedPayoutTx() {
log.debug("onResultSendSignedPayoutTx called " + step++);
listener.onWaitingForPeerResponse(state);
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer // Incoming message from peer
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void onPayoutTxPublishedMessage(PayoutTxPublishedMessage message) { // 10. handlePayoutTxPublishedMessage
log.debug("onPayoutTxPublishedMessage called " + step++); public void handlePayoutTxPublishedMessage(PayoutTxPublishedMessage message) {
log.debug("state " + state); log.debug("onPayoutTxPublishedMessage called: state = " + state);
// validation // validation
checkState(state == State.SendSignedPayoutTx); checkState(state == State.SendSignedPayoutTx);
checkArgument(tradeId.equals(message.getTradeId())); checkTradeId(tradeId, message);
String payoutTxAsHex = nonEmptyStringOf(message.getPayoutTxAsHex()); String payoutTxAsHex = nonEmptyStringOf(message.getPayoutTxAsHex());
state = State.onPayoutTxPublishedMessage; // apply new state
state = State.handlePayoutTxPublishedMessage;
Transaction payoutTx = new Transaction(walletService.getWallet().getParams(), Transaction payoutTx = new Transaction(walletService.getWallet().getParams(), Utils.parseAsHexOrBase58(payoutTxAsHex));
Utils.parseAsHexOrBase58(payoutTxAsHex));
listener.onPayoutTxPublished(payoutTx); listener.onPayoutTxPublished(payoutTx);
} }
///////////////////////////////////////////////////////////////////////////////////////////
// Getters, Setters
///////////////////////////////////////////////////////////////////////////////////////////
public String getId() {
return tradeId;
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Private // Private
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// generic fault handler // generic fault handler
private void onFault(Throwable throwable) { private void handleFault(Throwable throwable) {
trade.setFault(throwable);
trade.setState(Trade.State.FAILED);
listener.onFault(throwable, state); listener.onFault(throwable, state);
} }
private void handleErrorMessage(String errorMessage) {
handleFault(new Exception(errorMessage));
}
} }

View file

@ -21,12 +21,14 @@ import io.bitsquare.trade.protocol.trade.TradeMessage;
import java.io.Serializable; import java.io.Serializable;
import org.jetbrains.annotations.NotNull;
public class RespondToTakeOfferRequestMessage implements Serializable, TradeMessage { public class RespondToTakeOfferRequestMessage implements Serializable, TradeMessage {
private static final long serialVersionUID = 6177387534087739018L; private static final long serialVersionUID = 6177387534087739018L;
private final String tradeId; private final String tradeId;
private final boolean takeOfferRequestAccepted; private final boolean takeOfferRequestAccepted;
public RespondToTakeOfferRequestMessage(String tradeId, boolean takeOfferRequestAccepted) { public RespondToTakeOfferRequestMessage(@NotNull String tradeId, boolean takeOfferRequestAccepted) {
this.tradeId = tradeId; this.tradeId = tradeId;
this.takeOfferRequestAccepted = takeOfferRequestAccepted; this.takeOfferRequestAccepted = takeOfferRequestAccepted;
} }

View file

@ -22,7 +22,7 @@ import io.bitsquare.trade.protocol.trade.TradeMessage;
import java.io.Serializable; import java.io.Serializable;
public class RequestTakerDepositPaymentMessage implements Serializable, TradeMessage { public class TakerDepositPaymentRequestMessage implements Serializable, TradeMessage {
private static final long serialVersionUID = -3988720410493712913L; private static final long serialVersionUID = -3988720410493712913L;
private final String tradeId; private final String tradeId;
@ -32,7 +32,7 @@ public class RequestTakerDepositPaymentMessage implements Serializable, TradeMes
private final String preparedOffererDepositTxAsHex; private final String preparedOffererDepositTxAsHex;
private final long offererTxOutIndex; private final long offererTxOutIndex;
public RequestTakerDepositPaymentMessage(String tradeId, BankAccount bankAccount, String accountID, public TakerDepositPaymentRequestMessage(String tradeId, BankAccount bankAccount, String accountID,
String offererPubKey, String preparedOffererDepositTxAsHex, String offererPubKey, String preparedOffererDepositTxAsHex,
long offererTxOutIndex) { long offererTxOutIndex) {
this.tradeId = tradeId; this.tradeId = tradeId;

View file

@ -38,20 +38,19 @@ public class CreateDepositTx {
Coin offererInputAmount, Coin offererInputAmount,
String takerMultiSigPubKey, String takerMultiSigPubKey,
String arbitratorPubKeyAsHex) { String arbitratorPubKeyAsHex) {
log.trace("Run task"); log.trace("Run CreateDepositTx task");
try { try {
String offererPubKey = walletService.getAddressInfoByTradeID(tradeId).getPubKeyAsHexString(); String offererPubKey = walletService.getAddressInfoByTradeID(tradeId).getPubKeyAsHexString();
Transaction transaction = walletService.offererCreatesMSTxAndAddPayment( Transaction transaction = walletService.offererCreatesMSTxAndAddPayment(offererInputAmount, offererPubKey, takerMultiSigPubKey,
offererInputAmount, offererPubKey, takerMultiSigPubKey, arbitratorPubKeyAsHex, tradeId); arbitratorPubKeyAsHex, tradeId);
String preparedOffererDepositTxAsHex = Utils.HEX.encode(transaction.bitcoinSerialize()); String preparedOffererDepositTxAsHex = Utils.HEX.encode(transaction.bitcoinSerialize());
long offererTxOutIndex = transaction.getInput(0).getOutpoint().getIndex(); long offererTxOutIndex = transaction.getInput(0).getOutpoint().getIndex();
resultHandler.onResult(offererPubKey, preparedOffererDepositTxAsHex, offererTxOutIndex); resultHandler.onResult(offererPubKey, preparedOffererDepositTxAsHex, offererTxOutIndex);
} catch (InsufficientMoneyException e) { } catch (InsufficientMoneyException e) {
log.error("Create deposit tx faultHandler.onFault due InsufficientMoneyException " + e); log.error("Create deposit tx failed due InsufficientMoneyException " + e);
exceptionHandler.handleException( exceptionHandler.handleException(e);
new Exception("Create deposit tx faultHandler.onFault due InsufficientMoneyException " + e));
} }
} }

View file

@ -22,38 +22,38 @@ import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeMessageService; import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.listeners.SendMessageListener; import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.trade.protocol.trade.offerer.messages.RespondToTakeOfferRequestMessage; import io.bitsquare.trade.protocol.trade.offerer.messages.RespondToTakeOfferRequestMessage;
import io.bitsquare.util.handlers.ExceptionHandler; import io.bitsquare.util.handlers.ErrorMessageHandler;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class HandleTakeOfferRequest { public class RespondToTakeOfferRequest {
private static final Logger log = LoggerFactory.getLogger(HandleTakeOfferRequest.class); private static final Logger log = LoggerFactory.getLogger(RespondToTakeOfferRequest.class);
public static void run(ResultHandler resultHandler, ExceptionHandler exceptionHandler, Peer peer, public static void run(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler,
TradeMessageService tradeMessageService, Trade.State tradeState, String tradeId) { TradeMessageService tradeMessageService, Peer peer, Trade.State tradeState, String tradeId) {
log.trace("Run HandleTakeOfferRequest task"); log.trace("Run HandleTakeOfferRequest task");
boolean isTradeIsOpen = tradeState == Trade.State.OPEN; boolean takeOfferRequestAccepted = tradeState == Trade.State.OPEN;
if (!isTradeIsOpen) { if (!takeOfferRequestAccepted) {
log.warn("Received take offer request but the offer not marked as open anymore."); log.warn("Received take offer request but the offer not marked as open anymore.");
} }
RespondToTakeOfferRequestMessage tradeMessage = new RespondToTakeOfferRequestMessage(tradeId, isTradeIsOpen); RespondToTakeOfferRequestMessage tradeMessage = new RespondToTakeOfferRequestMessage(tradeId, takeOfferRequestAccepted);
tradeMessageService.sendMessage(peer, tradeMessage, new SendMessageListener() { tradeMessageService.sendMessage(peer, tradeMessage, new SendMessageListener() {
@Override @Override
public void handleResult() { public void handleResult() {
log.trace("RespondToTakeOfferRequestMessage successfully arrived at peer"); log.trace("RespondToTakeOfferRequestMessage successfully arrived at peer");
resultHandler.handleResult(isTradeIsOpen); resultHandler.handleResult();
} }
@Override @Override
public void handleFault() { public void handleFault() {
log.error("AcceptTakeOfferRequestMessage did not arrive at peer"); log.error("AcceptTakeOfferRequestMessage did not arrive at peer");
exceptionHandler.handleException(new Exception("AcceptTakeOfferRequestMessage did not arrive at peer")); errorMessageHandler.handleErrorMessage("AcceptTakeOfferRequestMessage did not arrive at peer");
} }
}); });
} }
public interface ResultHandler { public interface ResultHandler {
void handleResult(boolean takeOfferRequestAccepted); void handleResult();
} }
} }

View file

@ -17,11 +17,11 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks; package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.TradeMessageService; import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.listeners.SendMessageListener; import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.protocol.trade.offerer.messages.DepositTxPublishedMessage; import io.bitsquare.trade.protocol.trade.offerer.messages.DepositTxPublishedMessage;
import io.bitsquare.util.handlers.ExceptionHandler; import io.bitsquare.util.handlers.ErrorMessageHandler;
import io.bitsquare.util.handlers.ResultHandler; import io.bitsquare.util.handlers.ResultHandler;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
@ -33,7 +33,7 @@ import org.slf4j.LoggerFactory;
public class SendDepositTxIdToTaker { public class SendDepositTxIdToTaker {
private static final Logger log = LoggerFactory.getLogger(SendDepositTxIdToTaker.class); private static final Logger log = LoggerFactory.getLogger(SendDepositTxIdToTaker.class);
public static void run(ResultHandler resultHandler, ExceptionHandler exceptionHandler, Peer peer, public static void run(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler, Peer peer,
TradeMessageService tradeMessageService, String tradeId, Transaction depositTransaction) { TradeMessageService tradeMessageService, String tradeId, Transaction depositTransaction) {
log.trace("Run task"); log.trace("Run task");
DepositTxPublishedMessage tradeMessage = DepositTxPublishedMessage tradeMessage =
@ -49,7 +49,7 @@ public class SendDepositTxIdToTaker {
@Override @Override
public void handleFault() { public void handleFault() {
log.error("DepositTxPublishedMessage did not arrive at peer"); log.error("DepositTxPublishedMessage did not arrive at peer");
exceptionHandler.handleException(new Exception("DepositTxPublishedMessage did not arrive at peer")); errorMessageHandler.handleErrorMessage("DepositTxPublishedMessage did not arrive at peer");
} }
}); });
} }

View file

@ -18,12 +18,11 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks; package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.btc.WalletService; import io.bitsquare.btc.WalletService;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.TradeMessageService; import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.listeners.SendMessageListener; import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.protocol.trade.offerer.messages.BankTransferInitedMessage; import io.bitsquare.trade.protocol.trade.offerer.messages.BankTransferInitedMessage;
import io.bitsquare.util.handlers.ExceptionHandler; import io.bitsquare.util.handlers.ExceptionHandler;
import io.bitsquare.util.handlers.ResultHandler;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.core.ECKey; import org.bitcoinj.core.ECKey;
@ -36,8 +35,7 @@ import org.slf4j.LoggerFactory;
public class SendSignedPayoutTx { public class SendSignedPayoutTx {
private static final Logger log = LoggerFactory.getLogger(SendSignedPayoutTx.class); private static final Logger log = LoggerFactory.getLogger(SendSignedPayoutTx.class);
public static void run(ResultHandler resultHandler, public static void run(ExceptionHandler exceptionHandler,
ExceptionHandler exceptionHandler,
Peer peer, Peer peer,
TradeMessageService tradeMessageService, TradeMessageService tradeMessageService,
WalletService walletService, WalletService walletService,
@ -72,7 +70,6 @@ public class SendSignedPayoutTx {
@Override @Override
public void handleResult() { public void handleResult() {
log.trace("BankTransferInitedMessage successfully arrived at peer"); log.trace("BankTransferInitedMessage successfully arrived at peer");
resultHandler.handleResult();
} }
@Override @Override

View file

@ -18,21 +18,19 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks; package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.bank.BankAccount; import io.bitsquare.bank.BankAccount;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.TradeMessageService; import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.listeners.SendMessageListener; import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.network.Peer; import io.bitsquare.trade.protocol.trade.offerer.messages.TakerDepositPaymentRequestMessage;
import io.bitsquare.trade.protocol.trade.offerer.messages.RequestTakerDepositPaymentMessage; import io.bitsquare.util.handlers.ErrorMessageHandler;
import io.bitsquare.util.handlers.ExceptionHandler;
import io.bitsquare.util.handlers.ResultHandler;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class RequestTakerDepositPayment { public class SendTakerDepositPaymentRequest {
private static final Logger log = LoggerFactory.getLogger(RequestTakerDepositPayment.class); private static final Logger log = LoggerFactory.getLogger(SendTakerDepositPaymentRequest.class);
public static void run(ResultHandler resultHandler, public static void run(ErrorMessageHandler errorMessageHandler,
ExceptionHandler exceptionHandler,
Peer peer, Peer peer,
TradeMessageService tradeMessageService, TradeMessageService tradeMessageService,
String tradeId, String tradeId,
@ -41,21 +39,19 @@ public class RequestTakerDepositPayment {
String offererPubKey, String offererPubKey,
String preparedOffererDepositTxAsHex, String preparedOffererDepositTxAsHex,
long offererTxOutIndex) { long offererTxOutIndex) {
log.trace("Run task"); log.trace("Run SendTakerDepositPaymentRequest task");
RequestTakerDepositPaymentMessage tradeMessage = new RequestTakerDepositPaymentMessage( TakerDepositPaymentRequestMessage tradeMessage = new TakerDepositPaymentRequestMessage(
tradeId, bankAccount, accountId, offererPubKey, preparedOffererDepositTxAsHex, offererTxOutIndex); tradeId, bankAccount, accountId, offererPubKey, preparedOffererDepositTxAsHex, offererTxOutIndex);
tradeMessageService.sendMessage(peer, tradeMessage, new SendMessageListener() { tradeMessageService.sendMessage(peer, 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");
resultHandler.handleResult();
} }
@Override @Override
public void handleFault() { public void handleFault() {
log.error("RequestTakerDepositPaymentMessage did not arrive at peer"); log.error("RequestTakerDepositPaymentMessage did not arrive at peer");
exceptionHandler.handleException(new Exception("RequestTakerDepositPaymentMessage did not arrive at " + errorMessageHandler.handleErrorMessage("RequestTakerDepositPaymentMessage did not arrive at peer");
"peer"));
} }
}); });
} }

View file

@ -17,8 +17,7 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks; package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.trade.protocol.trade.offerer.BuyerAcceptsOfferProtocolListener; import io.bitsquare.trade.listeners.BuyerAcceptsOfferProtocolListener;
import io.bitsquare.util.handlers.ResultHandler;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionConfidence; import org.bitcoinj.core.TransactionConfidence;
@ -29,9 +28,8 @@ import org.slf4j.LoggerFactory;
public class SetupListenerForBlockChainConfirmation { public class SetupListenerForBlockChainConfirmation {
private static final Logger log = LoggerFactory.getLogger(SetupListenerForBlockChainConfirmation.class); private static final Logger log = LoggerFactory.getLogger(SetupListenerForBlockChainConfirmation.class);
public static void run(ResultHandler resultHandler, public static void run(Transaction depositTransaction, BuyerAcceptsOfferProtocolListener listener) {
Transaction depositTransaction, BuyerAcceptsOfferProtocolListener listener) { log.trace("Run SetupListenerForBlockChainConfirmation task");
log.trace("Run task");
//TODO //TODO
// sharedModel.offererPaymentProtocolListener.onDepositTxConfirmedInBlockchain(); // sharedModel.offererPaymentProtocolListener.onDepositTxConfirmedInBlockchain();
@ -44,7 +42,6 @@ public class SetupListenerForBlockChainConfirmation {
listener.onDepositTxConfirmedInBlockchain(); listener.onDepositTxConfirmedInBlockchain();
depositTransaction.getConfidence().removeEventListener(this); depositTransaction.getConfidence().removeEventListener(this);
log.trace("Tx is in blockchain"); log.trace("Tx is in blockchain");
resultHandler.handleResult();
} }
} }
}); });

View file

@ -29,7 +29,7 @@ public class VerifyTakeOfferFeePayment {
public static void run(ResultHandler resultHandler, ExceptionHandler exceptionHandler, WalletService walletService, public static void run(ResultHandler resultHandler, ExceptionHandler exceptionHandler, WalletService walletService,
String takeOfferFeeTxId) { String takeOfferFeeTxId) {
log.trace("Run task"); log.trace("Run VerifyTakeOfferFeePayment task");
//TODO mocked yet, need a confidence listeners //TODO mocked yet, need a confidence listeners
int numOfPeersSeenTx = walletService.getNumOfPeersSeenTx(takeOfferFeeTxId); int numOfPeersSeenTx = walletService.getNumOfPeersSeenTx(takeOfferFeeTxId);
if (numOfPeersSeenTx > 2) { if (numOfPeersSeenTx > 2) {

View file

@ -26,10 +26,11 @@ import io.bitsquare.offer.Offer;
import io.bitsquare.trade.Contract; import io.bitsquare.trade.Contract;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeMessageService; import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.listeners.SellerTakesOfferProtocolListener;
import io.bitsquare.trade.protocol.trade.offerer.messages.BankTransferInitedMessage; import io.bitsquare.trade.protocol.trade.offerer.messages.BankTransferInitedMessage;
import io.bitsquare.trade.protocol.trade.offerer.messages.DepositTxPublishedMessage; import io.bitsquare.trade.protocol.trade.offerer.messages.DepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.offerer.messages.RequestTakerDepositPaymentMessage;
import io.bitsquare.trade.protocol.trade.offerer.messages.RespondToTakeOfferRequestMessage; import io.bitsquare.trade.protocol.trade.offerer.messages.RespondToTakeOfferRequestMessage;
import io.bitsquare.trade.protocol.trade.offerer.messages.TakerDepositPaymentRequestMessage;
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.GetPeerAddress; import io.bitsquare.trade.protocol.trade.taker.tasks.GetPeerAddress;
import io.bitsquare.trade.protocol.trade.taker.tasks.PayDeposit; import io.bitsquare.trade.protocol.trade.taker.tasks.PayDeposit;
@ -37,8 +38,9 @@ import io.bitsquare.trade.protocol.trade.taker.tasks.PayTakeOfferFee;
import io.bitsquare.trade.protocol.trade.taker.tasks.RequestTakeOffer; import io.bitsquare.trade.protocol.trade.taker.tasks.RequestTakeOffer;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxToOfferer; import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxToOfferer;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendSignedTakerDepositTxAsHex; import io.bitsquare.trade.protocol.trade.taker.tasks.SendSignedTakerDepositTxAsHex;
import io.bitsquare.trade.protocol.trade.taker.tasks.SendTakeOfferFeePayedTxId; import io.bitsquare.trade.protocol.trade.taker.tasks.SendTakeOfferFeePayedMessage;
import io.bitsquare.trade.protocol.trade.taker.tasks.SignAndPublishPayoutTx; import io.bitsquare.trade.protocol.trade.taker.tasks.SignAndPublishPayoutTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.TakerCommitDepositTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOffererAccount; import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOffererAccount;
import io.bitsquare.user.User; import io.bitsquare.user.User;
@ -54,6 +56,7 @@ import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.*; import static com.google.common.base.Preconditions.*;
import static io.bitsquare.util.Validator.*; import static io.bitsquare.util.Validator.*;
/** /**
* Responsible for the correct execution of the sequence of tasks, message passing to the peer and message processing * Responsible for the correct execution of the sequence of tasks, message passing to the peer and message processing
* from the peer. * from the peer.
@ -69,16 +72,20 @@ public class SellerTakesOfferProtocol {
Init, Init,
GetPeerAddress, GetPeerAddress,
RequestTakeOffer, RequestTakeOffer,
handleRespondToTakeOfferRequestMessage,
PayTakeOfferFee, PayTakeOfferFee,
SendTakeOfferFeePayedMessage,
onRequestTakerDepositPaymentMessage, handleTakerDepositPaymentRequestMessage,
SendTakeOfferFeePayedTxId,
VerifyOffererAccount, VerifyOffererAccount,
CreateAndSignContract, CreateAndSignContract,
PayDeposit, PayDeposit,
SendSignedTakerDepositTxAsHex, SendSignedTakerDepositTxAsHex,
onBankTransferInitedMessage,
handleDepositTxPublishedMessage,
TakerCommitDepositTx,
handleBankTransferInitedMessage,
SignAndPublishPayoutTx, SignAndPublishPayoutTx,
SendPayoutTxToOfferer SendPayoutTxToOfferer
} }
@ -98,7 +105,7 @@ public class SellerTakesOfferProtocol {
private final String accountId; private final String accountId;
private final PublicKey messagePublicKey; private final PublicKey messagePublicKey;
private final Coin tradeAmount; private final Coin tradeAmount;
private final String pubKeyForThatTrade; private final String tradePubKeyAsHex;
private final ECKey accountKey; private final ECKey accountKey;
private final PublicKey offererMessagePublicKey; private final PublicKey offererMessagePublicKey;
private final Coin securityDeposit; private final Coin securityDeposit;
@ -120,12 +127,9 @@ public class SellerTakesOfferProtocol {
private Coin offererPaybackAmount; private Coin offererPaybackAmount;
private Coin takerPaybackAmount; private Coin takerPaybackAmount;
private String offererPayoutAddress; private String offererPayoutAddress;
private int repeatCounter = 0;
// state // state
private State state; private State state;
private int step = 0;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -159,7 +163,7 @@ public class SellerTakesOfferProtocol {
accountId = user.getAccountId(); accountId = user.getAccountId();
messagePublicKey = user.getMessagePublicKey(); messagePublicKey = user.getMessagePublicKey();
pubKeyForThatTrade = walletService.getAddressInfoByTradeID(tradeId).getPubKeyAsHexString(); tradePubKeyAsHex = walletService.getAddressInfoByTradeID(tradeId).getPubKeyAsHexString();
accountKey = walletService.getRegistrationAddressEntry().getKey(); accountKey = walletService.getRegistrationAddressEntry().getKey();
state = State.Init; state = State.Init;
@ -170,38 +174,18 @@ public class SellerTakesOfferProtocol {
} }
// 1. GetPeerAddress // 1. GetPeerAddress
// Async
// In case of an error: Repeat once, then give up. No rollback activity needed
private void getPeerAddress() { private void getPeerAddress() {
log.debug("getPeerAddress called " + step++); log.debug("getPeerAddress called: state = " + state);
state = State.GetPeerAddress; state = State.GetPeerAddress;
GetPeerAddress.run(this::onResultGetPeerAddress, this::onGetPeerAddressFault, tradeMessageService, offererMessagePublicKey); GetPeerAddress.run(this::handleGetPeerAddressResult, this::handleErrorMessage, tradeMessageService, offererMessagePublicKey);
}
private void onGetPeerAddressFault(String errorMessage) {
log.debug("Run getPeerAddress again after onGetPeerAddressFault" + step);
GetPeerAddress.run(this::onResultGetPeerAddress, this::onErrorMessage, tradeMessageService, offererMessagePublicKey);
} }
// 2. RequestTakeOffer // 2. RequestTakeOffer
// Async private void handleGetPeerAddressResult(Peer peer) {
// In case of an error: Repeat once, then give up. No rollback activity needed log.debug("handleGetPeerAddressResult called: state = " + state);
public void onResultGetPeerAddress(Peer peer) {
log.debug("onResultGetPeerAddress called " + step++);
this.peer = peer; this.peer = peer;
state = State.RequestTakeOffer; state = State.RequestTakeOffer;
RequestTakeOffer.run(this::onResultRequestTakeOffer, this::onRequestTakeOfferFault, peer, tradeMessageService, tradeId); RequestTakeOffer.run(this::handleErrorMessage, tradeMessageService, peer, tradeId);
}
private void onRequestTakeOfferFault(Throwable throwable) {
log.debug("Run getPeerAddress again after onGetPeerAddressFault" + step);
RequestTakeOffer.run(this::onResultRequestTakeOffer, this::onFault, peer, tradeMessageService, tradeId);
}
public void onResultRequestTakeOffer() {
log.debug("onResultRequestTakeOffer called " + step++);
listener.onWaitingForPeerResponse(state);
} }
@ -209,52 +193,57 @@ public class SellerTakesOfferProtocol {
// Incoming message from peer // Incoming message from peer
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// 3. PayTakeOfferFee // 5. handleRespondToTakeOfferRequestMessage
// Async public void handleRespondToTakeOfferRequestMessage(RespondToTakeOfferRequestMessage message) {
// In case of an error: Repeat once, then give up. No rollback activity needed log.debug("handleRespondToTakeOfferRequestMessage called: state = " + state);
public void onRespondToTakeOfferRequestMessage(RespondToTakeOfferRequestMessage message) {
log.debug("onRespondToTakeOfferRequestMessage called " + step++);
log.debug("state " + state);
checkState(state == State.RequestTakeOffer);
checkArgument(tradeId.equals(message.getTradeId()));
if (message.isTakeOfferRequestAccepted()) {
state = State.PayTakeOfferFee;
listener.onTakeOfferRequestAccepted(trade);
PayTakeOfferFee.run(this::onResultPayTakeOfferFee, this::onFault, walletService, tradeId);
}
else {
listener.onTakeOfferRequestRejected(trade);
// exit case
}
}
public void onResultPayTakeOfferFee(String takeOfferFeeTxId) {
log.debug("onResultPayTakeOfferFee called " + step++);
trade.setTakeOfferFeeTxID(takeOfferFeeTxId);
state = State.SendTakeOfferFeePayedTxId;
SendTakeOfferFeePayedTxId.run(this::onResultSendTakeOfferFeePayedTxId, this::onFault, peer,
tradeMessageService, tradeId, takeOfferFeeTxId, tradeAmount, pubKeyForThatTrade);
}
public void onResultSendTakeOfferFeePayedTxId() {
log.debug("onResultSendTakeOfferFeePayedTxId called " + step++);
listener.onWaitingForPeerResponse(state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
public void onRequestTakerDepositPaymentMessage(RequestTakerDepositPaymentMessage message) {
log.debug("onRequestTakerDepositPaymentMessage called " + step++);
log.debug("state " + state);
// validation // validation
checkState(state == State.SendTakeOfferFeePayedTxId); checkState(state == State.RequestTakeOffer);
checkArgument(tradeId.equals(message.getTradeId())); checkTradeId(tradeId, message);
// apply new state
state = State.handleRespondToTakeOfferRequestMessage;
if (message.isTakeOfferRequestAccepted()) {
trade.setState(Trade.State.OFFERER_ACCEPTED);
listener.onTakeOfferRequestAccepted();
// next task
payTakeOfferFee();
}
else {
// exit case
trade.setState(Trade.State.OFFERER_REJECTED);
listener.onTakeOfferRequestRejected();
}
}
// 6. PayTakeOfferFee
private void payTakeOfferFee() {
state = State.PayTakeOfferFee;
PayTakeOfferFee.run(this::handlePayTakeOfferFeeResult, this::handleFault, walletService, tradeId);
}
// 7. SendTakeOfferFeePayedMessage
private void handlePayTakeOfferFeeResult(String takeOfferFeeTxId) {
log.debug("handlePayTakeOfferFeeResult called: state = " + state);
trade.setTakeOfferFeeTxID(takeOfferFeeTxId);
state = State.SendTakeOfferFeePayedMessage;
SendTakeOfferFeePayedMessage.run(this::handleErrorMessage, peer,
tradeMessageService, tradeId, takeOfferFeeTxId, tradeAmount, tradePubKeyAsHex);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer
///////////////////////////////////////////////////////////////////////////////////////////
// 5. VerifyOffererAccount
public void handleTakerDepositPaymentRequestMessage(TakerDepositPaymentRequestMessage message) {
log.debug("handleTakerDepositPaymentRequestMessage called: state = " + state);
// validation
checkState(state == State.SendTakeOfferFeePayedMessage);
checkTradeId(tradeId, message);
String peersAccountId = nonEmptyStringOf(message.getAccountId()); String peersAccountId = nonEmptyStringOf(message.getAccountId());
BankAccount peersBankAccount = checkNotNull(message.getBankAccount()); BankAccount peersBankAccount = checkNotNull(message.getBankAccount());
String offererPubKey = nonEmptyStringOf(message.getOffererPubKey()); String offererPubKey = nonEmptyStringOf(message.getOffererPubKey());
@ -262,7 +251,7 @@ public class SellerTakesOfferProtocol {
long offererTxOutIndex = nonNegativeLongOf(message.getOffererTxOutIndex()); long offererTxOutIndex = nonNegativeLongOf(message.getOffererTxOutIndex());
// apply new state // apply new state
state = State.onRequestTakerDepositPaymentMessage; state = State.handleTakerDepositPaymentRequestMessage;
this.peersAccountId = peersAccountId; this.peersAccountId = peersAccountId;
this.peersBankAccount = peersBankAccount; this.peersBankAccount = peersBankAccount;
this.peersPubKey = offererPubKey; this.peersPubKey = offererPubKey;
@ -271,16 +260,17 @@ public class SellerTakesOfferProtocol {
// next task // next task
state = State.VerifyOffererAccount; state = State.VerifyOffererAccount;
VerifyOffererAccount.run(this::onResultVerifyOffererAccount, this::onFault, blockChainService, peersAccountId, VerifyOffererAccount.run(this::handleVerifyOffererAccountResult, this::handleFault, blockChainService, peersAccountId, peersBankAccount);
peersBankAccount);
} }
public void onResultVerifyOffererAccount() { // 6. CreateAndSignContract
log.debug("onResultVerifyOffererAccount called " + step++); private void handleVerifyOffererAccountResult() {
log.debug("handleVerifyOffererAccountResult called: state = " + state);
checkState(state == State.VerifyOffererAccount);
String takeOfferFeeTxId = trade.getTakeOfferFeeTxId(); String takeOfferFeeTxId = trade.getTakeOfferFeeTxId();
state = State.CreateAndSignContract; state = State.CreateAndSignContract;
CreateAndSignContract.run(this::onResultCreateAndSignContract, CreateAndSignContract.run(this::handleCreateAndSignContractResult,
this::onFault, this::handleFault,
signatureService, signatureService,
offer, offer,
tradeAmount, tradeAmount,
@ -294,26 +284,26 @@ public class SellerTakesOfferProtocol {
accountKey); accountKey);
} }
public void onResultCreateAndSignContract(Contract contract, String contractAsJson, String signature) { // 7. PayDeposit
log.debug("onResultCreateAndSignContract called " + step++); private void handleCreateAndSignContractResult(Contract contract, String contractAsJson, String signature) {
log.debug("handleCreateAndSignContractResult called: state = " + state);
checkState(state == State.CreateAndSignContract);
trade.setContract(contract); trade.setContract(contract);
trade.setContractAsJson(contractAsJson); trade.setContractAsJson(contractAsJson);
trade.setContractTakerSignature(signature); trade.setTakerContractSignature(signature);
state = State.PayDeposit; state = State.PayDeposit;
PayDeposit.run(this::onResultPayDeposit, this::onFault, walletService, securityDeposit, tradeAmount, tradeId, PayDeposit.run(this::handlePayDepositResult, this::handleFault, walletService, securityDeposit, tradeAmount, tradeId,
pubKeyForThatTrade, arbitratorPubKey, peersPubKey, preparedPeersDepositTxAsHex); tradePubKeyAsHex, arbitratorPubKey, peersPubKey, preparedPeersDepositTxAsHex);
} }
public void onResultPayDeposit(Transaction signedTakerDepositTx) { // 8. SendSignedTakerDepositTxAsHex
log.debug("onResultPayDeposit called " + step++); private void handlePayDepositResult(Transaction signedTakerDepositTx) {
log.debug("handlePayDepositResult called: state = " + state);
checkState(state == State.PayDeposit);
String contractAsJson = trade.getContractAsJson(); String contractAsJson = trade.getContractAsJson();
String takerSignature = trade.getTakerSignature(); String takerContractSignature = trade.getTakerContractSignature();
state = State.SendSignedTakerDepositTxAsHex; state = State.SendSignedTakerDepositTxAsHex;
SendSignedTakerDepositTxAsHex.run(this::onResultSendSignedTakerDepositTxAsHex, SendSignedTakerDepositTxAsHex.run(this::handleErrorMessage,
this::onFault,
peer, peer,
tradeMessageService, tradeMessageService,
walletService, walletService,
@ -322,30 +312,39 @@ public class SellerTakesOfferProtocol {
messagePublicKey, messagePublicKey,
tradeId, tradeId,
contractAsJson, contractAsJson,
takerSignature, takerContractSignature,
signedTakerDepositTx, signedTakerDepositTx,
peersTxOutIndex); peersTxOutIndex);
} }
public void onResultSendSignedTakerDepositTxAsHex() {
log.debug("onResultSendSignedTakerDepositTxAsHex called " + step++);
listener.onWaitingForPeerResponse(state);
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer // Incoming message from peer
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// informational, does only trigger UI feedback/update // 9.a TakerCommitDepositTx
public void onDepositTxPublishedMessage(DepositTxPublishedMessage message) { public void handleDepositTxPublishedMessage(DepositTxPublishedMessage message) {
log.debug("onDepositTxPublishedMessage called " + step++); log.debug("onDepositTxPublishedMessage called: state = " + state);
log.debug("state " + state); log.debug("state " + state);
// validation
checkState(state.ordinal() >= State.SendSignedTakerDepositTxAsHex.ordinal()); checkState(state.ordinal() >= State.SendSignedTakerDepositTxAsHex.ordinal());
checkArgument(tradeId.equals(message.getTradeId())); checkTradeId(tradeId, message);
//TODO takerCommitDepositTx should be in task as well nonEmptyStringOf(message.getDepositTxAsHex());
Transaction tx = walletService.takerCommitDepositTx(message.getDepositTxAsHex());
listener.onDepositTxPublished(tx); // apply new state
state = State.handleDepositTxPublishedMessage;
String depositTxAsHex = message.getDepositTxAsHex();
// next task
state = State.TakerCommitDepositTx;
TakerCommitDepositTx.run(this::handleTakerCommitDepositTxResult, this::handleFault, walletService, depositTxAsHex);
}
private void handleTakerCommitDepositTxResult(Transaction transaction) {
log.debug("handleTakerCommitDepositTxResult called: state = " + state);
listener.onDepositTxPublished(transaction);
} }
@ -353,14 +352,15 @@ public class SellerTakesOfferProtocol {
// Incoming message from peer // Incoming message from peer
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// informational, store data for later, does only trigger UI feedback/update // 9.b. handleBankTransferInitedMessage
public void onBankTransferInitedMessage(BankTransferInitedMessage message) { public void handleBankTransferInitedMessage(BankTransferInitedMessage message) {
log.debug("onBankTransferInitedMessage called " + step++); log.debug("onBankTransferInitedMessage called: state = " + state);
log.debug("state " + state); log.debug("state " + state);
// validate // validate
checkState(state.ordinal() >= State.SendSignedTakerDepositTxAsHex.ordinal() && checkState(state.ordinal() >= State.SendSignedTakerDepositTxAsHex.ordinal() &&
state.ordinal() < State.SignAndPublishPayoutTx.ordinal()); state.ordinal() < State.SignAndPublishPayoutTx.ordinal());
checkArgument(tradeId.equals(message.getTradeId())); checkTradeId(tradeId, message);
String depositTxAsHex = nonEmptyStringOf(message.getDepositTxAsHex()); String depositTxAsHex = nonEmptyStringOf(message.getDepositTxAsHex());
String offererSignatureR = nonEmptyStringOf(message.getOffererSignatureR()); String offererSignatureR = nonEmptyStringOf(message.getOffererSignatureR());
String offererSignatureS = nonEmptyStringOf(message.getOffererSignatureS()); String offererSignatureS = nonEmptyStringOf(message.getOffererSignatureS());
@ -369,7 +369,7 @@ public class SellerTakesOfferProtocol {
String offererPayoutAddress = nonEmptyStringOf(message.getOffererPayoutAddress()); String offererPayoutAddress = nonEmptyStringOf(message.getOffererPayoutAddress());
// apply state // apply state
state = State.onBankTransferInitedMessage; state = State.handleBankTransferInitedMessage;
this.depositTxAsHex = depositTxAsHex; this.depositTxAsHex = depositTxAsHex;
this.offererSignatureR = offererSignatureR; this.offererSignatureR = offererSignatureR;
this.offererSignatureS = offererSignatureS; this.offererSignatureS = offererSignatureS;
@ -386,14 +386,15 @@ public class SellerTakesOfferProtocol {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// User clicked the "bank transfer received" button, so we release the funds for pay out // User clicked the "bank transfer received" button, so we release the funds for pay out
public void onUIEventFiatReceived() { // 10. SignAndPublishPayoutTx
log.debug("onUIEventFiatReceived called " + step++); public void handleUIEventFiatReceived() {
log.debug("onUIEventFiatReceived called: state = " + state);
log.debug("state " + state); log.debug("state " + state);
checkState(state == State.onBankTransferInitedMessage); checkState(state == State.handleBankTransferInitedMessage || state == State.TakerCommitDepositTx);
state = State.SignAndPublishPayoutTx; state = State.SignAndPublishPayoutTx;
SignAndPublishPayoutTx.run(this::onResultSignAndPublishPayoutTx, SignAndPublishPayoutTx.run(this::handleSignAndPublishPayoutTxResult,
this::onFault, this::handleFault,
walletService, walletService,
tradeId, tradeId,
depositTxAsHex, depositTxAsHex,
@ -404,26 +405,17 @@ public class SellerTakesOfferProtocol {
offererPayoutAddress); offererPayoutAddress);
} }
public void onResultSignAndPublishPayoutTx(Transaction transaction, String payoutTxAsHex) { // 11. SendPayoutTxToOfferer
log.debug("onResultSignAndPublishPayoutTx called " + step++); private void handleSignAndPublishPayoutTxResult(Transaction transaction, String payoutTxAsHex) {
log.debug("handleSignAndPublishPayoutTxResult called: state = " + state);
listener.onPayoutTxPublished(trade, transaction); listener.onPayoutTxPublished(trade, transaction);
state = State.SendPayoutTxToOfferer; state = State.SendPayoutTxToOfferer;
SendPayoutTxToOfferer.run(this::onResultSendPayoutTxToOfferer, this::onFault, peer, tradeMessageService, SendPayoutTxToOfferer.run(this::handleSendPayoutTxToOffererResult, this::handleErrorMessage, peer, tradeMessageService,
tradeId, payoutTxAsHex); tradeId, payoutTxAsHex);
} }
public void onResultSendPayoutTxToOfferer() { private void handleSendPayoutTxToOffererResult() {
log.debug("onResultSendPayoutTxToOfferer called " + step++); log.debug("onResultSendPayoutTxToOfferer called: state = " + state);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters, Setters
///////////////////////////////////////////////////////////////////////////////////////////
public String getId() {
return tradeId;
} }
@ -432,12 +424,14 @@ public class SellerTakesOfferProtocol {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// generic fault handler // generic fault handler
private void onFault(Throwable throwable) { private void handleFault(Throwable throwable) {
trade.setFault(throwable);
trade.setState(Trade.State.FAILED);
listener.onFault(throwable, state); listener.onFault(throwable, state);
} }
private void onErrorMessage(String errorMessage) { private void handleErrorMessage(String errorMessage) {
listener.onFault(new Exception(errorMessage), state); handleFault(new Exception(errorMessage));
} }
} }

View file

@ -29,13 +29,13 @@ public class TakeOfferFeePayedMessage implements Serializable, TradeMessage {
private final Coin tradeAmount; private final Coin tradeAmount;
private final String takeOfferFeeTxID; private final String takeOfferFeeTxID;
private final String takerPubKey; private final String tradePubKeyAsHex;
public TakeOfferFeePayedMessage(String tradeId, String takeOfferFeeTxID, Coin tradeAmount, String takerPubKey) { public TakeOfferFeePayedMessage(String tradeId, String takeOfferFeeTxID, Coin tradeAmount, String tradePubKeyAsHex) {
this.tradeId = tradeId; this.tradeId = tradeId;
this.takeOfferFeeTxID = takeOfferFeeTxID; this.takeOfferFeeTxID = takeOfferFeeTxID;
this.tradeAmount = tradeAmount; this.tradeAmount = tradeAmount;
this.takerPubKey = takerPubKey; this.tradePubKeyAsHex = tradePubKeyAsHex;
} }
@Override @Override
@ -51,8 +51,8 @@ public class TakeOfferFeePayedMessage implements Serializable, TradeMessage {
return takeOfferFeeTxID; return takeOfferFeeTxID;
} }
public String getTakerPubKey() { public String getTakerPubKeyAsHex() {
return takerPubKey; return tradePubKeyAsHex;
} }
} }

View file

@ -48,7 +48,7 @@ public class CreateAndSignContract {
String peersAccountId, String peersAccountId,
BankAccount peersBankAccount, BankAccount peersBankAccount,
ECKey registrationKey) { ECKey registrationKey) {
log.trace("Run task"); log.trace("Run CreateAndSignContract task");
try { try {
Contract contract = new Contract(offer, tradeAmount, takeOfferFeeTxId, peersAccountId, accountId, Contract contract = new Contract(offer, tradeAmount, takeOfferFeeTxId, peersAccountId, accountId,
peersBankAccount, bankAccount, peersMessagePublicKey, messagePublicKey); peersBankAccount, bankAccount, peersMessagePublicKey, messagePublicKey);

View file

@ -29,7 +29,7 @@ import org.slf4j.LoggerFactory;
public class GetPeerAddress { public class GetPeerAddress {
private static final Logger log = LoggerFactory.getLogger(GetPeerAddress.class); private static final Logger log = LoggerFactory.getLogger(GetPeerAddress.class);
public static void run(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler, public static void run(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler,
TradeMessageService tradeMessageService, PublicKey messagePublicKey) { TradeMessageService tradeMessageService, PublicKey messagePublicKey) {
log.trace("Run GetPeerAddress task"); log.trace("Run GetPeerAddress task");
@ -42,8 +42,8 @@ public class GetPeerAddress {
@Override @Override
public void onFailed() { public void onFailed() {
log.error("Lookup for peer address failed."); log.error("DHT lookup for peer address failed.");
errorMessageHandler.handleErrorMessage("Lookup for peer address failed."); errorMessageHandler.handleErrorMessage("DHT lookup for peer address failed.");
} }
}); });
} }

View file

@ -40,7 +40,7 @@ public class PayDeposit {
String arbitratorPubKey, String arbitratorPubKey,
String offererPubKey, String offererPubKey,
String preparedOffererDepositTxAsHex) { String preparedOffererDepositTxAsHex) {
log.trace("Run task"); log.trace("Run PayDeposit task");
try { try {
Coin amountToPay = tradeAmount.add(securityDeposit); Coin amountToPay = tradeAmount.add(securityDeposit);
Coin msOutputAmount = amountToPay.add(securityDeposit); Coin msOutputAmount = amountToPay.add(securityDeposit);
@ -53,18 +53,15 @@ public class PayDeposit {
preparedOffererDepositTxAsHex, preparedOffererDepositTxAsHex,
tradeId); tradeId);
log.trace("sharedModel.signedTakerDepositTx: " + signedTakerDepositTx); log.trace("signedTakerDepositTx: " + signedTakerDepositTx);
resultHandler.onResult(signedTakerDepositTx); resultHandler.onResult(signedTakerDepositTx);
} catch (InsufficientMoneyException e) { } catch (InsufficientMoneyException e) {
log.error("Pay deposit faultHandler.onFault due InsufficientMoneyException " + e); log.error("Pay deposit failed due InsufficientMoneyException " + e);
exceptionHandler.handleException( exceptionHandler.handleException(e);
new Exception("Pay deposit faultHandler.onFault due InsufficientMoneyException " + e));
} }
} }
public interface ResultHandler { public interface ResultHandler {
void onResult(Transaction signedTakerDepositTx); void onResult(Transaction signedTakerDepositTx);
} }
} }

View file

@ -35,7 +35,7 @@ public class PayTakeOfferFee {
public static void run(ResultHandler resultHandler, ExceptionHandler exceptionHandler, WalletService walletService, public static void run(ResultHandler resultHandler, ExceptionHandler exceptionHandler, WalletService walletService,
String tradeId) { String tradeId) {
log.trace("Run task"); log.trace("Run PayTakeOfferFee task");
try { try {
walletService.payTakeOfferFee(tradeId, new FutureCallback<Transaction>() { walletService.payTakeOfferFee(tradeId, new FutureCallback<Transaction>() {
@Override @Override
@ -46,15 +46,13 @@ public class PayTakeOfferFee {
@Override @Override
public void onFailure(@NotNull Throwable t) { public void onFailure(@NotNull Throwable t) {
log.error("Take offer fee paid faultHandler.onFault with exception: " + t); log.error("Pay take offer fee caused an exception: " + t);
exceptionHandler.handleException( exceptionHandler.handleException(t);
new Exception("Take offer fee paid faultHandler.onFault with exception: " + t));
} }
}); });
} catch (InsufficientMoneyException e) { } catch (InsufficientMoneyException e) {
log.error("Take offer fee paid faultHandler.onFault due InsufficientMoneyException " + e); log.error("Pay take offer fee caused an exception: " + e);
exceptionHandler.handleException( exceptionHandler.handleException(e);
new Exception("Take offer fee paid faultHandler.onFault due to InsufficientMoneyException " + e));
} }
} }

View file

@ -17,12 +17,11 @@
package io.bitsquare.trade.protocol.trade.taker.tasks; package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.TradeMessageService; import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.listeners.SendMessageListener; import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestTakeOfferMessage; import io.bitsquare.trade.protocol.trade.taker.messages.RequestTakeOfferMessage;
import io.bitsquare.util.handlers.ExceptionHandler; import io.bitsquare.util.handlers.ErrorMessageHandler;
import io.bitsquare.util.handlers.ResultHandler;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -30,21 +29,20 @@ import org.slf4j.LoggerFactory;
public class RequestTakeOffer { public class RequestTakeOffer {
private static final Logger log = LoggerFactory.getLogger(RequestTakeOffer.class); private static final Logger log = LoggerFactory.getLogger(RequestTakeOffer.class);
public static void run(ResultHandler resultHandler, ExceptionHandler exceptionHandler, Peer peer, public static void run(ErrorMessageHandler errorMessageHandler,
TradeMessageService tradeMessageService, String tradeId) { TradeMessageService tradeMessageService, Peer peer, String tradeId) {
log.trace("Run RequestTakeOffer task"); log.trace("Run RequestTakeOffer task");
tradeMessageService.sendMessage(peer, new RequestTakeOfferMessage(tradeId), tradeMessageService.sendMessage(peer, new RequestTakeOfferMessage(tradeId),
new SendMessageListener() { new SendMessageListener() {
@Override @Override
public void handleResult() { public void handleResult() {
log.trace("RequestTakeOfferMessage successfully arrived at peer"); log.trace("Sending RequestTakeOfferMessage succeeded.");
resultHandler.handleResult();
} }
@Override @Override
public void handleFault() { public void handleFault() {
log.error("RequestTakeOfferMessage did not arrive at peer"); log.error("Sending RequestTakeOfferMessage failed.");
exceptionHandler.handleException(new Exception("RequestTakeOfferMessage did not arrive at peer")); errorMessageHandler.handleErrorMessage("Sending RequestTakeOfferMessage failed.");
} }
}); });
} }

View file

@ -17,11 +17,11 @@
package io.bitsquare.trade.protocol.trade.taker.tasks; package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.TradeMessageService; import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.listeners.SendMessageListener; import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.protocol.trade.taker.messages.PayoutTxPublishedMessage; import io.bitsquare.trade.protocol.trade.taker.messages.PayoutTxPublishedMessage;
import io.bitsquare.util.handlers.ExceptionHandler; import io.bitsquare.util.handlers.ErrorMessageHandler;
import io.bitsquare.util.handlers.ResultHandler; import io.bitsquare.util.handlers.ResultHandler;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -30,7 +30,7 @@ import org.slf4j.LoggerFactory;
public class SendPayoutTxToOfferer { public class SendPayoutTxToOfferer {
private static final Logger log = LoggerFactory.getLogger(SendPayoutTxToOfferer.class); private static final Logger log = LoggerFactory.getLogger(SendPayoutTxToOfferer.class);
public static void run(ResultHandler resultHandler, ExceptionHandler exceptionHandler, Peer peer, public static void run(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler, Peer peer,
TradeMessageService tradeMessageService, String tradeId, String payoutTxAsHex) { TradeMessageService tradeMessageService, String tradeId, String payoutTxAsHex) {
log.trace("Run task"); log.trace("Run task");
PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(tradeId, payoutTxAsHex); PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(tradeId, payoutTxAsHex);
@ -44,7 +44,7 @@ public class SendPayoutTxToOfferer {
@Override @Override
public void handleFault() { public void handleFault() {
log.error("PayoutTxPublishedMessage did not arrive at peer"); log.error("PayoutTxPublishedMessage did not arrive at peer");
exceptionHandler.handleException(new Exception("PayoutTxPublishedMessage did not arrive at peer")); errorMessageHandler.handleErrorMessage("PayoutTxPublishedMessage did not arrive at peer");
} }
}); });

View file

@ -19,12 +19,11 @@ package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.bank.BankAccount; import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.WalletService; import io.bitsquare.btc.WalletService;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.TradeMessageService; import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.listeners.SendMessageListener; import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.protocol.trade.taker.messages.RequestOffererPublishDepositTxMessage; import io.bitsquare.trade.protocol.trade.taker.messages.RequestOffererPublishDepositTxMessage;
import io.bitsquare.util.handlers.ExceptionHandler; import io.bitsquare.util.handlers.ErrorMessageHandler;
import io.bitsquare.util.handlers.ResultHandler;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.Utils; import org.bitcoinj.core.Utils;
@ -37,8 +36,7 @@ import org.slf4j.LoggerFactory;
public class SendSignedTakerDepositTxAsHex { public class SendSignedTakerDepositTxAsHex {
private static final Logger log = LoggerFactory.getLogger(SendSignedTakerDepositTxAsHex.class); private static final Logger log = LoggerFactory.getLogger(SendSignedTakerDepositTxAsHex.class);
public static void run(ResultHandler resultHandler, public static void run(ErrorMessageHandler errorMessageHandler,
ExceptionHandler exceptionHandler,
Peer peer, Peer peer,
TradeMessageService tradeMessageService, TradeMessageService tradeMessageService,
WalletService walletService, WalletService walletService,
@ -47,10 +45,10 @@ public class SendSignedTakerDepositTxAsHex {
PublicKey messagePublicKey, PublicKey messagePublicKey,
String tradeId, String tradeId,
String contractAsJson, String contractAsJson,
String takerSignature, String takerContractSignature,
Transaction signedTakerDepositTx, Transaction signedTakerDepositTx,
long offererTxOutIndex) { long offererTxOutIndex) {
log.trace("Run task"); log.trace("Run SendSignedTakerDepositTxAsHex task");
long takerTxOutIndex = signedTakerDepositTx.getInput(1).getOutpoint().getIndex(); long takerTxOutIndex = signedTakerDepositTx.getInput(1).getOutpoint().getIndex();
RequestOffererPublishDepositTxMessage tradeMessage = new RequestOffererPublishDepositTxMessage(tradeId, RequestOffererPublishDepositTxMessage tradeMessage = new RequestOffererPublishDepositTxMessage(tradeId,
@ -64,7 +62,7 @@ public class SendSignedTakerDepositTxAsHex {
.getParentTransaction() .getParentTransaction()
.bitcoinSerialize()), .bitcoinSerialize()),
contractAsJson, contractAsJson,
takerSignature, takerContractSignature,
walletService.getAddressInfoByTradeID(tradeId).getAddressString(), walletService.getAddressInfoByTradeID(tradeId).getAddressString(),
takerTxOutIndex, takerTxOutIndex,
offererTxOutIndex); offererTxOutIndex);
@ -72,14 +70,12 @@ public class SendSignedTakerDepositTxAsHex {
@Override @Override
public void handleResult() { public void handleResult() {
log.trace("RequestOffererDepositPublicationMessage successfully arrived at peer"); log.trace("RequestOffererDepositPublicationMessage successfully arrived at peer");
resultHandler.handleResult();
} }
@Override @Override
public void handleFault() { public void handleFault() {
log.error("RequestOffererDepositPublicationMessage did not arrive at peer"); log.error("RequestOffererDepositPublicationMessage did not arrive at peer");
exceptionHandler.handleException( errorMessageHandler.handleErrorMessage("RequestOffererDepositPublicationMessage did not arrive at peer");
new Exception("RequestOffererDepositPublicationMessage did not arrive at peer"));
} }
}); });
} }

View file

@ -17,44 +17,41 @@
package io.bitsquare.trade.protocol.trade.taker.tasks; package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.TradeMessageService; import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.listeners.SendMessageListener; import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.network.Peer;
import io.bitsquare.trade.protocol.trade.taker.messages.TakeOfferFeePayedMessage; import io.bitsquare.trade.protocol.trade.taker.messages.TakeOfferFeePayedMessage;
import io.bitsquare.util.handlers.ExceptionHandler; import io.bitsquare.util.handlers.ErrorMessageHandler;
import io.bitsquare.util.handlers.ResultHandler;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class SendTakeOfferFeePayedTxId { public class SendTakeOfferFeePayedMessage {
private static final Logger log = LoggerFactory.getLogger(SendTakeOfferFeePayedTxId.class); private static final Logger log = LoggerFactory.getLogger(SendTakeOfferFeePayedMessage.class);
public static void run(ResultHandler resultHandler, public static void run(ErrorMessageHandler errorMessageHandler,
ExceptionHandler exceptionHandler,
Peer peer, Peer peer,
TradeMessageService tradeMessageService, TradeMessageService tradeMessageService,
String tradeId, String tradeId,
String takeOfferFeeTxId, String takeOfferFeeTxId,
Coin tradeAmount, Coin tradeAmount,
String pubKeyForThatTradeAsHex) { String tradePubKeyAsHex) {
log.trace("Run task"); log.trace("Run SendTakeOfferFeePayedMessage task");
TakeOfferFeePayedMessage msg = new TakeOfferFeePayedMessage(tradeId, takeOfferFeeTxId, tradeAmount, TakeOfferFeePayedMessage msg = new TakeOfferFeePayedMessage(tradeId, takeOfferFeeTxId, tradeAmount,
pubKeyForThatTradeAsHex); tradePubKeyAsHex);
tradeMessageService.sendMessage(peer, msg, new SendMessageListener() { tradeMessageService.sendMessage(peer, msg, new SendMessageListener() {
@Override @Override
public void handleResult() { public void handleResult() {
log.trace("TakeOfferFeePayedMessage successfully arrived at peer"); log.trace("TakeOfferFeePayedMessage succeeded.");
resultHandler.handleResult();
} }
@Override @Override
public void handleFault() { public void handleFault() {
log.error("TakeOfferFeePayedMessage did not arrive at peer"); log.error("Sending TakeOfferFeePayedMessage failed.");
exceptionHandler.handleException(new Exception("TakeOfferFeePayedMessage did not arrive at peer")); errorMessageHandler.handleErrorMessage("Sending TakeOfferFeePayedMessage failed.");
} }
}); });
} }

View file

@ -0,0 +1,45 @@
/*
* 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.tasks;
import io.bitsquare.btc.WalletService;
import io.bitsquare.util.handlers.ExceptionHandler;
import org.bitcoinj.core.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TakerCommitDepositTx {
private static final Logger log = LoggerFactory.getLogger(TakerCommitDepositTx.class);
public static void run(ResultHandler resultHandler, ExceptionHandler exceptionHandler, WalletService walletService, String depositTxAsHex) {
log.trace("Run PayDeposit task");
try {
Transaction transaction = walletService.takerCommitDepositTx(depositTxAsHex);
resultHandler.onResult(transaction);
} catch (Exception e) {
log.error("takerCommitDepositTx failed with exception " + e);
exceptionHandler.handleException(e);
}
}
public interface ResultHandler {
void onResult(Transaction transaction);
}
}

View file

@ -31,7 +31,7 @@ public class VerifyOffererAccount {
public static void run(ResultHandler resultHandler, ExceptionHandler exceptionHandler, public static void run(ResultHandler resultHandler, ExceptionHandler exceptionHandler,
BlockChainService blockChainService, String peersAccountId, BankAccount peersBankAccount) { BlockChainService blockChainService, String peersAccountId, BankAccount peersBankAccount) {
log.trace("Run task"); log.trace("Run VerifyOffererAccount task");
VerifyPeerAccount.run(resultHandler, exceptionHandler, blockChainService, peersAccountId, peersBankAccount); VerifyPeerAccount.run(resultHandler, exceptionHandler, blockChainService, peersAccountId, peersBankAccount);
} }
} }

View file

@ -17,6 +17,8 @@
package io.bitsquare.util; package io.bitsquare.util;
import io.bitsquare.trade.protocol.trade.TradeMessage;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import static com.google.common.base.Preconditions.*; import static com.google.common.base.Preconditions.*;
@ -49,4 +51,9 @@ public class Validator {
return value; return value;
} }
public static void checkTradeId(String tradeId, TradeMessage tradeMessage) {
checkArgument(tradeId.equals(tradeMessage.getTradeId()));
}
} }

View file

@ -48,7 +48,7 @@
<logger name="org.bitcoinj.core.BitcoinSerializer" level="WARN"/> <logger name="org.bitcoinj.core.BitcoinSerializer" level="WARN"/>
<logger name="org.bitcoinj.core.AbstractBlockChain" level="WARN"/> <logger name="org.bitcoinj.core.AbstractBlockChain" level="WARN"/>
<logger name="org.bitcoinj.wallet.DeterministicKeyChain" level="WARN"/> <logger name="org.bitcoinj.wallet.DeterministicKeyChain" level="WARN"/>
<logger name="io.bitsquare.btc.WalletService" level="WARN"/> <!-- <logger name="io.bitsquare.btc.WalletService" level="WARN"/>-->
<!-- <!--
<logger name="org.bitcoinj.core.Wallet" level="OFF"/> <logger name="org.bitcoinj.core.Wallet" level="OFF"/>