Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reset pending trade protocol of same offer #6487

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 26 additions & 5 deletions core/src/main/java/bisq/core/trade/TradeManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,18 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
private final Provider provider;
private final ClockWatcher clockWatcher;

private final Map<String, TradeProtocol> tradeProtocolByTradeId = new HashMap<>();
// We use uid for that map not the trade ID
private final Map<String, TradeProtocol> 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<String, TradeProtocol> pendingTradeProtocolByTradeId = new HashMap<>();

private final PersistenceManager<TradableList<Trade>> persistenceManager;
private final TradableList<Trade> tradableList = new TradableList<>();
@Getter
Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -618,14 +634,19 @@ 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());
}
if (tradeModel instanceof Trade) {
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down