From a3a5b96c0661230aa1fed1ef5d96ce9093bb2a0d Mon Sep 17 00:00:00 2001 From: woodser Date: Tue, 26 Jul 2022 01:03:19 -0400 Subject: [PATCH] stagenet deployment fixes execute protocol tasks off main thread fix confirmation progress indicators fix expected unlock height process sign contract request after contract signature requested deposit listener only advances trade state --- .../java/bisq/core/api/model/TradeInfo.java | 2 +- core/src/main/java/bisq/core/trade/Trade.java | 56 +++++++------ .../java/bisq/core/trade/TradeManager.java | 4 +- .../trade/protocol/ArbitratorProtocol.java | 8 +- .../trade/protocol/BuyerAsMakerProtocol.java | 79 +++++++++++-------- .../trade/protocol/BuyerAsTakerProtocol.java | 68 +++++++++------- .../core/trade/protocol/BuyerProtocol.java | 7 +- .../core/trade/protocol/FluentProtocol.java | 52 ++++++------ .../trade/protocol/SellerAsMakerProtocol.java | 66 +++++++++------- .../trade/protocol/SellerAsTakerProtocol.java | 76 ++++++++++-------- .../core/trade/protocol/SellerProtocol.java | 4 +- .../core/trade/protocol/TradeProtocol.java | 1 + .../tasks/ProcessSignContractRequest.java | 2 +- .../SendSignContractRequestAfterMultisig.java | 2 + .../buyer/BuyerSendsPaymentSentMessage.java | 1 + .../desktop/components/TxIdTextField.java | 11 ++- .../pendingtrades/PendingTradesView.java | 7 +- .../pendingtrades/steps/TradeStepView.java | 28 +++---- .../steps/buyer/BuyerStep2View.java | 2 +- .../steps/seller/SellerStep3View.java | 1 + .../main/java/bisq/desktop/util/GUIUtil.java | 5 +- 21 files changed, 259 insertions(+), 223 deletions(-) diff --git a/core/src/main/java/bisq/core/api/model/TradeInfo.java b/core/src/main/java/bisq/core/api/model/TradeInfo.java index fc656a19d5..b53142edcc 100644 --- a/core/src/main/java/bisq/core/api/model/TradeInfo.java +++ b/core/src/main/java/bisq/core/api/model/TradeInfo.java @@ -154,7 +154,7 @@ public class TradeInfo implements Payload { .withPhase(trade.getPhase().name()) .withPeriodState(trade.getPeriodState().name()) .withIsDepositPublished(trade.isDepositPublished()) - .withIsDepositUnlocked(trade.isDepositConfirmed()) + .withIsDepositUnlocked(trade.isDepositUnlocked()) .withIsPaymentSent(trade.isPaymentSent()) .withIsPaymentReceived(trade.isPaymentReceived()) .withIsPayoutPublished(trade.isPayoutPublished()) diff --git a/core/src/main/java/bisq/core/trade/Trade.java b/core/src/main/java/bisq/core/trade/Trade.java index 2f4bbc5a26..efa0c5b711 100644 --- a/core/src/main/java/bisq/core/trade/Trade.java +++ b/core/src/main/java/bisq/core/trade/Trade.java @@ -39,7 +39,7 @@ import bisq.core.util.ParsingUtils; import bisq.core.util.VolumeUtil; import bisq.network.p2p.AckMessage; import bisq.network.p2p.NodeAddress; - +import bisq.common.UserThread; import bisq.common.crypto.PubKeyRing; import bisq.common.proto.ProtoUtil; import bisq.common.taskrunner.Model; @@ -876,20 +876,19 @@ public abstract class Trade implements Tradable, Model { // handle deposit txs seen if (txs.size() == 2) { - - // update state - setState(this instanceof MakerTrade ? Trade.State.MAKER_SAW_DEPOSIT_TX_IN_NETWORK : Trade.State.TAKER_SAW_DEPOSIT_TX_IN_NETWORK); boolean makerFirst = txs.get(0).getHash().equals(processModel.getMaker().getDepositTxHash()); makerDepositTx = makerFirst ? txs.get(0) : txs.get(1); takerDepositTx = makerFirst ? txs.get(1) : txs.get(0); - + // check if deposit txs unlocked if (txs.get(0).isConfirmed() && txs.get(1).isConfirmed()) { - long unlockHeight = Math.max(txs.get(0).getHeight(), txs.get(0).getHeight()) + XmrWalletService.NUM_BLOCKS_UNLOCK - 1; + long unlockHeight = Math.max(txs.get(0).getHeight(), txs.get(1).getHeight()) + XmrWalletService.NUM_BLOCKS_UNLOCK; if (havenoWallet.getHeight() >= unlockHeight) { - setConfirmedState(); + setUnlockedState(); return; } + } else { + setStateIfValidTransitionTo(this instanceof MakerTrade ? Trade.State.MAKER_SAW_DEPOSIT_TX_IN_NETWORK : Trade.State.TAKER_SAW_DEPOSIT_TX_IN_NETWORK); } } @@ -900,40 +899,37 @@ public abstract class Trade implements Tradable, Model { @Override public void onNewBlock(long height) { - + // ignore if no longer listening if (depositTxListener == null) return; - + // ignore if before unlock height if (unlockHeight != null && height < unlockHeight) return; - + // fetch txs from daemon List txs = daemon.getTxs(Arrays.asList(processModel.getMaker().getDepositTxHash(), processModel.getTaker().getDepositTxHash()), true); - + // ignore if deposit txs not seen if (txs.size() != 2) return; - + // update deposit txs boolean makerFirst = txs.get(0).getHash().equals(processModel.getMaker().getDepositTxHash()); makerDepositTx = makerFirst ? txs.get(0) : txs.get(1); takerDepositTx = makerFirst ? txs.get(1) : txs.get(0); - - // update state when deposit txs seen - if (txs.size() == 2) { - setState(this instanceof MakerTrade ? Trade.State.MAKER_SAW_DEPOSIT_TX_IN_NETWORK : Trade.State.TAKER_SAW_DEPOSIT_TX_IN_NETWORK); - } - + // compute unlock height if (unlockHeight == null && txs.size() == 2 && txs.get(0).isConfirmed() && txs.get(1).isConfirmed()) { - unlockHeight = Math.max(txs.get(0).getHeight(), txs.get(0).getHeight()) + XmrWalletService.NUM_BLOCKS_UNLOCK - 1; + unlockHeight = Math.max(txs.get(0).getHeight(), txs.get(1).getHeight()) + XmrWalletService.NUM_BLOCKS_UNLOCK; } - - // check if txs unlocked + + // check if deposit txs unlocked if (unlockHeight != null && height == unlockHeight) { log.info("Multisig deposits unlocked for trade {}", getId()); - setConfirmedState(); // TODO (woodser): bisq "confirmed" = xmr unlocked after 10 confirmations + setUnlockedState(); xmrWalletService.removeWalletListener(depositTxListener); // remove listener when notified depositTxListener = null; // prevent re-applying trade state in subsequent requests + } else if (txs.size() == 2) { + setStateIfValidTransitionTo(this instanceof MakerTrade ? Trade.State.MAKER_SAW_DEPOSIT_TX_IN_NETWORK : Trade.State.TAKER_SAW_DEPOSIT_TX_IN_NETWORK); } } }; @@ -1079,8 +1075,10 @@ public abstract class Trade implements Tradable, Model { } this.state = state; - stateProperty.set(state); - statePhaseProperty.set(state.getPhase()); + UserThread.execute(() -> { + stateProperty.set(state); + statePhaseProperty.set(state.getPhase()); + }); } public void setDisputeState(DisputeState disputeState) { @@ -1242,7 +1240,7 @@ public abstract class Trade implements Tradable, Model { final MoneroTx takerDepositTx = getTakerDepositTx(); final MoneroTx makerDepositTx = getMakerDepositTx(); if (makerDepositTx != null && takerDepositTx != null && getTakeOfferDate() != null) { - if (isDepositConfirmed()) { + if (isDepositUnlocked()) { final long tradeTime = getTakeOfferDate().getTime(); long maxHeight = Math.max(makerDepositTx.getHeight(), takerDepositTx.getHeight()); MoneroDaemon daemonRpc = xmrWalletService.getDaemon(); @@ -1318,7 +1316,7 @@ public abstract class Trade implements Tradable, Model { disputeState != DisputeState.REFUND_REQUEST_CLOSED; } - public boolean isDepositConfirmed() { + public boolean isDepositUnlocked() { return getState().getPhase().ordinal() >= Phase.DEPOSIT_UNLOCKED.ordinal(); } @@ -1479,13 +1477,13 @@ public abstract class Trade implements Tradable, Model { // } // } - private void setConfirmedState() { + private void setUnlockedState() { // we only apply the state if we are not already further in the process - if (!isDepositConfirmed()) { + if (!isDepositUnlocked()) { // As setState is called here from the trade itself we cannot trigger a requestPersistence call. // But as we get setupConfidenceListener called at startup anyway there is no issue if it would not be // persisted in case the shutdown routine did not persist the trade. - setState(State.DEPOSIT_UNLOCKED_IN_BLOCK_CHAIN); // TODO (woodser): for xmr this means deposit txs have unlocked after 10 confirmations + setStateIfValidTransitionTo(State.DEPOSIT_UNLOCKED_IN_BLOCK_CHAIN); // TODO (woodser): for xmr this means deposit txs have unlocked after 10 confirmations } } diff --git a/core/src/main/java/bisq/core/trade/TradeManager.java b/core/src/main/java/bisq/core/trade/TradeManager.java index edbc81a8ea..6cadaaaaed 100644 --- a/core/src/main/java/bisq/core/trade/TradeManager.java +++ b/core/src/main/java/bisq/core/trade/TradeManager.java @@ -884,8 +884,8 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi } private void updateTradePeriodState() { - getObservableList().forEach(trade -> { - UserThread.execute(() -> { // prevent concurrent modification error + UserThread.execute(() -> { // prevent concurrent modification error + getObservableList().forEach(trade -> { if (!trade.isPayoutPublished()) { Date maxTradePeriodDate = trade.getMaxTradePeriodDate(); Date halfTradePeriodDate = trade.getHalfTradePeriodDate(); diff --git a/core/src/main/java/bisq/core/trade/protocol/ArbitratorProtocol.java b/core/src/main/java/bisq/core/trade/protocol/ArbitratorProtocol.java index 793749dfa2..60163dcd80 100644 --- a/core/src/main/java/bisq/core/trade/protocol/ArbitratorProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/ArbitratorProtocol.java @@ -53,7 +53,7 @@ public class ArbitratorProtocol extends DisputeProtocol { handleTaskRunnerFault(peer, message, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } } @@ -79,7 +79,7 @@ public class ArbitratorProtocol extends DisputeProtocol { handleTaskRunnerFault(sender, request, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } } @@ -106,7 +106,7 @@ public class ArbitratorProtocol extends DisputeProtocol { handleTaskRunnerFault(sender, message, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } } @@ -134,7 +134,7 @@ public class ArbitratorProtocol extends DisputeProtocol { handleTaskRunnerFault(sender, request, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } } diff --git a/core/src/main/java/bisq/core/trade/protocol/BuyerAsMakerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/BuyerAsMakerProtocol.java index 5e57637959..a8637a9655 100644 --- a/core/src/main/java/bisq/core/trade/protocol/BuyerAsMakerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/BuyerAsMakerProtocol.java @@ -1,5 +1,5 @@ /* - * This file is part of Haveno. +e * This file is part of Haveno. * * Haveno is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by @@ -95,7 +95,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol handleTaskRunnerFault(peer, message, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } } @@ -122,40 +122,13 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol handleTaskRunnerFault(sender, request, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } } @Override public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) { - System.out.println(getClass().getCanonicalName() + ".handleSignContractRequest()"); - synchronized (trade) { - latchTrade(); - Validator.checkTradeId(processModel.getOfferId(), message); - processModel.setTradeMessage(message); - expect(anyPhase(Trade.Phase.INIT) - .with(message) - .from(sender)) - .setup(tasks( - // TODO (woodser): validate request - ProcessSignContractRequest.class) - .using(new TradeTaskRunner(trade, - () -> { - startTimeout(TRADE_TIMEOUT); - handleTaskRunnerSuccess(sender, message); - }, - errorMessage -> { - handleTaskRunnerFault(sender, message, errorMessage); - })) - .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); - awaitTradeLatch(); - } - } - - @Override - public void handleSignContractResponse(SignContractResponse message, NodeAddress sender) { System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse() " + trade.getId()); synchronized (trade) { Validator.checkTradeId(processModel.getOfferId(), message); @@ -164,6 +137,41 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol Validator.checkTradeId(processModel.getOfferId(), message); processModel.setTradeMessage(message); expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED) + .with(message) + .from(sender)) + .setup(tasks( + // TODO (woodser): validate request + ProcessSignContractRequest.class) + .using(new TradeTaskRunner(trade, + () -> { + startTimeout(TRADE_TIMEOUT); + handleTaskRunnerSuccess(sender, message); + }, + errorMessage -> { + handleTaskRunnerFault(sender, message, errorMessage); + })) + .withTimeout(TRADE_TIMEOUT)) // extend timeout + .executeTasks(true); + awaitTradeLatch(); + } else { + // process sign contract request after contract signature requested + EasyBind.subscribe(trade.stateProperty(), state -> { + if (state == Trade.State.CONTRACT_SIGNATURE_REQUESTED) new Thread(() -> handleSignContractRequest(message, sender)).start(); // process notification without trade lock + }); + } + } + } + + @Override + public void handleSignContractResponse(SignContractResponse message, NodeAddress sender) { + System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse() " + trade.getId()); + synchronized (trade) { + Validator.checkTradeId(processModel.getOfferId(), message); + if (trade.getState() == Trade.State.CONTRACT_SIGNED) { + latchTrade(); + Validator.checkTradeId(processModel.getOfferId(), message); + processModel.setTradeMessage(message); + expect(state(Trade.State.CONTRACT_SIGNED) .with(message) .from(sender)) .setup(tasks( @@ -178,11 +186,12 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol handleTaskRunnerFault(sender, message, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) // extend timeout - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } else { + // process sign contract response after contract signed EasyBind.subscribe(trade.stateProperty(), state -> { - if (state == Trade.State.CONTRACT_SIGNATURE_REQUESTED) new Thread(() -> handleSignContractResponse(message, sender)).start(); // process notification without trade lock + if (state == Trade.State.CONTRACT_SIGNED) new Thread(() -> handleSignContractResponse(message, sender)).start(); // process notification without trade lock }); } } @@ -210,7 +219,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol handleTaskRunnerFault(sender, response, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } } @@ -241,7 +250,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol handleTaskRunnerFault(sender, request, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } else { EasyBind.subscribe(trade.stateProperty(), state -> { @@ -295,7 +304,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol BuyerFinalizesDelayedPayoutTx.class, BuyerSendsDelayedPayoutTxSignatureResponse.class) .withTimeout(60)) - .executeTasks(); + .executeTasks(true); } // We keep the handler here in as well to make it more transparent which messages we expect diff --git a/core/src/main/java/bisq/core/trade/protocol/BuyerAsTakerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/BuyerAsTakerProtocol.java index e6054e6fd8..9597bbe537 100644 --- a/core/src/main/java/bisq/core/trade/protocol/BuyerAsTakerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/BuyerAsTakerProtocol.java @@ -112,7 +112,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol handleError(errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } } @@ -139,35 +139,43 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol handleTaskRunnerFault(sender, request, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } } @Override public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) { - System.out.println(getClass().getCanonicalName() + ".handleSignContractRequest()"); + System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse() " + trade.getId()); synchronized (trade) { - latchTrade(); Validator.checkTradeId(processModel.getOfferId(), message); - processModel.setTradeMessage(message); - expect(anyPhase(Trade.Phase.INIT) - .with(message) - .from(sender)) - .setup(tasks( - // TODO (woodser): validate request - ProcessSignContractRequest.class) - .using(new TradeTaskRunner(trade, - () -> { - startTimeout(TRADE_TIMEOUT); - handleTaskRunnerSuccess(sender, message); - }, - errorMessage -> { - handleTaskRunnerFault(sender, message, errorMessage); - })) - .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); - awaitTradeLatch(); + if (trade.getState() == Trade.State.CONTRACT_SIGNATURE_REQUESTED) { + latchTrade(); + Validator.checkTradeId(processModel.getOfferId(), message); + processModel.setTradeMessage(message); + expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED) + .with(message) + .from(sender)) + .setup(tasks( + // TODO (woodser): validate request + ProcessSignContractRequest.class) + .using(new TradeTaskRunner(trade, + () -> { + startTimeout(TRADE_TIMEOUT); + handleTaskRunnerSuccess(sender, message); + }, + errorMessage -> { + handleTaskRunnerFault(sender, message, errorMessage); + })) + .withTimeout(TRADE_TIMEOUT)) // extend timeout + .executeTasks(true); + awaitTradeLatch(); + } else { + // process sign contract request after contract signature requested + EasyBind.subscribe(trade.stateProperty(), state -> { + if (state == Trade.State.CONTRACT_SIGNATURE_REQUESTED) new Thread(() -> handleSignContractRequest(message, sender)).start(); // process notification without trade lock + }); + } } } @@ -176,11 +184,11 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse()"); synchronized (trade) { Validator.checkTradeId(processModel.getOfferId(), message); - if (trade.getState() == Trade.State.CONTRACT_SIGNATURE_REQUESTED) { + if (trade.getState() == Trade.State.CONTRACT_SIGNED) { latchTrade(); Validator.checkTradeId(processModel.getOfferId(), message); processModel.setTradeMessage(message); - expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED) + expect(state(Trade.State.CONTRACT_SIGNED) .with(message) .from(sender)) .setup(tasks( @@ -195,11 +203,11 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol handleTaskRunnerFault(sender, message, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) // extend timeout - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } else { EasyBind.subscribe(trade.stateProperty(), state -> { - if (state == Trade.State.CONTRACT_SIGNATURE_REQUESTED) new Thread(() -> handleSignContractResponse(message, sender)).start(); // process notification without trade lock + if (state == Trade.State.CONTRACT_SIGNED) new Thread(() -> handleSignContractResponse(message, sender)).start(); // process notification without trade lock }); } } @@ -227,7 +235,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol handleTaskRunnerFault(sender, response, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } } @@ -258,7 +266,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol handleTaskRunnerFault(sender, request, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } else { EasyBind.subscribe(trade.stateProperty(), state -> { @@ -325,7 +333,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol BuyerSetupDepositTxListener.class, BuyerAsTakerSendsDepositTxMessage.class) .withTimeout(60)) - .executeTasks(); + .executeTasks(true); } @Override @@ -340,7 +348,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol BuyerFinalizesDelayedPayoutTx.class, BuyerSendsDelayedPayoutTxSignatureResponse.class) .withTimeout(60)) - .executeTasks(); + .executeTasks(true); } // We keep the handler here in as well to make it more transparent which messages we expect diff --git a/core/src/main/java/bisq/core/trade/protocol/BuyerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/BuyerProtocol.java index 254bebd50e..1c0d1f8073 100644 --- a/core/src/main/java/bisq/core/trade/protocol/BuyerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/BuyerProtocol.java @@ -161,7 +161,7 @@ public abstract class BuyerProtocol extends DisputeProtocol { latchTrade(); Validator.checkTradeId(processModel.getOfferId(), message); processModel.setTradeMessage(message); - expect(anyPhase(Trade.Phase.PAYMENT_SENT, Trade.Phase.PAYOUT_PUBLISHED) + expect(anyPhase(Trade.Phase.PAYMENT_SENT, Trade.Phase.PAYMENT_RECEIVED) .with(message) .from(peer)) .setup(tasks( @@ -177,7 +177,7 @@ public abstract class BuyerProtocol extends DisputeProtocol { handleTaskRunnerFault(peer, message, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } } @@ -191,9 +191,6 @@ public abstract class BuyerProtocol extends DisputeProtocol { protected void onTradeMessage(TradeMessage message, NodeAddress peer) { super.onTradeMessage(message, peer); - log.info("Received {} from {} with tradeId {} and uid {}", - message.getClass().getSimpleName(), peer, message.getTradeId(), message.getUid()); - if (message instanceof DelayedPayoutTxSignatureRequest) { handle((DelayedPayoutTxSignatureRequest) message, peer); } else if (message instanceof DepositTxAndDelayedPayoutTxMessage) { diff --git a/core/src/main/java/bisq/core/trade/protocol/FluentProtocol.java b/core/src/main/java/bisq/core/trade/protocol/FluentProtocol.java index cc24fcbfb7..5150196b3a 100644 --- a/core/src/main/java/bisq/core/trade/protocol/FluentProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/FluentProtocol.java @@ -83,6 +83,17 @@ public class FluentProtocol { return this; } + public FluentProtocol executeTasks(boolean newThread) { + if (newThread) { + new Thread(() -> { + executeTasks(); + }).start(); + } else { + executeTasks(); + } + return this; + } + public FluentProtocol executeTasks() { Condition.Result result = condition.getResult(); if (!result.isValid) { @@ -92,30 +103,27 @@ public class FluentProtocol { return this; } - synchronized (tradeProtocol.trade) { - if (setup.getTimeoutSec() > 0) { - tradeProtocol.startTimeout(setup.getTimeoutSec()); - } - - NodeAddress peer = condition.getPeer(); - if (peer != null) { - tradeProtocol.processModel.setTempTradingPeerNodeAddress(peer); // TODO (woodser): node has multiple peers (arbitrator and maker or taker), but fluent protocol assumes only one - tradeProtocol.processModel.getTradeManager().requestPersistence(); - } - - TradeMessage message = condition.getMessage(); - if (message != null) { - tradeProtocol.processModel.setTradeMessage(message); - tradeProtocol.processModel.getTradeManager().requestPersistence(); - } - - TradeTaskRunner taskRunner = setup.getTaskRunner(peer, message, condition.getEvent()); - taskRunner.addTasks(setup.getTasks()); - taskRunner.run(); - return this; + if (setup.getTimeoutSec() > 0) { + tradeProtocol.startTimeout(setup.getTimeoutSec()); } - } + NodeAddress peer = condition.getPeer(); + if (peer != null) { + tradeProtocol.processModel.setTempTradingPeerNodeAddress(peer); // TODO (woodser): node has multiple peers (arbitrator and maker or taker), but fluent protocol assumes only one + tradeProtocol.processModel.getTradeManager().requestPersistence(); + } + + TradeMessage message = condition.getMessage(); + if (message != null) { + tradeProtocol.processModel.setTradeMessage(message); + tradeProtocol.processModel.getTradeManager().requestPersistence(); + } + + TradeTaskRunner taskRunner = setup.getTaskRunner(peer, message, condition.getEvent()); + taskRunner.addTasks(setup.getTasks()); + taskRunner.run(); + return this; + } /////////////////////////////////////////////////////////////////////////////////////////// // Condition class diff --git a/core/src/main/java/bisq/core/trade/protocol/SellerAsMakerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/SellerAsMakerProtocol.java index fa75aec285..4cfb4f13e8 100644 --- a/core/src/main/java/bisq/core/trade/protocol/SellerAsMakerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/SellerAsMakerProtocol.java @@ -95,7 +95,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc handleTaskRunnerFault(peer, message, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } } @@ -122,35 +122,43 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc handleTaskRunnerFault(sender, request, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } } @Override public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) { - System.out.println(getClass().getCanonicalName() + ".handleSignContractRequest()"); + System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse() " + trade.getId()); synchronized (trade) { - latchTrade(); Validator.checkTradeId(processModel.getOfferId(), message); - processModel.setTradeMessage(message); - expect(anyPhase(Trade.Phase.INIT) - .with(message) - .from(sender)) - .setup(tasks( - // TODO (woodser): validate request - ProcessSignContractRequest.class) - .using(new TradeTaskRunner(trade, - () -> { - startTimeout(TRADE_TIMEOUT); - handleTaskRunnerSuccess(sender, message); - }, - errorMessage -> { - handleTaskRunnerFault(sender, message, errorMessage); - })) - .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); - awaitTradeLatch(); + if (trade.getState() == Trade.State.CONTRACT_SIGNATURE_REQUESTED) { + latchTrade(); + Validator.checkTradeId(processModel.getOfferId(), message); + processModel.setTradeMessage(message); + expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED) + .with(message) + .from(sender)) + .setup(tasks( + // TODO (woodser): validate request + ProcessSignContractRequest.class) + .using(new TradeTaskRunner(trade, + () -> { + startTimeout(TRADE_TIMEOUT); + handleTaskRunnerSuccess(sender, message); + }, + errorMessage -> { + handleTaskRunnerFault(sender, message, errorMessage); + })) + .withTimeout(TRADE_TIMEOUT)) // extend timeout + .executeTasks(true); + awaitTradeLatch(); + } else { + // process sign contract request after contract signature requested + EasyBind.subscribe(trade.stateProperty(), state -> { + if (state == Trade.State.CONTRACT_SIGNATURE_REQUESTED) new Thread(() -> handleSignContractRequest(message, sender)).start(); // process notification without trade lock + }); + } } } @@ -159,11 +167,11 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse()"); synchronized (trade) { Validator.checkTradeId(processModel.getOfferId(), message); - if (trade.getState() == Trade.State.CONTRACT_SIGNATURE_REQUESTED) { + if (trade.getState() == Trade.State.CONTRACT_SIGNED) { latchTrade(); Validator.checkTradeId(processModel.getOfferId(), message); processModel.setTradeMessage(message); - expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED) + expect(state(Trade.State.CONTRACT_SIGNED) .with(message) .from(sender)) .setup(tasks( @@ -178,11 +186,11 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc handleTaskRunnerFault(sender, message, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) // extend timeout - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } else { EasyBind.subscribe(trade.stateProperty(), state -> { - if (state == Trade.State.CONTRACT_SIGNATURE_REQUESTED) new Thread(() -> handleSignContractResponse(message, sender)).start(); // process notification without trade lock + if (state == Trade.State.CONTRACT_SIGNED) new Thread(() -> handleSignContractResponse(message, sender)).start(); // process notification without trade lock }); } } @@ -210,7 +218,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc handleTaskRunnerFault(sender, response, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } } @@ -241,7 +249,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc handleTaskRunnerFault(sender, request, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } else { EasyBind.subscribe(trade.stateProperty(), state -> { @@ -300,7 +308,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc SellerSignsDelayedPayoutTx.class, SellerSendDelayedPayoutTxSignatureRequest.class) .withTimeout(60)) - .executeTasks(); + .executeTasks(true); } diff --git a/core/src/main/java/bisq/core/trade/protocol/SellerAsTakerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/SellerAsTakerProtocol.java index cb8f86298b..caa6be17dc 100644 --- a/core/src/main/java/bisq/core/trade/protocol/SellerAsTakerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/SellerAsTakerProtocol.java @@ -105,7 +105,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc handleError(errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } } @@ -132,40 +132,13 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc handleTaskRunnerFault(sender, request, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } } @Override public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) { - System.out.println(getClass().getCanonicalName() + ".handleSignContractRequest()"); - synchronized (trade) { - latchTrade(); - Validator.checkTradeId(processModel.getOfferId(), message); - processModel.setTradeMessage(message); - expect(anyPhase(Trade.Phase.INIT) - .with(message) - .from(sender)) - .setup(tasks( - // TODO (woodser): validate request - ProcessSignContractRequest.class) - .using(new TradeTaskRunner(trade, - () -> { - startTimeout(TRADE_TIMEOUT); - handleTaskRunnerSuccess(sender, message); - }, - errorMessage -> { - handleTaskRunnerFault(sender, message, errorMessage); - })) - .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); - awaitTradeLatch(); - } - } - - @Override - public void handleSignContractResponse(SignContractResponse message, NodeAddress sender) { System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse() " + trade.getId()); synchronized (trade) { Validator.checkTradeId(processModel.getOfferId(), message); @@ -174,6 +147,41 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc Validator.checkTradeId(processModel.getOfferId(), message); processModel.setTradeMessage(message); expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED) + .with(message) + .from(sender)) + .setup(tasks( + // TODO (woodser): validate request + ProcessSignContractRequest.class) + .using(new TradeTaskRunner(trade, + () -> { + startTimeout(TRADE_TIMEOUT); + handleTaskRunnerSuccess(sender, message); + }, + errorMessage -> { + handleTaskRunnerFault(sender, message, errorMessage); + })) + .withTimeout(TRADE_TIMEOUT)) // extend timeout + .executeTasks(true); + awaitTradeLatch(); + } else { + // process sign contract request after contract signature requested + EasyBind.subscribe(trade.stateProperty(), state -> { + if (state == Trade.State.CONTRACT_SIGNATURE_REQUESTED) new Thread(() -> handleSignContractRequest(message, sender)).start(); // process notification without trade lock + }); + } + } + } + + @Override + public void handleSignContractResponse(SignContractResponse message, NodeAddress sender) { + System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse() " + trade.getId()); + synchronized (trade) { + Validator.checkTradeId(processModel.getOfferId(), message); + if (trade.getState() == Trade.State.CONTRACT_SIGNED) { + latchTrade(); + Validator.checkTradeId(processModel.getOfferId(), message); + processModel.setTradeMessage(message); + expect(state(Trade.State.CONTRACT_SIGNED) .with(message) .from(sender)) .setup(tasks( @@ -188,11 +196,11 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc handleTaskRunnerFault(sender, message, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) // extend timeout - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } else { EasyBind.subscribe(trade.stateProperty(), state -> { - if (state == Trade.State.CONTRACT_SIGNATURE_REQUESTED) new Thread(() -> handleSignContractResponse(message, sender)).start(); // process notification without trade lock + if (state == Trade.State.CONTRACT_SIGNED) new Thread(() -> handleSignContractResponse(message, sender)).start(); // process notification without trade lock }); } } @@ -220,7 +228,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc handleTaskRunnerFault(sender, response, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } } @@ -251,7 +259,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc handleTaskRunnerFault(sender, request, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } else { EasyBind.subscribe(trade.stateProperty(), state -> { @@ -324,6 +332,6 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc SellerSignsDelayedPayoutTx.class, SellerSendDelayedPayoutTxSignatureRequest.class) .withTimeout(60)) - .executeTasks(); + .executeTasks(true); } } diff --git a/core/src/main/java/bisq/core/trade/protocol/SellerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/SellerProtocol.java index 89d2c425c6..ab361513d7 100644 --- a/core/src/main/java/bisq/core/trade/protocol/SellerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/SellerProtocol.java @@ -113,7 +113,7 @@ public abstract class SellerProtocol extends DisputeProtocol { handleTaskRunnerFault(peer, message, errorMessage); })) .withTimeout(TRADE_TIMEOUT)) - .executeTasks(); + .executeTasks(true); awaitTradeLatch(); } } @@ -126,7 +126,7 @@ public abstract class SellerProtocol extends DisputeProtocol { log.info("SellerProtocol.onPaymentReceived()"); synchronized (trade) { SellerEvent event = SellerEvent.PAYMENT_RECEIVED; - expect(anyPhase(Trade.Phase.PAYMENT_SENT) + expect(anyPhase(Trade.Phase.PAYMENT_SENT, Trade.Phase.PAYMENT_RECEIVED) .with(event) .preCondition(trade.confirmPermitted())) .setup(tasks( diff --git a/core/src/main/java/bisq/core/trade/protocol/TradeProtocol.java b/core/src/main/java/bisq/core/trade/protocol/TradeProtocol.java index 2028a967b7..a3d0568485 100644 --- a/core/src/main/java/bisq/core/trade/protocol/TradeProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/TradeProtocol.java @@ -461,6 +461,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D handleError(errorMessage); } + // these are not thread safe, so they must be used within a lock on the trade protected void handleError(String errorMessage) { stopTimeout(); diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/ProcessSignContractRequest.java b/core/src/main/java/bisq/core/trade/protocol/tasks/ProcessSignContractRequest.java index e249227453..6e10528039 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/ProcessSignContractRequest.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/ProcessSignContractRequest.java @@ -134,7 +134,7 @@ public class ProcessSignContractRequest extends TradeTask { } private void completeAux() { - trade.setState(State.CONTRACT_SIGNATURE_REQUESTED); // TODO: rename to contract_signature_request_received + trade.setState(State.CONTRACT_SIGNED); processModel.getTradeManager().requestPersistence(); complete(); } diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/SendSignContractRequestAfterMultisig.java b/core/src/main/java/bisq/core/trade/protocol/tasks/SendSignContractRequestAfterMultisig.java index 72f3a96d31..477b73e6a4 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/SendSignContractRequestAfterMultisig.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/SendSignContractRequestAfterMultisig.java @@ -21,6 +21,7 @@ import bisq.common.app.Version; import bisq.common.taskrunner.TaskRunner; import bisq.core.btc.model.XmrAddressEntry; import bisq.core.trade.Trade; +import bisq.core.trade.Trade.State; import bisq.core.trade.messages.SignContractRequest; import bisq.network.p2p.SendDirectMessageListener; import java.util.Date; @@ -124,6 +125,7 @@ public class SendSignContractRequestAfterMultisig extends TradeTask { } private void completeAux() { + trade.setState(State.CONTRACT_SIGNATURE_REQUESTED); processModel.getTradeManager().requestPersistence(); processModel.getXmrWalletService().saveWallet(processModel.getXmrWalletService().getWallet()); complete(); diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerSendsPaymentSentMessage.java b/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerSendsPaymentSentMessage.java index b939435bea..4c757c6a27 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerSendsPaymentSentMessage.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerSendsPaymentSentMessage.java @@ -97,6 +97,7 @@ public class BuyerSendsPaymentSentMessage extends SendMailboxMessageTask { @Override protected void setStateArrived() { + trade.setStateIfValidTransitionTo(Trade.State.BUYER_SAW_ARRIVED_PAYMENT_SENT_MSG); // the message has arrived but we're ultimately waiting for an AckMessage response if (!trade.isPayoutPublished()) { tryToSendAgainLater(); diff --git a/desktop/src/main/java/bisq/desktop/components/TxIdTextField.java b/desktop/src/main/java/bisq/desktop/components/TxIdTextField.java index 73b99b56bd..277fa6cce4 100644 --- a/desktop/src/main/java/bisq/desktop/components/TxIdTextField.java +++ b/desktop/src/main/java/bisq/desktop/components/TxIdTextField.java @@ -40,7 +40,7 @@ import javafx.scene.layout.AnchorPane; import lombok.Getter; import lombok.Setter; -import monero.wallet.model.MoneroTxWallet; +import monero.daemon.model.MoneroTx; import monero.wallet.model.MoneroWalletListener; import javax.annotation.Nullable; @@ -176,9 +176,10 @@ public class TxIdTextField extends AnchorPane { } private void updateConfidence(String txId) { - MoneroTxWallet tx = null; + MoneroTx tx = null; try { - tx = xmrWalletService.getWallet().getTx(txId); + tx = xmrWalletService.getDaemon().getTx(txId); // TODO: cache results and don't re-fetch + tx.setNumConfirmations(tx.isConfirmed() ? xmrWalletService.getConnectionsService().getLastInfo().getHeight() - tx.getHeight() : 0l); // TODO: use tx.getNumConfirmations() when MoneroDaemonRpc supports it } catch (Exception e) { // do nothing } @@ -188,6 +189,10 @@ public class TxIdTextField extends AnchorPane { txConfidenceIndicator.setVisible(true); AnchorPane.setRightAnchor(txConfidenceIndicator, 0.0); } + if (txConfidenceIndicator.getProgress() >= 1.0 && txUpdater != null) { + xmrWalletService.removeWalletListener(txUpdater); // unregister listener + txUpdater = null; + } } else { //TODO we should show some placeholder in case of a tx which we are not aware of but which can be // confirmed already. This is for instance the case of the other peers trade fee tx, as it is not related diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesView.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesView.java index af95e605ba..65582c0979 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesView.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesView.java @@ -640,11 +640,7 @@ public class PendingTradesView extends ActivatableViewAndModel Platform.runLater(new Runnable() { - @Override public void run() { - update(); - } - }); + listener = (observable, oldValue, newValue) -> UserThread.execute(() -> update()); trade.stateProperty().addListener(listener); update(); } else { @@ -805,7 +801,6 @@ public class PendingTradesView extends ActivatableViewAndModel errorMessageListener; protected Label infoLabel; @@ -175,15 +175,11 @@ public abstract class TradeStepView extends AnchorPane { } public void activate() { - UserThread.execute(() -> { activateAux(); }); - } - - private void activateAux() { if (selfTxIdTextField != null) { - if (makerTxIdSubscription != null) - makerTxIdSubscription.unsubscribe(); + if (selfTxIdSubscription != null) + selfTxIdSubscription.unsubscribe(); - makerTxIdSubscription = EasyBind.subscribe(model.dataModel.makerTxId, id -> { + selfTxIdSubscription = EasyBind.subscribe(model.dataModel.isMaker() ? model.dataModel.makerTxId : model.dataModel.takerTxId, id -> { if (!id.isEmpty()) selfTxIdTextField.setup(id); else @@ -191,10 +187,10 @@ public abstract class TradeStepView extends AnchorPane { }); } if (peerTxIdTextField != null) { - if (takerTxIdSubscription != null) - takerTxIdSubscription.unsubscribe(); + if (peerTxIdSubscription != null) + peerTxIdSubscription.unsubscribe(); - takerTxIdSubscription = EasyBind.subscribe(model.dataModel.takerTxId, id -> { + selfTxIdSubscription = EasyBind.subscribe(model.dataModel.isMaker() ? model.dataModel.takerTxId : model.dataModel.makerTxId, id -> { if (!id.isEmpty()) peerTxIdTextField.setup(id); else @@ -288,10 +284,10 @@ public abstract class TradeStepView extends AnchorPane { } public void deactivate() { - if (makerTxIdSubscription != null) - makerTxIdSubscription.unsubscribe(); - if (takerTxIdSubscription != null) - takerTxIdSubscription.unsubscribe(); + if (selfTxIdSubscription != null) + selfTxIdSubscription.unsubscribe(); + if (peerTxIdSubscription != null) + peerTxIdSubscription.unsubscribe(); if (selfTxIdTextField != null) selfTxIdTextField.cleanup(); diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java index 428ff685a3..2a6435f77c 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java @@ -155,7 +155,7 @@ public class BuyerStep2View extends TradeStepView { if (timeoutTimer != null) timeoutTimer.stop(); - if (trade.isDepositConfirmed() && !trade.isPaymentSent()) { + if (trade.isDepositUnlocked() && !trade.isPaymentSent()) { showPopup(); } else if (state.ordinal() <= Trade.State.BUYER_SEND_FAILED_PAYMENT_SENT_MSG.ordinal()) { if (!trade.hasFailed()) { diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java index b079b96d96..3ed7b7e68d 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java @@ -136,6 +136,7 @@ public class SellerStep3View extends TradeStepView { busyAnimation.stop(); statusLabel.setText(Res.get("shared.messageArrived")); break; + case SELLER_STORED_IN_MAILBOX_PAYMENT_RECEIVED_MSG: case SELLER_STORED_IN_MAILBOX_PAYOUT_TX_PUBLISHED_MSG: busyAnimation.stop(); statusLabel.setText(Res.get("shared.messageStoredInMailbox")); diff --git a/desktop/src/main/java/bisq/desktop/util/GUIUtil.java b/desktop/src/main/java/bisq/desktop/util/GUIUtil.java index bf5ad29604..359b8f4785 100644 --- a/desktop/src/main/java/bisq/desktop/util/GUIUtil.java +++ b/desktop/src/main/java/bisq/desktop/util/GUIUtil.java @@ -65,7 +65,6 @@ import bisq.common.util.Utilities; import org.bitcoinj.core.Address; import org.bitcoinj.core.Coin; -import org.bitcoinj.core.TransactionConfidence; import org.bitcoinj.uri.BitcoinURI; import com.googlecode.jcsv.CSVStrategy; @@ -135,7 +134,7 @@ import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import lombok.extern.slf4j.Slf4j; -import monero.wallet.model.MoneroTxWallet; +import monero.daemon.model.MoneroTx; import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; @@ -567,7 +566,7 @@ public class GUIUtil { }; } - public static void updateConfidence(MoneroTxWallet tx, + public static void updateConfidence(MoneroTx tx, Tooltip tooltip, TxConfidenceIndicator txConfidenceIndicator) { if (tx != null) {