improve error handling when clones taken at the same time

This commit is contained in:
woodser 2025-04-19 22:28:32 -04:00 committed by GitHub
parent c7a3a9740f
commit cf9a37f295
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 46 additions and 24 deletions

View File

@ -145,6 +145,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
private static final long DELETE_AFTER_MS = TradeProtocol.TRADE_STEP_TIMEOUT_SECONDS;
private static final int NUM_CONFIRMATIONS_FOR_SCHEDULED_IMPORT = 5;
protected final Object pollLock = new Object();
private final Object removeTradeOnErrorLock = new Object();
protected static final Object importMultisigLock = new Object();
private boolean pollInProgress;
private boolean restartInProgress;
@ -1608,11 +1609,12 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
}
// shut down trade threads
isInitialized = false;
isShutDown = true;
List<Runnable> shutDownThreads = new ArrayList<>();
shutDownThreads.add(() -> ThreadUtils.shutDown(getId()));
ThreadUtils.awaitTasks(shutDownThreads);
stopProtocolTimeout();
isInitialized = false;
// save and close
if (wallet != null) {
@ -1765,24 +1767,30 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
}
private void removeTradeOnError() {
log.warn("removeTradeOnError() trade={}, tradeId={}, state={}", getClass().getSimpleName(), getShortId(), getState());
synchronized (removeTradeOnErrorLock) {
// force close and re-open wallet in case stuck
forceCloseWallet();
if (isDepositRequested()) getWallet();
// skip if already shut down or removed
if (isShutDown || !processModel.getTradeManager().hasTrade(getId())) return;
log.warn("removeTradeOnError() trade={}, tradeId={}, state={}", getClass().getSimpleName(), getShortId(), getState());
// shut down trade thread
try {
ThreadUtils.shutDown(getId(), 1000l);
} catch (Exception e) {
log.warn("Error shutting down trade thread for {} {}: {}", getClass().getSimpleName(), getId(), e.getMessage());
// force close and re-open wallet in case stuck
forceCloseWallet();
if (isDepositRequested()) getWallet();
// clear and shut down trade
onShutDownStarted();
clearAndShutDown();
// shut down trade thread
try {
ThreadUtils.shutDown(getId(), 5000l);
} catch (Exception e) {
log.warn("Error shutting down trade thread for {} {}: {}", getClass().getSimpleName(), getId(), e.getMessage());
}
// unregister trade
processModel.getTradeManager().unregisterTrade(this);
}
// clear and shut down trade
clearAndShutDown();
// unregister trade
processModel.getTradeManager().unregisterTrade(this);
}
///////////////////////////////////////////////////////////////////////////////////////////
@ -1824,6 +1832,13 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
getProtocol().startTimeout(TradeProtocol.TRADE_STEP_TIMEOUT_SECONDS);
}
public void stopProtocolTimeout() {
if (!isInitialized) return;
TradeProtocol protocol = getProtocol();
if (protocol == null) return;
protocol.stopTimeout();
}
public void setState(State state) {
if (isInitialized) {
// We don't want to log at startup the setState calls from all persisted trades

View File

@ -563,9 +563,14 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
Optional<OpenOffer> openOfferOptional = openOfferManager.getOpenOffer(request.getOfferId());
if (!openOfferOptional.isPresent()) return;
OpenOffer openOffer = openOfferOptional.get();
if (openOffer.getState() != OpenOffer.State.AVAILABLE) return;
Offer offer = openOffer.getOffer();
// check availability
if (openOffer.getState() != OpenOffer.State.AVAILABLE) {
log.warn("Ignoring InitTradeRequest to maker because offer is not available, offerId={}, sender={}", request.getOfferId(), sender);
return;
}
// validate challenge
if (openOffer.getChallenge() != null && !HavenoUtils.getChallengeHash(openOffer.getChallenge()).equals(HavenoUtils.getChallengeHash(request.getChallenge()))) {
log.warn("Ignoring InitTradeRequest to maker because challenge is incorrect, tradeId={}, sender={}", request.getOfferId(), sender);
@ -980,9 +985,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
closedTradableManager.add(trade);
trade.setCompleted(true);
removeTrade(trade, true);
// TODO The address entry should have been removed already. Check and if its the case remove that.
xmrWalletService.swapPayoutAddressEntryToAvailable(trade.getId());
xmrWalletService.swapPayoutAddressEntryToAvailable(trade.getId()); // TODO The address entry should have been removed already. Check and if its the case remove that.
requestPersistence();
}
@ -990,6 +993,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
log.warn("Unregistering {} {}", trade.getClass().getSimpleName(), trade.getId());
removeTrade(trade, true);
removeFailedTrade(trade);
xmrWalletService.swapPayoutAddressEntryToAvailable(trade.getId()); // TODO The address entry should have been removed already. Check and if its the case remove that.
requestPersistence();
}
@ -1274,11 +1278,15 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
return offer.getDirection() == OfferDirection.SELL;
}
// TODO (woodser): make Optional<Trade> versus Trade return types consistent
// TODO: make Optional<Trade> versus Trade return types consistent
public Trade getTrade(String tradeId) {
return getOpenTrade(tradeId).orElseGet(() -> getClosedTrade(tradeId).orElseGet(() -> getFailedTrade(tradeId).orElseGet(() -> null)));
}
public boolean hasTrade(String tradeId) {
return getTrade(tradeId) != null;
}
public Optional<Trade> getOpenTrade(String tradeId) {
synchronized (tradableList.getList()) {
return tradableList.stream().filter(e -> e.getId().equals(tradeId)).findFirst();

View File

@ -842,7 +842,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
}
}
protected synchronized void stopTimeout() {
public synchronized void stopTimeout() {
synchronized (timeoutTimerLock) {
if (timeoutTimer != null) {
timeoutTimer.stop();

View File

@ -346,8 +346,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
List<XmrAddressEntry> addressEntries = xmrWalletService.getAddressEntries();
List<DepositListItem> items = new ArrayList<>();
for (XmrAddressEntry addressEntry : addressEntries) {
DepositListItem item = new DepositListItem(addressEntry, xmrWalletService, formatter);
if (addressEntry.isTradePayout() && BigInteger.ZERO.equals(item.getBalanceAsBI())) continue; // do not show empty trade payout addresses
if (addressEntry.isTradePayout()) continue; // do not show trade payout addresses
items.add(new DepositListItem(addressEntry, xmrWalletService, formatter));
}