refactoring trade protocol

This commit is contained in:
Manfred Karrer 2014-07-05 01:00:35 +02:00
parent 5da272bdbf
commit cb4ca6b2a7
7 changed files with 184 additions and 733 deletions

View file

@ -7,6 +7,7 @@ import com.google.inject.Inject;
import io.bitsquare.btc.BlockChainFacade; import io.bitsquare.btc.BlockChainFacade;
import io.bitsquare.btc.WalletFacade; import io.bitsquare.btc.WalletFacade;
import io.bitsquare.crypto.CryptoFacade; import io.bitsquare.crypto.CryptoFacade;
import io.bitsquare.gui.popups.Popups;
import io.bitsquare.msg.MessageFacade; import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.TradeMessage; import io.bitsquare.msg.TradeMessage;
import io.bitsquare.msg.listeners.TakeOfferRequestListener; import io.bitsquare.msg.listeners.TakeOfferRequestListener;
@ -233,6 +234,32 @@ public class Trading
log.debug("trading onPayoutTxPublishedMessage"); log.debug("trading onPayoutTxPublishedMessage");
} }
@Override
public void onFault(Throwable throwable, OffererAsBuyerProtocol.State state)
{
log.error("Error while executing trade process at state: " + state + " / " + throwable);
Popups.openErrorPopup("Error while executing trade process", "Error while executing trade process at state: " + state + " / " + throwable);
}
@Override
public void onWaitingForPeerResponse(OffererAsBuyerProtocol.State state)
{
log.debug("Waiting for peers response at state " + state);
}
@Override
public void onCompleted(OffererAsBuyerProtocol.State state)
{
log.debug("Trade protocol completed at state " + state);
}
@Override
public void onWaitingForUserInteraction(OffererAsBuyerProtocol.State state)
{
log.debug("Waiting for UI activity at state " + state);
}
@Override @Override
public void onDepositTxConfirmedInBlockchain() public void onDepositTxConfirmedInBlockchain()
{ {

View file

@ -14,4 +14,12 @@ public interface OffererAsBuyerProtocolListener
void onDepositTxConfirmedUpdate(TransactionConfidence confidence); void onDepositTxConfirmedUpdate(TransactionConfidence confidence);
void onPayoutTxPublished(String payoutTxID); void onPayoutTxPublished(String payoutTxID);
void onFault(Throwable throwable, OffererAsBuyerProtocol.State state);
void onWaitingForPeerResponse(OffererAsBuyerProtocol.State state);
void onCompleted(OffererAsBuyerProtocol.State state);
void onWaitingForUserInteraction(OffererAsBuyerProtocol.State state);
} }

View file

