From 3e2206cf5eb75cb5f3700b328d0a288a52ee4130 Mon Sep 17 00:00:00 2001 From: woodser Date: Fri, 24 May 2024 10:15:05 -0400 Subject: [PATCH] add logging and popup when trade wallet returns null txs --- .../main/java/haveno/core/trade/Trade.java | 47 +++++++++++++++---- .../haveno/core/trade/protocol/TradePeer.java | 4 +- .../core/xmr/wallet/XmrWalletService.java | 2 +- 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/haveno/core/trade/Trade.java b/core/src/main/java/haveno/core/trade/Trade.java index ea3743dfb9..c9520ac036 100644 --- a/core/src/main/java/haveno/core/trade/Trade.java +++ b/core/src/main/java/haveno/core/trade/Trade.java @@ -94,6 +94,7 @@ import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import monero.common.MoneroRpcConnection; +import monero.common.MoneroUtils; import monero.common.TaskLooper; import monero.daemon.MoneroDaemon; import monero.daemon.model.MoneroKeyImage; @@ -1082,16 +1083,40 @@ public abstract class Trade implements Tradable, Model { private MoneroTxWallet doCreatePayoutTx() { // check if multisig import needed - MoneroWallet multisigWallet = getWallet(); - if (multisigWallet.isMultisigImportNeeded()) throw new RuntimeException("Cannot create payout tx because multisig import is needed"); + if (wallet.isMultisigImportNeeded()) throw new RuntimeException("Cannot create payout tx because multisig import is needed"); // gather info String sellerPayoutAddress = this.getSeller().getPayoutAddressString(); String buyerPayoutAddress = this.getBuyer().getPayoutAddressString(); Preconditions.checkNotNull(sellerPayoutAddress, "Seller payout address must not be null"); Preconditions.checkNotNull(buyerPayoutAddress, "Buyer payout address must not be null"); - BigInteger sellerDepositAmount = multisigWallet.getTx(this.getSeller().getDepositTxHash()).getIncomingAmount(); - BigInteger buyerDepositAmount = multisigWallet.getTx(this.getBuyer().getDepositTxHash()).getIncomingAmount(); + + // TODO: wallet query to get deposit txs can sometimes return null, maybe when disconnected? + if (wallet.getTx(getSeller().getDepositTxHash()) == null || wallet.getTx(getBuyer().getDepositTxHash()) == null) { + String warningMsg = "Issue detected with trade wallet " + getShortId() + ". Please send logs to Haveno developers and restart your application if you encounter further problems:"; + warningMsg += "\n\nSeller deposit tx id: " + getSeller().getDepositTxHash(); + warningMsg += "\nBuyer deposit tx id: " + getBuyer().getDepositTxHash(); + warningMsg += "\nSeller deposit tx is initialized: " + (getSeller().getDepositTx() != null); + warningMsg += "\nBuyer deposit tx is initialized: " + (getBuyer().getDepositTx() != null); + log.warn(warningMsg); + + // request with logging + int previousLogLevel = MoneroUtils.getLogLevel(); + MoneroUtils.setLogLevel(3); + log.warn("Requesting seller tx with logging"); + MoneroTxWallet fetchedTx = wallet.getTx(getSeller().getDepositTxHash()); + log.info("Seller tx: " + fetchedTx); + log.warn("Requesting buyer tx with logging"); + fetchedTx = wallet.getTx(getBuyer().getDepositTxHash()); + log.info("Buyer tx: " + fetchedTx); + MoneroUtils.setLogLevel(previousLogLevel); + + // set top level error message to notify user + HavenoUtils.havenoSetup.getTopErrorMsg().set(warningMsg); + } + + BigInteger sellerDepositAmount = getSeller().getDepositTx().getIncomingAmount(); + BigInteger buyerDepositAmount = getBuyer().getDepositTx().getIncomingAmount(); BigInteger tradeAmount = getAmount(); BigInteger buyerPayoutAmount = buyerDepositAmount.add(tradeAmount); BigInteger sellerPayoutAmount = sellerDepositAmount.subtract(tradeAmount); @@ -1112,7 +1137,7 @@ public abstract class Trade implements Tradable, Model { getBuyer().setPayoutAmount(HavenoUtils.getDestination(buyerPayoutAddress, payoutTx).getAmount()); getSeller().setPayoutTxFee(payoutTxFeeSplit); getSeller().setPayoutAmount(HavenoUtils.getDestination(sellerPayoutAddress, payoutTx).getAmount()); - getSelf().setUpdatedMultisigHex(multisigWallet.exportMultisigHex()); + getSelf().setUpdatedMultisigHex(wallet.exportMultisigHex()); return payoutTx; } @@ -1147,8 +1172,8 @@ public abstract class Trade implements Tradable, Model { // gather relevant info MoneroWallet wallet = getWallet(); Contract contract = getContract(); - BigInteger sellerDepositAmount = wallet.getTx(getSeller().getDepositTxHash()).getIncomingAmount(); // TODO (woodser): redundancy of processModel.getPreparedDepositTxId() vs this.getDepositTxId() necessary or avoidable? - BigInteger buyerDepositAmount = wallet.getTx(getBuyer().getDepositTxHash()).getIncomingAmount(); + BigInteger sellerDepositAmount = getSeller().getDepositTx().getIncomingAmount(); + BigInteger buyerDepositAmount = getBuyer().getDepositTx().getIncomingAmount(); BigInteger tradeAmount = getAmount(); // describe payout tx @@ -2283,6 +2308,10 @@ public abstract class Trade implements Tradable, Model { private void pollWallet() { if (pollInProgress) return; + doPollWallet(); + } + + private void doPollWallet() { synchronized (pollLock) { pollInProgress = true; try { @@ -2424,8 +2453,8 @@ public abstract class Trade implements Tradable, Model { return walletHeight.get() < xmrConnectionService.getTargetHeight(); } - private void setDepositTxs(List txs) { - for (MoneroTx tx : txs) { + private void setDepositTxs(List txs) { + for (MoneroTxWallet tx : txs) { if (tx.getHash().equals(getMaker().getDepositTxHash())) getMaker().setDepositTx(tx); if (tx.getHash().equals(getTaker().getDepositTxHash())) getTaker().setDepositTx(tx); } diff --git a/core/src/main/java/haveno/core/trade/protocol/TradePeer.java b/core/src/main/java/haveno/core/trade/protocol/TradePeer.java index 4dc4d84882..b076826b95 100644 --- a/core/src/main/java/haveno/core/trade/protocol/TradePeer.java +++ b/core/src/main/java/haveno/core/trade/protocol/TradePeer.java @@ -33,7 +33,7 @@ import haveno.network.p2p.NodeAddress; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import monero.daemon.model.MoneroTx; +import monero.wallet.model.MoneroTxWallet; import javax.annotation.Nullable; import java.math.BigInteger; @@ -56,7 +56,7 @@ public final class TradePeer implements PersistablePayload { @Setter @Nullable transient private byte[] preparedDepositTx; - transient private MoneroTx depositTx; + transient private MoneroTxWallet depositTx; // Persistable mutable @Nullable 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 d10b270ef3..63c48bd0c3 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java +++ b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java @@ -118,6 +118,7 @@ public class XmrWalletService { public static final String MONERO_WALLET_RPC_PATH = MONERO_BINS_DIR + File.separator + MONERO_WALLET_RPC_NAME; public static final double MINER_FEE_TOLERANCE = 0.25; // miner fee must be within percent of estimated fee public static final MoneroTxPriority PROTOCOL_FEE_PRIORITY = MoneroTxPriority.ELEVATED; + public static final int MONERO_LOG_LEVEL = -1; // monero library log level, -1 to disable private static final MoneroNetworkType MONERO_NETWORK_TYPE = getMoneroNetworkType(); private static final MoneroWalletRpcManager MONERO_WALLET_RPC_MANAGER = new MoneroWalletRpcManager(); private static final String MONERO_WALLET_RPC_USERNAME = "haveno_user"; @@ -126,7 +127,6 @@ public class XmrWalletService { private static final String KEYS_FILE_POSTFIX = ".keys"; private static final String ADDRESS_FILE_POSTFIX = ".address.txt"; private static final int NUM_MAX_WALLET_BACKUPS = 1; - private static final int MONERO_LOG_LEVEL = -1; // monero library log level, -1 to disable private static final int MAX_SYNC_ATTEMPTS = 3; private static final boolean PRINT_RPC_STACK_TRACE = false; private static final String THREAD_ID = XmrWalletService.class.getSimpleName();