diff --git a/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java b/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java index b09584ae00..74a50f44f4 100644 --- a/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java @@ -510,6 +510,12 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D protected void handle(PaymentSentMessage message, NodeAddress peer, boolean reprocessOnError) { log.info(LOG_HIGHLIGHT + "handle(PaymentSentMessage) for " + trade.getClass().getSimpleName() + " " + trade.getShortId() + " from " + peer); + // ignore if not seller or arbitrator + if (!(trade instanceof SellerTrade || trade instanceof ArbitratorTrade)) { + log.warn("Ignoring PaymentSentMessage since not seller or arbitrator"); + return; + } + // validate signature try { HavenoUtils.verifyPaymentSentMessage(trade, message); @@ -522,11 +528,8 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D trade.getBuyer().setPaymentSentMessage(message); trade.requestPersistence(); + // process message on trade thread if (!trade.isInitialized() || trade.isShutDownStarted()) return; - if (!(trade instanceof SellerTrade || trade instanceof ArbitratorTrade)) { - log.warn("Ignoring PaymentSentMessage since not seller or arbitrator"); - return; - } ThreadUtils.execute(() -> { // We are more tolerant with expected phase and allow also DEPOSITS_PUBLISHED as it can be the case // that the wallet is still syncing and so the DEPOSITS_CONFIRMED state to yet triggered when we received @@ -549,7 +552,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D return; } latchTrade(); - expect(anyPhase(Trade.Phase.DEPOSITS_CONFIRMED, Trade.Phase.DEPOSITS_UNLOCKED) + expect(anyPhase() .with(message) .from(peer)) .setup(tasks( @@ -589,6 +592,12 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D private void handle(PaymentReceivedMessage message, NodeAddress peer, boolean reprocessOnError) { log.info(LOG_HIGHLIGHT + "handle(PaymentReceivedMessage) for " + trade.getClass().getSimpleName() + " " + trade.getShortId() + " from " + peer); + // ignore if not buyer or arbitrator + if (!(trade instanceof BuyerTrade || trade instanceof ArbitratorTrade)) { + log.warn("Ignoring PaymentReceivedMessage since not buyer or arbitrator"); + return; + } + // validate signature try { HavenoUtils.verifyPaymentReceivedMessage(trade, message); @@ -601,12 +610,9 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D trade.getSeller().setPaymentReceivedMessage(message); trade.requestPersistence(); + // process message on trade thread if (!trade.isInitialized() || trade.isShutDownStarted()) return; ThreadUtils.execute(() -> { - if (!(trade instanceof BuyerTrade || trade instanceof ArbitratorTrade)) { - log.warn("Ignoring PaymentReceivedMessage since not buyer or arbitrator"); - return; - } synchronized (trade.getLock()) { if (!trade.isInitialized() || trade.isShutDownStarted()) return; latchTrade(); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentReceivedMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentReceivedMessage.java index d46b0e0668..5d55bbaea7 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentReceivedMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentReceivedMessage.java @@ -72,6 +72,7 @@ public class ProcessPaymentReceivedMessage extends TradeTask { // update to the latest peer address of our peer if message is correct trade.getSeller().setNodeAddress(processModel.getTempTradePeerNodeAddress()); if (trade.getSeller().getNodeAddress().equals(trade.getBuyer().getNodeAddress())) trade.getBuyer().setNodeAddress(null); // tests can reuse addresses + trade.requestPersistence(); // ack and complete if already processed if (trade.getPhase().ordinal() >= Trade.Phase.PAYMENT_RECEIVED.ordinal() && trade.isPayoutPublished()) { @@ -80,6 +81,14 @@ public class ProcessPaymentReceivedMessage extends TradeTask { return; } + // cannot process until wallet sees deposits unlocked + if (!trade.isDepositsUnlocked()) { + trade.syncAndPollWallet(); + if (!trade.isDepositsUnlocked()) { + throw new RuntimeException("Cannot process PaymentReceivedMessage until wallet sees that deposits are unlocked for " + trade.getClass().getSimpleName() + " " + trade.getId()); + } + } + // set state trade.getSeller().setUpdatedMultisigHex(message.getUpdatedMultisigHex()); trade.getBuyer().setAccountAgeWitness(message.getBuyerAccountAgeWitness()); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentSentMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentSentMessage.java index de7d949ade..1f99d64806 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentSentMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentSentMessage.java @@ -46,6 +46,15 @@ public class ProcessPaymentSentMessage extends TradeTask { // update latest peer address trade.getBuyer().setNodeAddress(processModel.getTempTradePeerNodeAddress()); + trade.requestPersistence(); + + // cannot process until wallet sees deposits confirmed + if (!trade.isDepositsConfirmed()) { + trade.syncAndPollWallet(); + if (!trade.isDepositsConfirmed()) { + throw new RuntimeException("Cannot process PaymentSentMessage until wallet sees that deposits are confirmed for " + trade.getClass().getSimpleName() + " " + trade.getId()); + } + } // update state from message trade.getBuyer().setUpdatedMultisigHex(message.getUpdatedMultisigHex());