From b196b6184166fc7a6ec90fca2dbe4edb730d64f4 Mon Sep 17 00:00:00 2001 From: woodser <13068859+woodser@users.noreply.github.com> Date: Fri, 11 Apr 2025 17:51:05 -0400 Subject: [PATCH] fix startup when missing multisig wallets --- .../main/java/haveno/core/trade/Trade.java | 11 +++---- .../java/haveno/core/trade/TradeManager.java | 24 +++++++-------- .../core/xmr/wallet/XmrWalletService.java | 30 ++++++++++--------- .../haveno/desktop/main/MainViewModel.java | 1 + .../pendingtrades/steps/TradeStepView.java | 1 + 5 files changed, 36 insertions(+), 31 deletions(-) diff --git a/core/src/main/java/haveno/core/trade/Trade.java b/core/src/main/java/haveno/core/trade/Trade.java index b1c893abaa..5a6f502d0c 100644 --- a/core/src/main/java/haveno/core/trade/Trade.java +++ b/core/src/main/java/haveno/core/trade/Trade.java @@ -753,11 +753,9 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { importMultisigHexIfScheduled(); }); - // trade is initialized - isInitialized = true; - // done if deposit not requested or payout unlocked if (!isDepositRequested() || isPayoutUnlocked()) { + isInitialized = true; isFullyInitialized = true; return; } @@ -769,14 +767,17 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { if (payoutTx != null && payoutTx.getNumConfirmations() >= XmrWalletService.NUM_BLOCKS_UNLOCK) { log.warn("Payout state for {} {} is {} but payout is unlocked, updating state", getClass().getSimpleName(), getId(), getPayoutState()); setPayoutStateUnlocked(); + isInitialized = true; isFullyInitialized = true; return; } else { - log.warn("Missing trade wallet for {} {}, state={}, marked completed={}", getClass().getSimpleName(), getShortId(), getState(), isCompleted()); - return; + throw new RuntimeException("Missing trade wallet for " + getClass().getSimpleName() + " " + getShortId() + ", state=" + getState() + ", marked completed=" + isCompleted()); } } + // trade is initialized + isInitialized = true; + // init syncing if deposit requested if (isDepositRequested()) { tryInitSyncing(); diff --git a/core/src/main/java/haveno/core/trade/TradeManager.java b/core/src/main/java/haveno/core/trade/TradeManager.java index 420dbb9119..ea01a7c927 100644 --- a/core/src/main/java/haveno/core/trade/TradeManager.java +++ b/core/src/main/java/haveno/core/trade/TradeManager.java @@ -470,6 +470,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi if (!isShutDownStarted) { log.warn("Error initializing {} {}: {}\n", trade.getClass().getSimpleName(), trade.getId(), e.getMessage(), e); trade.setInitError(e); + trade.prependErrorMessage(e.getMessage()); } } }); @@ -1041,18 +1042,17 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi if (isShutDownStarted) return; synchronized (tradableList.getList()) { for (Trade trade : tradableList.getList()) { - if (!trade.isPayoutPublished()) { - Date maxTradePeriodDate = trade.getMaxTradePeriodDate(); - Date halfTradePeriodDate = trade.getHalfTradePeriodDate(); - if (maxTradePeriodDate != null && halfTradePeriodDate != null) { - Date now = new Date(); - if (now.after(maxTradePeriodDate)) { - trade.setPeriodState(Trade.TradePeriodState.TRADE_PERIOD_OVER); - requestPersistence(); - } else if (now.after(halfTradePeriodDate)) { - trade.setPeriodState(Trade.TradePeriodState.SECOND_HALF); - requestPersistence(); - } + if (!trade.isInitialized() || trade.isPayoutPublished()) continue; + Date maxTradePeriodDate = trade.getMaxTradePeriodDate(); + Date halfTradePeriodDate = trade.getHalfTradePeriodDate(); + if (maxTradePeriodDate != null && halfTradePeriodDate != null) { + Date now = new Date(); + if (now.after(maxTradePeriodDate)) { + trade.setPeriodState(Trade.TradePeriodState.TRADE_PERIOD_OVER); + requestPersistence(); + } else if (now.after(halfTradePeriodDate)) { + trade.setPeriodState(Trade.TradePeriodState.SECOND_HALF); + requestPersistence(); } } } diff --git a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java index e62a78ae3b..499d20c0a7 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java +++ b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java @@ -689,22 +689,24 @@ public class XmrWalletService extends XmrWalletBase { } private MoneroTxWallet createTradeTxFromSubaddress(BigInteger feeAmount, String feeAddress, BigInteger sendAmount, String sendAddress, Integer subaddressIndex) { + synchronized (walletLock) { - // create tx - MoneroTxConfig txConfig = new MoneroTxConfig() - .setAccountIndex(0) - .setSubaddressIndices(subaddressIndex) - .addDestination(sendAddress, sendAmount) - .setSubtractFeeFrom(0) // pay mining fee from send amount - .setPriority(XmrWalletService.PROTOCOL_FEE_PRIORITY); - if (!BigInteger.valueOf(0).equals(feeAmount)) txConfig.addDestination(feeAddress, feeAmount); - MoneroTxWallet tradeTx = createTx(txConfig); + // create tx + MoneroTxConfig txConfig = new MoneroTxConfig() + .setAccountIndex(0) + .setSubaddressIndices(subaddressIndex) + .addDestination(sendAddress, sendAmount) + .setSubtractFeeFrom(0) // pay mining fee from send amount + .setPriority(XmrWalletService.PROTOCOL_FEE_PRIORITY); + if (!BigInteger.valueOf(0).equals(feeAmount)) txConfig.addDestination(feeAddress, feeAmount); + MoneroTxWallet tradeTx = createTx(txConfig); - // freeze inputs - List keyImages = new ArrayList(); - for (MoneroOutput input : tradeTx.getInputs()) keyImages.add(input.getKeyImage().getHex()); - freezeOutputs(keyImages); - return tradeTx; + // freeze inputs + List keyImages = new ArrayList(); + for (MoneroOutput input : tradeTx.getInputs()) keyImages.add(input.getKeyImage().getHex()); + freezeOutputs(keyImages); + return tradeTx; + } } public MoneroTx verifyReserveTx(String offerId, BigInteger penaltyFee, BigInteger tradeFee, BigInteger sendTradeAmount, BigInteger securityDeposit, String returnAddress, String txHash, String txHex, String txKey, List keyImages) { diff --git a/desktop/src/main/java/haveno/desktop/main/MainViewModel.java b/desktop/src/main/java/haveno/desktop/main/MainViewModel.java index 4ee10d7846..16cef449d6 100644 --- a/desktop/src/main/java/haveno/desktop/main/MainViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/MainViewModel.java @@ -228,6 +228,7 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener new Popup().warning("Error initializing trade" + " " + trade.getShortId() + "\n\n" + trade.getInitError().getMessage()) .show(); + return; } // check trade period diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/TradeStepView.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/TradeStepView.java index 263e4d0ef0..3af019e6d0 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/TradeStepView.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/TradeStepView.java @@ -405,6 +405,7 @@ public abstract class TradeStepView extends AnchorPane { } private void updateTimeLeft() { + if (!trade.isInitialized()) return; if (timeLeftTextField != null) { // TODO (woodser): extra TradeStepView created but not deactivated on trade.setState(), so deactivate when model's trade is null