@ -20,8 +20,15 @@ import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import static io.bitsquare.util.Validator.*; import static io.bitsquare.util.Validator.nonEmptyStringOf;
import static io.bitsquare.util.Validator.nonNegativeLongOf;
/**
* Responsible for the correct execution of the sequence of tasks, message passing to the peer and message processing from the peer.
* That class handles the role of the taker as the Bitcoin seller.
* It uses sub tasks to not pollute the main class too much with all the async result/fault handling.
* Any data from incoming messages as well data used to send to the peer need to be validated before further processing.
*/
public class TakerAsSellerProtocol public class TakerAsSellerProtocol
{ {
private static final Logger log = LoggerFactory.getLogger(TakerAsSellerProtocol.class); private static final Logger log = LoggerFactory.getLogger(TakerAsSellerProtocol.class);
@ -92,7 +99,7 @@ public class TakerAsSellerProtocol
public void start() public void start()
{ {
String messagePubKeyAsHex = validString(offer.getMessagePubKeyAsHex()); String messagePubKeyAsHex = nonEmptyStringOf(offer.getMessagePubKeyAsHex());
GetPeerAddress.run(this::onResultGetPeerAddress, this::onFault, messageFacade, messagePubKeyAsHex); GetPeerAddress.run(this::onResultGetPeerAddress, this::onFault, messageFacade, messagePubKeyAsHex);
state = State.GetPeerAddress; state = State.GetPeerAddress;
@ -105,7 +112,7 @@ public class TakerAsSellerProtocol
public void onResultGetPeerAddress(PeerAddress peerAddress) public void onResultGetPeerAddress(PeerAddress peerAddress)
{ {
this.peerAddress = validPeerAddress(peerAddress); this.peerAddress = checkNotNull(peerAddress);
RequestTakeOffer.run(this::onResultRequestTakeOffer, this::onFault, this.peerAddress, messageFacade, tradeId); RequestTakeOffer.run(this::onResultRequestTakeOffer, this::onFault, this.peerAddress, messageFacade, tradeId);
state = State.RequestTakeOffer; state = State.RequestTakeOffer;
@ -143,7 +150,7 @@ public class TakerAsSellerProtocol
public void onResultPayTakeOfferFee(Transaction transaction) public void onResultPayTakeOfferFee(Transaction transaction)
{ {
checkNotNull(transaction); checkNotNull(transaction);
String transactionId = validString(transaction.getHashAsString()); String transactionId = nonEmptyStringOf(transaction.getHashAsString());
trade.setTakeOfferFeeTxID(transactionId); trade.setTakeOfferFeeTxID(transactionId);
@ -178,11 +185,11 @@ public class TakerAsSellerProtocol
checkState(state == State.SendTakeOfferFeePayedTxId); checkState(state == State.SendTakeOfferFeePayedTxId);
peersAccountId = validString(message.getAccountID()); peersAccountId = nonEmptyStringOf(message.getAccountID());
peersBankAccount = checkNotNull(message.getBankAccount()); peersBankAccount = checkNotNull(message.getBankAccount());
offererPubKey = validString(message.getOffererPubKey()); offererPubKey = nonEmptyStringOf(message.getOffererPubKey());
preparedOffererDepositTxAsHex = validString(message.getPreparedOffererDepositTxAsHex()); preparedOffererDepositTxAsHex = nonEmptyStringOf(message.getPreparedOffererDepositTxAsHex());
offererTxOutIndex = validNonNegativeLong(message.getOffererTxOutIndex()); offererTxOutIndex = nonNegativeLongOf(message.getOffererTxOutIndex());
VerifyOffererAccount.run(this::onResultVerifyOffererAccount, VerifyOffererAccount.run(this::onResultVerifyOffererAccount,
this::onFault, this::onFault,

View file

@ -1,9 +1,9 @@
package io.bitsquare.trade.protocol.tasks.offerer; package io.bitsquare.trade.protocol.tasks.offerer;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Utils; import com.google.bitcoin.core.Utils;
import io.bitsquare.msg.MessageFacade; import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener; import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.messages.offerer.DepositTxPublishedMessage; import io.bitsquare.trade.protocol.messages.offerer.DepositTxPublishedMessage;
import io.bitsquare.trade.protocol.tasks.FaultHandler; import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler; import io.bitsquare.trade.protocol.tasks.ResultHandler;
@ -15,9 +15,9 @@ 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, FaultHandler faultHandler, PeerAddress peerAddress, MessageFacade messageFacade, Trade trade) public static void run(ResultHandler resultHandler, FaultHandler faultHandler, PeerAddress peerAddress, MessageFacade messageFacade, String tradeId, Transaction depositTransaction)
{ {
DepositTxPublishedMessage tradeMessage = new DepositTxPublishedMessage(trade.getId(), Utils.bytesToHexString(trade.getDepositTransaction().bitcoinSerialize())); DepositTxPublishedMessage tradeMessage = new DepositTxPublishedMessage(tradeId, Utils.bytesToHexString(depositTransaction.bitcoinSerialize()));
messageFacade.sendTradeMessage(peerAddress, tradeMessage, new OutgoingTradeMessageListener() messageFacade.sendTradeMessage(peerAddress, tradeMessage, new OutgoingTradeMessageListener()
{ {
@Override @Override

View file

@ -1,11 +1,9 @@
package io.bitsquare.trade.protocol.tasks.offerer; package io.bitsquare.trade.protocol.tasks.offerer;
import com.google.bitcoin.core.ECKey; import com.google.bitcoin.core.ECKey;
import com.google.bitcoin.core.Transaction;
import io.bitsquare.btc.WalletFacade; import io.bitsquare.btc.WalletFacade;
import io.bitsquare.msg.MessageFacade; import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener; import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.messages.offerer.BankTransferInitedMessage; import io.bitsquare.trade.protocol.messages.offerer.BankTransferInitedMessage;
import io.bitsquare.trade.protocol.tasks.FaultHandler; import io.bitsquare.trade.protocol.tasks.FaultHandler;
import io.bitsquare.trade.protocol.tasks.ResultHandler; import io.bitsquare.trade.protocol.tasks.ResultHandler;
@ -24,34 +22,30 @@ public class SendSignedPayoutTx
PeerAddress peerAddress, PeerAddress peerAddress,
MessageFacade messageFacade, MessageFacade messageFacade,
WalletFacade walletFacade, WalletFacade walletFacade,
Trade trade, String tradeId,
String takerPayoutAddress) String takerPayoutAddress,
String offererPayoutAddress,
String depositTransactionId,
BigInteger collateral,
BigInteger tradeAmount)
{ {
try try
{ {
Transaction depositTransaction = trade.getDepositTransaction(); BigInteger offererPaybackAmount = tradeAmount.add(collateral);
BigInteger collateral = trade.getCollateralAmount();
BigInteger offererPaybackAmount = trade.getTradeAmount().add(collateral);
BigInteger takerPaybackAmount = collateral; BigInteger takerPaybackAmount = collateral;
log.trace("offererPaybackAmount " + offererPaybackAmount); Pair<ECKey.ECDSASignature, String> result = walletFacade.offererCreatesAndSignsPayoutTx(depositTransactionId,
log.trace("takerPaybackAmount " + takerPaybackAmount);
log.trace("depositTransaction.getHashAsString() " + depositTransaction.getHashAsString());
log.trace("takerPayoutAddress " + takerPayoutAddress);
Pair<ECKey.ECDSASignature, String> result = walletFacade.offererCreatesAndSignsPayoutTx(depositTransaction.getHashAsString(),
offererPaybackAmount, offererPaybackAmount,
takerPaybackAmount, takerPaybackAmount,
takerPayoutAddress, takerPayoutAddress,
trade.getId()); tradeId);
ECKey.ECDSASignature offererSignature = result.getKey(); ECKey.ECDSASignature offererSignature = result.getKey();
String offererSignatureR = offererSignature.r.toString(); String offererSignatureR = offererSignature.r.toString();
String offererSignatureS = offererSignature.s.toString(); String offererSignatureS = offererSignature.s.toString();
String depositTxAsHex = result.getValue(); String depositTxAsHex = result.getValue();
String offererPayoutAddress = walletFacade.getAddressInfoByTradeID(trade.getId()).getAddressString();
BankTransferInitedMessage tradeMessage = new BankTransferInitedMessage(trade.getId(), BankTransferInitedMessage tradeMessage = new BankTransferInitedMessage(tradeId,
depositTxAsHex, depositTxAsHex,
offererSignatureR, offererSignatureR,
offererSignatureS, offererSignatureS,
@ -59,13 +53,6 @@ public class SendSignedPayoutTx
takerPaybackAmount, takerPaybackAmount,
offererPayoutAddress); offererPayoutAddress);
log.trace("depositTxAsHex " + depositTxAsHex);
log.trace("offererSignatureR " + offererSignatureR);
log.trace("offererSignatureS " + offererSignatureS);
log.trace("offererPaybackAmount " + offererPaybackAmount);
log.trace("takerPaybackAmount " + takerPaybackAmount);
log.trace("offererPayoutAddress " + offererPayoutAddress);
messageFacade.sendTradeMessage(peerAddress, tradeMessage, new OutgoingTradeMessageListener() messageFacade.sendTradeMessage(peerAddress, tradeMessage, new OutgoingTradeMessageListener()
{ {
@Override @Override

View file

@ -1,6 +1,6 @@
package io.bitsquare.util; package io.bitsquare.util;
import net.tomp2p.peers.PeerAddress; import java.math.BigInteger;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -11,24 +11,31 @@ public class Validator
{ {
private static final Logger log = LoggerFactory.getLogger(Validator.class); private static final Logger log = LoggerFactory.getLogger(Validator.class);
public static String validString(String value) public static String nonEmptyStringOf(String value)
{ {
checkNotNull(value); checkNotNull(value);
checkArgument(value.length() > 0); checkArgument(value.length() > 0);
return value; return value;
} }
public static long validNonNegativeLong(long value) public static long nonNegativeLongOf(long value)
{ {
checkArgument(value >= 0); checkArgument(value >= 0);
return value; return value;
} }
public static PeerAddress validPeerAddress(PeerAddress value) public static BigInteger nonZeroBigIntegerOf(BigInteger value)
{ {
checkNotNull(value); checkNotNull(value);
checkArgument(value.compareTo(BigInteger.ZERO) != 0);
return value; return value;
} }
public static BigInteger nonNegativeBigIntegerOf(BigInteger value)
{
checkNotNull(value);
checkArgument(value.compareTo(BigInteger.ZERO) >= 0);
return value;
}
} }