diff --git a/core/src/main/java/bisq/core/trade/TradeManager.java b/core/src/main/java/bisq/core/trade/TradeManager.java index 0384187bf15..507e1934e88 100644 --- a/core/src/main/java/bisq/core/trade/TradeManager.java +++ b/core/src/main/java/bisq/core/trade/TradeManager.java @@ -156,7 +156,18 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi private final Provider provider; private final ClockWatcher clockWatcher; - private final Map tradeProtocolByTradeId = new HashMap<>(); + // We use uid for that map not the trade ID + private final Map tradeProtocolByTradeUid = new HashMap<>(); + + // We maintain a map with trade (offer) ID to reset a pending trade protocol for the same offer. + // Pending trade protocol could happen in edge cases when an early error did not cause a removal of the + // offer and the same peer takes the offer later again. Usually it is prevented for the taker to take again after a + // failure but that is only based on failed trades state and it can be that either the taker deletes the failed trades + // file or it was not persisted. Such rare cases could lead to a pending protocol and when taker takes again the + // offer the message listener from the old pending protocol gets invoked and processes the messages based on + // potentially outdated model data (e.g. old inputs). + private final Map pendingTradeProtocolByTradeId = new HashMap<>(); + private final PersistenceManager> persistenceManager; private final TradableList tradableList = new TradableList<>(); @Getter @@ -408,15 +419,20 @@ public void onUpdatedDataReceived() { public TradeProtocol getTradeProtocol(TradeModel trade) { String uid = trade.getUid(); - if (tradeProtocolByTradeId.containsKey(uid)) { - return tradeProtocolByTradeId.get(uid); + if (tradeProtocolByTradeUid.containsKey(uid)) { + return tradeProtocolByTradeUid.get(uid); } else { TradeProtocol tradeProtocol = TradeProtocolFactory.getNewTradeProtocol(trade); - TradeProtocol prev = tradeProtocolByTradeId.put(uid, tradeProtocol); + TradeProtocol prev = tradeProtocolByTradeUid.put(uid, tradeProtocol); if (prev != null) { log.error("We had already an entry with uid {}", trade.getUid()); } + TradeProtocol pending = pendingTradeProtocolByTradeId.put(trade.getId(), tradeProtocol); + if (pending != null) { + pending.reset(); + } + return tradeProtocol; } } @@ -618,7 +634,7 @@ public void onTakeBsqSwapOffer(Offer offer, private TradeProtocol createTradeProtocol(TradeModel tradeModel) { TradeProtocol tradeProtocol = TradeProtocolFactory.getNewTradeProtocol(tradeModel); - TradeProtocol prev = tradeProtocolByTradeId.put(tradeModel.getUid(), tradeProtocol); + TradeProtocol prev = tradeProtocolByTradeUid.put(tradeModel.getUid(), tradeProtocol); if (prev != null) { log.error("We had already an entry with uid {}", tradeModel.getUid()); } @@ -626,6 +642,11 @@ private TradeProtocol createTradeProtocol(TradeModel tradeModel) { tradableList.add((Trade) tradeModel); } + TradeProtocol pending = pendingTradeProtocolByTradeId.put(tradeModel.getId(), tradeProtocol); + if (pending != null) { + pending.reset(); + } + // For BsqTrades we only store the trade at completion return tradeProtocol; diff --git a/core/src/main/java/bisq/core/trade/protocol/TradeProtocol.java b/core/src/main/java/bisq/core/trade/protocol/TradeProtocol.java index 549439e61b7..933ba70ceba 100644 --- a/core/src/main/java/bisq/core/trade/protocol/TradeProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/TradeProtocol.java @@ -96,6 +96,12 @@ public void onWithdrawCompleted() { cleanup(); } + // Resets a potentially pending protocol + public void reset() { + tradeModel.setErrorMessage("Outdated pending protocol got reset."); + protocolModel.getP2PService().removeDecryptedDirectMessageListener(this); + } + protected void onMailboxMessage(TradeMessage message, NodeAddress peerNodeAddress) { log.info("Received {} as MailboxMessage from {} with tradeId {} and uid {}", message.getClass().getSimpleName(), peerNodeAddress, message.getTradeId(), message.getUid()); diff --git a/core/src/main/java/bisq/core/trade/protocol/bisq_v1/SellerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/bisq_v1/SellerProtocol.java index a3e4fd90d6f..46a4a74fd15 100644 --- a/core/src/main/java/bisq/core/trade/protocol/bisq_v1/SellerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/bisq_v1/SellerProtocol.java @@ -167,11 +167,11 @@ public void onPaymentReceived(ResultHandler resultHandler, ErrorMessageHandler e @Override protected void onTradeMessage(TradeMessage message, NodeAddress peer) { - super.onTradeMessage(message, peer); - log.info("Received {} from {} with tradeId {} and uid {}", message.getClass().getSimpleName(), peer, message.getTradeId(), message.getUid()); + super.onTradeMessage(message, peer); + if (message instanceof DelayedPayoutTxSignatureResponse) { handle((DelayedPayoutTxSignatureResponse) message, peer); } else if (message instanceof ShareBuyerPaymentAccountMessage) {