Move fee verification task to end

This commit is contained in:
Manfred Karrer 2015-03-10 23:29:28 +01:00
parent aee5addacf
commit 033709f288
14 changed files with 398 additions and 265 deletions

View file

@ -611,7 +611,6 @@ public class WalletService {
// 1. step: deposit tx // 1. step: deposit tx
// Offerer creates the 2of3 multiSig deposit tx with his unsigned input and change output // Offerer creates the 2of3 multiSig deposit tx with his unsigned input and change output
public Transaction offererCreatesMSTxAndAddPayment(Coin offererInputAmount, public Transaction offererCreatesMSTxAndAddPayment(Coin offererInputAmount,
String offererPubKey, String offererPubKey,
String takerPubKey, String takerPubKey,

View file

@ -281,12 +281,10 @@ public class TradeManager {
@Override @Override
public void onDepositTxPublished(Transaction depositTx) { public void onDepositTxPublished(Transaction depositTx) {
trade.setDepositTx(depositTx);
trade.setState(Trade.State.DEPOSIT_PUBLISHED);
persistPendingTrades(); persistPendingTrades();
log.trace("trading onDepositTxPublishedMessage " + depositTx.getHashAsString());
} }
// TODO should be removed
@Override @Override
public void onDepositTxConfirmedInBlockchain() { public void onDepositTxConfirmedInBlockchain() {
log.trace("trading onDepositTxConfirmedInBlockchain"); log.trace("trading onDepositTxConfirmedInBlockchain");
@ -311,6 +309,36 @@ public class TradeManager {
case RespondToTakeOfferRequest: case RespondToTakeOfferRequest:
removeFailedTrade(trade); removeFailedTrade(trade);
break; break;
case ValidateTakeOfferFeePayedMessage:
removeFailedTrade(trade);
break;
case CreateDepositTx:
removeFailedTrade(trade);
break;
case SendTakerDepositPaymentRequest:
removeFailedTrade(trade);
break;
case ValidateRequestOffererPublishDepositTxMessage:
removeFailedTrade(trade);
break;
case VerifyTakerAccount:
removeFailedTrade(trade);
break;
case VerifyAndSignContract:
removeFailedTrade(trade);
break;
case SignAndPublishDepositTx:
removeFailedTrade(trade);
break;
case SignAndPublishDepositTxResulted:
removeFailedTrade(trade);
break;
case SendSignedPayoutTx:
removeFailedTrade(trade);
break;
default:
log.error("Unhandled state: " + state);
break;
} }
} }
}); });
@ -347,9 +375,7 @@ public class TradeManager {
} }
@Override @Override
public void onDepositTxPublished(Transaction depositTx) { public void onDepositTxPublished() {
trade.setDepositTx(depositTx);
trade.setState(Trade.State.DEPOSIT_PUBLISHED);
persistPendingTrades(); persistPendingTrades();
} }
@ -378,12 +404,19 @@ public class TradeManager {
case RequestTakeOffer: case RequestTakeOffer:
removeFailedTrade(trade); removeFailedTrade(trade);
break; break;
case ValidateRespondToTakeOfferRequestMessage:
// TODO might need further inspection. Removal could be used for sabotage.
//removeFailedTrade(trade);
break;
case PayTakeOfferFee: case PayTakeOfferFee:
removeFailedTrade(trade); removeFailedTrade(trade);
break; break;
case SendTakeOfferFeePayedMessage: case SendTakeOfferFeePayedMessage:
removeFailedTrade(trade); removeFailedTrade(trade);
break; break;
case ValidateTakerDepositPaymentRequestMessage:
removeFailedTrade(trade);
break;
} }
@ -410,7 +443,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).handleUIEventBankTransferInited(); offererAsBuyerProtocolMap.get(tradeId).handleUIEventBankTransferStarted();
pendingTrades.get(tradeId).setState(Trade.State.PAYMENT_STARTED); pendingTrades.get(tradeId).setState(Trade.State.PAYMENT_STARTED);
persistPendingTrades(); persistPendingTrades();
} }

View file

