From 0a43b2b2bc125bdd64a57fa1a24b1bd3be03d760 Mon Sep 17 00:00:00 2001 From: woodser Date: Thu, 18 Sep 2025 09:07:52 -0400 Subject: [PATCH] recover from import multisig needed error (#1965) --- .../java/haveno/core/trade/HavenoUtils.java | 4 +++ .../main/java/haveno/core/trade/Trade.java | 32 +++++++++++-------- .../tasks/BuyerPreparePaymentSentMessage.java | 21 +++++++----- 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/core/src/main/java/haveno/core/trade/HavenoUtils.java b/core/src/main/java/haveno/core/trade/HavenoUtils.java index ba73712598..984dd11a92 100644 --- a/core/src/main/java/haveno/core/trade/HavenoUtils.java +++ b/core/src/main/java/haveno/core/trade/HavenoUtils.java @@ -642,6 +642,10 @@ public class HavenoUtils { return e != null && e.getMessage().contains("was rejected"); } + public static boolean isLRNotFound(Throwable e) { + return e != null && e.getMessage().contains("LR not found for enough participants"); + } + public static boolean isIllegal(Throwable e) { return e instanceof IllegalArgumentException || e instanceof IllegalStateException; } diff --git a/core/src/main/java/haveno/core/trade/Trade.java b/core/src/main/java/haveno/core/trade/Trade.java index dac04924d1..63e35f7a6f 100644 --- a/core/src/main/java/haveno/core/trade/Trade.java +++ b/core/src/main/java/haveno/core/trade/Trade.java @@ -1247,22 +1247,20 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { String errorMessage = "Multisig import still needed for " + getClass().getSimpleName() + " " + getShortId() + " after already importing, multisigHexes=" + multisigHexes; log.warn(errorMessage); - // ignore multisig hex which is significantly shorter than others + // remove shortest multisig hex if applicable int maxLength = 0; - boolean removed = false; - for (String hex : multisigHexes) maxLength = Math.max(maxLength, hex.length()); - for (String hex : new ArrayList<>(multisigHexes)) { - if (hex.length() < maxLength / 2) { - String ignoringMessage = "Ignoring multisig hex from " + getMultisigHexRole(hex) + " for " + getClass().getSimpleName() + " " + getShortId() + " because it is too short, multisigHex=" + hex; - setErrorMessage(ignoringMessage); - log.warn(ignoringMessage); - multisigHexes.remove(hex); - removed = true; - } + String shortestMultisigHex = null; + for (String hex : multisigHexes) { + if (shortestMultisigHex == null || hex.length() < shortestMultisigHex.length()) shortestMultisigHex = hex; + if (hex.length() > maxLength) maxLength = hex.length(); + } + if (shortestMultisigHex.length() < maxLength) { + log.warn("Removing multisig hex from " + getMultisigHexRole(shortestMultisigHex) + " for " + getClass().getSimpleName() + " " + getShortId() + " because it's the shortest, multisigHex=" + shortestMultisigHex); + multisigHexes.remove(shortestMultisigHex); + wallet.importMultisigHex(multisigHexes.toArray(new String[0])); } - // re-import valid multisig hexes - if (removed) wallet.importMultisigHex(multisigHexes.toArray(new String[0])); + // throw if multisig import still needed if (wallet.isMultisigImportNeeded()) throw new IllegalStateException(errorMessage); } @@ -1372,13 +1370,19 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { BigInteger sellerPayoutAmount = sellerDepositAmount.subtract(tradeAmount); // create payout tx - MoneroTxWallet payoutTx = createTx(new MoneroTxConfig() + MoneroTxWallet payoutTx; + try { + payoutTx = createTx(new MoneroTxConfig() .setAccountIndex(0) .addDestination(buyerPayoutAddress, buyerPayoutAmount) .addDestination(sellerPayoutAddress, sellerPayoutAmount) .setSubtractFeeFrom(0, 1) // split tx fee .setRelay(false) .setPriority(XmrWalletService.PROTOCOL_FEE_PRIORITY)); + } catch (Exception e) { + if (HavenoUtils.isLRNotFound(e)) throw new IllegalStateException(e); + else throw e; + } // update state BigInteger payoutTxFeeSplit = payoutTx.getFee().divide(BigInteger.valueOf(2)); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerPreparePaymentSentMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerPreparePaymentSentMessage.java index b4562874e3..ad40f761e9 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerPreparePaymentSentMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerPreparePaymentSentMessage.java @@ -83,16 +83,21 @@ public class BuyerPreparePaymentSentMessage extends TradeTask { // synchronize on lock for wallet operations synchronized (trade.getWalletLock()) { synchronized (HavenoUtils.getWalletFunctionLock()) { + try { - // import multisig hex - trade.importMultisigHex(); + // import multisig hex + trade.importMultisigHex(); - // create payout tx - log.info("Buyer creating unsigned payout tx for {} {} ", trade.getClass().getSimpleName(), trade.getShortId()); - MoneroTxWallet payoutTx = trade.createPayoutTx(); - trade.setPayoutTx(payoutTx); - trade.getSelf().setUnsignedPayoutTxHex(payoutTx.getTxSet().getMultisigTxHex()); - trade.requestPersistence(); + // create payout tx + log.info("Buyer creating unsigned payout tx for {} {} ", trade.getClass().getSimpleName(), trade.getShortId()); + MoneroTxWallet payoutTx = trade.createPayoutTx(); + trade.setPayoutTx(payoutTx); + trade.getSelf().setUnsignedPayoutTxHex(payoutTx.getTxSet().getMultisigTxHex()); + trade.requestPersistence(); + } catch (Exception e) { + if (HavenoUtils.isIllegal(e)) log.warn("Failed to create unsigned payout tx for " + trade.getClass().getSimpleName() + " " + trade.getShortId(), e); // continue to send message if illegal state + else throw e; + } } } }