mirror of
https://github.com/retoaccess1/haveno-reto.git
synced 2024-11-10 13:13:36 +01:00
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
This commit is contained in:
parent
3dcaf67edd
commit
a3a5b96c06
@ -154,7 +154,7 @@ public class TradeInfo implements Payload {
|
|||||||
.withPhase(trade.getPhase().name())
|
.withPhase(trade.getPhase().name())
|
||||||
.withPeriodState(trade.getPeriodState().name())
|
.withPeriodState(trade.getPeriodState().name())
|
||||||
.withIsDepositPublished(trade.isDepositPublished())
|
.withIsDepositPublished(trade.isDepositPublished())
|
||||||
.withIsDepositUnlocked(trade.isDepositConfirmed())
|
.withIsDepositUnlocked(trade.isDepositUnlocked())
|
||||||
.withIsPaymentSent(trade.isPaymentSent())
|
.withIsPaymentSent(trade.isPaymentSent())
|
||||||
.withIsPaymentReceived(trade.isPaymentReceived())
|
.withIsPaymentReceived(trade.isPaymentReceived())
|
||||||
.withIsPayoutPublished(trade.isPayoutPublished())
|
.withIsPayoutPublished(trade.isPayoutPublished())
|
||||||
|
@ -39,7 +39,7 @@ import bisq.core.util.ParsingUtils;
|
|||||||
import bisq.core.util.VolumeUtil;
|
import bisq.core.util.VolumeUtil;
|
||||||
import bisq.network.p2p.AckMessage;
|
import bisq.network.p2p.AckMessage;
|
||||||
import bisq.network.p2p.NodeAddress;
|
import bisq.network.p2p.NodeAddress;
|
||||||
|
import bisq.common.UserThread;
|
||||||
import bisq.common.crypto.PubKeyRing;
|
import bisq.common.crypto.PubKeyRing;
|
||||||
import bisq.common.proto.ProtoUtil;
|
import bisq.common.proto.ProtoUtil;
|
||||||
import bisq.common.taskrunner.Model;
|
import bisq.common.taskrunner.Model;
|
||||||
@ -876,20 +876,19 @@ public abstract class Trade implements Tradable, Model {
|
|||||||
|
|
||||||
// handle deposit txs seen
|
// handle deposit txs seen
|
||||||
if (txs.size() == 2) {
|
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());
|
boolean makerFirst = txs.get(0).getHash().equals(processModel.getMaker().getDepositTxHash());
|
||||||
makerDepositTx = makerFirst ? txs.get(0) : txs.get(1);
|
makerDepositTx = makerFirst ? txs.get(0) : txs.get(1);
|
||||||
takerDepositTx = makerFirst ? txs.get(1) : txs.get(0);
|
takerDepositTx = makerFirst ? txs.get(1) : txs.get(0);
|
||||||
|
|
||||||
// check if deposit txs unlocked
|
// check if deposit txs unlocked
|
||||||
if (txs.get(0).isConfirmed() && txs.get(1).isConfirmed()) {
|
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) {
|
if (havenoWallet.getHeight() >= unlockHeight) {
|
||||||
setConfirmedState();
|
setUnlockedState();
|
||||||
return;
|
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
|
@Override
|
||||||
public void onNewBlock(long height) {
|
public void onNewBlock(long height) {
|
||||||
|
|
||||||
// ignore if no longer listening
|
// ignore if no longer listening
|
||||||
if (depositTxListener == null) return;
|
if (depositTxListener == null) return;
|
||||||
|
|
||||||
// ignore if before unlock height
|
// ignore if before unlock height
|
||||||
if (unlockHeight != null && height < unlockHeight) return;
|
if (unlockHeight != null && height < unlockHeight) return;
|
||||||
|
|
||||||
// fetch txs from daemon
|
// fetch txs from daemon
|
||||||
List<MoneroTx> txs = daemon.getTxs(Arrays.asList(processModel.getMaker().getDepositTxHash(), processModel.getTaker().getDepositTxHash()), true);
|
List<MoneroTx> txs = daemon.getTxs(Arrays.asList(processModel.getMaker().getDepositTxHash(), processModel.getTaker().getDepositTxHash()), true);
|
||||||
|
|
||||||
// ignore if deposit txs not seen
|
// ignore if deposit txs not seen
|
||||||
if (txs.size() != 2) return;
|
if (txs.size() != 2) return;
|
||||||
|
|
||||||
// update deposit txs
|
// update deposit txs
|
||||||
boolean makerFirst = txs.get(0).getHash().equals(processModel.getMaker().getDepositTxHash());
|
boolean makerFirst = txs.get(0).getHash().equals(processModel.getMaker().getDepositTxHash());
|
||||||
makerDepositTx = makerFirst ? txs.get(0) : txs.get(1);
|
makerDepositTx = makerFirst ? txs.get(0) : txs.get(1);
|
||||||
takerDepositTx = makerFirst ? txs.get(1) : txs.get(0);
|
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
|
// compute unlock height
|
||||||
if (unlockHeight == null && txs.size() == 2 && txs.get(0).isConfirmed() && txs.get(1).isConfirmed()) {
|
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) {
|
if (unlockHeight != null && height == unlockHeight) {
|
||||||
log.info("Multisig deposits unlocked for trade {}", getId());
|
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
|
xmrWalletService.removeWalletListener(depositTxListener); // remove listener when notified
|
||||||
depositTxListener = null; // prevent re-applying trade state in subsequent requests
|
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;
|
this.state = state;
|
||||||
stateProperty.set(state);
|
UserThread.execute(() -> {
|
||||||
statePhaseProperty.set(state.getPhase());
|
stateProperty.set(state);
|
||||||
|
statePhaseProperty.set(state.getPhase());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDisputeState(DisputeState disputeState) {
|
public void setDisputeState(DisputeState disputeState) {
|
||||||
@ -1242,7 +1240,7 @@ public abstract class Trade implements Tradable, Model {
|
|||||||
final MoneroTx takerDepositTx = getTakerDepositTx();
|
final MoneroTx takerDepositTx = getTakerDepositTx();
|
||||||
final MoneroTx makerDepositTx = getMakerDepositTx();
|
final MoneroTx makerDepositTx = getMakerDepositTx();
|
||||||
if (makerDepositTx != null && takerDepositTx != null && getTakeOfferDate() != null) {
|
if (makerDepositTx != null && takerDepositTx != null && getTakeOfferDate() != null) {
|
||||||
if (isDepositConfirmed()) {
|
if (isDepositUnlocked()) {
|
||||||
final long tradeTime = getTakeOfferDate().getTime();
|
final long tradeTime = getTakeOfferDate().getTime();
|
||||||
long maxHeight = Math.max(makerDepositTx.getHeight(), takerDepositTx.getHeight());
|
long maxHeight = Math.max(makerDepositTx.getHeight(), takerDepositTx.getHeight());
|
||||||
MoneroDaemon daemonRpc = xmrWalletService.getDaemon();
|
MoneroDaemon daemonRpc = xmrWalletService.getDaemon();
|
||||||
@ -1318,7 +1316,7 @@ public abstract class Trade implements Tradable, Model {
|
|||||||
disputeState != DisputeState.REFUND_REQUEST_CLOSED;
|
disputeState != DisputeState.REFUND_REQUEST_CLOSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDepositConfirmed() {
|
public boolean isDepositUnlocked() {
|
||||||
return getState().getPhase().ordinal() >= Phase.DEPOSIT_UNLOCKED.ordinal();
|
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
|
// 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.
|
// 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
|
// 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.
|
// 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -884,8 +884,8 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateTradePeriodState() {
|
private void updateTradePeriodState() {
|
||||||
getObservableList().forEach(trade -> {
|
UserThread.execute(() -> { // prevent concurrent modification error
|
||||||
UserThread.execute(() -> { // prevent concurrent modification error
|
getObservableList().forEach(trade -> {
|
||||||
if (!trade.isPayoutPublished()) {
|
if (!trade.isPayoutPublished()) {
|
||||||
Date maxTradePeriodDate = trade.getMaxTradePeriodDate();
|
Date maxTradePeriodDate = trade.getMaxTradePeriodDate();
|
||||||
Date halfTradePeriodDate = trade.getHalfTradePeriodDate();
|
Date halfTradePeriodDate = trade.getHalfTradePeriodDate();
|
||||||
|
@ -53,7 +53,7 @@ public class ArbitratorProtocol extends DisputeProtocol {
|
|||||||
handleTaskRunnerFault(peer, message, errorMessage);
|
handleTaskRunnerFault(peer, message, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,7 +79,7 @@ public class ArbitratorProtocol extends DisputeProtocol {
|
|||||||
handleTaskRunnerFault(sender, request, errorMessage);
|
handleTaskRunnerFault(sender, request, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,7 +106,7 @@ public class ArbitratorProtocol extends DisputeProtocol {
|
|||||||
handleTaskRunnerFault(sender, message, errorMessage);
|
handleTaskRunnerFault(sender, message, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,7 +134,7 @@ public class ArbitratorProtocol extends DisputeProtocol {
|
|||||||
handleTaskRunnerFault(sender, request, errorMessage);
|
handleTaskRunnerFault(sender, request, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
* 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
|
* 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);
|
handleTaskRunnerFault(peer, message, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,40 +122,13 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
|||||||
handleTaskRunnerFault(sender, request, errorMessage);
|
handleTaskRunnerFault(sender, request, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) {
|
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());
|
System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse() " + trade.getId());
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
@ -164,6 +137,41 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
|||||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
processModel.setTradeMessage(message);
|
processModel.setTradeMessage(message);
|
||||||
expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED)
|
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)
|
.with(message)
|
||||||
.from(sender))
|
.from(sender))
|
||||||
.setup(tasks(
|
.setup(tasks(
|
||||||
@ -178,11 +186,12 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
|||||||
handleTaskRunnerFault(sender, message, errorMessage);
|
handleTaskRunnerFault(sender, message, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
} else {
|
} else {
|
||||||
|
// process sign contract response after contract signed
|
||||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
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);
|
handleTaskRunnerFault(sender, response, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,7 +250,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
|||||||
handleTaskRunnerFault(sender, request, errorMessage);
|
handleTaskRunnerFault(sender, request, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
} else {
|
} else {
|
||||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||||
@ -295,7 +304,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
|||||||
BuyerFinalizesDelayedPayoutTx.class,
|
BuyerFinalizesDelayedPayoutTx.class,
|
||||||
BuyerSendsDelayedPayoutTxSignatureResponse.class)
|
BuyerSendsDelayedPayoutTxSignatureResponse.class)
|
||||||
.withTimeout(60))
|
.withTimeout(60))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We keep the handler here in as well to make it more transparent which messages we expect
|
// We keep the handler here in as well to make it more transparent which messages we expect
|
||||||
|
@ -112,7 +112,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
|||||||
handleError(errorMessage);
|
handleError(errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,35 +139,43 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
|||||||
handleTaskRunnerFault(sender, request, errorMessage);
|
handleTaskRunnerFault(sender, request, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) {
|
public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) {
|
||||||
System.out.println(getClass().getCanonicalName() + ".handleSignContractRequest()");
|
System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse() " + trade.getId());
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
latchTrade();
|
|
||||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
processModel.setTradeMessage(message);
|
if (trade.getState() == Trade.State.CONTRACT_SIGNATURE_REQUESTED) {
|
||||||
expect(anyPhase(Trade.Phase.INIT)
|
latchTrade();
|
||||||
.with(message)
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
.from(sender))
|
processModel.setTradeMessage(message);
|
||||||
.setup(tasks(
|
expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED)
|
||||||
// TODO (woodser): validate request
|
.with(message)
|
||||||
ProcessSignContractRequest.class)
|
.from(sender))
|
||||||
.using(new TradeTaskRunner(trade,
|
.setup(tasks(
|
||||||
() -> {
|
// TODO (woodser): validate request
|
||||||
startTimeout(TRADE_TIMEOUT);
|
ProcessSignContractRequest.class)
|
||||||
handleTaskRunnerSuccess(sender, message);
|
.using(new TradeTaskRunner(trade,
|
||||||
},
|
() -> {
|
||||||
errorMessage -> {
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerFault(sender, message, errorMessage);
|
handleTaskRunnerSuccess(sender, message);
|
||||||
}))
|
},
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
errorMessage -> {
|
||||||
.executeTasks();
|
handleTaskRunnerFault(sender, message, errorMessage);
|
||||||
awaitTradeLatch();
|
}))
|
||||||
|
.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()");
|
System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
if (trade.getState() == Trade.State.CONTRACT_SIGNATURE_REQUESTED) {
|
if (trade.getState() == Trade.State.CONTRACT_SIGNED) {
|
||||||
latchTrade();
|
latchTrade();
|
||||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
processModel.setTradeMessage(message);
|
processModel.setTradeMessage(message);
|
||||||
expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED)
|
expect(state(Trade.State.CONTRACT_SIGNED)
|
||||||
.with(message)
|
.with(message)
|
||||||
.from(sender))
|
.from(sender))
|
||||||
.setup(tasks(
|
.setup(tasks(
|
||||||
@ -195,11 +203,11 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
|||||||
handleTaskRunnerFault(sender, message, errorMessage);
|
handleTaskRunnerFault(sender, message, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
} else {
|
} else {
|
||||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
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);
|
handleTaskRunnerFault(sender, response, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -258,7 +266,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
|||||||
handleTaskRunnerFault(sender, request, errorMessage);
|
handleTaskRunnerFault(sender, request, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
} else {
|
} else {
|
||||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||||
@ -325,7 +333,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
|||||||
BuyerSetupDepositTxListener.class,
|
BuyerSetupDepositTxListener.class,
|
||||||
BuyerAsTakerSendsDepositTxMessage.class)
|
BuyerAsTakerSendsDepositTxMessage.class)
|
||||||
.withTimeout(60))
|
.withTimeout(60))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -340,7 +348,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
|||||||
BuyerFinalizesDelayedPayoutTx.class,
|
BuyerFinalizesDelayedPayoutTx.class,
|
||||||
BuyerSendsDelayedPayoutTxSignatureResponse.class)
|
BuyerSendsDelayedPayoutTxSignatureResponse.class)
|
||||||
.withTimeout(60))
|
.withTimeout(60))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We keep the handler here in as well to make it more transparent which messages we expect
|
// We keep the handler here in as well to make it more transparent which messages we expect
|
||||||
|
@ -161,7 +161,7 @@ public abstract class BuyerProtocol extends DisputeProtocol {
|
|||||||
latchTrade();
|
latchTrade();
|
||||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
processModel.setTradeMessage(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)
|
.with(message)
|
||||||
.from(peer))
|
.from(peer))
|
||||||
.setup(tasks(
|
.setup(tasks(
|
||||||
@ -177,7 +177,7 @@ public abstract class BuyerProtocol extends DisputeProtocol {
|
|||||||
handleTaskRunnerFault(peer, message, errorMessage);
|
handleTaskRunnerFault(peer, message, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -191,9 +191,6 @@ public abstract class BuyerProtocol extends DisputeProtocol {
|
|||||||
protected void onTradeMessage(TradeMessage message, NodeAddress peer) {
|
protected void onTradeMessage(TradeMessage message, NodeAddress peer) {
|
||||||
super.onTradeMessage(message, 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) {
|
if (message instanceof DelayedPayoutTxSignatureRequest) {
|
||||||
handle((DelayedPayoutTxSignatureRequest) message, peer);
|
handle((DelayedPayoutTxSignatureRequest) message, peer);
|
||||||
} else if (message instanceof DepositTxAndDelayedPayoutTxMessage) {
|
} else if (message instanceof DepositTxAndDelayedPayoutTxMessage) {
|
||||||
|
@ -83,6 +83,17 @@ public class FluentProtocol {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FluentProtocol executeTasks(boolean newThread) {
|
||||||
|
if (newThread) {
|
||||||
|
new Thread(() -> {
|
||||||
|
executeTasks();
|
||||||
|
}).start();
|
||||||
|
} else {
|
||||||
|
executeTasks();
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public FluentProtocol executeTasks() {
|
public FluentProtocol executeTasks() {
|
||||||
Condition.Result result = condition.getResult();
|
Condition.Result result = condition.getResult();
|
||||||
if (!result.isValid) {
|
if (!result.isValid) {
|
||||||
@ -92,30 +103,27 @@ public class FluentProtocol {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (tradeProtocol.trade) {
|
if (setup.getTimeoutSec() > 0) {
|
||||||
if (setup.getTimeoutSec() > 0) {
|
tradeProtocol.startTimeout(setup.getTimeoutSec());
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
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
|
// Condition class
|
||||||
|
@ -95,7 +95,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
|||||||
handleTaskRunnerFault(peer, message, errorMessage);
|
handleTaskRunnerFault(peer, message, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,35 +122,43 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
|||||||
handleTaskRunnerFault(sender, request, errorMessage);
|
handleTaskRunnerFault(sender, request, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) {
|
public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) {
|
||||||
System.out.println(getClass().getCanonicalName() + ".handleSignContractRequest()");
|
System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse() " + trade.getId());
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
latchTrade();
|
|
||||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
processModel.setTradeMessage(message);
|
if (trade.getState() == Trade.State.CONTRACT_SIGNATURE_REQUESTED) {
|
||||||
expect(anyPhase(Trade.Phase.INIT)
|
latchTrade();
|
||||||
.with(message)
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
.from(sender))
|
processModel.setTradeMessage(message);
|
||||||
.setup(tasks(
|
expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED)
|
||||||
// TODO (woodser): validate request
|
.with(message)
|
||||||
ProcessSignContractRequest.class)
|
.from(sender))
|
||||||
.using(new TradeTaskRunner(trade,
|
.setup(tasks(
|
||||||
() -> {
|
// TODO (woodser): validate request
|
||||||
startTimeout(TRADE_TIMEOUT);
|
ProcessSignContractRequest.class)
|
||||||
handleTaskRunnerSuccess(sender, message);
|
.using(new TradeTaskRunner(trade,
|
||||||
},
|
() -> {
|
||||||
errorMessage -> {
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerFault(sender, message, errorMessage);
|
handleTaskRunnerSuccess(sender, message);
|
||||||
}))
|
},
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
errorMessage -> {
|
||||||
.executeTasks();
|
handleTaskRunnerFault(sender, message, errorMessage);
|
||||||
awaitTradeLatch();
|
}))
|
||||||
|
.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()");
|
System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
if (trade.getState() == Trade.State.CONTRACT_SIGNATURE_REQUESTED) {
|
if (trade.getState() == Trade.State.CONTRACT_SIGNED) {
|
||||||
latchTrade();
|
latchTrade();
|
||||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
processModel.setTradeMessage(message);
|
processModel.setTradeMessage(message);
|
||||||
expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED)
|
expect(state(Trade.State.CONTRACT_SIGNED)
|
||||||
.with(message)
|
.with(message)
|
||||||
.from(sender))
|
.from(sender))
|
||||||
.setup(tasks(
|
.setup(tasks(
|
||||||
@ -178,11 +186,11 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
|||||||
handleTaskRunnerFault(sender, message, errorMessage);
|
handleTaskRunnerFault(sender, message, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
} else {
|
} else {
|
||||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
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);
|
handleTaskRunnerFault(sender, response, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,7 +249,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
|||||||
handleTaskRunnerFault(sender, request, errorMessage);
|
handleTaskRunnerFault(sender, request, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
} else {
|
} else {
|
||||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||||
@ -300,7 +308,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
|||||||
SellerSignsDelayedPayoutTx.class,
|
SellerSignsDelayedPayoutTx.class,
|
||||||
SellerSendDelayedPayoutTxSignatureRequest.class)
|
SellerSendDelayedPayoutTxSignatureRequest.class)
|
||||||
.withTimeout(60))
|
.withTimeout(60))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
|||||||
handleError(errorMessage);
|
handleError(errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,40 +132,13 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
|||||||
handleTaskRunnerFault(sender, request, errorMessage);
|
handleTaskRunnerFault(sender, request, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) {
|
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());
|
System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse() " + trade.getId());
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
@ -174,6 +147,41 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
|||||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
processModel.setTradeMessage(message);
|
processModel.setTradeMessage(message);
|
||||||
expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED)
|
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)
|
.with(message)
|
||||||
.from(sender))
|
.from(sender))
|
||||||
.setup(tasks(
|
.setup(tasks(
|
||||||
@ -188,11 +196,11 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
|||||||
handleTaskRunnerFault(sender, message, errorMessage);
|
handleTaskRunnerFault(sender, message, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
} else {
|
} else {
|
||||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
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);
|
handleTaskRunnerFault(sender, response, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -251,7 +259,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
|||||||
handleTaskRunnerFault(sender, request, errorMessage);
|
handleTaskRunnerFault(sender, request, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
} else {
|
} else {
|
||||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||||
@ -324,6 +332,6 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
|||||||
SellerSignsDelayedPayoutTx.class,
|
SellerSignsDelayedPayoutTx.class,
|
||||||
SellerSendDelayedPayoutTxSignatureRequest.class)
|
SellerSendDelayedPayoutTxSignatureRequest.class)
|
||||||
.withTimeout(60))
|
.withTimeout(60))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ public abstract class SellerProtocol extends DisputeProtocol {
|
|||||||
handleTaskRunnerFault(peer, message, errorMessage);
|
handleTaskRunnerFault(peer, message, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks(true);
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,7 +126,7 @@ public abstract class SellerProtocol extends DisputeProtocol {
|
|||||||
log.info("SellerProtocol.onPaymentReceived()");
|
log.info("SellerProtocol.onPaymentReceived()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
SellerEvent event = SellerEvent.PAYMENT_RECEIVED;
|
SellerEvent event = SellerEvent.PAYMENT_RECEIVED;
|
||||||
expect(anyPhase(Trade.Phase.PAYMENT_SENT)
|
expect(anyPhase(Trade.Phase.PAYMENT_SENT, Trade.Phase.PAYMENT_RECEIVED)
|
||||||
.with(event)
|
.with(event)
|
||||||
.preCondition(trade.confirmPermitted()))
|
.preCondition(trade.confirmPermitted()))
|
||||||
.setup(tasks(
|
.setup(tasks(
|
||||||
|
@ -461,6 +461,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
|||||||
handleError(errorMessage);
|
handleError(errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// these are not thread safe, so they must be used within a lock on the trade
|
||||||
|
|
||||||
protected void handleError(String errorMessage) {
|
protected void handleError(String errorMessage) {
|
||||||
stopTimeout();
|
stopTimeout();
|
||||||
|
@ -134,7 +134,7 @@ public class ProcessSignContractRequest extends TradeTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void completeAux() {
|
private void completeAux() {
|
||||||
trade.setState(State.CONTRACT_SIGNATURE_REQUESTED); // TODO: rename to contract_signature_request_received
|
trade.setState(State.CONTRACT_SIGNED);
|
||||||
processModel.getTradeManager().requestPersistence();
|
processModel.getTradeManager().requestPersistence();
|
||||||
complete();
|
complete();
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import bisq.common.app.Version;
|
|||||||
import bisq.common.taskrunner.TaskRunner;
|
import bisq.common.taskrunner.TaskRunner;
|
||||||
import bisq.core.btc.model.XmrAddressEntry;
|
import bisq.core.btc.model.XmrAddressEntry;
|
||||||
import bisq.core.trade.Trade;
|
import bisq.core.trade.Trade;
|
||||||
|
import bisq.core.trade.Trade.State;
|
||||||
import bisq.core.trade.messages.SignContractRequest;
|
import bisq.core.trade.messages.SignContractRequest;
|
||||||
import bisq.network.p2p.SendDirectMessageListener;
|
import bisq.network.p2p.SendDirectMessageListener;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -124,6 +125,7 @@ public class SendSignContractRequestAfterMultisig extends TradeTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void completeAux() {
|
private void completeAux() {
|
||||||
|
trade.setState(State.CONTRACT_SIGNATURE_REQUESTED);
|
||||||
processModel.getTradeManager().requestPersistence();
|
processModel.getTradeManager().requestPersistence();
|
||||||
processModel.getXmrWalletService().saveWallet(processModel.getXmrWalletService().getWallet());
|
processModel.getXmrWalletService().saveWallet(processModel.getXmrWalletService().getWallet());
|
||||||
complete();
|
complete();
|
||||||
|
@ -97,6 +97,7 @@ public class BuyerSendsPaymentSentMessage extends SendMailboxMessageTask {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setStateArrived() {
|
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
|
// the message has arrived but we're ultimately waiting for an AckMessage response
|
||||||
if (!trade.isPayoutPublished()) {
|
if (!trade.isPayoutPublished()) {
|
||||||
tryToSendAgainLater();
|
tryToSendAgainLater();
|
||||||
|
@ -40,7 +40,7 @@ import javafx.scene.layout.AnchorPane;
|
|||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import monero.wallet.model.MoneroTxWallet;
|
import monero.daemon.model.MoneroTx;
|
||||||
import monero.wallet.model.MoneroWalletListener;
|
import monero.wallet.model.MoneroWalletListener;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@ -176,9 +176,10 @@ public class TxIdTextField extends AnchorPane {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateConfidence(String txId) {
|
private void updateConfidence(String txId) {
|
||||||
MoneroTxWallet tx = null;
|
MoneroTx tx = null;
|
||||||
try {
|
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) {
|
} catch (Exception e) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
@ -188,6 +189,10 @@ public class TxIdTextField extends AnchorPane {
|
|||||||
txConfidenceIndicator.setVisible(true);
|
txConfidenceIndicator.setVisible(true);
|
||||||
AnchorPane.setRightAnchor(txConfidenceIndicator, 0.0);
|
AnchorPane.setRightAnchor(txConfidenceIndicator, 0.0);
|
||||||
}
|
}
|
||||||
|
if (txConfidenceIndicator.getProgress() >= 1.0 && txUpdater != null) {
|
||||||
|
xmrWalletService.removeWalletListener(txUpdater); // unregister listener
|
||||||
|
txUpdater = null;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
//TODO we should show some placeholder in case of a tx which we are not aware of but which can be
|
//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
|
// confirmed already. This is for instance the case of the other peers trade fee tx, as it is not related
|
||||||
|
@ -640,11 +640,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||||||
|
|
||||||
if (item != null && !empty) {
|
if (item != null && !empty) {
|
||||||
trade = item.getTrade();
|
trade = item.getTrade();
|
||||||
listener = (observable, oldValue, newValue) -> Platform.runLater(new Runnable() {
|
listener = (observable, oldValue, newValue) -> UserThread.execute(() -> update());
|
||||||
@Override public void run() {
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
trade.stateProperty().addListener(listener);
|
trade.stateProperty().addListener(listener);
|
||||||
update();
|
update();
|
||||||
} else {
|
} else {
|
||||||
@ -805,7 +801,6 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||||||
@Override
|
@Override
|
||||||
public void updateItem(final PendingTradesListItem item, boolean empty) {
|
public void updateItem(final PendingTradesListItem item, boolean empty) {
|
||||||
super.updateItem(item, empty);
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
if (item != null && !empty) {
|
if (item != null && !empty) {
|
||||||
setGraphic(new AutoTooltipLabel(item.getMarketDescription()));
|
setGraphic(new AutoTooltipLabel(item.getMarketDescription()));
|
||||||
} else {
|
} else {
|
||||||
|
@ -98,8 +98,8 @@ public abstract class TradeStepView extends AnchorPane {
|
|||||||
private TxIdTextField selfTxIdTextField;
|
private TxIdTextField selfTxIdTextField;
|
||||||
private TxIdTextField peerTxIdTextField;
|
private TxIdTextField peerTxIdTextField;
|
||||||
private TradeStepInfo tradeStepInfo;
|
private TradeStepInfo tradeStepInfo;
|
||||||
private Subscription makerTxIdSubscription;
|
private Subscription selfTxIdSubscription;
|
||||||
private Subscription takerTxIdSubscription;
|
private Subscription peerTxIdSubscription;
|
||||||
private ClockWatcher.Listener clockListener;
|
private ClockWatcher.Listener clockListener;
|
||||||
private final ChangeListener<String> errorMessageListener;
|
private final ChangeListener<String> errorMessageListener;
|
||||||
protected Label infoLabel;
|
protected Label infoLabel;
|
||||||
@ -175,15 +175,11 @@ public abstract class TradeStepView extends AnchorPane {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void activate() {
|
public void activate() {
|
||||||
UserThread.execute(() -> { activateAux(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
private void activateAux() {
|
|
||||||
if (selfTxIdTextField != null) {
|
if (selfTxIdTextField != null) {
|
||||||
if (makerTxIdSubscription != null)
|
if (selfTxIdSubscription != null)
|
||||||
makerTxIdSubscription.unsubscribe();
|
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())
|
if (!id.isEmpty())
|
||||||
selfTxIdTextField.setup(id);
|
selfTxIdTextField.setup(id);
|
||||||
else
|
else
|
||||||
@ -191,10 +187,10 @@ public abstract class TradeStepView extends AnchorPane {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (peerTxIdTextField != null) {
|
if (peerTxIdTextField != null) {
|
||||||
if (takerTxIdSubscription != null)
|
if (peerTxIdSubscription != null)
|
||||||
takerTxIdSubscription.unsubscribe();
|
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())
|
if (!id.isEmpty())
|
||||||
peerTxIdTextField.setup(id);
|
peerTxIdTextField.setup(id);
|
||||||
else
|
else
|
||||||
@ -288,10 +284,10 @@ public abstract class TradeStepView extends AnchorPane {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void deactivate() {
|
public void deactivate() {
|
||||||
if (makerTxIdSubscription != null)
|
if (selfTxIdSubscription != null)
|
||||||
makerTxIdSubscription.unsubscribe();
|
selfTxIdSubscription.unsubscribe();
|
||||||
if (takerTxIdSubscription != null)
|
if (peerTxIdSubscription != null)
|
||||||
takerTxIdSubscription.unsubscribe();
|
peerTxIdSubscription.unsubscribe();
|
||||||
|
|
||||||
if (selfTxIdTextField != null)
|
if (selfTxIdTextField != null)
|
||||||
selfTxIdTextField.cleanup();
|
selfTxIdTextField.cleanup();
|
||||||
|
@ -155,7 +155,7 @@ public class BuyerStep2View extends TradeStepView {
|
|||||||
if (timeoutTimer != null)
|
if (timeoutTimer != null)
|
||||||
timeoutTimer.stop();
|
timeoutTimer.stop();
|
||||||
|
|
||||||
if (trade.isDepositConfirmed() && !trade.isPaymentSent()) {
|
if (trade.isDepositUnlocked() && !trade.isPaymentSent()) {
|
||||||
showPopup();
|
showPopup();
|
||||||
} else if (state.ordinal() <= Trade.State.BUYER_SEND_FAILED_PAYMENT_SENT_MSG.ordinal()) {
|
} else if (state.ordinal() <= Trade.State.BUYER_SEND_FAILED_PAYMENT_SENT_MSG.ordinal()) {
|
||||||
if (!trade.hasFailed()) {
|
if (!trade.hasFailed()) {
|
||||||
|
@ -136,6 +136,7 @@ public class SellerStep3View extends TradeStepView {
|
|||||||
busyAnimation.stop();
|
busyAnimation.stop();
|
||||||
statusLabel.setText(Res.get("shared.messageArrived"));
|
statusLabel.setText(Res.get("shared.messageArrived"));
|
||||||
break;
|
break;
|
||||||
|
case SELLER_STORED_IN_MAILBOX_PAYMENT_RECEIVED_MSG:
|
||||||
case SELLER_STORED_IN_MAILBOX_PAYOUT_TX_PUBLISHED_MSG:
|
case SELLER_STORED_IN_MAILBOX_PAYOUT_TX_PUBLISHED_MSG:
|
||||||
busyAnimation.stop();
|
busyAnimation.stop();
|
||||||
statusLabel.setText(Res.get("shared.messageStoredInMailbox"));
|
statusLabel.setText(Res.get("shared.messageStoredInMailbox"));
|
||||||
|
@ -65,7 +65,6 @@ import bisq.common.util.Utilities;
|
|||||||
|
|
||||||
import org.bitcoinj.core.Address;
|
import org.bitcoinj.core.Address;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
import org.bitcoinj.core.TransactionConfidence;
|
|
||||||
import org.bitcoinj.uri.BitcoinURI;
|
import org.bitcoinj.uri.BitcoinURI;
|
||||||
|
|
||||||
import com.googlecode.jcsv.CSVStrategy;
|
import com.googlecode.jcsv.CSVStrategy;
|
||||||
@ -135,7 +134,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import monero.wallet.model.MoneroTxWallet;
|
import monero.daemon.model.MoneroTx;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
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,
|
Tooltip tooltip,
|
||||||
TxConfidenceIndicator txConfidenceIndicator) {
|
TxConfidenceIndicator txConfidenceIndicator) {
|
||||||
if (tx != null) {
|
if (tx != null) {
|
||||||
|
Loading…
Reference in New Issue
Block a user