@ -23,7 +23,7 @@ import io.bitsquare.trade.protocol.trade.taker.SellerTakesOfferProtocol;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
public interface SellerTakesOfferProtocolListener { public interface SellerTakesOfferProtocolListener {
void onDepositTxPublished(Transaction depositTx); void onDepositTxPublished();
void onBankTransferInited(String tradeId); void onBankTransferInited(String tradeId);

View file

@ -19,7 +19,6 @@ package io.bitsquare.trade.protocol.trade.offerer;
import io.bitsquare.bank.BankAccount; import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainService; import io.bitsquare.btc.BlockChainService;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.WalletService; import io.bitsquare.btc.WalletService;
import io.bitsquare.crypto.SignatureService; import io.bitsquare.crypto.SignatureService;
import io.bitsquare.network.Peer; import io.bitsquare.network.Peer;
@ -30,12 +29,14 @@ import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.listeners.BuyerAcceptsOfferProtocolListener; 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.RespondToTakeOfferRequest; import io.bitsquare.trade.protocol.trade.offerer.tasks.RespondToTakeOfferRequest;
import io.bitsquare.trade.protocol.trade.offerer.tasks.SendBankTransferInitedMessage;
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.SendTakerDepositPaymentRequest; 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.SignPayoutTx;
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;
@ -49,8 +50,6 @@ import org.bitcoinj.core.Utils;
import java.security.PublicKey; import java.security.PublicKey;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -74,22 +73,19 @@ public class BuyerAcceptsOfferProtocol {
Init, Init,
RespondToTakeOfferRequest, RespondToTakeOfferRequest,
handleTakeOfferFeePayedMessage, /* VerifyTakeOfferFeePayment,*/
/* VerifyTakeOfferFeePayment,*/ ValidateTakeOfferFeePayedMessage,
CreateDepositTx, CreateDepositTx,
RequestTakerDepositPayment, SendTakerDepositPaymentRequest,
handleRequestOffererPublishDepositTxMessage, ValidateRequestOffererPublishDepositTxMessage,
VerifyTakerAccount, VerifyTakerAccount,
VerifyAndSignContract, VerifyAndSignContract,
SignAndPublishDepositTx, SignAndPublishDepositTx,
SendDepositTxIdToTaker, SignAndPublishDepositTxResulted,
SetupListenerForBlockChainConfirmation,
handleUIEventBankTransferInited, SignPayoutTx,
SendSignedPayoutTx, SendSignedPayoutTx
handlePayoutTxPublishedMessage
} }
// provided // provided
@ -203,46 +199,46 @@ public class BuyerAcceptsOfferProtocol {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// 8. handleTakeOfferFeePayedMessage // 8. handleTakeOfferFeePayedMessage
public void handleTakeOfferFeePayedMessage(@NotNull TakeOfferFeePayedMessage message) { public void handleTakeOfferFeePayedMessage(TakeOfferFeePayedMessage message) {
log.debug("handleTakeOfferFeePayedMessage called: state = " + state); log.debug("handleTakeOfferFeePayedMessage called: state = " + state);
// validation // validation
checkState(state == State.RespondToTakeOfferRequest); try {
checkTradeId(tradeId, message); checkState(state == State.RespondToTakeOfferRequest);
String takeOfferFeeTxId = nonEmptyStringOf(message.getTakeOfferFeeTxId()); state = State.ValidateTakeOfferFeePayedMessage;
Coin tradeAmount = positiveCoinOf(nonZeroCoinOf(message.getTradeAmount())); checkTradeId(tradeId, message);
String tradePubKeyAsHex = nonEmptyStringOf(message.getTakerPubKeyAsHex()); String takeOfferFeeTxId = nonEmptyStringOf(message.getTakeOfferFeeTxId());
Coin tradeAmount = positiveCoinOf(nonZeroCoinOf(message.getTradeAmount()));
String tradePubKeyAsHex = nonEmptyStringOf(message.getTakerPubKeyAsHex());
// apply new state // apply new state
state = State.handleTakeOfferFeePayedMessage; this.takeOfferFeeTxId = takeOfferFeeTxId;
this.takeOfferFeeTxId = takeOfferFeeTxId; this.tradePubKeyAsHex = tradePubKeyAsHex;
this.tradePubKeyAsHex = tradePubKeyAsHex; trade.setTakeOfferFeeTxID(takeOfferFeeTxId);
trade.setTakeOfferFeeTxID(takeOfferFeeTxId); trade.setTradeAmount(tradeAmount);
trade.setTradeAmount(tradeAmount);
// next task // next task
createDepositTx(); createDepositTx();
} catch (Throwable t) {
handleValidationFault(t);
}
} }
// 9. CreateDepositTx // 9. CreateDepositTx
private void createDepositTx() { private void createDepositTx() {
log.debug("handleVerifyTakeOfferFeePaymentResult called: state = " + state); log.debug("handleVerifyTakeOfferFeePaymentResult called: state = " + state);
checkState(state == State.handleTakeOfferFeePayedMessage);
Coin offererInputAmount = trade.getSecurityDeposit().add(FeePolicy.TX_FEE);
state = State.CreateDepositTx; state = State.CreateDepositTx;
CreateDepositTx.run(this::handleCreateDepositTxResult, this::handleFault, walletService, tradeId, offererInputAmount, CreateDepositTx.run(this::handleCreateDepositTxResult, this::handleFault, walletService, trade, tradePubKeyAsHex, arbitratorPubKey);
tradePubKeyAsHex, arbitratorPubKey);
} }
// 4. RequestTakerDepositPayment // 10. RequestTakerDepositPayment
private void handleCreateDepositTxResult(String offererPubKey, String preparedOffererDepositTxAsHex, long offererTxOutIndex) { private void handleCreateDepositTxResult(String offererPubKey, String preparedOffererDepositTxAsHex, long offererTxOutIndex) {
log.debug("handleCreateDepositTxResult called: state = " + state); 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.SendTakerDepositPaymentRequest;
SendTakerDepositPaymentRequest.run(this::handleErrorMessage, SendTakerDepositPaymentRequest.run(this::handleErrorMessage,
peer, peer,
tradeMessageService, tradeMessageService,
@ -259,43 +255,52 @@ public class BuyerAcceptsOfferProtocol {
// Incoming message from peer // Incoming message from peer
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// 5. VerifyTakerAccount // 16. VerifyTakerAccount
public void handleRequestOffererPublishDepositTxMessage(RequestOffererPublishDepositTxMessage message) { public void handleRequestOffererPublishDepositTxMessage(RequestOffererPublishDepositTxMessage message) {
log.debug("handleRequestOffererPublishDepositTxMessage called: state = " + state); log.debug("handleRequestOffererPublishDepositTxMessage called: state = " + state);
log.debug("state " + state);
// validation
checkState(state == State.RequestTakerDepositPayment);
checkTradeId(tradeId, message);
String peersPayoutAddress = nonEmptyStringOf(message.getTakerPayoutAddress());
String peersAccountId = nonEmptyStringOf(message.getTakerAccountId());
BankAccount peersBankAccount = checkNotNull(message.getTakerBankAccount());
PublicKey peersMessagePublicKey = checkNotNull(message.getTakerMessagePublicKey());
String peersContractAsJson = nonEmptyStringOf(message.getTakerContractAsJson());
String signedTakerDepositTxAsHex = nonEmptyStringOf(message.getSignedTakerDepositTxAsHex());
String txConnOutAsHex = nonEmptyStringOf(message.getTxConnOutAsHex());
String txScriptSigAsHex = nonEmptyStringOf(message.getTxScriptSigAsHex());
long takerTxOutIndex = nonNegativeLongOf(message.getTakerTxOutIndex());
// apply new state try {
state = State.handleRequestOffererPublishDepositTxMessage; // validation
this.peersPayoutAddress = peersPayoutAddress; checkState(state == State.SendTakerDepositPaymentRequest);
this.peersAccountId = peersAccountId; state = State.ValidateRequestOffererPublishDepositTxMessage;
this.peersBankAccount = peersBankAccount; checkTradeId(tradeId, message);
this.peersMessagePublicKey = peersMessagePublicKey; String peersPayoutAddress = nonEmptyStringOf(message.getTakerPayoutAddress());
this.peersContractAsJson = peersContractAsJson; String peersAccountId = nonEmptyStringOf(message.getTakerAccountId());
this.signedTakerDepositTxAsHex = signedTakerDepositTxAsHex; BankAccount peersBankAccount = checkNotNull(message.getTakerBankAccount());
this.txConnOutAsHex = txConnOutAsHex; PublicKey peersMessagePublicKey = checkNotNull(message.getTakerMessagePublicKey());
this.txScriptSigAsHex = txScriptSigAsHex; String peersContractAsJson = nonEmptyStringOf(message.getTakerContractAsJson());
this.takerTxOutIndex = takerTxOutIndex; String signedTakerDepositTxAsHex = nonEmptyStringOf(message.getSignedTakerDepositTxAsHex());
String txConnOutAsHex = nonEmptyStringOf(message.getTxConnOutAsHex());
String txScriptSigAsHex = nonEmptyStringOf(message.getTxScriptSigAsHex());
long takerTxOutIndex = nonNegativeLongOf(message.getTakerTxOutIndex());
// next task // apply new state
this.peersPayoutAddress = peersPayoutAddress;
this.peersAccountId = peersAccountId;
this.peersBankAccount = peersBankAccount;
this.peersMessagePublicKey = peersMessagePublicKey;
this.peersContractAsJson = peersContractAsJson;
this.signedTakerDepositTxAsHex = signedTakerDepositTxAsHex;
this.txConnOutAsHex = txConnOutAsHex;
this.txScriptSigAsHex = txScriptSigAsHex;
this.takerTxOutIndex = takerTxOutIndex;
// next task
verifyTakerAccount();
} catch (Throwable t) {
handleValidationFault(t);
}
}
// 17. VerifyTakerAccount
private void verifyTakerAccount() {
state = State.VerifyTakerAccount; state = State.VerifyTakerAccount;
VerifyTakerAccount.run(this::handleVerifyTakerAccountResult, this::handleFault, blockChainService, VerifyTakerAccount.run(this::handleVerifyTakerAccountResult, this::handleFault, blockChainService,
this.peersAccountId, this.peersBankAccount); this.peersAccountId, this.peersBankAccount);
} }
// 6. VerifyAndSignContract // 18. VerifyAndSignContract
private void handleVerifyTakerAccountResult() { private void handleVerifyTakerAccountResult() {
log.debug("handleVerifyTakerAccountResult called: state = " + state); log.debug("handleVerifyTakerAccountResult called: state = " + state);
@ -317,7 +322,7 @@ public class BuyerAcceptsOfferProtocol {
accountKey); accountKey);
} }
// 7. SignAndPublishDepositTx // 19. SignAndPublishDepositTx
private void handleVerifyAndSignContractResult(Contract contract, String contractAsJson, String signature) { private void handleVerifyAndSignContractResult(Contract contract, String contractAsJson, String signature) {
log.debug("handleVerifyAndSignContractResult called: state = " + state); log.debug("handleVerifyAndSignContractResult called: state = " + state);
@ -336,66 +341,47 @@ public class BuyerAcceptsOfferProtocol {
takerTxOutIndex); takerTxOutIndex);
} }
// 8. SendDepositTxIdToTaker
private void handleSignAndPublishDepositTxResult(Transaction depositTransaction) { private void handleSignAndPublishDepositTxResult(Transaction depositTransaction) {
log.debug("handleSignAndPublishDepositTxResult called: state = " + state); log.debug("handleSignAndPublishDepositTxResult called: state = " + state);
state = State.SignAndPublishDepositTxResulted;
trade.setDepositTx(depositTransaction);
trade.setState(Trade.State.DEPOSIT_PUBLISHED);
listener.onDepositTxPublished(depositTransaction); listener.onDepositTxPublished(depositTransaction);
state = State.SendDepositTxIdToTaker; sendDepositTxIdToTaker(depositTransaction);
SendDepositTxIdToTaker.run(this::handleSendDepositTxIdToTakerResult, this::handleErrorMessage, peer, tradeMessageService, setupListenerForBlockChainConfirmation();
tradeId, depositTransaction);
} }
private void handleSendDepositTxIdToTakerResult() { // 20a. SendDepositTxIdToTaker
log.debug("handleSendDepositTxIdToTakerResult called: state = " + state); private void sendDepositTxIdToTaker(Transaction depositTransaction) {
log.debug("sendDepositTxIdToTaker called: state = " + state);
SendDepositTxIdToTaker.run(this::handleErrorMessage, peer, tradeMessageService, tradeId, depositTransaction);
}
state = State.SetupListenerForBlockChainConfirmation; // TODO remove
// 20b. SetupListenerForBlockChainConfirmation
private void setupListenerForBlockChainConfirmation() {
log.debug("setupListenerForBlockChainConfirmation called: state = " + state);
SetupListenerForBlockChainConfirmation.run(trade.getDepositTx(), listener); SetupListenerForBlockChainConfirmation.run(trade.getDepositTx(), listener);
} }
/*
// 9. VerifyTakeOfferFeePayment
private void verifyTakeOfferFeePayment() {
state = State.VerifyTakeOfferFeePayment;
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"
// 9. SendSignedPayoutTx // 23. SignPayoutTx
public void handleUIEventBankTransferInited() { public void handleUIEventBankTransferStarted() {
log.debug("onUIEventBankTransferInited called: state = " + state); log.debug("handleUIEventBankTransferStarted called: state = " + state);
log.debug("state " + state);
// validation
checkState(state.ordinal() >= State.SignAndPublishDepositTx.ordinal() &&
state.ordinal() <= State.SetupListenerForBlockChainConfirmation.ordinal());
state = State.handleUIEventBankTransferInited;
// next task
String depositTransactionId = trade.getDepositTx().getHashAsString(); String depositTransactionId = trade.getDepositTx().getHashAsString();
Coin tradeAmount = trade.getTradeAmount();
Coin securityDeposit = trade.getSecurityDeposit(); Coin securityDeposit = trade.getSecurityDeposit();
state = State.SendSignedPayoutTx; Coin tradeAmount = trade.getTradeAmount();
SendSignedPayoutTx.run(this::handleFault, state = State.SignPayoutTx;
peer, SignPayoutTx.run(this::handleSignPayoutTxResult,
tradeMessageService, this::handleFault,
walletService, walletService,
tradeId, tradeId,
peersPayoutAddress, peersPayoutAddress,
@ -405,24 +391,55 @@ public class BuyerAcceptsOfferProtocol {
tradeAmount); tradeAmount);
} }
// 24a. SendBankTransferInitedMessage
private void handleSignPayoutTxResult(String depositTxAsHex,
String offererSignatureR,
String offererSignatureS,
Coin offererPaybackAmount,
Coin takerPaybackAmount,
String offererPayoutAddress) {
log.debug("handleSignPayoutTxResult called: state = " + state);
state = State.SendSignedPayoutTx;
SendBankTransferInitedMessage.run(this::handleFault,
peer,
tradeMessageService,
tradeId,
depositTxAsHex,
offererSignatureR,
offererSignatureS,
offererPaybackAmount,
takerPaybackAmount,
offererPayoutAddress);
verifyTakeOfferFeePayment();
}
// 24b VerifyTakeOfferFeePayment
private void verifyTakeOfferFeePayment() {
VerifyTakeOfferFeePayment.run(this::handleFault, walletService, this.takeOfferFeeTxId);
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message from peer // Incoming message from peer
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// 10. handlePayoutTxPublishedMessage // 28. handlePayoutTxPublishedMessage
public void handlePayoutTxPublishedMessage(PayoutTxPublishedMessage message) { public void handlePayoutTxPublishedMessage(PayoutTxPublishedMessage message) {
log.debug("onPayoutTxPublishedMessage called: state = " + state); log.debug("onPayoutTxPublishedMessage called: state = " + state);
// validation try {
checkState(state == State.SendSignedPayoutTx); // validation
checkTradeId(tradeId, message); checkState(state == State.SendSignedPayoutTx);
String payoutTxAsHex = nonEmptyStringOf(message.getPayoutTxAsHex()); checkTradeId(tradeId, message);
String payoutTxAsHex = nonEmptyStringOf(message.getPayoutTxAsHex());
// apply new state // apply new state
state = State.handlePayoutTxPublishedMessage; Transaction payoutTx = new Transaction(walletService.getWallet().getParams(), Utils.parseAsHexOrBase58(payoutTxAsHex));
Transaction payoutTx = new Transaction(walletService.getWallet().getParams(), Utils.parseAsHexOrBase58(payoutTxAsHex)); listener.onPayoutTxPublished(payoutTx);
listener.onPayoutTxPublished(payoutTx); } catch (Throwable t) {
handleValidationFault(t);
}
} }
@ -430,7 +447,6 @@ public class BuyerAcceptsOfferProtocol {
// Private // Private
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// generic fault handler
private void handleFault(Throwable throwable) { private void handleFault(Throwable throwable) {
trade.setFault(throwable); trade.setFault(throwable);
trade.setState(Trade.State.FAILED); trade.setState(Trade.State.FAILED);
@ -441,4 +457,9 @@ public class BuyerAcceptsOfferProtocol {
handleFault(new Exception(errorMessage)); handleFault(new Exception(errorMessage));
} }
private void handleValidationFault(Throwable throwable) {
throwable.printStackTrace();
log.error(throwable.getMessage());
handleErrorMessage("Validation of incoming message failed. Error message = " + throwable.getMessage());
}
} }

View file

@ -17,7 +17,9 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks; package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.WalletService; import io.bitsquare.btc.WalletService;
import io.bitsquare.trade.Trade;
import io.bitsquare.util.handlers.ExceptionHandler; import io.bitsquare.util.handlers.ExceptionHandler;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
@ -34,15 +36,15 @@ public class CreateDepositTx {
public static void run(ResultHandler resultHandler, public static void run(ResultHandler resultHandler,
ExceptionHandler exceptionHandler, ExceptionHandler exceptionHandler,
WalletService walletService, WalletService walletService,
String tradeId, Trade trade,
Coin offererInputAmount,
String takerMultiSigPubKey, String takerMultiSigPubKey,
String arbitratorPubKeyAsHex) { String arbitratorPubKeyAsHex) {
log.trace("Run CreateDepositTx task"); log.trace("Run CreateDepositTx task");
try { try {
String offererPubKey = walletService.getAddressInfoByTradeID(tradeId).getPubKeyAsHexString(); String offererPubKey = walletService.getAddressInfoByTradeID(trade.getId()).getPubKeyAsHexString();
Coin offererInputAmount = trade.getSecurityDeposit().add(FeePolicy.TX_FEE);
Transaction transaction = walletService.offererCreatesMSTxAndAddPayment(offererInputAmount, offererPubKey, takerMultiSigPubKey, Transaction transaction = walletService.offererCreatesMSTxAndAddPayment(offererInputAmount, offererPubKey, takerMultiSigPubKey,
arbitratorPubKeyAsHex, tradeId); arbitratorPubKeyAsHex, trade.getId());
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();

View file

@ -17,7 +17,6 @@
package io.bitsquare.trade.protocol.trade.offerer.tasks; package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.btc.WalletService;
import io.bitsquare.network.Peer; 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;
@ -25,39 +24,25 @@ import io.bitsquare.trade.protocol.trade.offerer.messages.BankTransferInitedMess
import io.bitsquare.util.handlers.ExceptionHandler; import io.bitsquare.util.handlers.ExceptionHandler;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.core.ECKey;
import javafx.util.Pair;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class SendSignedPayoutTx { public class SendBankTransferInitedMessage {
private static final Logger log = LoggerFactory.getLogger(SendSignedPayoutTx.class); private static final Logger log = LoggerFactory.getLogger(SendBankTransferInitedMessage.class);
public static void run(ExceptionHandler exceptionHandler, public static void run(ExceptionHandler exceptionHandler,
Peer peer, Peer peer,
TradeMessageService tradeMessageService, TradeMessageService tradeMessageService,
WalletService walletService,
String tradeId, String tradeId,
String takerPayoutAddress, String depositTxAsHex,
String offererPayoutAddress, String offererSignatureR,
String depositTransactionId, String offererSignatureS,
Coin securityDeposit, Coin offererPaybackAmount,
Coin tradeAmount) { Coin takerPaybackAmount,
log.trace("Run task"); String offererPayoutAddress) {
log.trace("Run SendSignedPayoutTx task");
try { try {
Coin offererPaybackAmount = tradeAmount.add(securityDeposit);
@SuppressWarnings("UnnecessaryLocalVariable") Coin takerPaybackAmount = securityDeposit;
Pair<ECKey.ECDSASignature, String> result = walletService.offererCreatesAndSignsPayoutTx(
depositTransactionId, offererPaybackAmount, takerPaybackAmount, takerPayoutAddress, tradeId);
ECKey.ECDSASignature offererSignature = result.getKey();
String offererSignatureR = offererSignature.r.toString();
String offererSignatureS = offererSignature.s.toString();
String depositTxAsHex = result.getValue();
BankTransferInitedMessage tradeMessage = new BankTransferInitedMessage(tradeId, BankTransferInitedMessage tradeMessage = new BankTransferInitedMessage(tradeId,
depositTxAsHex, depositTxAsHex,
offererSignatureR, offererSignatureR,
@ -65,22 +50,19 @@ public class SendSignedPayoutTx {
offererPaybackAmount, offererPaybackAmount,
takerPaybackAmount, takerPaybackAmount,
offererPayoutAddress); offererPayoutAddress);
tradeMessageService.sendMessage(peer, tradeMessage, new SendMessageListener() { tradeMessageService.sendMessage(peer, tradeMessage, new SendMessageListener() {
@Override @Override
public void handleResult() { public void handleResult() {
log.trace("BankTransferInitedMessage successfully arrived at peer"); log.trace("Sending BankTransferInitedMessage succeeded.");
} }
@Override @Override
public void handleFault() { public void handleFault() {
log.error("BankTransferInitedMessage did not arrive at peer"); exceptionHandler.handleException(new Exception("Sending BankTransferInitedMessage failed."));
exceptionHandler.handleException(new Exception("BankTransferInitedMessage did not arrive at peer"));
} }
}); });
} catch (Exception e) { } catch (Exception e) {
log.error("Exception at OffererCreatesAndSignsPayoutTx " + e);
exceptionHandler.handleException(e); exceptionHandler.handleException(e);
} }
} }

View file

@ -22,7 +22,6 @@ 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.DepositTxPublishedMessage; import io.bitsquare.trade.protocol.trade.offerer.messages.DepositTxPublishedMessage;
import io.bitsquare.util.handlers.ErrorMessageHandler; 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;
@ -33,7 +32,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, ErrorMessageHandler errorMessageHandler, Peer peer, public static void run( 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 =
@ -43,7 +42,6 @@ public class SendDepositTxIdToTaker {
@Override @Override
public void handleResult() { public void handleResult() {
log.trace("DepositTxPublishedMessage successfully arrived at peer"); log.trace("DepositTxPublishedMessage successfully arrived at peer");
resultHandler.handleResult();
} }
@Override @Override

View file

@ -25,6 +25,7 @@ import org.bitcoinj.core.TransactionConfidence;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
// TODO should be removed
public class SetupListenerForBlockChainConfirmation { public class SetupListenerForBlockChainConfirmation {
private static final Logger log = LoggerFactory.getLogger(SetupListenerForBlockChainConfirmation.class); private static final Logger log = LoggerFactory.getLogger(SetupListenerForBlockChainConfirmation.class);

View file

@ -0,0 +1,72 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.btc.WalletService;
import io.bitsquare.util.handlers.ExceptionHandler;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.ECKey;
import javafx.util.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SignPayoutTx {
private static final Logger log = LoggerFactory.getLogger(SignPayoutTx.class);
public static void run(ResultHandler resultHandler,
ExceptionHandler exceptionHandler,
WalletService walletService,
String tradeId,
String takerPayoutAddress,
String offererPayoutAddress,
String depositTransactionId,
Coin securityDeposit,
Coin tradeAmount) {
log.trace("Run SignPayoutTx task");
try {
Coin offererPaybackAmount = tradeAmount.add(securityDeposit);
@SuppressWarnings("UnnecessaryLocalVariable") Coin takerPaybackAmount = securityDeposit;
Pair<ECKey.ECDSASignature, String> result = walletService.offererCreatesAndSignsPayoutTx(
depositTransactionId, offererPaybackAmount, takerPaybackAmount, takerPayoutAddress, tradeId);
ECKey.ECDSASignature offererSignature = result.getKey();
String offererSignatureR = offererSignature.r.toString();
String offererSignatureS = offererSignature.s.toString();
String depositTxAsHex = result.getValue();
resultHandler.handleResult(depositTxAsHex, offererSignatureR, offererSignatureS, offererPaybackAmount, takerPaybackAmount, offererPayoutAddress);
} catch (Exception e) {
exceptionHandler.handleException(e);
}
}
public interface ResultHandler {
void handleResult(String depositTxAsHex,
String offererSignatureR,
String offererSignatureS,
Coin offererPaybackAmount,
Coin takerPaybackAmount,
String offererPayoutAddress);
}
}

View file

@ -19,7 +19,6 @@ package io.bitsquare.trade.protocol.trade.offerer.tasks;
import io.bitsquare.btc.WalletService; import io.bitsquare.btc.WalletService;
import io.bitsquare.util.handlers.ExceptionHandler; 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;
@ -27,14 +26,14 @@ import org.slf4j.LoggerFactory;
public class VerifyTakeOfferFeePayment { public class VerifyTakeOfferFeePayment {
private static final Logger log = LoggerFactory.getLogger(VerifyTakeOfferFeePayment.class); private static final Logger log = LoggerFactory.getLogger(VerifyTakeOfferFeePayment.class);
public static void run(ResultHandler resultHandler, ExceptionHandler exceptionHandler, WalletService walletService, public static void run(ExceptionHandler exceptionHandler, WalletService walletService,
String takeOfferFeeTxId) { String takeOfferFeeTxId) {
log.trace("Run VerifyTakeOfferFeePayment 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) {
resultHandler.handleResult(); resultHandler.handleResult();
} }*/
} }
} }

