do not revert trade funds on init timeout until error processing

This commit is contained in:
woodser 2025-09-15 02:31:37 -04:00 committed by woodser
parent deb92b71b2
commit 812dcf27e8
3 changed files with 27 additions and 15 deletions

View file

@ -1812,19 +1812,6 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
return;
}
// unreserve taker's key images
if (this instanceof TakerTrade) {
ThreadUtils.submitToPool(() -> {
xmrWalletService.thawOutputs(getSelf().getReserveTxKeyImages());
});
}
// unreserve maker's open offer
Optional<OpenOffer> openOffer = processModel.getOpenOfferManager().getOpenOffer(this.getId());
if (this instanceof MakerTrade && openOffer.isPresent()) {
processModel.getOpenOfferManager().unreserveOpenOffer(openOffer.get());
}
// remove if deposit not requested or is failed
if (!isDepositRequested() || isDepositRequestFailed()) {
removeTradeOnError();
@ -1832,7 +1819,10 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
}
// done if wallet already deleted
if (!walletExists()) return;
if (!walletExists()) {
removeTradeOnError();
return;
}
// set error height
if (processModel.getTradeProtocolErrorHeight() == 0) {
@ -1927,6 +1917,19 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
forceCloseWallet();
if (isDepositRequested()) getWallet();
// unreserve taker's key images
if (this instanceof TakerTrade) {
ThreadUtils.submitToPool(() -> {
xmrWalletService.thawOutputs(getSelf().getReserveTxKeyImages());
});
}
// unreserve maker's open offer
Optional<OpenOffer> openOffer = processModel.getOpenOfferManager().getOpenOffer(this.getId());
if (this instanceof MakerTrade && openOffer.isPresent()) {
processModel.getOpenOfferManager().unreserveOpenOffer(openOffer.get());
}
// clear and shut down trade
onShutDownStarted();
clearAndShutDown();

View file

@ -445,7 +445,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
Set<Trade> uninitializedTrades = new HashSet<Trade>();
for (Trade trade : trades) {
Runnable initTradeTask = getInitTradeTask(trade, trades, tradesToSkip, uninitializedTrades, uids);
if (trade.isDepositsPublished() && !trade.isPayoutUnlocked()) initTasksP1.add(initTradeTask);
if (trade.isDepositRequested() && !trade.isPayoutUnlocked()) initTasksP1.add(initTradeTask);
else initTasksP2.add(initTradeTask);
};
ThreadUtils.awaitTasks(initTasksP1, threadPoolSize);
@ -920,6 +920,10 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
// ensure trade is not already open
Optional<Trade> tradeOptional = getOpenTrade(offer.getId());
if (tradeOptional.isPresent()) throw new RuntimeException("Cannot create trade protocol because trade with ID " + offer.getId() + " is already open");
// ensure failed trade is not processing
tradeOptional = getFailedTrade(offer.getId());
if (tradeOptional.isPresent() && tradeOptional.get().walletExists()) throw new RuntimeException("Cannot create trade protocol because trade with ID " + offer.getId() + " has failed but is not processed");
// create trade
Trade trade;

View file

@ -536,6 +536,11 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
return;
}
// log warning if trade not open
if (!processModel.getTradeManager().hasOpenTrade(trade)) {
log.warn("We received a PaymentSentMessage for {} {} but it is not an open trade. This can happen if the trade is pending processing as a failed trade.", trade.getClass().getSimpleName(), trade.getId());
}
// validate signature
try {
HavenoUtils.verifyPaymentSentMessage(trade, message);