From ca7d596175518a033dcf1e43a4678f5ed20dabb7 Mon Sep 17 00:00:00 2001 From: woodser Date: Sun, 4 Aug 2024 13:26:59 -0400 Subject: [PATCH] refactor base wallet so trades can sync with progress timeout, etc --- .../haveno/core/api/CoreDisputesService.java | 4 +- .../haveno/core/offer/OpenOfferManager.java | 2 +- .../tasks/MakerReserveOfferFunds.java | 7 +- .../core/support/dispute/DisputeManager.java | 2 +- .../arbitration/ArbitrationManager.java | 6 +- .../java/haveno/core/trade/HavenoUtils.java | 2 + .../main/java/haveno/core/trade/Trade.java | 31 +-- .../trade/protocol/ArbitratorProtocol.java | 4 +- .../trade/protocol/BuyerAsMakerProtocol.java | 2 +- .../trade/protocol/BuyerAsTakerProtocol.java | 4 +- .../core/trade/protocol/BuyerProtocol.java | 4 +- .../trade/protocol/SellerAsMakerProtocol.java | 2 +- .../trade/protocol/SellerAsTakerProtocol.java | 4 +- .../core/trade/protocol/SellerProtocol.java | 4 +- .../core/trade/protocol/TradeProtocol.java | 22 +- .../tasks/MaybeSendSignContractRequest.java | 3 +- .../tasks/TakerReserveTradeFunds.java | 3 +- .../main/java/haveno/core/xmr/Balances.java | 3 +- .../haveno/core/xmr/wallet/XmrWalletBase.java | 165 +++++++++++++++ .../core/xmr/wallet/XmrWalletService.java | 191 +++--------------- .../desktop/components/TxIdTextField.java | 2 +- .../main/funds/withdrawal/WithdrawalView.java | 4 +- .../java/haveno/desktop/util/GUIUtil.java | 2 +- 23 files changed, 247 insertions(+), 226 deletions(-) create mode 100644 core/src/main/java/haveno/core/xmr/wallet/XmrWalletBase.java diff --git a/core/src/main/java/haveno/core/api/CoreDisputesService.java b/core/src/main/java/haveno/core/api/CoreDisputesService.java index d786069a..6f17d88f 100644 --- a/core/src/main/java/haveno/core/api/CoreDisputesService.java +++ b/core/src/main/java/haveno/core/api/CoreDisputesService.java @@ -118,7 +118,7 @@ public class CoreDisputesService { } public Dispute createDisputeForTrade(Trade trade, Offer offer, PubKeyRing pubKey, boolean isMaker, boolean isSupportTicket) { - synchronized (trade) { + synchronized (trade.getLock()) { byte[] payoutTxSerialized = null; String payoutTxHashAsString = null; @@ -163,7 +163,7 @@ public class CoreDisputesService { if (winningDisputeOptional.isPresent()) winningDispute = winningDisputeOptional.get(); else throw new IllegalStateException(format("dispute for tradeId '%s' not found", tradeId)); - synchronized (trade) { + synchronized (trade.getLock()) { try { // create dispute result diff --git a/core/src/main/java/haveno/core/offer/OpenOfferManager.java b/core/src/main/java/haveno/core/offer/OpenOfferManager.java index 537c5fe0..aa561f12 100644 --- a/core/src/main/java/haveno/core/offer/OpenOfferManager.java +++ b/core/src/main/java/haveno/core/offer/OpenOfferManager.java @@ -1085,7 +1085,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe BigInteger reserveAmount = openOffer.getOffer().getAmountNeeded(); xmrWalletService.swapAddressEntryToAvailable(openOffer.getId(), XmrAddressEntry.Context.OFFER_FUNDING); // change funding subaddress in case funded with unsuitable output(s) MoneroTxWallet splitOutputTx = null; - synchronized (XmrWalletService.WALLET_LOCK) { + synchronized (HavenoUtils.xmrWalletService.getWalletLock()) { XmrAddressEntry entry = xmrWalletService.getOrCreateAddressEntry(openOffer.getId(), XmrAddressEntry.Context.OFFER_FUNDING); synchronized (HavenoUtils.getWalletFunctionLock()) { long startTime = System.currentTimeMillis(); diff --git a/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerReserveOfferFunds.java b/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerReserveOfferFunds.java index 305ff6e2..7bfbda31 100644 --- a/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerReserveOfferFunds.java +++ b/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerReserveOfferFunds.java @@ -30,7 +30,6 @@ import haveno.core.offer.placeoffer.PlaceOfferModel; import haveno.core.trade.HavenoUtils; import haveno.core.trade.protocol.TradeProtocol; import haveno.core.xmr.model.XmrAddressEntry; -import haveno.core.xmr.wallet.XmrWalletService; import lombok.extern.slf4j.Slf4j; import monero.common.MoneroRpcConnection; import monero.daemon.model.MoneroOutput; @@ -60,11 +59,11 @@ public class MakerReserveOfferFunds extends Task { } // verify monero connection - model.getXmrWalletService().getConnectionService().verifyConnection(); + model.getXmrWalletService().getXmrConnectionService().verifyConnection(); // create reserve tx MoneroTxWallet reserveTx = null; - synchronized (XmrWalletService.WALLET_LOCK) { + synchronized (HavenoUtils.xmrWalletService.getWalletLock()) { // reset protocol timeout verifyPending(); @@ -83,7 +82,7 @@ public class MakerReserveOfferFunds extends Task { try { synchronized (HavenoUtils.getWalletFunctionLock()) { for (int i = 0; i < TradeProtocol.MAX_ATTEMPTS; i++) { - MoneroRpcConnection sourceConnection = model.getXmrWalletService().getConnectionService().getConnection(); + MoneroRpcConnection sourceConnection = model.getXmrWalletService().getXmrConnectionService().getConnection(); try { //if (true) throw new RuntimeException("Pretend error"); reserveTx = model.getXmrWalletService().createReserveTx(penaltyFee, makerFee, sendAmount, securityDeposit, returnAddress, openOffer.isReserveExactAmount(), preferredSubaddressIndex); diff --git a/core/src/main/java/haveno/core/support/dispute/DisputeManager.java b/core/src/main/java/haveno/core/support/dispute/DisputeManager.java index c4561a7f..05bcfaf1 100644 --- a/core/src/main/java/haveno/core/support/dispute/DisputeManager.java +++ b/core/src/main/java/haveno/core/support/dispute/DisputeManager.java @@ -499,7 +499,7 @@ public abstract class DisputeManager> extends Sup // process on trade thread ThreadUtils.execute(() -> { - synchronized (trade) { + synchronized (trade.getLock()) { String errorMessage = null; PubKeyRing senderPubKeyRing = null; try { diff --git a/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationManager.java b/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationManager.java index 7bc74d72..9209ef77 100644 --- a/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationManager.java +++ b/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationManager.java @@ -240,7 +240,7 @@ public final class ArbitrationManager extends DisputeManager { ChatMessage chatMessage = null; Dispute dispute = null; - synchronized (trade) { + synchronized (trade.getLock()) { try { DisputeResult disputeResult = disputeClosedMessage.getDisputeResult(); chatMessage = disputeResult.getChatMessage(); @@ -384,7 +384,7 @@ public final class ArbitrationManager extends DisputeManager { - synchronized (trade) { + synchronized (trade.getLock()) { // skip if no need to reprocess if (trade.isArbitrator() || trade.getArbitrator().getDisputeClosedMessage() == null || trade.getArbitrator().getDisputeClosedMessage().getUnsignedPayoutTxHex() == null || trade.getDisputeState().ordinal() >= Trade.DisputeState.DISPUTE_CLOSED.ordinal()) { @@ -478,7 +478,7 @@ public final class ArbitrationManager extends DisputeManager stateProperty = new SimpleObjectProperty<>(state); transient final private ObjectProperty phaseProperty = new SimpleObjectProperty<>(state.phase); @@ -441,10 +434,6 @@ public abstract class Trade implements Tradable, Model { @Getter transient private boolean isInitialized; transient private boolean isFullyInitialized; - @Getter - transient private boolean isShutDownStarted; - @Getter - transient private boolean isShutDown; // Added in v1.2.0 transient private ObjectProperty tradeAmountProperty; @@ -511,11 +500,12 @@ public abstract class Trade implements Tradable, Model { @Nullable NodeAddress makerNodeAddress, @Nullable NodeAddress takerNodeAddress, @Nullable NodeAddress arbitratorNodeAddress) { + super(); this.offer = offer; this.amount = tradeAmount.longValueExact(); this.price = tradePrice; this.xmrWalletService = xmrWalletService; - this.xmrConnectionService = xmrWalletService.getConnectionService(); + this.xmrConnectionService = xmrWalletService.getXmrConnectionService(); this.processModel = processModel; this.uid = uid; this.takeOfferDate = new Date().getTime(); @@ -1512,13 +1502,13 @@ public abstract class Trade implements Tradable, Model { // repeatedly acquire lock to clear tasks for (int i = 0; i < 20; i++) { - synchronized (this) { + synchronized (getLock()) { HavenoUtils.waitFor(10); } } // shut down trade threads - synchronized (this) { + synchronized (getLock()) { isInitialized = false; isShutDown = true; List shutDownThreads = new ArrayList<>(); @@ -2636,8 +2626,7 @@ public abstract class Trade implements Tradable, Model { private void syncWalletIfBehind() { if (isWalletBehind()) { synchronized (walletLock) { - xmrWalletService.syncWallet(wallet); - walletHeight.set(wallet.getHeight()); + syncWithProgress(); } } } @@ -2812,7 +2801,7 @@ public abstract class Trade implements Tradable, Model { if (!isInitialized || isShutDownStarted) return; if (isWalletConnectedToDaemon()) { e.printStackTrace(); - log.warn("Error polling idle trade for {} {}: {}. Monerod={}", getClass().getSimpleName(), getId(), e.getMessage(), getXmrWalletService().getConnectionService().getConnection()); + log.warn("Error polling idle trade for {} {}: {}. Monerod={}", getClass().getSimpleName(), getId(), e.getMessage(), getXmrWalletService().getXmrConnectionService().getConnection()); }; } }, getId()); diff --git a/core/src/main/java/haveno/core/trade/protocol/ArbitratorProtocol.java b/core/src/main/java/haveno/core/trade/protocol/ArbitratorProtocol.java index 0c116eb6..98b3f1ab 100644 --- a/core/src/main/java/haveno/core/trade/protocol/ArbitratorProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/ArbitratorProtocol.java @@ -45,7 +45,7 @@ public class ArbitratorProtocol extends DisputeProtocol { public void handleInitTradeRequest(InitTradeRequest message, NodeAddress peer, ErrorMessageHandler errorMessageHandler) { System.out.println("ArbitratorProtocol.handleInitTradeRequest()"); ThreadUtils.execute(() -> { - synchronized (trade) { + synchronized (trade.getLock()) { latchTrade(); this.errorMessageHandler = errorMessageHandler; processModel.setTradeMessage(message); // TODO (woodser): confirm these are null without being set @@ -80,7 +80,7 @@ public class ArbitratorProtocol extends DisputeProtocol { public void handleDepositRequest(DepositRequest request, NodeAddress sender) { System.out.println("ArbitratorProtocol.handleDepositRequest() " + trade.getId()); ThreadUtils.execute(() -> { - synchronized (trade) { + synchronized (trade.getLock()) { latchTrade(); Validator.checkTradeId(processModel.getOfferId(), request); processModel.setTradeMessage(request); diff --git a/core/src/main/java/haveno/core/trade/protocol/BuyerAsMakerProtocol.java b/core/src/main/java/haveno/core/trade/protocol/BuyerAsMakerProtocol.java index c88433f8..160e1bee 100644 --- a/core/src/main/java/haveno/core/trade/protocol/BuyerAsMakerProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/BuyerAsMakerProtocol.java @@ -62,7 +62,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol ErrorMessageHandler errorMessageHandler) { System.out.println(getClass().getCanonicalName() + ".handleInitTradeRequest()"); ThreadUtils.execute(() -> { - synchronized (trade) { + synchronized (trade.getLock()) { latchTrade(); this.errorMessageHandler = errorMessageHandler; expect(phase(Trade.Phase.INIT) diff --git a/core/src/main/java/haveno/core/trade/protocol/BuyerAsTakerProtocol.java b/core/src/main/java/haveno/core/trade/protocol/BuyerAsTakerProtocol.java index d20a531b..7a5a899e 100644 --- a/core/src/main/java/haveno/core/trade/protocol/BuyerAsTakerProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/BuyerAsTakerProtocol.java @@ -70,7 +70,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol ErrorMessageHandler errorMessageHandler) { System.out.println(getClass().getSimpleName() + ".onTakeOffer()"); ThreadUtils.execute(() -> { - synchronized (trade) { + synchronized (trade.getLock()) { latchTrade(); this.tradeResultHandler = tradeResultHandler; this.errorMessageHandler = errorMessageHandler; @@ -101,7 +101,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol NodeAddress peer) { System.out.println(getClass().getCanonicalName() + ".handleInitTradeRequest()"); ThreadUtils.execute(() -> { - synchronized (trade) { + synchronized (trade.getLock()) { latchTrade(); expect(phase(Trade.Phase.INIT) .with(message) diff --git a/core/src/main/java/haveno/core/trade/protocol/BuyerProtocol.java b/core/src/main/java/haveno/core/trade/protocol/BuyerProtocol.java index 55f253b5..06e1eead 100644 --- a/core/src/main/java/haveno/core/trade/protocol/BuyerProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/BuyerProtocol.java @@ -75,7 +75,7 @@ public class BuyerProtocol extends DisputeProtocol { // re-send payment sent message if not acked ThreadUtils.execute(() -> { if (trade.isShutDownStarted() || trade.isPayoutPublished()) return; - synchronized (trade) { + synchronized (trade.getLock()) { if (trade.isShutDownStarted() || trade.isPayoutPublished()) return; if (trade.getState().ordinal() >= Trade.State.BUYER_SENT_PAYMENT_SENT_MSG.ordinal() && trade.getState().ordinal() < Trade.State.SELLER_RECEIVED_PAYMENT_SENT_MSG.ordinal()) { latchTrade(); @@ -121,7 +121,7 @@ public class BuyerProtocol extends DisputeProtocol { public void onPaymentSent(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { System.out.println("BuyerProtocol.onPaymentSent()"); ThreadUtils.execute(() -> { - synchronized (trade) { + synchronized (trade.getLock()) { latchTrade(); this.errorMessageHandler = errorMessageHandler; BuyerEvent event = BuyerEvent.PAYMENT_SENT; diff --git a/core/src/main/java/haveno/core/trade/protocol/SellerAsMakerProtocol.java b/core/src/main/java/haveno/core/trade/protocol/SellerAsMakerProtocol.java index 3f30901f..15d92ff7 100644 --- a/core/src/main/java/haveno/core/trade/protocol/SellerAsMakerProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/SellerAsMakerProtocol.java @@ -67,7 +67,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc ErrorMessageHandler errorMessageHandler) { System.out.println(getClass().getCanonicalName() + ".handleInitTradeRequest()"); ThreadUtils.execute(() -> { - synchronized (trade) { + synchronized (trade.getLock()) { latchTrade(); this.errorMessageHandler = errorMessageHandler; expect(phase(Trade.Phase.INIT) diff --git a/core/src/main/java/haveno/core/trade/protocol/SellerAsTakerProtocol.java b/core/src/main/java/haveno/core/trade/protocol/SellerAsTakerProtocol.java index 75076bd3..2332ca20 100644 --- a/core/src/main/java/haveno/core/trade/protocol/SellerAsTakerProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/SellerAsTakerProtocol.java @@ -70,7 +70,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc ErrorMessageHandler errorMessageHandler) { System.out.println(getClass().getSimpleName() + ".onTakeOffer()"); ThreadUtils.execute(() -> { - synchronized (trade) { + synchronized (trade.getLock()) { latchTrade(); this.tradeResultHandler = tradeResultHandler; this.errorMessageHandler = errorMessageHandler; @@ -101,7 +101,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc NodeAddress peer) { System.out.println(getClass().getCanonicalName() + ".handleInitTradeRequest()"); ThreadUtils.execute(() -> { - synchronized (trade) { + synchronized (trade.getLock()) { latchTrade(); expect(phase(Trade.Phase.INIT) .with(message) diff --git a/core/src/main/java/haveno/core/trade/protocol/SellerProtocol.java b/core/src/main/java/haveno/core/trade/protocol/SellerProtocol.java index 10baf591..4de8fa0d 100644 --- a/core/src/main/java/haveno/core/trade/protocol/SellerProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/SellerProtocol.java @@ -70,7 +70,7 @@ public class SellerProtocol extends DisputeProtocol { // re-send payment received message if payout not published ThreadUtils.execute(() -> { if (trade.isShutDownStarted() || trade.isPayoutPublished()) return; - synchronized (trade) { + synchronized (trade.getLock()) { if (trade.isShutDownStarted() || trade.isPayoutPublished()) return; if (trade.getState().ordinal() >= Trade.State.SELLER_SENT_PAYMENT_RECEIVED_MSG.ordinal() && !trade.isPayoutPublished()) { latchTrade(); @@ -117,7 +117,7 @@ public class SellerProtocol extends DisputeProtocol { public void onPaymentReceived(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { log.info("SellerProtocol.onPaymentReceived()"); ThreadUtils.execute(() -> { - synchronized (trade) { + synchronized (trade.getLock()) { latchTrade(); this.errorMessageHandler = errorMessageHandler; SellerEvent event = SellerEvent.PAYMENT_RECEIVED; diff --git a/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java b/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java index 7b8b5e7d..684dfb7c 100644 --- a/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java @@ -243,7 +243,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D if (!trade.isCompleted()) processModel.getP2PService().addDecryptedDirectMessageListener(this); // initialize trade - synchronized (trade) { + synchronized (trade.getLock()) { trade.initialize(processModel.getProvider()); // process mailbox messages @@ -261,7 +261,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D ThreadUtils.execute(() -> { if (!trade.isDepositsConfirmed() || trade.isDepositsConfirmedAcked() || trade.isPayoutPublished() || depositsConfirmedTasksCalled) return; depositsConfirmedTasksCalled = true; - synchronized (trade) { + synchronized (trade.getLock()) { if (!trade.isInitialized() || trade.isShutDownStarted()) return; // skip if shutting down latchTrade(); expect(new Condition(trade)) @@ -282,7 +282,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D public void maybeReprocessPaymentReceivedMessage(boolean reprocessOnError) { if (trade.isShutDownStarted()) return; ThreadUtils.execute(() -> { - synchronized (trade) { + synchronized (trade.getLock()) { // skip if no need to reprocess if (trade.isSeller() || trade.getSeller().getPaymentReceivedMessage() == null || (trade.getState().ordinal() >= Trade.State.SELLER_SENT_PAYMENT_RECEIVED_MSG.ordinal() && trade.isPayoutPublished())) { @@ -299,7 +299,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D System.out.println(getClass().getSimpleName() + ".handleInitMultisigRequest() for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); trade.addInitProgressStep(); ThreadUtils.execute(() -> { - synchronized (trade) { + synchronized (trade.getLock()) { // check trade if (trade.hasFailed()) { @@ -335,7 +335,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) { System.out.println(getClass().getSimpleName() + ".handleSignContractRequest() for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); ThreadUtils.execute(() -> { - synchronized (trade) { + synchronized (trade.getLock()) { // check trade if (trade.hasFailed()) { @@ -379,7 +379,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D System.out.println(getClass().getSimpleName() + ".handleSignContractResponse() for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); trade.addInitProgressStep(); ThreadUtils.execute(() -> { - synchronized (trade) { + synchronized (trade.getLock()) { // check trade if (trade.hasFailed()) { @@ -425,7 +425,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D System.out.println(getClass().getSimpleName() + ".handleDepositResponse() for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); trade.addInitProgressStep(); ThreadUtils.execute(() -> { - synchronized (trade) { + synchronized (trade.getLock()) { Validator.checkTradeId(processModel.getOfferId(), response); latchTrade(); processModel.setTradeMessage(response); @@ -455,7 +455,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D System.out.println(getClass().getSimpleName() + ".handle(DepositsConfirmedMessage) from " + sender + " for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); if (!trade.isInitialized() || trade.isShutDown()) return; ThreadUtils.execute(() -> { - synchronized (trade) { + synchronized (trade.getLock()) { if (!trade.isInitialized() || trade.isShutDown()) return; latchTrade(); this.errorMessageHandler = null; @@ -493,7 +493,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D // a mailbox message with PaymentSentMessage. // TODO A better fix would be to add a listener for the wallet sync state and process // the mailbox msg once wallet is ready and trade state set. - synchronized (trade) { + synchronized (trade.getLock()) { if (!trade.isInitialized() || trade.isShutDown()) return; if (trade.getPhase().ordinal() >= Trade.Phase.PAYMENT_SENT.ordinal()) { log.warn("Received another PaymentSentMessage which was already processed for {} {}, ACKing", trade.getClass().getSimpleName(), trade.getId()); @@ -542,7 +542,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D log.warn("Ignoring PaymentReceivedMessage since not buyer or arbitrator"); return; } - synchronized (trade) { + synchronized (trade.getLock()) { if (!trade.isInitialized() || trade.isShutDown()) return; latchTrade(); Validator.checkTradeId(processModel.getOfferId(), message); @@ -817,7 +817,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D } void handleTaskRunnerFault(NodeAddress ackReceiver, @Nullable TradeMessage message, String source, String errorMessage) { - log.error("Task runner failed with error {}. Triggered from {}. Monerod={}" , errorMessage, source, trade.getXmrWalletService().getConnectionService().getConnection()); + log.error("Task runner failed with error {}. Triggered from {}. Monerod={}" , errorMessage, source, trade.getXmrWalletService().getXmrConnectionService().getConnection()); if (message != null) { sendAckMessage(ackReceiver, message, false, errorMessage); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/MaybeSendSignContractRequest.java b/core/src/main/java/haveno/core/trade/protocol/tasks/MaybeSendSignContractRequest.java index 20c889f8..6dcef7f0 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/MaybeSendSignContractRequest.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/MaybeSendSignContractRequest.java @@ -28,7 +28,6 @@ import haveno.core.trade.Trade.State; import haveno.core.trade.messages.SignContractRequest; import haveno.core.trade.protocol.TradeProtocol; import haveno.core.xmr.model.XmrAddressEntry; -import haveno.core.xmr.wallet.XmrWalletService; import haveno.network.p2p.SendDirectMessageListener; import lombok.extern.slf4j.Slf4j; import monero.common.MoneroRpcConnection; @@ -78,7 +77,7 @@ public class MaybeSendSignContractRequest extends TradeTask { // create deposit tx and freeze inputs MoneroTxWallet depositTx = null; - synchronized (XmrWalletService.WALLET_LOCK) { + synchronized (HavenoUtils.xmrWalletService.getWalletLock()) { // check for timeout if (isTimedOut()) throw new RuntimeException("Trade protocol has timed out while getting lock to create deposit tx, tradeId=" + trade.getShortId()); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/TakerReserveTradeFunds.java b/core/src/main/java/haveno/core/trade/protocol/tasks/TakerReserveTradeFunds.java index 69c72211..0ac0a540 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/TakerReserveTradeFunds.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/TakerReserveTradeFunds.java @@ -24,7 +24,6 @@ import haveno.core.trade.TakerTrade; import haveno.core.trade.Trade; import haveno.core.trade.protocol.TradeProtocol; import haveno.core.xmr.model.XmrAddressEntry; -import haveno.core.xmr.wallet.XmrWalletService; import lombok.extern.slf4j.Slf4j; import monero.common.MoneroRpcConnection; import monero.wallet.model.MoneroTxWallet; @@ -50,7 +49,7 @@ public class TakerReserveTradeFunds extends TradeTask { // create reserve tx MoneroTxWallet reserveTx = null; - synchronized (XmrWalletService.WALLET_LOCK) { + synchronized (HavenoUtils.xmrWalletService.getWalletLock()) { // check for timeout if (isTimedOut()) throw new RuntimeException("Trade protocol has timed out while getting lock to create reserve tx, tradeId=" + trade.getShortId()); diff --git a/core/src/main/java/haveno/core/xmr/Balances.java b/core/src/main/java/haveno/core/xmr/Balances.java index cfae1cb5..6958c828 100644 --- a/core/src/main/java/haveno/core/xmr/Balances.java +++ b/core/src/main/java/haveno/core/xmr/Balances.java @@ -44,6 +44,7 @@ import haveno.core.offer.OpenOfferManager; import haveno.core.support.dispute.Dispute; import haveno.core.support.dispute.refund.RefundManager; import haveno.core.trade.ClosedTradableManager; +import haveno.core.trade.HavenoUtils; import haveno.core.trade.MakerTrade; import haveno.core.trade.Trade; import haveno.core.trade.TradeManager; @@ -124,7 +125,7 @@ public class Balances { private void doUpdateBalances() { synchronized (this) { - synchronized (XmrWalletService.WALLET_LOCK) { + synchronized (HavenoUtils.xmrWalletService.getWalletLock()) { // get wallet balances BigInteger balance = xmrWalletService.getWallet() == null ? BigInteger.ZERO : xmrWalletService.getBalance(); diff --git a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletBase.java b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletBase.java new file mode 100644 index 00000000..cca9daa0 --- /dev/null +++ b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletBase.java @@ -0,0 +1,165 @@ +package haveno.core.xmr.wallet; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import haveno.common.Timer; +import haveno.common.UserThread; +import haveno.core.api.XmrConnectionService; +import haveno.core.trade.HavenoUtils; +import haveno.core.xmr.setup.DownloadListener; +import javafx.beans.property.LongProperty; +import javafx.beans.property.SimpleLongProperty; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import monero.common.TaskLooper; +import monero.daemon.model.MoneroTx; +import monero.wallet.MoneroWallet; +import monero.wallet.MoneroWalletFull; +import monero.wallet.model.MoneroWalletListener; + +@Slf4j +public class XmrWalletBase { + + // constants + public static final int SYNC_PROGRESS_TIMEOUT_SECONDS = 60; + + // inherited + protected MoneroWallet wallet; + @Getter + protected final Object walletLock = new Object(); + @Getter + protected XmrConnectionService xmrConnectionService; + protected boolean wasWalletSynced; + protected final Map> txCache = new HashMap>(); + protected boolean isClosingWallet; + protected boolean isSyncingWithProgress; + protected Long syncStartHeight; + protected TaskLooper syncProgressLooper; + protected CountDownLatch syncProgressLatch; + protected Exception syncProgressError; + protected Timer syncProgressTimeout; + protected final DownloadListener downloadListener = new DownloadListener(); + protected final LongProperty walletHeight = new SimpleLongProperty(0); + @Getter + protected boolean isShutDownStarted; + @Getter + protected boolean isShutDown; + + // private + private boolean testReconnectOnStartup = false; // test reconnecting on startup while syncing so the wallet is blocked + private String testReconnectMonerod1 = "http://node.community.rino.io:18081"; + private String testReconnectMonerod2 = "http://nodex.monerujo.io:18081"; + + public XmrWalletBase() { + this.xmrConnectionService = HavenoUtils.xmrConnectionService; + } + + public void syncWithProgress() { + synchronized (walletLock) { + + // set initial state + isSyncingWithProgress = true; + syncProgressError = null; + updateSyncProgress(walletHeight.get()); + + // test connection changing on startup before wallet synced + if (testReconnectOnStartup) { + UserThread.runAfter(() -> { + log.warn("Testing connection change on startup before wallet synced"); + if (xmrConnectionService.getConnection().getUri().equals(testReconnectMonerod1)) xmrConnectionService.setConnection(testReconnectMonerod2); + else xmrConnectionService.setConnection(testReconnectMonerod1); + }, 1); + testReconnectOnStartup = false; // only run once + } + + // native wallet provides sync notifications + if (wallet instanceof MoneroWalletFull) { + if (testReconnectOnStartup) HavenoUtils.waitFor(1000); // delay sync to test + wallet.sync(new MoneroWalletListener() { + @Override + public void onSyncProgress(long height, long startHeight, long endHeight, double percentDone, String message) { + updateSyncProgress(height); + } + }); + setWalletSyncedWithProgress(); + return; + } + + // start polling wallet for progress + syncProgressLatch = new CountDownLatch(1); + syncProgressLooper = new TaskLooper(() -> { + if (wallet == null) return; + long height; + try { + height = wallet.getHeight(); // can get read timeout while syncing + } catch (Exception e) { + log.warn("Error getting wallet height while syncing with progress: " + e.getMessage()); + if (wallet != null && !isShutDownStarted) e.printStackTrace(); + + // stop polling and release latch + syncProgressError = e; + syncProgressLatch.countDown(); + return; + } + updateSyncProgress(height); + if (height >= xmrConnectionService.getTargetHeight()) { + setWalletSyncedWithProgress(); + syncProgressLatch.countDown(); + } + }); + wallet.startSyncing(xmrConnectionService.getRefreshPeriodMs()); + syncProgressLooper.start(1000); + + // wait for sync to complete + HavenoUtils.awaitLatch(syncProgressLatch); + + // stop polling + syncProgressLooper.stop(); + syncProgressTimeout.stop(); + if (wallet != null) wallet.stopSyncing(); // can become null if interrupted by force close + isSyncingWithProgress = false; + if (syncProgressError != null) throw new RuntimeException(syncProgressError); + } + } + + private void updateSyncProgress(long height) { + resetSyncProgressTimeout(); + UserThread.execute(() -> { + + // set wallet height + walletHeight.set(height); + + // new wallet reports height 1 before synced + if (height == 1) { + downloadListener.progress(0, xmrConnectionService.getTargetHeight() - height, null); + return; + } + + // set progress + long targetHeight = xmrConnectionService.getTargetHeight(); + long blocksLeft = targetHeight - walletHeight.get(); + if (syncStartHeight == null) syncStartHeight = walletHeight.get(); + double percent = Math.min(1.0, targetHeight == syncStartHeight ? 1.0 : ((double) walletHeight.get() - syncStartHeight) / (double) (targetHeight - syncStartHeight)); + downloadListener.progress(percent, blocksLeft, null); + }); + } + + private synchronized void resetSyncProgressTimeout() { + if (syncProgressTimeout != null) syncProgressTimeout.stop(); + syncProgressTimeout = UserThread.runAfter(() -> { + if (isShutDownStarted) return; + syncProgressError = new RuntimeException("Sync progress timeout called"); + syncProgressLatch.countDown(); + }, SYNC_PROGRESS_TIMEOUT_SECONDS, TimeUnit.SECONDS); + } + + private void setWalletSyncedWithProgress() { + wasWalletSynced = true; + isSyncingWithProgress = false; + syncProgressTimeout.stop(); + } +} 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 587ed33c..2fb9ddcd 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java +++ b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java @@ -24,7 +24,6 @@ import com.google.inject.name.Named; import common.utils.JsonUtils; import haveno.common.ThreadUtils; -import haveno.common.Timer; import haveno.common.UserThread; import haveno.common.config.Config; import haveno.common.file.FileUtil; @@ -43,7 +42,6 @@ import haveno.core.user.User; import haveno.core.xmr.listeners.XmrBalanceListener; import haveno.core.xmr.model.XmrAddressEntry; import haveno.core.xmr.model.XmrAddressEntryList; -import haveno.core.xmr.setup.DownloadListener; import haveno.core.xmr.setup.MoneroWalletRpcManager; import haveno.core.xmr.setup.WalletsSetup; import java.io.File; @@ -55,26 +53,22 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.Callable; import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.Stream; import javafx.beans.property.LongProperty; import javafx.beans.property.ReadOnlyDoubleProperty; -import javafx.beans.property.SimpleLongProperty; import javafx.beans.value.ChangeListener; +import lombok.Getter; import monero.common.MoneroError; import monero.common.MoneroRpcConnection; import monero.common.MoneroRpcError; @@ -103,14 +97,13 @@ import monero.wallet.model.MoneroTxPriority; import monero.wallet.model.MoneroTxQuery; import monero.wallet.model.MoneroTxWallet; import monero.wallet.model.MoneroWalletConfig; -import monero.wallet.model.MoneroWalletListener; import monero.wallet.model.MoneroWalletListenerI; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class XmrWalletService { +public class XmrWalletService extends XmrWalletBase { private static final Logger log = LoggerFactory.getLogger(XmrWalletService.class); // monero configuration @@ -138,11 +131,8 @@ public class XmrWalletService { private final User user; private final Preferences preferences; private final CoreAccountService accountService; - private final XmrConnectionService xmrConnectionService; private final XmrAddressEntryList xmrAddressEntryList; private final WalletsSetup walletsSetup; - private final DownloadListener downloadListener = new DownloadListener(); - private final LongProperty walletHeight = new SimpleLongProperty(0); private final File walletDir; private final File xmrWalletFile; @@ -153,22 +143,10 @@ public class XmrWalletService { private ChangeListener walletInitListener; private TradeManager tradeManager; - private MoneroWallet wallet; - public static final Object WALLET_LOCK = new Object(); - private boolean wasWalletSynced; - private final Map> txCache = new HashMap>(); - private boolean isClosingWallet; - private boolean isShutDownStarted; private ExecutorService syncWalletThreadPool = Executors.newFixedThreadPool(10); // TODO: adjust based on connection type - private boolean isSyncingWithProgress; - private Long syncStartHeight; - private TaskLooper syncProgressLooper; - private CountDownLatch syncProgressLatch; - private Exception syncProgressError; - private Timer syncProgressTimeout; - private static final int SYNC_PROGRESS_TIMEOUT_SECONDS = 60; - // wallet polling and cache + @Getter + public final Object lock = new Object(); private TaskLooper pollLooper; private boolean pollInProgress; private Long pollPeriodMs; @@ -180,9 +158,6 @@ public class XmrWalletService { private List cachedSubaddresses; private List cachedOutputs; private List cachedTxs; - private boolean testReconnectOnStartup = false; // test reconnecting on startup while syncing so the wallet is blocked - private String testReconnectMonerod1 = "http://node.community.rino.io:18081"; - private String testReconnectMonerod2 = "http://nodex.monerujo.io:18081"; @SuppressWarnings("unused") @Inject @@ -198,7 +173,6 @@ public class XmrWalletService { this.user = user; this.preferences = preferences; this.accountService = accountService; - this.xmrConnectionService = xmrConnectionService; this.walletsSetup = walletsSetup; this.xmrAddressEntryList = xmrAddressEntryList; this.walletDir = walletDir; @@ -206,6 +180,8 @@ public class XmrWalletService { this.useNativeXmrWallet = useNativeXmrWallet; this.xmrWalletFile = new File(walletDir, MONERO_WALLET_NAME); HavenoUtils.xmrWalletService = this; + HavenoUtils.xmrConnectionService = xmrConnectionService; + this.xmrConnectionService = xmrConnectionService; // TODO: super's is null unless set here from injection // set monero logging if (MONERO_LOG_LEVEL >= 0) MoneroUtils.setLogLevel(MONERO_LOG_LEVEL); @@ -320,10 +296,6 @@ public class XmrWalletService { return xmrConnectionService.getDaemon(); } - public XmrConnectionService getConnectionService() { - return xmrConnectionService; - } - public boolean isProxyApplied() { return isProxyApplied(wasWalletSynced); } @@ -464,7 +436,7 @@ public class XmrWalletService { } public MoneroTxWallet createTx(MoneroTxConfig txConfig) { - synchronized (WALLET_LOCK) { + synchronized (walletLock) { synchronized (HavenoUtils.getWalletFunctionLock()) { MoneroTxWallet tx = wallet.createTx(txConfig); if (Boolean.TRUE.equals(txConfig.getRelay())) { @@ -478,7 +450,7 @@ public class XmrWalletService { } public String relayTx(String metadata) { - synchronized (WALLET_LOCK) { + synchronized (walletLock) { String txId = wallet.relayTx(metadata); requestSaveMainWallet(); return txId; @@ -495,7 +467,7 @@ public class XmrWalletService { * Freeze reserved outputs and thaw unreserved outputs. */ public void fixReservedOutputs() { - synchronized (WALLET_LOCK) { + synchronized (walletLock) { // collect reserved outputs Set reservedKeyImages = new HashSet(); @@ -514,7 +486,7 @@ public class XmrWalletService { } private void freezeReservedOutputs(Set reservedKeyImages) { - synchronized (WALLET_LOCK) { + synchronized (walletLock) { // ensure wallet is open if (wallet == null) { @@ -538,7 +510,7 @@ public class XmrWalletService { } private void thawUnreservedOutputs(Set reservedKeyImages) { - synchronized (WALLET_LOCK) { + synchronized (walletLock) { // ensure wallet is open if (wallet == null) { @@ -568,7 +540,7 @@ public class XmrWalletService { */ public void freezeOutputs(Collection keyImages) { if (keyImages == null || keyImages.isEmpty()) return; - synchronized (WALLET_LOCK) { + synchronized (walletLock) { // collect outputs to freeze List unfrozenKeyImages = getOutputs(new MoneroOutputQuery().setIsFrozen(false).setIsSpent(false)).stream() @@ -590,7 +562,7 @@ public class XmrWalletService { */ public void thawOutputs(Collection keyImages) { if (keyImages == null || keyImages.isEmpty()) return; - synchronized (WALLET_LOCK) { + synchronized (walletLock) { // collect outputs to thaw List frozenKeyImages = getOutputs(new MoneroOutputQuery().setIsFrozen(true).setIsSpent(false)).stream() @@ -643,7 +615,7 @@ public class XmrWalletService { * @return the reserve tx */ public MoneroTxWallet createReserveTx(BigInteger penaltyFee, BigInteger tradeFee, BigInteger sendTradeAmount, BigInteger securityDeposit, String returnAddress, boolean reserveExactAmount, Integer preferredSubaddressIndex) { - synchronized (WALLET_LOCK) { + synchronized (walletLock) { synchronized (HavenoUtils.getWalletFunctionLock()) { log.info("Creating reserve tx with preferred subaddress index={}, return address={}", preferredSubaddressIndex, returnAddress); long time = System.currentTimeMillis(); @@ -664,7 +636,7 @@ public class XmrWalletService { * @return MoneroTxWallet the multisig deposit tx */ public MoneroTxWallet createDepositTx(Trade trade, boolean reserveExactAmount, Integer preferredSubaddressIndex) { - synchronized (WALLET_LOCK) { + synchronized (walletLock) { synchronized (HavenoUtils.getWalletFunctionLock()) { BigInteger feeAmount = trade instanceof MakerTrade ? trade.getMakerFee() : trade.getTakerFee(); String feeAddress = trade.getProcessModel().getTradeFeeAddress(); @@ -682,7 +654,7 @@ public class XmrWalletService { } private MoneroTxWallet createTradeTx(BigInteger feeAmount, String feeAddress, BigInteger sendAmount, String sendAddress, boolean reserveExactAmount, Integer preferredSubaddressIndex) { - synchronized (WALLET_LOCK) { + synchronized (walletLock) { MoneroWallet wallet = getWallet(); // create a list of subaddresses to attempt spending from in preferred order @@ -919,7 +891,7 @@ public class XmrWalletService { Runnable shutDownTask = () -> { // remove listeners - synchronized (WALLET_LOCK) { + synchronized (walletLock) { if (wallet != null) { for (MoneroWalletListenerI listener : new HashSet<>(wallet.getListeners())) { wallet.removeListener(listener); @@ -929,7 +901,7 @@ public class XmrWalletService { } // shut down threads - synchronized (this) { + synchronized (getLock()) { List shutDownThreads = new ArrayList<>(); shutDownThreads.add(() -> ThreadUtils.shutDown(THREAD_ID)); ThreadUtils.awaitTasks(shutDownThreads); @@ -1345,7 +1317,7 @@ public class XmrWalletService { } private void doMaybeInitMainWallet(boolean sync, int numAttempts) { - synchronized (WALLET_LOCK) { + synchronized (walletLock) { if (isShutDownStarted) return; // open or create wallet main wallet @@ -1467,111 +1439,6 @@ public class XmrWalletService { } } - private void syncWithProgress() { - synchronized (WALLET_LOCK) { - - // set initial state - isSyncingWithProgress = true; - syncProgressError = null; - updateSyncProgress(walletHeight.get()); - - // test connection changing on startup before wallet synced - if (testReconnectOnStartup) { - UserThread.runAfter(() -> { - log.warn("Testing connection change on startup before wallet synced"); - if (xmrConnectionService.getConnection().getUri().equals(testReconnectMonerod1)) xmrConnectionService.setConnection(testReconnectMonerod2); - else xmrConnectionService.setConnection(testReconnectMonerod1); - }, 1); - testReconnectOnStartup = false; // only run once - } - - // native wallet provides sync notifications - if (wallet instanceof MoneroWalletFull) { - if (testReconnectOnStartup) HavenoUtils.waitFor(1000); // delay sync to test - wallet.sync(new MoneroWalletListener() { - @Override - public void onSyncProgress(long height, long startHeight, long endHeight, double percentDone, String message) { - updateSyncProgress(height); - } - }); - setWalletSyncedWithProgress(); - return; - } - - // start polling wallet for progress - syncProgressLatch = new CountDownLatch(1); - syncProgressLooper = new TaskLooper(() -> { - if (wallet == null) return; - long height; - try { - height = wallet.getHeight(); // can get read timeout while syncing - } catch (Exception e) { - log.warn("Error getting wallet height while syncing with progress: " + e.getMessage()); - if (wallet != null && !isShutDownStarted) e.printStackTrace(); - - // stop polling and release latch - syncProgressError = e; - syncProgressLatch.countDown(); - return; - } - updateSyncProgress(height); - if (height >= xmrConnectionService.getTargetHeight()) { - setWalletSyncedWithProgress(); - syncProgressLatch.countDown(); - } - }); - wallet.startSyncing(xmrConnectionService.getRefreshPeriodMs()); - syncProgressLooper.start(1000); - - // wait for sync to complete - HavenoUtils.awaitLatch(syncProgressLatch); - - // stop polling - syncProgressLooper.stop(); - syncProgressTimeout.stop(); - if (wallet != null) wallet.stopSyncing(); // can become null if interrupted by force close - isSyncingWithProgress = false; - if (syncProgressError != null) throw new RuntimeException(syncProgressError); - } - } - - private void updateSyncProgress(long height) { - resetSyncProgressTimeout(); - UserThread.execute(() -> { - - // set wallet height - walletHeight.set(height); - - // new wallet reports height 1 before synced - if (height == 1) { - downloadListener.progress(0, xmrConnectionService.getTargetHeight() - height, null); - return; - } - - // set progress - long targetHeight = xmrConnectionService.getTargetHeight(); - long blocksLeft = targetHeight - walletHeight.get(); - if (syncStartHeight == null) syncStartHeight = walletHeight.get(); - double percent = Math.min(1.0, targetHeight == syncStartHeight ? 1.0 : ((double) walletHeight.get() - syncStartHeight) / (double) (targetHeight - syncStartHeight)); - downloadListener.progress(percent, blocksLeft, null); - }); - } - - private synchronized void resetSyncProgressTimeout() { - if (syncProgressTimeout != null) syncProgressTimeout.stop(); - syncProgressTimeout = UserThread.runAfter(() -> { - if (isShutDownStarted) return; - syncProgressError = new RuntimeException("Sync progress timeout called"); - syncProgressLatch.countDown(); - }, SYNC_PROGRESS_TIMEOUT_SECONDS, TimeUnit.SECONDS); - } - - private void setWalletSyncedWithProgress() { - wasWalletSynced = true; - isSyncingWithProgress = false; - syncProgressTimeout.stop(); - } - private MoneroWalletFull createWalletFull(MoneroWalletConfig config) { // must be connected to daemon @@ -1724,7 +1591,7 @@ public class XmrWalletService { } private void onConnectionChanged(MoneroRpcConnection connection) { - synchronized (WALLET_LOCK) { + synchronized (walletLock) { // use current connection connection = xmrConnectionService.getConnection(); @@ -1798,7 +1665,7 @@ public class XmrWalletService { private void closeMainWallet(boolean save) { stopPolling(); - synchronized (WALLET_LOCK) { + synchronized (walletLock) { try { if (wallet != null) { isClosingWallet = true; @@ -1834,7 +1701,7 @@ public class XmrWalletService { } private void startPolling() { - synchronized (WALLET_LOCK) { + synchronized (walletLock) { if (isShutDownStarted || isPolling()) return; updatePollPeriod(); pollLooper = new TaskLooper(() -> pollWallet()); @@ -1863,7 +1730,7 @@ public class XmrWalletService { } private void setPollPeriod(long pollPeriodMs) { - synchronized (WALLET_LOCK) { + synchronized (walletLock) { if (this.isShutDownStarted) return; if (this.pollPeriodMs != null && this.pollPeriodMs == pollPeriodMs) return; this.pollPeriodMs = pollPeriodMs; @@ -1900,7 +1767,7 @@ public class XmrWalletService { } // sync wallet if behind daemon if (walletHeight.get() < xmrConnectionService.getTargetHeight()) { - synchronized (WALLET_LOCK) { // avoid long sync from blocking other operations + synchronized (walletLock) { // avoid long sync from blocking other operations syncWithProgress(); } } @@ -1908,7 +1775,7 @@ public class XmrWalletService { // fetch transactions from pool and store to cache // TODO: ideally wallet should sync every poll and then avoid updating from pool on fetching txs? if (updateTxs) { - synchronized (WALLET_LOCK) { // avoid long fetch from blocking other operations + synchronized (walletLock) { // avoid long fetch from blocking other operations synchronized (HavenoUtils.getDaemonLock()) { MoneroRpcConnection sourceConnection = xmrConnectionService.getConnection(); try { @@ -1931,13 +1798,13 @@ public class XmrWalletService { if (wallet == null || isShutDownStarted) return; if (HavenoUtils.isUnresponsive(e)) forceRestartMainWallet(); else if (isWalletConnectedToDaemon()) { - log.warn("Error polling main wallet, errorMessage={}. Monerod={}", e.getMessage(), getConnectionService().getConnection()); + log.warn("Error polling main wallet, errorMessage={}. Monerod={}", e.getMessage(), getXmrConnectionService().getConnection()); //e.printStackTrace(); } } finally { // cache wallet info last - synchronized (WALLET_LOCK) { + synchronized (walletLock) { if (wallet != null && !isShutDownStarted) { try { cacheWalletInfo(); @@ -1954,7 +1821,7 @@ public class XmrWalletService { } private MoneroSyncResult syncMainWallet() { - synchronized (WALLET_LOCK) { + synchronized (walletLock) { MoneroSyncResult result = syncWallet(wallet); walletHeight.set(wallet.getHeight()); return result; @@ -1962,7 +1829,7 @@ public class XmrWalletService { } public boolean isWalletConnectedToDaemon() { - synchronized (WALLET_LOCK) { + synchronized (walletLock) { try { if (wallet == null) return false; return wallet.isConnectedToDaemon(); diff --git a/desktop/src/main/java/haveno/desktop/components/TxIdTextField.java b/desktop/src/main/java/haveno/desktop/components/TxIdTextField.java index 70155b13..e9ced56c 100644 --- a/desktop/src/main/java/haveno/desktop/components/TxIdTextField.java +++ b/desktop/src/main/java/haveno/desktop/components/TxIdTextField.java @@ -197,7 +197,7 @@ public class TxIdTextField extends AnchorPane { try { if (trade == null) { tx = useCache ? xmrWalletService.getDaemonTxWithCache(txId) : xmrWalletService.getDaemonTx(txId); - tx.setNumConfirmations(tx.isConfirmed() ? (height == null ? xmrWalletService.getConnectionService().getLastInfo().getHeight() : height) - tx.getHeight(): 0l); // TODO: don't set if tx.getNumConfirmations() works reliably on non-local testnet + tx.setNumConfirmations(tx.isConfirmed() ? (height == null ? xmrWalletService.getXmrConnectionService().getLastInfo().getHeight() : height) - tx.getHeight(): 0l); // TODO: don't set if tx.getNumConfirmations() works reliably on non-local testnet } else { if (txId.equals(trade.getMaker().getDepositTxHash())) tx = trade.getMakerDepositTx(); else if (txId.equals(trade.getTaker().getDepositTxHash())) tx = trade.getTakerDepositTx(); diff --git a/desktop/src/main/java/haveno/desktop/main/funds/withdrawal/WithdrawalView.java b/desktop/src/main/java/haveno/desktop/main/funds/withdrawal/WithdrawalView.java index 55bd970e..0fa45624 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/withdrawal/WithdrawalView.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/withdrawal/WithdrawalView.java @@ -257,7 +257,7 @@ public class WithdrawalView extends ActivatableView { // create tx MoneroTxWallet tx = null; for (int i = 0; i < TradeProtocol.MAX_ATTEMPTS; i++) { - MoneroRpcConnection sourceConnection = xmrWalletService.getConnectionService().getConnection(); + MoneroRpcConnection sourceConnection = xmrWalletService.getXmrConnectionService().getConnection(); try { log.info("Creating withdraw tx"); long startTime = System.currentTimeMillis(); @@ -272,7 +272,7 @@ public class WithdrawalView extends ActivatableView { if (isNotEnoughMoney(e.getMessage())) throw e; log.warn("Error creating creating withdraw tx, attempt={}/{}, error={}", i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage()); if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e; - if (xmrWalletService.getConnectionService().isConnected()) xmrWalletService.requestSwitchToNextBestConnection(sourceConnection); + if (xmrWalletService.getXmrConnectionService().isConnected()) xmrWalletService.requestSwitchToNextBestConnection(sourceConnection); HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying } } diff --git a/desktop/src/main/java/haveno/desktop/util/GUIUtil.java b/desktop/src/main/java/haveno/desktop/util/GUIUtil.java index deeb742b..f2ad96c2 100644 --- a/desktop/src/main/java/haveno/desktop/util/GUIUtil.java +++ b/desktop/src/main/java/haveno/desktop/util/GUIUtil.java @@ -701,7 +701,7 @@ public class GUIUtil { } public static boolean isReadyForTxBroadcastOrShowPopup(XmrWalletService xmrWalletService) { - XmrConnectionService xmrConnectionService = xmrWalletService.getConnectionService(); + XmrConnectionService xmrConnectionService = xmrWalletService.getXmrConnectionService(); if (!xmrConnectionService.hasSufficientPeersForBroadcast()) { new Popup().information(Res.get("popup.warning.notSufficientConnectionsToXmrNetwork", xmrConnectionService.getMinBroadcastConnections())).show(); return false;