From f498d393b0b2250664353c2dc3bdba69fe372f14 Mon Sep 17 00:00:00 2001 From: Manfred Karrer Date: Sat, 4 Apr 2015 19:24:53 +0200 Subject: [PATCH] Add timeouts, improve interrupted trade handling --- .../bitsquare/crypto/EncryptionService.java | 15 +++- .../closed/ClosedTradesDataModel.java | 2 +- .../closed/ClosedTradesViewModel.java | 2 +- .../pending/PendingTradesDataModel.java | 2 +- .../pending/PendingTradesListItem.java | 2 +- .../pending/PendingTradesViewModel.java | 12 --- .../main/portfolio/pending/SellerSubView.java | 11 ++- .../steps/ConfirmFiatReceivedView.java | 7 ++ .../pending/steps/StartFiatView.java | 6 ++ .../p2p/tomp2p/TomP2PMessageService.java | 8 +- .../main/java/io/bitsquare/trade/Trade.java | 28 ++++--- .../java/io/bitsquare/trade/TradeManager.java | 80 +++++++++++-------- .../CheckOfferAvailabilityProtocol.java | 41 +++++++++- .../trade/BuyerAsOffererProtocol.java | 8 +- .../protocol/trade/BuyerAsTakerProtocol.java | 10 ++- .../trade/protocol/trade/ProcessModel.java | 11 ++- .../trade/SellerAsOffererProtocol.java | 13 ++- .../protocol/trade/SellerAsTakerProtocol.java | 19 +++-- .../trade/protocol/trade/TradeProtocol.java | 6 +- .../tasks/buyer/SignAndPublishDepositTx.java | 4 + 20 files changed, 185 insertions(+), 102 deletions(-) diff --git a/core/src/main/java/io/bitsquare/crypto/EncryptionService.java b/core/src/main/java/io/bitsquare/crypto/EncryptionService.java index 8c249ca07c..c684ce4946 100644 --- a/core/src/main/java/io/bitsquare/crypto/EncryptionService.java +++ b/core/src/main/java/io/bitsquare/crypto/EncryptionService.java @@ -40,7 +40,6 @@ import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; -// TODO consider to use SealedObject public class EncryptionService { private static final Logger log = LoggerFactory.getLogger(EncryptionService.class); private static final String ALGO_SYM = "AES"; @@ -55,15 +54,21 @@ public class EncryptionService { } public KeyPair getGeneratedDSAKeyPair() throws NoSuchAlgorithmException { + long ts = System.currentTimeMillis(); final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA"); keyPairGenerator.initialize(1024); - return keyPairGenerator.genKeyPair(); + KeyPair keyPair = keyPairGenerator.genKeyPair(); + log.debug("getGeneratedDSAKeyPair needed {} ms", System.currentTimeMillis() - ts); + return keyPair; } public KeyPair getGeneratedRSAKeyPair() throws NoSuchAlgorithmException { + long ts = System.currentTimeMillis(); KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGO_ASYM); keyPairGenerator.initialize(KEY_SIZE_ASYM); - return keyPairGenerator.genKeyPair(); + KeyPair keyPair = keyPairGenerator.genKeyPair(); + log.debug("getGeneratedRSAKeyPair needed {} ms", System.currentTimeMillis() - ts); + return keyPair; } public Bucket encryptObject(PublicKey publicKey, Object object) throws IllegalBlockSizeException, InvalidKeyException, BadPaddingException, @@ -78,6 +83,7 @@ public class EncryptionService { public Bucket encrypt(PublicKey publicKey, byte[] payload) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { + long ts = System.currentTimeMillis(); // Create symmetric key and KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGO_SYM); keyGenerator.init(KEY_SIZE_SYM); @@ -95,11 +101,13 @@ public class EncryptionService { cipherSym.init(Cipher.ENCRYPT_MODE, keySpec); log.debug("encrypt payload length: " + payload.length); byte[] encryptedPayload = cipherSym.doFinal(payload); + log.debug("Encryption needed {} ms", System.currentTimeMillis() - ts); return new Bucket(encryptedKey, encryptedPayload); } public byte[] decrypt(PrivateKey privateKey, Bucket bucket) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { + long ts = System.currentTimeMillis(); byte[] encryptedPayload = bucket.encryptedPayload; byte[] encryptedKey = bucket.encryptedKey; @@ -114,6 +122,7 @@ public class EncryptionService { cipherSym.init(Cipher.DECRYPT_MODE, key); byte[] payload = cipherSym.doFinal(encryptedPayload); log.debug("decrypt payload length: " + payload.length); + log.debug("Decryption needed {} ms", System.currentTimeMillis() - ts); return payload; } } diff --git a/core/src/main/java/io/bitsquare/gui/main/portfolio/closed/ClosedTradesDataModel.java b/core/src/main/java/io/bitsquare/gui/main/portfolio/closed/ClosedTradesDataModel.java index 219f04f890..e26872b606 100644 --- a/core/src/main/java/io/bitsquare/gui/main/portfolio/closed/ClosedTradesDataModel.java +++ b/core/src/main/java/io/bitsquare/gui/main/portfolio/closed/ClosedTradesDataModel.java @@ -74,7 +74,7 @@ class ClosedTradesDataModel implements Activatable, DataModel { list.addAll(tradeManager.getClosedTrades().stream().map(ClosedTradesListItem::new).collect(Collectors.toList())); // we sort by date, earliest first - list.sort((o1, o2) -> o2.getTrade().getDate().compareTo(o1.getTrade().getDate())); + list.sort((o1, o2) -> o2.getTrade().getTakeOfferDate().compareTo(o1.getTrade().getTakeOfferDate())); } } diff --git a/core/src/main/java/io/bitsquare/gui/main/portfolio/closed/ClosedTradesViewModel.java b/core/src/main/java/io/bitsquare/gui/main/portfolio/closed/ClosedTradesViewModel.java index d6a908cac6..eb0eba68fc 100644 --- a/core/src/main/java/io/bitsquare/gui/main/portfolio/closed/ClosedTradesViewModel.java +++ b/core/src/main/java/io/bitsquare/gui/main/portfolio/closed/ClosedTradesViewModel.java @@ -65,7 +65,7 @@ class ClosedTradesViewModel extends ActivatableWithDataModel o2.getTrade().getDate().compareTo(o1.getTrade().getDate())); + list.sort((o1, o2) -> o2.getTrade().getTakeOfferDate().compareTo(o1.getTrade().getTakeOfferDate())); log.debug("onListChanged {}", list.size()); if (list.size() > 0) diff --git a/core/src/main/java/io/bitsquare/gui/main/portfolio/pending/PendingTradesListItem.java b/core/src/main/java/io/bitsquare/gui/main/portfolio/pending/PendingTradesListItem.java index 870992fdb0..7b9e780a76 100644 --- a/core/src/main/java/io/bitsquare/gui/main/portfolio/pending/PendingTradesListItem.java +++ b/core/src/main/java/io/bitsquare/gui/main/portfolio/pending/PendingTradesListItem.java @@ -65,7 +65,7 @@ public class PendingTradesListItem { } public Date getDate() { - return trade.getDate(); + return trade.getTakeOfferDate(); } public String getId() { diff --git a/core/src/main/java/io/bitsquare/gui/main/portfolio/pending/PendingTradesViewModel.java b/core/src/main/java/io/bitsquare/gui/main/portfolio/pending/PendingTradesViewModel.java index 975bde2219..e9bc881855 100644 --- a/core/src/main/java/io/bitsquare/gui/main/portfolio/pending/PendingTradesViewModel.java +++ b/core/src/main/java/io/bitsquare/gui/main/portfolio/pending/PendingTradesViewModel.java @@ -54,7 +54,6 @@ public class PendingTradesViewModel extends ActivatableWithDataModel txIdChangeListener; private ProgressIndicator statusProgressIndicator; + private Parent root; /////////////////////////////////////////////////////////////////////////////////////////// @@ -94,6 +96,8 @@ public class StartFiatView extends TradeStepDetailsView { model.txId.removeListener(txIdChangeListener); txIdTextField.cleanup(); + if (root != null) + root.setMouseTransparent(false); } /////////////////////////////////////////////////////////////////////////////////////////// @@ -107,6 +111,8 @@ public class StartFiatView extends TradeStepDetailsView { statusProgressIndicator.setVisible(true); statusProgressIndicator.setProgress(-1); statusLabel.setText("Sending message to trading partner..."); + root = statusProgressIndicator.getScene().getRoot(); + root.setMouseTransparent(true); } diff --git a/core/src/main/java/io/bitsquare/p2p/tomp2p/TomP2PMessageService.java b/core/src/main/java/io/bitsquare/p2p/tomp2p/TomP2PMessageService.java index 71c499cbf9..5ef72420e9 100644 --- a/core/src/main/java/io/bitsquare/p2p/tomp2p/TomP2PMessageService.java +++ b/core/src/main/java/io/bitsquare/p2p/tomp2p/TomP2PMessageService.java @@ -148,13 +148,13 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic @Override public void addMessageHandler(MessageHandler listener) { if (!messageHandlers.add(listener)) - throw new IllegalArgumentException("Add listener did not change list. Probably listener has been already added."); + log.error("Add listener did not change list. Probably listener has been already added."); } @Override public void removeMessageHandler(MessageHandler listener) { if (!messageHandlers.remove(listener)) - throw new IllegalArgumentException("Try to remove listener which was never added."); + log.error("Try to remove listener which was never added."); } @@ -171,10 +171,10 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic if (message instanceof Message) executor.execute(() -> messageHandlers.stream().forEach(e -> e.handleMessage((Message) message, new TomP2PPeer(sender)))); else - throw new RuntimeException("We got an object which is not type of Message. That must never happen. Request object = " + message); + log.error("We got an object which is not type of Message. That must never happen. Request object = " + message); } else { - throw new RuntimeException("Received msg from myself. That must never happen."); + log.error("Received msg from myself. That must never happen."); } return true; diff --git a/core/src/main/java/io/bitsquare/trade/Trade.java b/core/src/main/java/io/bitsquare/trade/Trade.java index 50d0f281ce..c9d6ded0af 100644 --- a/core/src/main/java/io/bitsquare/trade/Trade.java +++ b/core/src/main/java/io/bitsquare/trade/Trade.java @@ -90,10 +90,10 @@ abstract public class Trade implements Model, Serializable { // Immutable private final Offer offer; - private final Date date; private final ProcessModel processModel; // Mutable + private Date takeOfferDate; protected TradeState.ProcessState processState; protected TradeState.LifeCycleState lifeCycleState; private MailboxMessage mailboxMessage; @@ -118,7 +118,6 @@ abstract public class Trade implements Model, Serializable { this.offer = offer; this.storage = storage; - date = new Date(); processModel = new ProcessModel(); tradeVolumeProperty = new SimpleObjectProperty<>(); tradeAmountProperty = new SimpleObjectProperty<>(); @@ -165,8 +164,11 @@ abstract public class Trade implements Model, Serializable { createProtocol(); - if (mailboxMessage != null) - tradeProtocol.setMailboxMessage(mailboxMessage); + if (mailboxMessage != null) { + tradeProtocol.applyMailboxMessage(mailboxMessage); + // After applied to protocol we remove it + mailboxMessage = null; + } } protected void initStateProperties() { @@ -210,10 +212,6 @@ abstract public class Trade implements Model, Serializable { public void setMailboxMessage(MailboxMessage mailboxMessage) { this.mailboxMessage = mailboxMessage; - if (tradeProtocol != null) - tradeProtocol.setMailboxMessage(mailboxMessage); - - storage.queueUpForSave(); } public void setStorage(Storage storage) { @@ -253,10 +251,6 @@ abstract public class Trade implements Model, Serializable { // Getter only /////////////////////////////////////////////////////////////////////////////////////////// - public Date getDate() { - return date; - } - public String getId() { return offer.getId(); } @@ -312,6 +306,14 @@ abstract public class Trade implements Model, Serializable { // Getter/Setter for Mutable objects /////////////////////////////////////////////////////////////////////////////////////////// + public Date getTakeOfferDate() { + return takeOfferDate; + } + + public void setTakeOfferDate(Date takeOfferDate) { + this.takeOfferDate = takeOfferDate; + } + public void setTradingPeer(Peer tradingPeer) { this.tradingPeer = tradingPeer; } @@ -439,7 +441,7 @@ abstract public class Trade implements Model, Serializable { ", storage=" + storage + ", tradeProtocol=" + tradeProtocol + ", offer=" + offer + - ", date=" + date + + ", date=" + takeOfferDate + ", processModel=" + processModel + ", processState=" + processState + ", lifeCycleState=" + lifeCycleState + diff --git a/core/src/main/java/io/bitsquare/trade/TradeManager.java b/core/src/main/java/io/bitsquare/trade/TradeManager.java index 89e6ea6333..45c208f5c5 100644 --- a/core/src/main/java/io/bitsquare/trade/TradeManager.java +++ b/core/src/main/java/io/bitsquare/trade/TradeManager.java @@ -59,6 +59,7 @@ import com.google.common.util.concurrent.FutureCallback; import java.io.File; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -152,6 +153,7 @@ public class TradeManager { // When all services are initialized we create the protocols for our open offers and persisted pendingTrades // OffererAsBuyerProtocol listens for take offer requests, so we need to instantiate it early. public void onAllServicesInitialized() { + log.trace("onAllServicesInitialized"); for (Trade trade : openOfferTrades) { Offer offer = trade.getOffer(); // We add own offers to offerbook when we go online again @@ -161,8 +163,48 @@ public class TradeManager { setupDepositPublishedListener(trade); trade.setStorage(openOfferTradesStorage); initTrade(trade); - } + + // If there are messages in our mailbox we apply it and remove them from the DHT + // We run that before initializing the pending trades to be sure the state is correct + mailboxService.getAllMessages(user.getP2pSigPubKey(), + (encryptedMailboxMessages) -> { + log.trace("mailboxService.getAllMessages success"); + setMailboxMessagesToTrades(encryptedMailboxMessages); + emptyMailbox(); + initPendingTrades(); + }); + } + + private void setMailboxMessagesToTrades(List encryptedMailboxMessages) { + log.trace("applyMailboxMessage encryptedMailboxMessage.size=" + encryptedMailboxMessages.size()); + for (EncryptedMailboxMessage encrypted : encryptedMailboxMessages) { + try { + MailboxMessage mailboxMessage = encryptionService.decryptToObject(user.getP2pEncryptPrivateKey(), encrypted.getBucket()); + if (mailboxMessage instanceof TradeMessage) { + String tradeId = ((TradeMessage) mailboxMessage).tradeId; + Optional tradeOptional = pendingTrades.stream().filter(e -> e.getId().equals(tradeId)).findAny(); + if (tradeOptional.isPresent()) + tradeOptional.get().setMailboxMessage(mailboxMessage); + } + } catch (Throwable e) { + e.printStackTrace(); + log.error(e.getMessage()); + } + } + } + + private void emptyMailbox() { + mailboxService.removeAllMessages(user.getP2pSigPubKey(), + () -> log.debug("All mailbox entries removed"), + (errorMessage, fault) -> { + log.error(errorMessage); + log.error(fault.getMessage()); + }); + } + + private void initPendingTrades() { + log.trace("initPendingTrades"); List failedTrades = new ArrayList<>(); for (Trade trade : pendingTrades) { // We continue an interrupted trade. @@ -188,42 +230,8 @@ public class TradeManager { pendingTrades.remove(trade); closedTrades.add(trade); } - - // if there are messages in our mailbox we apply it and remove them from the DHT - mailboxService.getAllMessages(user.getP2pSigPubKey(), - (encryptedMailboxMessages) -> { - setMailboxMessagesToTrades(encryptedMailboxMessages); - emptyMailbox(); - }); } - private void setMailboxMessagesToTrades(List encryptedMailboxMessages) { - log.trace("applyMailboxMessage encryptedMailboxMessage.size=" + encryptedMailboxMessages.size()); - for (EncryptedMailboxMessage encrypted : encryptedMailboxMessages) { - try { - MailboxMessage mailboxMessage = encryptionService.decryptToObject(user.getP2pEncryptPrivateKey(), encrypted.getBucket()); - - if (mailboxMessage instanceof TradeMessage) { - String tradeId = ((TradeMessage) mailboxMessage).tradeId; - Optional tradeOptional = pendingTrades.stream().filter(e -> e.getId().equals(tradeId)).findAny(); - if (tradeOptional.isPresent()) - tradeOptional.get().setMailboxMessage(mailboxMessage); - } - } catch (Throwable e) { - e.printStackTrace(); - log.error(e.getMessage()); - } - } - } - - private void emptyMailbox() { - mailboxService.removeAllMessages(user.getP2pSigPubKey(), - () -> log.debug("All mailbox entries removed"), - (errorMessage, fault) -> { - log.error(errorMessage); - log.error(fault.getMessage()); - }); - } public void shutDown() { if (!shutDownRequested) { @@ -298,6 +306,7 @@ public class TradeManager { () -> log.debug("remove offer was successful"), log::error, false); + trade.setTakeOfferDate(new Date()); pendingTrades.add(trade); trade.setStorage(pendingTradesStorage); } @@ -383,6 +392,7 @@ public class TradeManager { else trade = new BuyerAsTakerTrade(offer, amount, model.getPeer(), pendingTradesStorage); + trade.setTakeOfferDate(new Date()); initTrade(trade); pendingTrades.add(trade); if (trade instanceof TakerTrade) diff --git a/core/src/main/java/io/bitsquare/trade/protocol/availability/CheckOfferAvailabilityProtocol.java b/core/src/main/java/io/bitsquare/trade/protocol/availability/CheckOfferAvailabilityProtocol.java index 06314555fe..ea732202f9 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/availability/CheckOfferAvailabilityProtocol.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/availability/CheckOfferAvailabilityProtocol.java @@ -29,16 +29,24 @@ import io.bitsquare.trade.protocol.availability.tasks.GetPeerAddress; import io.bitsquare.trade.protocol.availability.tasks.ProcessReportOfferAvailabilityMessage; import io.bitsquare.trade.protocol.availability.tasks.RequestIsOfferAvailable; +import java.util.Timer; +import java.util.TimerTask; + +import javafx.application.Platform; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CheckOfferAvailabilityProtocol { private static final Logger log = LoggerFactory.getLogger(CheckOfferAvailabilityProtocol.class); + private static final long TIMEOUT = 10000; + private final CheckOfferAvailabilityModel model; private final ResultHandler resultHandler; private final ErrorMessageHandler errorMessageHandler; private final MessageHandler messageHandler; + private Timer timeoutTimer; private boolean isCanceled; private TaskRunner taskRunner; @@ -56,6 +64,7 @@ public class CheckOfferAvailabilityProtocol { } private void cleanup() { + stopTimeout(); model.messageService.removeMessageHandler(messageHandler); } @@ -78,6 +87,7 @@ public class CheckOfferAvailabilityProtocol { GetPeerAddress.class, RequestIsOfferAvailable.class ); + startTimeout(); taskRunner.run(); } @@ -95,11 +105,12 @@ public class CheckOfferAvailabilityProtocol { private void handleMessage(Message message, @SuppressWarnings("UnusedParameters") Peer sender) { if (!isCanceled) { if (message instanceof ReportOfferAvailabilityMessage && model.offer.getId().equals(((ReportOfferAvailabilityMessage) message).offerId)) - handleReportOfferAvailabilityMessage((ReportOfferAvailabilityMessage) message); + handle((ReportOfferAvailabilityMessage) message); } } - private void handleReportOfferAvailabilityMessage(ReportOfferAvailabilityMessage message) { + private void handle(ReportOfferAvailabilityMessage message) { + stopTimeout(); model.setMessage(message); taskRunner = new TaskRunner<>(model, @@ -115,4 +126,30 @@ public class CheckOfferAvailabilityProtocol { taskRunner.addTasks(ProcessReportOfferAvailabilityMessage.class); taskRunner.run(); } + + protected void startTimeout() { + log.debug("startTimeout"); + stopTimeout(); + + timeoutTimer = new Timer(); + TimerTask task = new TimerTask() { + @Override + public void run() { + Platform.runLater(() -> { + log.debug("Timeout reached"); + errorMessageHandler.handleErrorMessage("Timeout reached: Peer has not responded."); + }); + } + }; + + timeoutTimer.schedule(task, TIMEOUT); + } + + protected void stopTimeout() { + log.debug("stopTimeout"); + if (timeoutTimer != null) { + timeoutTimer.cancel(); + timeoutTimer = null; + } + } } diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/BuyerAsOffererProtocol.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/BuyerAsOffererProtocol.java index 575cb3cc1e..e42ed35e48 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/BuyerAsOffererProtocol.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/BuyerAsOffererProtocol.java @@ -74,11 +74,11 @@ public class BuyerAsOffererProtocol extends TradeProtocol { /////////////////////////////////////////////////////////////////////////////////////////// @Override - public void setMailboxMessage(MailboxMessage mailboxMessage) { + public void applyMailboxMessage(MailboxMessage mailboxMessage) { log.debug("setMailboxMessage " + mailboxMessage); // Might be called twice, so check that its only processed once - if (processModel.getMailboxMessage() == null) { - processModel.setMailboxMessage(mailboxMessage); + if (!processModel.isMailboxMessageProcessed()) { + processModel.mailboxMessageProcessed(); if (mailboxMessage instanceof PayoutTxPublishedMessage) { handle((PayoutTxPublishedMessage) mailboxMessage); } @@ -137,9 +137,11 @@ public class BuyerAsOffererProtocol extends TradeProtocol { SendRequestPayDepositMessage.class ); taskRunner.run(); + startTimeout(); } private void handle(RequestPublishDepositTxMessage tradeMessage) { + stopTimeout(); processModel.setTradeMessage(tradeMessage); TaskRunner taskRunner = new TaskRunner<>(buyerAsOffererTrade, diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/BuyerAsTakerProtocol.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/BuyerAsTakerProtocol.java index b01bc407f1..f33b7e634e 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/BuyerAsTakerProtocol.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/BuyerAsTakerProtocol.java @@ -71,11 +71,11 @@ public class BuyerAsTakerProtocol extends TradeProtocol { /////////////////////////////////////////////////////////////////////////////////////////// @Override - public void setMailboxMessage(MailboxMessage mailboxMessage) { + public void applyMailboxMessage(MailboxMessage mailboxMessage) { log.debug("setMailboxMessage " + mailboxMessage); // Might be called twice, so check that its only processed once - if (processModel.getMailboxMessage() == null) { - processModel.setMailboxMessage(mailboxMessage); + if (!processModel.isMailboxMessageProcessed()) { + processModel.mailboxMessageProcessed(); if (mailboxMessage instanceof PayoutTxPublishedMessage) { handle((PayoutTxPublishedMessage) mailboxMessage); } @@ -94,6 +94,7 @@ public class BuyerAsTakerProtocol extends TradeProtocol { SendRequestPayDepositMessage.class ); taskRunner.run(); + startTimeout(); } @@ -102,6 +103,7 @@ public class BuyerAsTakerProtocol extends TradeProtocol { /////////////////////////////////////////////////////////////////////////////////////////// private void handle(RequestPublishDepositTxMessage tradeMessage) { + stopTimeout(); processModel.setTradeMessage(tradeMessage); TaskRunner taskRunner = new TaskRunner<>(buyerAsTakerTrade, @@ -137,7 +139,7 @@ public class BuyerAsTakerProtocol extends TradeProtocol { /////////////////////////////////////////////////////////////////////////////////////////// - // Incoming message handling + // After peer has received Fiat tx /////////////////////////////////////////////////////////////////////////////////////////// private void handle(PayoutTxPublishedMessage tradeMessage) { diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/ProcessModel.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/ProcessModel.java index dfe0496faf..566d902230 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/ProcessModel.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/ProcessModel.java @@ -26,7 +26,6 @@ import io.bitsquare.common.taskrunner.Model; import io.bitsquare.crypto.SignatureService; import io.bitsquare.fiat.FiatAccount; import io.bitsquare.offer.Offer; -import io.bitsquare.p2p.MailboxMessage; import io.bitsquare.p2p.MessageService; import io.bitsquare.trade.protocol.trade.messages.TradeMessage; import io.bitsquare.user.User; @@ -67,7 +66,7 @@ public class ProcessModel implements Model, Serializable { // Mutable public final TradingPeer tradingPeer; - transient private MailboxMessage mailboxMessage; + transient private boolean mailboxMessageProcessed; transient private TradeMessage tradeMessage; private String takeOfferFeeTxId; private Transaction payoutTx; @@ -158,13 +157,13 @@ public class ProcessModel implements Model, Serializable { return tradeMessage; } - public void setMailboxMessage(MailboxMessage mailboxMessage) { - this.mailboxMessage = mailboxMessage; + public void mailboxMessageProcessed() { + this.mailboxMessageProcessed = true; } @Nullable - public MailboxMessage getMailboxMessage() { - return mailboxMessage; + public boolean isMailboxMessageProcessed() { + return mailboxMessageProcessed; } @Nullable diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/SellerAsOffererProtocol.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/SellerAsOffererProtocol.java index 4232a1d1c1..efb0b90412 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/SellerAsOffererProtocol.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/SellerAsOffererProtocol.java @@ -73,11 +73,11 @@ public class SellerAsOffererProtocol extends TradeProtocol { /////////////////////////////////////////////////////////////////////////////////////////// @Override - public void setMailboxMessage(MailboxMessage mailboxMessage) { + public void applyMailboxMessage(MailboxMessage mailboxMessage) { log.debug("setMailboxMessage " + mailboxMessage); // Might be called twice, so check that its only processed once - if (processModel.getMailboxMessage() == null) { - processModel.setMailboxMessage(mailboxMessage); + if (!processModel.isMailboxMessageProcessed()) { + processModel.mailboxMessageProcessed(); if (mailboxMessage instanceof FiatTransferStartedMessage) { handle((FiatTransferStartedMessage) mailboxMessage); } @@ -148,9 +148,11 @@ public class SellerAsOffererProtocol extends TradeProtocol { SendRequestPublishDepositTxMessage.class ); taskRunner.run(); + startTimeout(); } private void handle(DepositTxPublishedMessage tradeMessage) { + stopTimeout(); processModel.setTradeMessage(tradeMessage); TaskRunner taskRunner = new TaskRunner<>(sellerAsOffererTrade, @@ -164,6 +166,11 @@ public class SellerAsOffererProtocol extends TradeProtocol { taskRunner.run(); } + + /////////////////////////////////////////////////////////////////////////////////////////// + // After peer has started Fiat tx + /////////////////////////////////////////////////////////////////////////////////////////// + private void handle(FiatTransferStartedMessage tradeMessage) { processModel.setTradeMessage(tradeMessage); diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/SellerAsTakerProtocol.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/SellerAsTakerProtocol.java index 129a70dbdb..240d44b7d1 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/SellerAsTakerProtocol.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/SellerAsTakerProtocol.java @@ -73,11 +73,11 @@ public class SellerAsTakerProtocol extends TradeProtocol { /////////////////////////////////////////////////////////////////////////////////////////// @Override - public void setMailboxMessage(MailboxMessage mailboxMessage) { + public void applyMailboxMessage(MailboxMessage mailboxMessage) { log.debug("setMailboxMessage " + mailboxMessage); // Might be called twice, so check that its only processed once - if (processModel.getMailboxMessage() == null) { - processModel.setMailboxMessage(mailboxMessage); + if (!processModel.isMailboxMessageProcessed()) { + processModel.mailboxMessageProcessed(); if (mailboxMessage instanceof FiatTransferStartedMessage) { handle((FiatTransferStartedMessage) mailboxMessage); } @@ -89,10 +89,7 @@ public class SellerAsTakerProtocol extends TradeProtocol { public void takeAvailableOffer() { TaskRunner taskRunner = new TaskRunner<>(sellerAsTakerTrade, - () -> { - log.debug("taskRunner at takeAvailableOffer completed"); - startTimeout(); - }, + () -> log.debug("taskRunner at takeAvailableOffer completed"), this::handleTaskRunnerFault); taskRunner.addTasks( @@ -101,6 +98,7 @@ public class SellerAsTakerProtocol extends TradeProtocol { SendRequestDepositTxInputsMessage.class ); taskRunner.run(); + startTimeout(); } @@ -125,9 +123,11 @@ public class SellerAsTakerProtocol extends TradeProtocol { SendRequestPublishDepositTxMessage.class ); taskRunner.run(); + startTimeout(); } private void handle(DepositTxPublishedMessage tradeMessage) { + stopTimeout(); processModel.setTradeMessage(tradeMessage); TaskRunner taskRunner = new TaskRunner<>(sellerAsTakerTrade, @@ -141,6 +141,11 @@ public class SellerAsTakerProtocol extends TradeProtocol { taskRunner.run(); } + + /////////////////////////////////////////////////////////////////////////////////////////// + // After peer has started Fiat tx + /////////////////////////////////////////////////////////////////////////////////////////// + private void handle(FiatTransferStartedMessage tradeMessage) { processModel.setTradeMessage(tradeMessage); diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/TradeProtocol.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/TradeProtocol.java index 92a68b2bd9..d6a2f3bad3 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/TradeProtocol.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/TradeProtocol.java @@ -34,6 +34,7 @@ import org.slf4j.LoggerFactory; public abstract class TradeProtocol { private static final Logger log = LoggerFactory.getLogger(TradeProtocol.class); + private static final long TIMEOUT = 10000; protected final ProcessModel processModel; protected MessageHandler messageHandler; @@ -46,10 +47,11 @@ public abstract class TradeProtocol { public void cleanup() { log.debug("cleanup " + this); + stopTimeout(); processModel.getMessageService().removeMessageHandler(messageHandler); } - abstract public void setMailboxMessage(MailboxMessage mailboxMessage); + abstract public void applyMailboxMessage(MailboxMessage mailboxMessage); protected void startTimeout() { log.debug("startTimeout"); @@ -69,7 +71,7 @@ public abstract class TradeProtocol { } }; - timeoutTimer.schedule(task, 3000); + timeoutTimer.schedule(task, TIMEOUT); } protected void stopTimeout() { diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/SignAndPublishDepositTx.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/SignAndPublishDepositTx.java index 57393698e4..a510588d1c 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/SignAndPublishDepositTx.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/SignAndPublishDepositTx.java @@ -31,6 +31,8 @@ import org.bitcoinj.core.Transaction; import com.google.common.util.concurrent.FutureCallback; +import java.util.Date; + import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; @@ -73,6 +75,8 @@ public class SignAndPublishDepositTx extends TradeTask { trade.setLifeCycleState(OffererTradeState.LifeCycleState.PENDING); } + trade.setTakeOfferDate(new Date()); + complete(); }