View file

@ -41,6 +41,7 @@ import io.bitsquare.trade.protocol.trade.taker.tasks.SendSignedTakerDepositTxAsH
import io.bitsquare.trade.protocol.trade.taker.tasks.SendTakeOfferFeePayedMessage; 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.TakerCommitDepositTx;
import io.bitsquare.trade.protocol.trade.taker.tasks.VerifyOfferFeePayment;
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;
@ -73,17 +74,17 @@ public class SellerTakesOfferProtocol {
GetPeerAddress, GetPeerAddress,
RequestTakeOffer, RequestTakeOffer,
handleRespondToTakeOfferRequestMessage, ValidateRespondToTakeOfferRequestMessage,
PayTakeOfferFee, PayTakeOfferFee,
SendTakeOfferFeePayedMessage, SendTakeOfferFeePayedMessage,
handleTakerDepositPaymentRequestMessage, ValidateTakerDepositPaymentRequestMessage,
VerifyOffererAccount, VerifyOffererAccount,
CreateAndSignContract, CreateAndSignContract,
PayDeposit, PayDeposit,
SendSignedTakerDepositTxAsHex, SendSignedTakerDepositTxAsHex,
handleDepositTxPublishedMessage, ValidateDepositTxPublishedMessage,
TakerCommitDepositTx, TakerCommitDepositTx,
handleBankTransferInitedMessage, handleBankTransferInitedMessage,
SignAndPublishPayoutTx, SignAndPublishPayoutTx,
@ -197,23 +198,27 @@ public class SellerTakesOfferProtocol {
public void handleRespondToTakeOfferRequestMessage(RespondToTakeOfferRequestMessage message) { public void handleRespondToTakeOfferRequestMessage(RespondToTakeOfferRequestMessage message) {
log.debug("handleRespondToTakeOfferRequestMessage called: state = " + state); log.debug("handleRespondToTakeOfferRequestMessage called: state = " + state);
// validation try {
checkState(state == State.RequestTakeOffer); // validation
checkTradeId(tradeId, message); checkState(state == State.RequestTakeOffer);
state = State.ValidateRespondToTakeOfferRequestMessage;
checkTradeId(tradeId, message);
// apply new state // apply new state
state = State.handleRespondToTakeOfferRequestMessage; if (message.isTakeOfferRequestAccepted()) {
if (message.isTakeOfferRequestAccepted()) { trade.setState(Trade.State.OFFERER_ACCEPTED);
trade.setState(Trade.State.OFFERER_ACCEPTED); listener.onTakeOfferRequestAccepted();
listener.onTakeOfferRequestAccepted();
// next task // next task
payTakeOfferFee(); payTakeOfferFee();
} }
else { else {
// exit case // exit case
trade.setState(Trade.State.OFFERER_REJECTED); trade.setState(Trade.State.OFFERER_REJECTED);
listener.onTakeOfferRequestRejected(); listener.onTakeOfferRequestRejected();
}
} catch (Throwable t) {
handleValidationFault(t);
} }
} }
@ -228,8 +233,7 @@ public class SellerTakesOfferProtocol {
log.debug("handlePayTakeOfferFeeResult called: state = " + state); log.debug("handlePayTakeOfferFeeResult called: state = " + state);
trade.setTakeOfferFeeTxID(takeOfferFeeTxId); trade.setTakeOfferFeeTxID(takeOfferFeeTxId);
state = State.SendTakeOfferFeePayedMessage; state = State.SendTakeOfferFeePayedMessage;
SendTakeOfferFeePayedMessage.run(this::handleErrorMessage, peer, SendTakeOfferFeePayedMessage.run(this::handleErrorMessage, peer, tradeMessageService, tradeId, takeOfferFeeTxId, tradeAmount, tradePubKeyAsHex);
tradeMessageService, tradeId, takeOfferFeeTxId, tradeAmount, tradePubKeyAsHex);
} }
@ -237,36 +241,44 @@ public class SellerTakesOfferProtocol {
// Incoming message from peer // Incoming message from peer
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// 5. VerifyOffererAccount // 11. VerifyOffererAccount
public void handleTakerDepositPaymentRequestMessage(TakerDepositPaymentRequestMessage message) { public void handleTakerDepositPaymentRequestMessage(TakerDepositPaymentRequestMessage message) {
log.debug("handleTakerDepositPaymentRequestMessage called: state = " + state); log.debug("handleTakerDepositPaymentRequestMessage called: state = " + state);
// validation try {
checkState(state == State.SendTakeOfferFeePayedMessage); // validation
checkTradeId(tradeId, message); checkState(state == State.SendTakeOfferFeePayedMessage);
String peersAccountId = nonEmptyStringOf(message.getAccountId()); state = State.ValidateTakerDepositPaymentRequestMessage;
BankAccount peersBankAccount = checkNotNull(message.getBankAccount()); checkTradeId(tradeId, message);
String offererPubKey = nonEmptyStringOf(message.getOffererPubKey()); String peersAccountId = nonEmptyStringOf(message.getAccountId());
String preparedOffererDepositTxAsHex = nonEmptyStringOf(message.getPreparedOffererDepositTxAsHex()); BankAccount peersBankAccount = checkNotNull(message.getBankAccount());
long offererTxOutIndex = nonNegativeLongOf(message.getOffererTxOutIndex()); String offererPubKey = nonEmptyStringOf(message.getOffererPubKey());
String preparedOffererDepositTxAsHex = nonEmptyStringOf(message.getPreparedOffererDepositTxAsHex());
long offererTxOutIndex = nonNegativeLongOf(message.getOffererTxOutIndex());
// apply new state // apply new state
state = State.handleTakerDepositPaymentRequestMessage; this.peersAccountId = peersAccountId;
this.peersAccountId = peersAccountId; this.peersBankAccount = peersBankAccount;
this.peersBankAccount = peersBankAccount; this.peersPubKey = offererPubKey;
this.peersPubKey = offererPubKey; this.preparedPeersDepositTxAsHex = preparedOffererDepositTxAsHex;
this.preparedPeersDepositTxAsHex = preparedOffererDepositTxAsHex; this.peersTxOutIndex = offererTxOutIndex;
this.peersTxOutIndex = offererTxOutIndex;
// next task // next task
verifyOffererAccount();
} catch (Throwable t) {
handleValidationFault(t);
}
}
// 12. VerifyOffererAccount
private void verifyOffererAccount() {
state = State.VerifyOffererAccount; state = State.VerifyOffererAccount;
VerifyOffererAccount.run(this::handleVerifyOffererAccountResult, this::handleFault, blockChainService, peersAccountId, peersBankAccount); VerifyOffererAccount.run(this::handleVerifyOffererAccountResult, this::handleFault, blockChainService, peersAccountId, peersBankAccount);
} }
// 6. CreateAndSignContract // 13. CreateAndSignContract
private void handleVerifyOffererAccountResult() { private void handleVerifyOffererAccountResult() {
log.debug("handleVerifyOffererAccountResult called: state = " + state); 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::handleCreateAndSignContractResult, CreateAndSignContract.run(this::handleCreateAndSignContractResult,
@ -284,10 +296,9 @@ public class SellerTakesOfferProtocol {
accountKey); accountKey);
} }
// 7. PayDeposit // 14. PayDeposit
private void handleCreateAndSignContractResult(Contract contract, String contractAsJson, String signature) { private void handleCreateAndSignContractResult(Contract contract, String contractAsJson, String signature) {
log.debug("handleCreateAndSignContractResult called: state = " + state); log.debug("handleCreateAndSignContractResult called: state = " + state);
checkState(state == State.CreateAndSignContract);
trade.setContract(contract); trade.setContract(contract);
trade.setContractAsJson(contractAsJson); trade.setContractAsJson(contractAsJson);
trade.setTakerContractSignature(signature); trade.setTakerContractSignature(signature);
@ -296,10 +307,9 @@ public class SellerTakesOfferProtocol {
tradePubKeyAsHex, arbitratorPubKey, peersPubKey, preparedPeersDepositTxAsHex); tradePubKeyAsHex, arbitratorPubKey, peersPubKey, preparedPeersDepositTxAsHex);
} }
// 8. SendSignedTakerDepositTxAsHex // 15. SendSignedTakerDepositTxAsHex
private void handlePayDepositResult(Transaction signedTakerDepositTx) { private void handlePayDepositResult(Transaction signedTakerDepositTx) {
log.debug("handlePayDepositResult called: state = " + state); log.debug("handlePayDepositResult called: state = " + state);
checkState(state == State.PayDeposit);
String contractAsJson = trade.getContractAsJson(); String contractAsJson = trade.getContractAsJson();
String takerContractSignature = trade.getTakerContractSignature(); String takerContractSignature = trade.getTakerContractSignature();
state = State.SendSignedTakerDepositTxAsHex; state = State.SendSignedTakerDepositTxAsHex;
@ -322,29 +332,37 @@ public class SellerTakesOfferProtocol {
// Incoming message from peer // Incoming message from peer
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// 9.a TakerCommitDepositTx // 21. TakerCommitDepositTx
public void handleDepositTxPublishedMessage(DepositTxPublishedMessage message) { public void handleDepositTxPublishedMessage(DepositTxPublishedMessage message) {
log.debug("onDepositTxPublishedMessage called: state = " + state); log.debug("onDepositTxPublishedMessage called: state = " + state);
log.debug("state " + state); log.debug("state " + state);
try {
// validation
checkState(state == State.SendSignedTakerDepositTxAsHex);
state = State.ValidateDepositTxPublishedMessage;
checkTradeId(tradeId, message);
String depositTxAsHex = message.getDepositTxAsHex();
nonEmptyStringOf(depositTxAsHex);
// validation // next task
checkState(state.ordinal() >= State.SendSignedTakerDepositTxAsHex.ordinal()); takerCommitDepositTx(depositTxAsHex);
checkTradeId(tradeId, message); } catch (Throwable t) {
nonEmptyStringOf(message.getDepositTxAsHex()); handleValidationFault(t);
}
}
// apply new state // 22. TakerCommitDepositTx
state = State.handleDepositTxPublishedMessage; private void takerCommitDepositTx(String depositTxAsHex) {
String depositTxAsHex = message.getDepositTxAsHex();
// next task
state = State.TakerCommitDepositTx; state = State.TakerCommitDepositTx;
TakerCommitDepositTx.run(this::handleTakerCommitDepositTxResult, this::handleFault, walletService, depositTxAsHex); TakerCommitDepositTx.run(this::handleTakerCommitDepositTxResult, this::handleFault, walletService, depositTxAsHex);
} }
private void handleTakerCommitDepositTxResult(Transaction transaction) { private void handleTakerCommitDepositTxResult(Transaction transaction) {
log.debug("handleTakerCommitDepositTxResult called: state = " + state); log.debug("handleTakerCommitDepositTxResult called: state = " + state);
listener.onDepositTxPublished(transaction); trade.setDepositTx(transaction);
trade.setState(Trade.State.DEPOSIT_PUBLISHED);
listener.onDepositTxPublished();
} }
@ -352,32 +370,34 @@ public class SellerTakesOfferProtocol {
// Incoming message from peer // Incoming message from peer
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// 9.b. handleBankTransferInitedMessage // 25. handleBankTransferInitedMessage
public void handleBankTransferInitedMessage(BankTransferInitedMessage message) { public void handleBankTransferInitedMessage(BankTransferInitedMessage message) {
log.debug("onBankTransferInitedMessage called: state = " + state); log.debug("handleBankTransferInitedMessage called: state = " + state);
log.debug("state " + state);
// validate try {
checkState(state.ordinal() >= State.SendSignedTakerDepositTxAsHex.ordinal() && // validate
state.ordinal() < State.SignAndPublishPayoutTx.ordinal()); checkState(state == State.TakerCommitDepositTx);
checkTradeId(tradeId, message); 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());
Coin offererPaybackAmount = positiveCoinOf(nonZeroCoinOf(message.getOffererPaybackAmount())); Coin offererPaybackAmount = positiveCoinOf(nonZeroCoinOf(message.getOffererPaybackAmount()));
Coin takerPaybackAmount = positiveCoinOf(nonZeroCoinOf(message.getTakerPaybackAmount())); Coin takerPaybackAmount = positiveCoinOf(nonZeroCoinOf(message.getTakerPaybackAmount()));
String offererPayoutAddress = nonEmptyStringOf(message.getOffererPayoutAddress()); String offererPayoutAddress = nonEmptyStringOf(message.getOffererPayoutAddress());
// apply state // apply state
state = State.handleBankTransferInitedMessage; state = State.handleBankTransferInitedMessage;
this.depositTxAsHex = depositTxAsHex; this.depositTxAsHex = depositTxAsHex;
this.offererSignatureR = offererSignatureR; this.offererSignatureR = offererSignatureR;
this.offererSignatureS = offererSignatureS; this.offererSignatureS = offererSignatureS;
this.offererPaybackAmount = offererPaybackAmount; this.offererPaybackAmount = offererPaybackAmount;
this.takerPaybackAmount = takerPaybackAmount; this.takerPaybackAmount = takerPaybackAmount;
this.offererPayoutAddress = offererPayoutAddress; this.offererPayoutAddress = offererPayoutAddress;
listener.onBankTransferInited(message.getTradeId()); listener.onBankTransferInited(message.getTradeId());
} catch (Throwable t) {
handleValidationFault(t);
}
} }
@ -386,11 +406,10 @@ 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
// 10. SignAndPublishPayoutTx // 26. SignAndPublishPayoutTx
public void handleUIEventFiatReceived() { public void handleUIEventFiatReceived() {
log.debug("onUIEventFiatReceived called: state = " + state); log.debug("handleUIEventFiatReceived called: state = " + state);
log.debug("state " + state); checkState(state == State.handleBankTransferInitedMessage);
checkState(state == State.handleBankTransferInitedMessage || state == State.TakerCommitDepositTx);
state = State.SignAndPublishPayoutTx; state = State.SignAndPublishPayoutTx;
SignAndPublishPayoutTx.run(this::handleSignAndPublishPayoutTxResult, SignAndPublishPayoutTx.run(this::handleSignAndPublishPayoutTxResult,
@ -403,19 +422,21 @@ public class SellerTakesOfferProtocol {
offererPaybackAmount, offererPaybackAmount,
takerPaybackAmount, takerPaybackAmount,
offererPayoutAddress); offererPayoutAddress);
verifyOfferFeePayment();
} }
// 11. SendPayoutTxToOfferer // 27a. SendPayoutTxToOfferer
private void handleSignAndPublishPayoutTxResult(Transaction transaction, String payoutTxAsHex) { private void handleSignAndPublishPayoutTxResult(Transaction transaction, String payoutTxAsHex) {
log.debug("handleSignAndPublishPayoutTxResult called: state = " + state); log.debug("handleSignAndPublishPayoutTxResult called: state = " + state);
listener.onPayoutTxPublished(trade, transaction); listener.onPayoutTxPublished(trade, transaction);
state = State.SendPayoutTxToOfferer; state = State.SendPayoutTxToOfferer;
SendPayoutTxToOfferer.run(this::handleSendPayoutTxToOffererResult, this::handleErrorMessage, peer, tradeMessageService, SendPayoutTxToOfferer.run(this::handleErrorMessage, peer, tradeMessageService, tradeId, payoutTxAsHex);
tradeId, payoutTxAsHex);
} }
private void handleSendPayoutTxToOffererResult() { // 27b VerifyTakeOfferFeePayment
log.debug("onResultSendPayoutTxToOfferer called: state = " + state); private void verifyOfferFeePayment() {
VerifyOfferFeePayment.run(this::handleFault, walletService, trade.getOffer().getOfferFeePaymentTxID());
} }
@ -423,7 +444,6 @@ public class SellerTakesOfferProtocol {
// Private // Private
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// generic fault handler
private void handleFault(Throwable throwable) { private void handleFault(Throwable throwable) {
trade.setFault(throwable); trade.setFault(throwable);
trade.setState(Trade.State.FAILED); trade.setState(Trade.State.FAILED);
@ -434,4 +454,9 @@ public class SellerTakesOfferProtocol {
handleFault(new Exception(errorMessage)); handleFault(new Exception(errorMessage));
} }
private void handleValidationFault(Throwable throwable) {
throwable.printStackTrace();
log.error(throwable.getMessage());
handleErrorMessage("Validation of incoming message failed. Error message = " + throwable.getMessage());
}
} }

View file

@ -22,7 +22,6 @@ import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.listeners.SendMessageListener; import io.bitsquare.trade.listeners.SendMessageListener;
import io.bitsquare.trade.protocol.trade.taker.messages.PayoutTxPublishedMessage; import io.bitsquare.trade.protocol.trade.taker.messages.PayoutTxPublishedMessage;
import io.bitsquare.util.handlers.ErrorMessageHandler; 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,18 @@ 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, ErrorMessageHandler errorMessageHandler, Peer peer, public static void run(ErrorMessageHandler errorMessageHandler, Peer peer, TradeMessageService tradeMessageService, String tradeId, String payoutTxAsHex) {
TradeMessageService tradeMessageService, String tradeId, String payoutTxAsHex) { log.trace("Run SendPayoutTxToOfferer task");
log.trace("Run task");
PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(tradeId, payoutTxAsHex); PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(tradeId, payoutTxAsHex);
tradeMessageService.sendMessage(peer, tradeMessage, new SendMessageListener() { tradeMessageService.sendMessage(peer, tradeMessage, new SendMessageListener() {
@Override @Override
public void handleResult() { public void handleResult() {
log.trace("PayoutTxPublishedMessage successfully arrived at peer"); log.trace("PayoutTxPublishedMessage successfully arrived at peer");
resultHandler.handleResult();
} }
@Override @Override
public void handleFault() { public void handleFault() {
log.error("PayoutTxPublishedMessage did not arrive at peer"); errorMessageHandler.handleErrorMessage("Sending PayoutTxPublishedMessage failed.");
errorMessageHandler.handleErrorMessage("PayoutTxPublishedMessage did not arrive at peer");
} }
}); });

View file

@ -44,9 +44,8 @@ public class SignAndPublishPayoutTx {
Coin offererPaybackAmount, Coin offererPaybackAmount,
Coin takerPaybackAmount, Coin takerPaybackAmount,
String offererPayoutAddress) { String offererPayoutAddress) {
log.trace("Run task"); log.trace("Run SignAndPublishPayoutTx task");
try { try {
walletService.takerSignsAndSendsTx(depositTxAsHex, walletService.takerSignsAndSendsTx(depositTxAsHex,
offererSignatureR, offererSignatureR,
offererSignatureS, offererSignatureS,
@ -64,12 +63,10 @@ public class SignAndPublishPayoutTx {
@Override @Override
public void onFailure(@NotNull Throwable t) { public void onFailure(@NotNull Throwable t) {
log.error("Exception at takerSignsAndSendsTx " + t);
exceptionHandler.handleException(t); exceptionHandler.handleException(t);
} }
}); });
} catch (Exception e) { } catch (Exception e) {
log.error("Exception at takerSignsAndSendsTx " + e);
exceptionHandler.handleException(e); exceptionHandler.handleException(e);
} }
} }

View file

@ -15,17 +15,25 @@
* 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; package io.bitsquare.trade.protocol.trade.taker.tasks;
import io.bitsquare.network.Message; import io.bitsquare.btc.WalletService;
import io.bitsquare.util.handlers.ExceptionHandler;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class TradeMessage implements Message { public class VerifyOfferFeePayment {
private static final Logger log = LoggerFactory.getLogger(TradeMessage.class); private static final Logger log = LoggerFactory.getLogger(VerifyOfferFeePayment.class);
public TradeMessage() {
public static void run(ExceptionHandler exceptionHandler, WalletService walletService,
String takeOfferFeeTxId) {
log.trace("Run VerifyOfferFeePayment task");
//TODO mocked yet, need a confidence listeners
int numOfPeersSeenTx = walletService.getNumOfPeersSeenTx(takeOfferFeeTxId);
/* if (numOfPeersSeenTx > 2) {
resultHandler.handleResult();
}*/
} }
} }