handle timeout in trade initialization with protocol latch

This commit is contained in:
woodser 2022-07-16 20:56:19 -04:00
parent 83b8616f6f
commit b4fe0f0ee6
14 changed files with 179 additions and 203 deletions

View file

@ -98,7 +98,7 @@ public class HavenoHeadlessApp implements HeadlessApp {
lastVersion, Version.VERSION)); lastVersion, Version.VERSION));
corruptedStorageFileHandler.getFiles().ifPresent(files -> log.warn("getCorruptedDatabaseFiles. files={}", files)); corruptedStorageFileHandler.getFiles().ifPresent(files -> log.warn("getCorruptedDatabaseFiles. files={}", files));
tradeManager.setTakeOfferRequestErrorMessageHandler(errorMessage -> log.error("onTakeOfferRequestErrorMessageHandler")); tradeManager.setTakeOfferRequestErrorMessageHandler(errorMessage -> log.error("Error taking offer: " + errorMessage));
} }
public void stop() { public void stop() {

View file

@ -633,7 +633,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
latch.countDown(); latch.countDown();
errorMessages.add(errorMessage); errorMessages.add(errorMessage);
}); });
TradeUtils.waitForLatch(latch); TradeUtils.awaitLatch(latch);
} }
requestPersistence(); requestPersistence();
if (errorMessages.size() > 0) errorMessageHandler.handleErrorMessage(errorMessages.toString()); if (errorMessages.size() > 0) errorMessageHandler.handleErrorMessage(errorMessages.toString());

View file

@ -305,7 +305,6 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
} }
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Init pending trade // Init pending trade
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -478,6 +477,12 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
return; return;
} }
Optional<Trade> tradeOptional = getOpenTrade(request.getTradeId());
if (tradeOptional.isPresent()) {
log.warn("Maker trade already exists with id " + request.getTradeId() + ". This should never happen.");
return;
}
openOfferManager.reserveOpenOffer(openOffer); // TODO (woodser): reserve offer if arbitrator? probably. or, arbitrator does not have open offer? openOfferManager.reserveOpenOffer(openOffer); // TODO (woodser): reserve offer if arbitrator? probably. or, arbitrator does not have open offer?
Trade trade; Trade trade;
@ -751,8 +756,8 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
requestPersistence(); requestPersistence();
}, errorMessage -> { }, errorMessage -> {
log.warn("Taker error during trade initialization: " + errorMessage); log.warn("Taker error during trade initialization: " + errorMessage);
removeTrade(trade);
errorMessageHandler.handleErrorMessage(errorMessage); errorMessageHandler.handleErrorMessage(errorMessage);
removeTrade(trade);
}); });
requestPersistence(); requestPersistence();
} }

View file

@ -205,7 +205,7 @@ public class TradeUtils {
// return new Tuple2<>(multiSigAddress.getAddressString(), payoutAddress); // return new Tuple2<>(multiSigAddress.getAddressString(), payoutAddress);
} }
public static void waitForLatch(CountDownLatch latch) { public static void awaitLatch(CountDownLatch latch) {
try { try {
latch.await(); latch.await();
} catch (InterruptedException e) { } catch (InterruptedException e) {

View file

@ -2,7 +2,6 @@ package bisq.core.trade.protocol;
import bisq.core.trade.ArbitratorTrade; import bisq.core.trade.ArbitratorTrade;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.trade.TradeUtils;
import bisq.core.trade.messages.DepositRequest; import bisq.core.trade.messages.DepositRequest;
import bisq.core.trade.messages.InitMultisigRequest; import bisq.core.trade.messages.InitMultisigRequest;
import bisq.core.trade.messages.InitTradeRequest; import bisq.core.trade.messages.InitTradeRequest;
@ -16,7 +15,6 @@ import bisq.core.trade.protocol.tasks.ProcessInitTradeRequest;
import bisq.core.trade.protocol.tasks.ProcessSignContractRequest; import bisq.core.trade.protocol.tasks.ProcessSignContractRequest;
import bisq.core.util.Validator; import bisq.core.util.Validator;
import bisq.network.p2p.NodeAddress; import bisq.network.p2p.NodeAddress;
import java.util.concurrent.CountDownLatch;
import bisq.common.handlers.ErrorMessageHandler; import bisq.common.handlers.ErrorMessageHandler;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -32,14 +30,12 @@ public class ArbitratorProtocol extends DisputeProtocol {
// Incoming messages // Incoming messages
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void handleInitTradeRequest(InitTradeRequest message, public void handleInitTradeRequest(InitTradeRequest message, NodeAddress peer, ErrorMessageHandler errorMessageHandler) {
NodeAddress peer, System.out.println("ArbitratorProtocol.handleInitTradeRequest()");
ErrorMessageHandler errorMessageHandler) {
synchronized (trade) { synchronized (trade) {
this.errorMessageHandler = errorMessageHandler; this.errorMessageHandler = errorMessageHandler;
processModel.setTradeMessage(message); // TODO (woodser): confirm these are null without being set processModel.setTradeMessage(message); // TODO (woodser): confirm these are null without being set
CountDownLatch latch = new CountDownLatch(1); latchTrade();
//processModel.setTempTradingPeerNodeAddress(peer);
expect(phase(Trade.Phase.INIT) expect(phase(Trade.Phase.INIT)
.with(message) .with(message)
.from(peer)) .from(peer))
@ -50,17 +46,16 @@ public class ArbitratorProtocol extends DisputeProtocol {
ArbitratorSendsInitTradeAndMultisigRequests.class) ArbitratorSendsInitTradeAndMultisigRequests.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(peer, message); handleTaskRunnerSuccess(peer, message);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
handleTaskRunnerFault(peer, message, errorMessage); handleTaskRunnerFault(peer, message, errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }
@ -70,7 +65,7 @@ public class ArbitratorProtocol extends DisputeProtocol {
synchronized (trade) { synchronized (trade) {
Validator.checkTradeId(processModel.getOfferId(), request); Validator.checkTradeId(processModel.getOfferId(), request);
processModel.setTradeMessage(request); processModel.setTradeMessage(request);
CountDownLatch latch = new CountDownLatch(1); latchTrade();
expect(anyPhase(Trade.Phase.INIT) expect(anyPhase(Trade.Phase.INIT)
.with(request) .with(request)
.from(sender)) .from(sender))
@ -78,17 +73,16 @@ public class ArbitratorProtocol extends DisputeProtocol {
ProcessInitMultisigRequest.class) ProcessInitMultisigRequest.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(sender, request); handleTaskRunnerSuccess(sender, request);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
handleTaskRunnerFault(sender, request, errorMessage); handleTaskRunnerFault(sender, request, errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }
@ -98,7 +92,7 @@ public class ArbitratorProtocol extends DisputeProtocol {
synchronized (trade) { synchronized (trade) {
Validator.checkTradeId(processModel.getOfferId(), message); Validator.checkTradeId(processModel.getOfferId(), message);
processModel.setTradeMessage(message); // TODO (woodser): synchronize access since concurrent requests processed processModel.setTradeMessage(message); // TODO (woodser): synchronize access since concurrent requests processed
CountDownLatch latch = new CountDownLatch(1); latchTrade();
expect(anyPhase(Trade.Phase.INIT) expect(anyPhase(Trade.Phase.INIT)
.with(message) .with(message)
.from(sender)) .from(sender))
@ -107,17 +101,16 @@ public class ArbitratorProtocol extends DisputeProtocol {
ProcessSignContractRequest.class) ProcessSignContractRequest.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(sender, message); handleTaskRunnerSuccess(sender, message);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
handleTaskRunnerFault(sender, message, errorMessage); handleTaskRunnerFault(sender, message, errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }
@ -126,7 +119,7 @@ public class ArbitratorProtocol extends DisputeProtocol {
synchronized (trade) { synchronized (trade) {
Validator.checkTradeId(processModel.getOfferId(), request); Validator.checkTradeId(processModel.getOfferId(), request);
processModel.setTradeMessage(request); processModel.setTradeMessage(request);
CountDownLatch latch = new CountDownLatch(1); latchTrade();
expect(anyPhase(Trade.Phase.INIT) expect(anyPhase(Trade.Phase.INIT)
.with(request) .with(request)
.from(sender)) .from(sender))
@ -134,18 +127,17 @@ public class ArbitratorProtocol extends DisputeProtocol {
ArbitratorProcessesDepositRequest.class) ArbitratorProcessesDepositRequest.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
stopTimeout(); stopTimeout();
handleTaskRunnerSuccess(sender, request); handleTaskRunnerSuccess(sender, request);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
handleTaskRunnerFault(sender, request, errorMessage); handleTaskRunnerFault(sender, request, errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }

View file

@ -20,7 +20,6 @@ package bisq.core.trade.protocol;
import bisq.core.trade.BuyerAsMakerTrade; import bisq.core.trade.BuyerAsMakerTrade;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.trade.Trade.State; import bisq.core.trade.Trade.State;
import bisq.core.trade.TradeUtils;
import bisq.core.trade.messages.DelayedPayoutTxSignatureRequest; import bisq.core.trade.messages.DelayedPayoutTxSignatureRequest;
import bisq.core.trade.messages.DepositResponse; import bisq.core.trade.messages.DepositResponse;
import bisq.core.trade.messages.DepositTxAndDelayedPayoutTxMessage; import bisq.core.trade.messages.DepositTxAndDelayedPayoutTxMessage;
@ -49,7 +48,6 @@ import bisq.core.trade.protocol.tasks.maker.MakerVerifyTakerFeePayment;
import bisq.core.util.Validator; import bisq.core.util.Validator;
import bisq.network.p2p.NodeAddress; import bisq.network.p2p.NodeAddress;
import java.util.concurrent.CountDownLatch;
import bisq.common.handlers.ErrorMessageHandler; import bisq.common.handlers.ErrorMessageHandler;
import bisq.common.handlers.ResultHandler; import bisq.common.handlers.ResultHandler;
@ -80,7 +78,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
System.out.println(getClass().getCanonicalName() + ".handleInitTradeRequest()"); System.out.println(getClass().getCanonicalName() + ".handleInitTradeRequest()");
synchronized (trade) { synchronized (trade) {
this.errorMessageHandler = errorMessageHandler; this.errorMessageHandler = errorMessageHandler;
CountDownLatch latch = new CountDownLatch(1); latchTrade();
expect(phase(Trade.Phase.INIT) expect(phase(Trade.Phase.INIT)
.with(message) .with(message)
.from(peer)) .from(peer))
@ -91,17 +89,16 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
MakerSendsInitTradeRequestIfUnreserved.class) MakerSendsInitTradeRequestIfUnreserved.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(peer, message); handleTaskRunnerSuccess(peer, message);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(peer, message, errorMessage); handleTaskRunnerFault(peer, message, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }
@ -111,7 +108,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
synchronized (trade) { synchronized (trade) {
Validator.checkTradeId(processModel.getOfferId(), request); Validator.checkTradeId(processModel.getOfferId(), request);
processModel.setTradeMessage(request); processModel.setTradeMessage(request);
CountDownLatch latch = new CountDownLatch(1); latchTrade();
expect(anyPhase(Trade.Phase.INIT) expect(anyPhase(Trade.Phase.INIT)
.with(request) .with(request)
.from(sender)) .from(sender))
@ -120,17 +117,15 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
SendSignContractRequestAfterMultisig.class) SendSignContractRequestAfterMultisig.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(sender, request); handleTaskRunnerSuccess(sender, request);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(sender, request, errorMessage); handleTaskRunnerFault(sender, request, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage); })))
}))
.withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }
@ -140,7 +135,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
synchronized (trade) { synchronized (trade) {
Validator.checkTradeId(processModel.getOfferId(), message); Validator.checkTradeId(processModel.getOfferId(), message);
processModel.setTradeMessage(message); processModel.setTradeMessage(message);
CountDownLatch latch = new CountDownLatch(1); latchTrade();
expect(anyPhase(Trade.Phase.INIT) expect(anyPhase(Trade.Phase.INIT)
.with(message) .with(message)
.from(sender)) .from(sender))
@ -149,17 +144,15 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
ProcessSignContractRequest.class) ProcessSignContractRequest.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(sender, message); handleTaskRunnerSuccess(sender, message);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(sender, message, errorMessage); handleTaskRunnerFault(sender, message, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage); })))
}))
.withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }
@ -170,7 +163,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
Validator.checkTradeId(processModel.getOfferId(), message); Validator.checkTradeId(processModel.getOfferId(), message);
if (trade.getState() == State.CONTRACT_SIGNATURE_REQUESTED) { if (trade.getState() == State.CONTRACT_SIGNATURE_REQUESTED) {
processModel.setTradeMessage(message); processModel.setTradeMessage(message);
CountDownLatch latch = new CountDownLatch(1); if (tradeLatch == null) latchTrade(); // may be initialized from previous message
expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED) expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED)
.with(message) .with(message)
.from(sender)) .from(sender))
@ -179,17 +172,16 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
ProcessSignContractResponse.class) ProcessSignContractResponse.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(sender, message); handleTaskRunnerSuccess(sender, message);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(sender, message, errorMessage); handleTaskRunnerFault(sender, message, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT)) // extend timeout
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} else { } else {
EasyBind.subscribe(trade.stateProperty(), state -> { EasyBind.subscribe(trade.stateProperty(), state -> {
if (state == State.CONTRACT_SIGNATURE_REQUESTED) handleSignContractResponse(message, sender); if (state == State.CONTRACT_SIGNATURE_REQUESTED) handleSignContractResponse(message, sender);
@ -204,7 +196,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
synchronized (trade) { synchronized (trade) {
Validator.checkTradeId(processModel.getOfferId(), response); Validator.checkTradeId(processModel.getOfferId(), response);
processModel.setTradeMessage(response); processModel.setTradeMessage(response);
CountDownLatch latch = new CountDownLatch(1); latchTrade();
expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED) expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED)
.with(response) .with(response)
.from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress() .from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress()
@ -213,17 +205,16 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
ProcessDepositResponse.class) ProcessDepositResponse.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(sender, response); handleTaskRunnerSuccess(sender, response);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(sender, response, errorMessage); handleTaskRunnerFault(sender, response, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }
@ -234,7 +225,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
Validator.checkTradeId(processModel.getOfferId(), request); Validator.checkTradeId(processModel.getOfferId(), request);
if (trade.getState() == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) { if (trade.getState() == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) {
processModel.setTradeMessage(request); processModel.setTradeMessage(request);
CountDownLatch latch = new CountDownLatch(1); if (tradeLatch == null) latchTrade(); // may be initialized from previous message
expect(state(Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) expect(state(Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG)
.with(request) .with(request)
.from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress() .from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress()
@ -244,18 +235,17 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
MakerRemovesOpenOffer.class) MakerRemovesOpenOffer.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown();
stopTimeout(); stopTimeout();
unlatchTrade();
handleTaskRunnerSuccess(sender, request); handleTaskRunnerSuccess(sender, request);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(sender, request, errorMessage); handleTaskRunnerFault(sender, request, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} else { } else {
EasyBind.subscribe(trade.stateProperty(), state -> { EasyBind.subscribe(trade.stateProperty(), state -> {
if (state == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) handlePaymentAccountPayloadRequest(request, sender); if (state == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) handlePaymentAccountPayloadRequest(request, sender);

View file

@ -22,7 +22,6 @@ import bisq.core.offer.Offer;
import bisq.core.trade.BuyerAsTakerTrade; import bisq.core.trade.BuyerAsTakerTrade;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.trade.Trade.State; import bisq.core.trade.Trade.State;
import bisq.core.trade.TradeUtils;
import bisq.core.trade.handlers.TradeResultHandler; import bisq.core.trade.handlers.TradeResultHandler;
import bisq.core.trade.messages.DelayedPayoutTxSignatureRequest; import bisq.core.trade.messages.DelayedPayoutTxSignatureRequest;
import bisq.core.trade.messages.DepositResponse; import bisq.core.trade.messages.DepositResponse;
@ -58,7 +57,6 @@ import bisq.core.trade.protocol.tasks.taker.TakerSendsInitTradeRequestToArbitrat
import bisq.core.trade.protocol.tasks.taker.TakerVerifyMakerFeePayment; import bisq.core.trade.protocol.tasks.taker.TakerVerifyMakerFeePayment;
import bisq.core.util.Validator; import bisq.core.util.Validator;
import bisq.network.p2p.NodeAddress; import bisq.network.p2p.NodeAddress;
import java.util.concurrent.CountDownLatch;
import bisq.common.handlers.ErrorMessageHandler; import bisq.common.handlers.ErrorMessageHandler;
import bisq.common.handlers.ResultHandler; import bisq.common.handlers.ResultHandler;
@ -98,7 +96,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
synchronized (trade) { synchronized (trade) {
this.tradeResultHandler = tradeResultHandler; this.tradeResultHandler = tradeResultHandler;
this.errorMessageHandler = errorMessageHandler; this.errorMessageHandler = errorMessageHandler;
CountDownLatch latch = new CountDownLatch(1); latchTrade();
expect(phase(Trade.Phase.INIT) expect(phase(Trade.Phase.INIT)
.with(TakerEvent.TAKE_OFFER) .with(TakerEvent.TAKE_OFFER)
.from(trade.getTradingPeerNodeAddress())) .from(trade.getTradingPeerNodeAddress()))
@ -108,15 +106,14 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
TakerSendsInitTradeRequestToArbitrator.class) TakerSendsInitTradeRequestToArbitrator.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }
@ -126,7 +123,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
synchronized (trade) { synchronized (trade) {
Validator.checkTradeId(processModel.getOfferId(), request); Validator.checkTradeId(processModel.getOfferId(), request);
processModel.setTradeMessage(request); processModel.setTradeMessage(request);
CountDownLatch latch = new CountDownLatch(1); latchTrade();
expect(anyPhase(Trade.Phase.INIT) expect(anyPhase(Trade.Phase.INIT)
.with(request) .with(request)
.from(sender)) .from(sender))
@ -135,17 +132,16 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
SendSignContractRequestAfterMultisig.class) SendSignContractRequestAfterMultisig.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(sender, request); handleTaskRunnerSuccess(sender, request);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(sender, request, errorMessage); handleTaskRunnerFault(sender, request, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }
@ -155,7 +151,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
synchronized (trade) { synchronized (trade) {
Validator.checkTradeId(processModel.getOfferId(), message); Validator.checkTradeId(processModel.getOfferId(), message);
processModel.setTradeMessage(message); processModel.setTradeMessage(message);
CountDownLatch latch = new CountDownLatch(1); latchTrade();
expect(anyPhase(Trade.Phase.INIT) expect(anyPhase(Trade.Phase.INIT)
.with(message) .with(message)
.from(sender)) .from(sender))
@ -164,17 +160,16 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
ProcessSignContractRequest.class) ProcessSignContractRequest.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(sender, message); handleTaskRunnerSuccess(sender, message);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(sender, message, errorMessage); handleTaskRunnerFault(sender, message, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }
@ -185,7 +180,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
Validator.checkTradeId(processModel.getOfferId(), message); Validator.checkTradeId(processModel.getOfferId(), message);
if (trade.getState() == State.CONTRACT_SIGNATURE_REQUESTED) { if (trade.getState() == State.CONTRACT_SIGNATURE_REQUESTED) {
processModel.setTradeMessage(message); processModel.setTradeMessage(message);
CountDownLatch latch = new CountDownLatch(1); if (tradeLatch == null) latchTrade(); // may be initialized from previous message
expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED) expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED)
.with(message) .with(message)
.from(sender)) .from(sender))
@ -194,17 +189,16 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
ProcessSignContractResponse.class) ProcessSignContractResponse.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(sender, message); handleTaskRunnerSuccess(sender, message);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(sender, message, errorMessage); handleTaskRunnerFault(sender, message, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} else { } else {
EasyBind.subscribe(trade.stateProperty(), state -> { EasyBind.subscribe(trade.stateProperty(), state -> {
if (state != State.CONTRACT_SIGNATURE_REQUESTED) return; if (state != State.CONTRACT_SIGNATURE_REQUESTED) return;
@ -220,7 +214,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
synchronized (trade) { synchronized (trade) {
Validator.checkTradeId(processModel.getOfferId(), response); Validator.checkTradeId(processModel.getOfferId(), response);
processModel.setTradeMessage(response); processModel.setTradeMessage(response);
CountDownLatch latch = new CountDownLatch(1); latchTrade();
expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED) expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED)
.with(response) .with(response)
.from(sender)) .from(sender))
@ -229,17 +223,16 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
ProcessDepositResponse.class) ProcessDepositResponse.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(sender, response); handleTaskRunnerSuccess(sender, response);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(sender, response, errorMessage); handleTaskRunnerFault(sender, response, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }
@ -248,7 +241,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
System.out.println(getClass().getCanonicalName() + ".handlePaymentAccountPayloadRequest()"); System.out.println(getClass().getCanonicalName() + ".handlePaymentAccountPayloadRequest()");
synchronized (trade) { synchronized (trade) {
Validator.checkTradeId(processModel.getOfferId(), request); Validator.checkTradeId(processModel.getOfferId(), request);
CountDownLatch latch = new CountDownLatch(1); if (tradeLatch == null) latchTrade(); // may be initialized from previous message
if (trade.getState() == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) { if (trade.getState() == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) {
processModel.setTradeMessage(request); processModel.setTradeMessage(request);
expect(state(Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) // TODO (woodser): rename to RECEIVED_DEPOSIT_TX_PUBLISHED_MSG expect(state(Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) // TODO (woodser): rename to RECEIVED_DEPOSIT_TX_PUBLISHED_MSG
@ -259,19 +252,18 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
ProcessPaymentAccountPayloadRequest.class) ProcessPaymentAccountPayloadRequest.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
stopTimeout(); stopTimeout();
handleTaskRunnerSuccess(sender, request); handleTaskRunnerSuccess(sender, request);
tradeResultHandler.handleResult(trade); // trade is initialized tradeResultHandler.handleResult(trade); // trade is initialized
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(sender, request, errorMessage); handleTaskRunnerFault(sender, request, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} else { } else {
EasyBind.subscribe(trade.stateProperty(), state -> { EasyBind.subscribe(trade.stateProperty(), state -> {
if (state == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) handlePaymentAccountPayloadRequest(request, sender); if (state == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) handlePaymentAccountPayloadRequest(request, sender);

View file

@ -19,7 +19,6 @@ package bisq.core.trade.protocol;
import bisq.core.trade.BuyerTrade; import bisq.core.trade.BuyerTrade;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.trade.TradeUtils;
import bisq.core.trade.messages.DelayedPayoutTxSignatureRequest; import bisq.core.trade.messages.DelayedPayoutTxSignatureRequest;
import bisq.core.trade.messages.DepositTxAndDelayedPayoutTxMessage; import bisq.core.trade.messages.DepositTxAndDelayedPayoutTxMessage;
import bisq.core.trade.messages.PaymentReceivedMessage; import bisq.core.trade.messages.PaymentReceivedMessage;
@ -164,8 +163,7 @@ public abstract class BuyerProtocol extends DisputeProtocol {
log.info("BuyerProtocol.handle(PaymentReceivedMessage)"); log.info("BuyerProtocol.handle(PaymentReceivedMessage)");
synchronized (trade) { synchronized (trade) {
processModel.setTradeMessage(message); processModel.setTradeMessage(message);
processModel.setTempTradingPeerNodeAddress(peer); latchTrade();
CountDownLatch latch = new CountDownLatch(1);
expect(anyPhase(Trade.Phase.PAYMENT_SENT, Trade.Phase.PAYOUT_PUBLISHED) expect(anyPhase(Trade.Phase.PAYMENT_SENT, Trade.Phase.PAYOUT_PUBLISHED)
.with(message) .with(message)
.from(peer)) .from(peer))
@ -174,15 +172,15 @@ public abstract class BuyerProtocol extends DisputeProtocol {
BuyerProcessesPaymentReceivedMessage.class) BuyerProcessesPaymentReceivedMessage.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(peer, message); handleTaskRunnerSuccess(peer, message);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(peer, message, errorMessage); handleTaskRunnerFault(peer, message, errorMessage);
}))) })))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }

View file

@ -21,7 +21,6 @@ package bisq.core.trade.protocol;
import bisq.core.trade.SellerAsMakerTrade; import bisq.core.trade.SellerAsMakerTrade;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.trade.Trade.State; import bisq.core.trade.Trade.State;
import bisq.core.trade.TradeUtils;
import bisq.core.trade.messages.PaymentSentMessage; import bisq.core.trade.messages.PaymentSentMessage;
import bisq.core.trade.messages.DepositResponse; import bisq.core.trade.messages.DepositResponse;
import bisq.core.trade.messages.DepositTxMessage; import bisq.core.trade.messages.DepositTxMessage;
@ -49,7 +48,6 @@ import bisq.core.trade.protocol.tasks.seller_as_maker.SellerAsMakerFinalizesDepo
import bisq.core.trade.protocol.tasks.seller_as_maker.SellerAsMakerProcessDepositTxMessage; import bisq.core.trade.protocol.tasks.seller_as_maker.SellerAsMakerProcessDepositTxMessage;
import bisq.core.util.Validator; import bisq.core.util.Validator;
import bisq.network.p2p.NodeAddress; import bisq.network.p2p.NodeAddress;
import java.util.concurrent.CountDownLatch;
import bisq.common.handlers.ErrorMessageHandler; import bisq.common.handlers.ErrorMessageHandler;
import bisq.common.handlers.ResultHandler; import bisq.common.handlers.ResultHandler;
@ -80,7 +78,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
System.out.println(getClass().getCanonicalName() + ".handleInitTradeRequest()"); System.out.println(getClass().getCanonicalName() + ".handleInitTradeRequest()");
synchronized (trade) { synchronized (trade) {
this.errorMessageHandler = errorMessageHandler; this.errorMessageHandler = errorMessageHandler;
CountDownLatch latch = new CountDownLatch(1); latchTrade();
expect(phase(Trade.Phase.INIT) expect(phase(Trade.Phase.INIT)
.with(message) .with(message)
.from(peer)) .from(peer))
@ -91,17 +89,16 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
MakerSendsInitTradeRequestIfUnreserved.class) MakerSendsInitTradeRequestIfUnreserved.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(peer, message); handleTaskRunnerSuccess(peer, message);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(peer, message, errorMessage); handleTaskRunnerFault(peer, message, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }
@ -111,7 +108,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
synchronized (trade) { synchronized (trade) {
Validator.checkTradeId(processModel.getOfferId(), request); Validator.checkTradeId(processModel.getOfferId(), request);
processModel.setTradeMessage(request); processModel.setTradeMessage(request);
CountDownLatch latch = new CountDownLatch(1); latchTrade();
expect(anyPhase(Trade.Phase.INIT) expect(anyPhase(Trade.Phase.INIT)
.with(request) .with(request)
.from(sender)) .from(sender))
@ -120,17 +117,16 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
SendSignContractRequestAfterMultisig.class) SendSignContractRequestAfterMultisig.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(sender, request); handleTaskRunnerSuccess(sender, request);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(sender, request, errorMessage); handleTaskRunnerFault(sender, request, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }
@ -140,7 +136,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
synchronized (trade) { synchronized (trade) {
Validator.checkTradeId(processModel.getOfferId(), message); Validator.checkTradeId(processModel.getOfferId(), message);
processModel.setTradeMessage(message); processModel.setTradeMessage(message);
CountDownLatch latch = new CountDownLatch(1); latchTrade();
expect(anyPhase(Trade.Phase.INIT) expect(anyPhase(Trade.Phase.INIT)
.with(message) .with(message)
.from(sender)) .from(sender))
@ -149,17 +145,16 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
ProcessSignContractRequest.class) ProcessSignContractRequest.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(sender, message); handleTaskRunnerSuccess(sender, message);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(sender, message, errorMessage); handleTaskRunnerFault(sender, message, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }
@ -170,7 +165,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
Validator.checkTradeId(processModel.getOfferId(), message); Validator.checkTradeId(processModel.getOfferId(), message);
if (trade.getState() == State.CONTRACT_SIGNATURE_REQUESTED) { if (trade.getState() == State.CONTRACT_SIGNATURE_REQUESTED) {
processModel.setTradeMessage(message); processModel.setTradeMessage(message);
CountDownLatch latch = new CountDownLatch(1); if (tradeLatch == null) latchTrade(); // may be initialized from previous message
expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED) expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED)
.with(message) .with(message)
.from(sender)) .from(sender))
@ -179,17 +174,16 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
ProcessSignContractResponse.class) ProcessSignContractResponse.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(sender, message); handleTaskRunnerSuccess(sender, message);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(sender, message, errorMessage); handleTaskRunnerFault(sender, message, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} else { } else {
EasyBind.subscribe(trade.stateProperty(), state -> { EasyBind.subscribe(trade.stateProperty(), state -> {
if (state == State.CONTRACT_SIGNATURE_REQUESTED) handleSignContractResponse(message, sender); if (state == State.CONTRACT_SIGNATURE_REQUESTED) handleSignContractResponse(message, sender);
@ -204,7 +198,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
synchronized (trade) { synchronized (trade) {
Validator.checkTradeId(processModel.getOfferId(), response); Validator.checkTradeId(processModel.getOfferId(), response);
processModel.setTradeMessage(response); processModel.setTradeMessage(response);
CountDownLatch latch = new CountDownLatch(1); latchTrade();
expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED) expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED)
.with(response) .with(response)
.from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress() .from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress()
@ -213,17 +207,16 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
ProcessDepositResponse.class) ProcessDepositResponse.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(sender, response); handleTaskRunnerSuccess(sender, response);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(sender, response, errorMessage); handleTaskRunnerFault(sender, response, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }
@ -234,7 +227,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
Validator.checkTradeId(processModel.getOfferId(), request); Validator.checkTradeId(processModel.getOfferId(), request);
if (trade.getState() == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) { if (trade.getState() == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) {
processModel.setTradeMessage(request); processModel.setTradeMessage(request);
CountDownLatch latch = new CountDownLatch(1); if (tradeLatch == null) latchTrade(); // may be initialized from previous message
expect(state(Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) expect(state(Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG)
.with(request) .with(request)
.from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress() .from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress()
@ -244,18 +237,17 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
MakerRemovesOpenOffer.class) MakerRemovesOpenOffer.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
stopTimeout(); stopTimeout();
handleTaskRunnerSuccess(sender, request); handleTaskRunnerSuccess(sender, request);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(sender, request, errorMessage); handleTaskRunnerFault(sender, request, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} else { } else {
EasyBind.subscribe(trade.stateProperty(), state -> { EasyBind.subscribe(trade.stateProperty(), state -> {
if (state == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) handlePaymentAccountPayloadRequest(request, sender); if (state == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) handlePaymentAccountPayloadRequest(request, sender);

View file

@ -22,7 +22,6 @@ import bisq.core.offer.Offer;
import bisq.core.trade.SellerAsTakerTrade; import bisq.core.trade.SellerAsTakerTrade;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.trade.Trade.State; import bisq.core.trade.Trade.State;
import bisq.core.trade.TradeUtils;
import bisq.core.trade.handlers.TradeResultHandler; import bisq.core.trade.handlers.TradeResultHandler;
import bisq.core.trade.messages.PaymentSentMessage; import bisq.core.trade.messages.PaymentSentMessage;
import bisq.core.trade.messages.DepositResponse; import bisq.core.trade.messages.DepositResponse;
@ -53,7 +52,6 @@ import bisq.core.trade.protocol.tasks.taker.TakerVerifyMakerFeePayment;
import bisq.core.util.Validator; import bisq.core.util.Validator;
import bisq.network.p2p.NodeAddress; import bisq.network.p2p.NodeAddress;
import java.util.concurrent.CountDownLatch;
import bisq.common.handlers.ErrorMessageHandler; import bisq.common.handlers.ErrorMessageHandler;
import bisq.common.handlers.ResultHandler; import bisq.common.handlers.ResultHandler;
@ -91,7 +89,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
synchronized (trade) { synchronized (trade) {
this.tradeResultHandler = tradeResultHandler; this.tradeResultHandler = tradeResultHandler;
this.errorMessageHandler = errorMessageHandler; this.errorMessageHandler = errorMessageHandler;
CountDownLatch latch = new CountDownLatch(1); latchTrade();
expect(phase(Trade.Phase.INIT) expect(phase(Trade.Phase.INIT)
.with(TakerEvent.TAKE_OFFER) .with(TakerEvent.TAKE_OFFER)
.from(trade.getTradingPeerNodeAddress())) .from(trade.getTradingPeerNodeAddress()))
@ -101,15 +99,14 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
TakerSendsInitTradeRequestToArbitrator.class) TakerSendsInitTradeRequestToArbitrator.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }
@ -119,7 +116,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
synchronized (trade) { synchronized (trade) {
Validator.checkTradeId(processModel.getOfferId(), request); Validator.checkTradeId(processModel.getOfferId(), request);
processModel.setTradeMessage(request); processModel.setTradeMessage(request);
CountDownLatch latch = new CountDownLatch(1); latchTrade();
expect(anyPhase(Trade.Phase.INIT) expect(anyPhase(Trade.Phase.INIT)
.with(request) .with(request)
.from(sender)) .from(sender))
@ -128,17 +125,16 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
SendSignContractRequestAfterMultisig.class) SendSignContractRequestAfterMultisig.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(sender, request); handleTaskRunnerSuccess(sender, request);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(sender, request, errorMessage); handleTaskRunnerFault(sender, request, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }
@ -148,7 +144,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
synchronized (trade) { synchronized (trade) {
Validator.checkTradeId(processModel.getOfferId(), message); Validator.checkTradeId(processModel.getOfferId(), message);
processModel.setTradeMessage(message); processModel.setTradeMessage(message);
CountDownLatch latch = new CountDownLatch(1); latchTrade();
expect(anyPhase(Trade.Phase.INIT) expect(anyPhase(Trade.Phase.INIT)
.with(message) .with(message)
.from(sender)) .from(sender))
@ -157,17 +153,16 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
ProcessSignContractRequest.class) ProcessSignContractRequest.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(sender, message); handleTaskRunnerSuccess(sender, message);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(sender, message, errorMessage); handleTaskRunnerFault(sender, message, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }
@ -178,7 +173,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
Validator.checkTradeId(processModel.getOfferId(), message); Validator.checkTradeId(processModel.getOfferId(), message);
if (trade.getState() == State.CONTRACT_SIGNATURE_REQUESTED) { if (trade.getState() == State.CONTRACT_SIGNATURE_REQUESTED) {
processModel.setTradeMessage(message); processModel.setTradeMessage(message);
CountDownLatch latch = new CountDownLatch(1); if (tradeLatch == null) latchTrade(); // may be initialized from previous message
expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED) expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED)
.with(message) .with(message)
.from(sender)) .from(sender))
@ -187,17 +182,16 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
ProcessSignContractResponse.class) ProcessSignContractResponse.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(sender, message); handleTaskRunnerSuccess(sender, message);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(sender, message, errorMessage); handleTaskRunnerFault(sender, message, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} else { } else {
EasyBind.subscribe(trade.stateProperty(), state -> { EasyBind.subscribe(trade.stateProperty(), state -> {
if (state != State.CONTRACT_SIGNATURE_REQUESTED) return; if (state != State.CONTRACT_SIGNATURE_REQUESTED) return;
@ -213,7 +207,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
synchronized (trade) { synchronized (trade) {
Validator.checkTradeId(processModel.getOfferId(), response); Validator.checkTradeId(processModel.getOfferId(), response);
processModel.setTradeMessage(response); processModel.setTradeMessage(response);
CountDownLatch latch = new CountDownLatch(1); latchTrade();
expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED) expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED)
.with(response) .with(response)
.from(sender)) .from(sender))
@ -222,17 +216,16 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
ProcessDepositResponse.class) ProcessDepositResponse.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
handleTaskRunnerSuccess(sender, response); handleTaskRunnerSuccess(sender, response);
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(sender, response, errorMessage); handleTaskRunnerFault(sender, response, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }
@ -241,7 +234,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
System.out.println(getClass().getCanonicalName() + ".handlePaymentAccountPayloadRequest()"); System.out.println(getClass().getCanonicalName() + ".handlePaymentAccountPayloadRequest()");
synchronized (trade) { synchronized (trade) {
Validator.checkTradeId(processModel.getOfferId(), request); Validator.checkTradeId(processModel.getOfferId(), request);
CountDownLatch latch = new CountDownLatch(1); if (tradeLatch == null) latchTrade(); // may be initialized from previous message
if (trade.getState() == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) { if (trade.getState() == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) {
processModel.setTradeMessage(request); processModel.setTradeMessage(request);
expect(state(Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) // TODO (woodser): rename to RECEIVED_DEPOSIT_TX_PUBLISHED_MSG expect(state(Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) // TODO (woodser): rename to RECEIVED_DEPOSIT_TX_PUBLISHED_MSG
@ -252,19 +245,18 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
ProcessPaymentAccountPayloadRequest.class) ProcessPaymentAccountPayloadRequest.class)
.using(new TradeTaskRunner(trade, .using(new TradeTaskRunner(trade,
() -> { () -> {
latch.countDown(); unlatchTrade();
stopTimeout(); stopTimeout();
handleTaskRunnerSuccess(sender, request); handleTaskRunnerSuccess(sender, request);
tradeResultHandler.handleResult(trade); // trade is initialized tradeResultHandler.handleResult(trade); // trade is initialized
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
handleTaskRunnerFault(sender, request, errorMessage); handleTaskRunnerFault(sender, request, errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
})) }))
.withTimeout(TRADE_TIMEOUT)) .withTimeout(TRADE_TIMEOUT))
.executeTasks(); .executeTasks();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} else { } else {
EasyBind.subscribe(trade.stateProperty(), state -> { EasyBind.subscribe(trade.stateProperty(), state -> {
if (state == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) handlePaymentAccountPayloadRequest(request, sender); if (state == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) handlePaymentAccountPayloadRequest(request, sender);

View file

@ -30,7 +30,6 @@ import bisq.core.trade.protocol.tasks.seller.SellerSendsPaymentReceivedMessage;
import bisq.core.trade.protocol.tasks.seller.SellerPreparesPaymentReceivedMessage; import bisq.core.trade.protocol.tasks.seller.SellerPreparesPaymentReceivedMessage;
import bisq.network.p2p.NodeAddress; import bisq.network.p2p.NodeAddress;
import java.util.concurrent.CountDownLatch;
import bisq.common.handlers.ErrorMessageHandler; import bisq.common.handlers.ErrorMessageHandler;
import bisq.common.handlers.ResultHandler; import bisq.common.handlers.ResultHandler;

View file

@ -64,6 +64,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
protected final ProcessModel processModel; protected final ProcessModel processModel;
protected final Trade trade; protected final Trade trade;
protected CountDownLatch tradeLatch; // to synchronize on trade
private Timer timeoutTimer; private Timer timeoutTimer;
protected TradeResultHandler tradeResultHandler; protected TradeResultHandler tradeResultHandler;
protected ErrorMessageHandler errorMessageHandler; protected ErrorMessageHandler errorMessageHandler;
@ -220,16 +221,15 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
synchronized (trade) { synchronized (trade) {
Validator.checkTradeId(processModel.getOfferId(), message); Validator.checkTradeId(processModel.getOfferId(), message);
processModel.setTradeMessage(message); processModel.setTradeMessage(message);
CountDownLatch latch = new CountDownLatch(1); latchTrade();
TradeTaskRunner taskRunner = new TradeTaskRunner(trade, TradeTaskRunner taskRunner = new TradeTaskRunner(trade,
() -> { () -> {
unlatchTrade();
stopTimeout(); stopTimeout();
latch.countDown();
handleTaskRunnerSuccess(peer, message, "handleUpdateMultisigRequest"); handleTaskRunnerSuccess(peer, message, "handleUpdateMultisigRequest");
}, },
errorMessage -> { errorMessage -> {
latch.countDown(); handleError(errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
handleTaskRunnerFault(peer, message, errorMessage); handleTaskRunnerFault(peer, message, errorMessage);
}); });
taskRunner.addTasks( taskRunner.addTasks(
@ -237,7 +237,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
); );
startTimeout(TRADE_TIMEOUT); startTimeout(TRADE_TIMEOUT);
taskRunner.run(); taskRunner.run();
TradeUtils.waitForLatch(latch); awaitTradeLatch();
} }
} }
@ -365,6 +365,32 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
); );
} }
// TODO: trade protocols block if these are synchronized
protected void handleError(String errorMessage) {
log.error(errorMessage);
unlatchTrade();
trade.setErrorMessage(errorMessage);
if (errorMessageHandler != null) errorMessageHandler.handleErrorMessage(errorMessage);
processModel.getTradeManager().requestPersistence();
cleanup();
}
protected void latchTrade() {
if (tradeLatch != null) throw new RuntimeException("Trade latch is not null. This should never happen.");
tradeLatch = new CountDownLatch(1);
}
protected void unlatchTrade() {
if (tradeLatch != null) tradeLatch.countDown();
tradeLatch = null;
}
protected void awaitTradeLatch() {
if (tradeLatch == null) return;
TradeUtils.awaitLatch(tradeLatch);
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Timeout // Timeout
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -372,11 +398,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
protected void startTimeout(long timeoutSec) { protected void startTimeout(long timeoutSec) {
stopTimeout(); stopTimeout();
timeoutTimer = UserThread.runAfter(() -> { timeoutTimer = UserThread.runAfter(() -> {
log.error("Timeout reached. TradeID={}, state={}, timeoutSec={}", trade.getId(), trade.stateProperty().get(), timeoutSec); handleError("Timeout reached. Protocol did not complete in " + timeoutSec + " sec. TradeID=" + trade.getId() + ", state=" + trade.stateProperty().get());
trade.setErrorMessage("Timeout reached. Protocol did not complete in " + timeoutSec + " sec.");
if (errorMessageHandler != null) errorMessageHandler.handleErrorMessage("Timeout reached. Protocol did not complete in " + timeoutSec + " sec. TradeID=" + trade.getId() + ", state=" + trade.stateProperty().get());
processModel.getTradeManager().requestPersistence();
cleanup();
}, timeoutSec); }, timeoutSec);
} }

View file

@ -22,7 +22,7 @@ import bisq.desktop.main.offer.OfferDataModel;
import bisq.desktop.main.offer.offerbook.OfferBook; import bisq.desktop.main.offer.offerbook.OfferBook;
import bisq.desktop.main.overlays.popups.Popup; import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.util.GUIUtil; import bisq.desktop.util.GUIUtil;
import bisq.common.handlers.ErrorMessageHandler;
import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.btc.listeners.XmrBalanceListener; import bisq.core.btc.listeners.XmrBalanceListener;
import bisq.core.btc.model.XmrAddressEntry; import bisq.core.btc.model.XmrAddressEntry;
@ -302,7 +302,7 @@ class TakeOfferDataModel extends OfferDataModel {
// errorMessageHandler is used only in the check availability phase. As soon we have a trade we write the error msg in the trade object as we want to // errorMessageHandler is used only in the check availability phase. As soon we have a trade we write the error msg in the trade object as we want to
// have it persisted as well. // have it persisted as well.
void onTakeOffer(TradeResultHandler tradeResultHandler) { void onTakeOffer(TradeResultHandler tradeResultHandler, ErrorMessageHandler errorMessageHandler) {
checkNotNull(txFeeFromFeeService, "txFeeFromFeeService must not be null"); checkNotNull(txFeeFromFeeService, "txFeeFromFeeService must not be null");
checkNotNull(getTakerFee(), "takerFee must not be null"); checkNotNull(getTakerFee(), "takerFee must not be null");
@ -334,7 +334,7 @@ class TakeOfferDataModel extends OfferDataModel {
tradeResultHandler, tradeResultHandler,
errorMessage -> { errorMessage -> {
log.warn(errorMessage); log.warn(errorMessage);
new Popup().warning(errorMessage).show(); errorMessageHandler.handleErrorMessage(errorMessage);
} }
); );
} }

View file

@ -29,7 +29,6 @@ import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil; import bisq.desktop.util.GUIUtil;
import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.btc.wallet.Restrictions; import bisq.core.btc.wallet.Restrictions;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.monetary.Price; import bisq.core.monetary.Price;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
@ -124,13 +123,11 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
private ChangeListener<Coin> amountAsCoinListener; private ChangeListener<Coin> amountAsCoinListener;
private ChangeListener<Boolean> isWalletFundedListener; private ChangeListener<Boolean> isWalletFundedListener;
private ChangeListener<Trade.State> tradeStateListener; private ChangeListener<Trade.State> tradeStateListener;
private ChangeListener<String> tradeErrorListener;
private ChangeListener<Offer.State> offerStateListener; private ChangeListener<Offer.State> offerStateListener;
private ChangeListener<String> offerErrorListener;
private ChangeListener<Number> getMempoolStatusListener; private ChangeListener<Number> getMempoolStatusListener;
private ConnectionListener connectionListener; private ConnectionListener connectionListener;
// private Subscription isFeeSufficientSubscription; // private Subscription isFeeSufficientSubscription;
private Runnable takeOfferSucceededHandler; private Runnable takeOfferResultHandler;
String marketPriceMargin; String marketPriceMargin;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -220,11 +217,6 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
checkNotNull(dataModel.getAddressEntry(), "dataModel.getAddressEntry() must not be null"); checkNotNull(dataModel.getAddressEntry(), "dataModel.getAddressEntry() must not be null");
offerErrorListener = (observable, oldValue, newValue) -> {
if (newValue != null)
errorMessage.set(newValue);
};
offer.errorMessageProperty().addListener(offerErrorListener);
errorMessage.set(offer.getErrorMessage()); errorMessage.set(offer.getErrorMessage());
btcValidator.setMaxValue(offer.getAmount()); btcValidator.setMaxValue(offer.getAmount());
@ -237,7 +229,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
void onTakeOffer(Runnable resultHandler) { void onTakeOffer(Runnable resultHandler) {
takeOfferSucceededHandler = resultHandler; takeOfferResultHandler = resultHandler;
takeOfferRequested = true; takeOfferRequested = true;
showTransactionPublishedScreen.set(false); showTransactionPublishedScreen.set(false);
dataModel.onTakeOffer(trade -> { dataModel.onTakeOffer(trade -> {
@ -245,9 +237,10 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
takeOfferCompleted.set(true); takeOfferCompleted.set(true);
trade.stateProperty().addListener(tradeStateListener); trade.stateProperty().addListener(tradeStateListener);
applyTradeState(); applyTradeState();
trade.errorMessageProperty().addListener(tradeErrorListener);
applyTradeErrorMessage(trade.getErrorMessage()); applyTradeErrorMessage(trade.getErrorMessage());
takeOfferCompleted.set(true); takeOfferCompleted.set(true);
}, errMessage -> {
applyTradeErrorMessage(errMessage);
}); });
updateButtonDisableState(); updateButtonDisableState();
@ -418,7 +411,8 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
private void applyTradeErrorMessage(@Nullable String errorMessage) { private void applyTradeErrorMessage(@Nullable String errorMessage) {
if (errorMessage != null) { if (errorMessage != null) {
String appendMsg = ""; String appendMsg = "";
switch (trade.getState().getPhase()) { if (trade != null) {
switch (trade.getState().getPhase()) {
case INIT: case INIT:
appendMsg = Res.get("takeOffer.error.noFundsLost"); appendMsg = Res.get("takeOffer.error.noFundsLost");
break; break;
@ -434,13 +428,16 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
case WITHDRAWN: case WITHDRAWN:
appendMsg = Res.get("takeOffer.error.payoutPublished"); appendMsg = Res.get("takeOffer.error.payoutPublished");
break; break;
default:
break;
}
} }
this.errorMessage.set(errorMessage + appendMsg); this.errorMessage.set(errorMessage + appendMsg);
updateSpinnerInfo(); updateSpinnerInfo();
if (takeOfferSucceededHandler != null) if (takeOfferResultHandler != null)
takeOfferSucceededHandler.run(); takeOfferResultHandler.run();
} else { } else {
this.errorMessage.set(null); this.errorMessage.set(null);
} }
@ -449,8 +446,8 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
private void applyTradeState() { private void applyTradeState() {
if (trade.isTakerFeePublished()) { if (trade.isTakerFeePublished()) {
if (trade.getTakerFeeTxId() != null) { if (trade.getTakerFeeTxId() != null) {
if (takeOfferSucceededHandler != null) if (takeOfferResultHandler != null)
takeOfferSucceededHandler.run(); takeOfferResultHandler.run();
showTransactionPublishedScreen.set(true); showTransactionPublishedScreen.set(true);
updateSpinnerInfo(); updateSpinnerInfo();
@ -505,7 +502,6 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
isWalletFundedListener = (ov, oldValue, newValue) -> updateButtonDisableState(); isWalletFundedListener = (ov, oldValue, newValue) -> updateButtonDisableState();
tradeStateListener = (ov, oldValue, newValue) -> applyTradeState(); tradeStateListener = (ov, oldValue, newValue) -> applyTradeState();
tradeErrorListener = (ov, oldValue, newValue) -> applyTradeErrorMessage(newValue);
offerStateListener = (ov, oldValue, newValue) -> applyOfferState(newValue); offerStateListener = (ov, oldValue, newValue) -> applyOfferState(newValue);
getMempoolStatusListener = (observable, oldValue, newValue) -> { getMempoolStatusListener = (observable, oldValue, newValue) -> {
@ -583,12 +579,10 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
dataModel.getIsBtcWalletFunded().removeListener(isWalletFundedListener); dataModel.getIsBtcWalletFunded().removeListener(isWalletFundedListener);
if (offer != null) { if (offer != null) {
offer.stateProperty().removeListener(offerStateListener); offer.stateProperty().removeListener(offerStateListener);
offer.errorMessageProperty().removeListener(offerErrorListener);
} }
if (trade != null) { if (trade != null) {
trade.stateProperty().removeListener(tradeStateListener); trade.stateProperty().removeListener(tradeStateListener);
trade.errorMessageProperty().removeListener(tradeErrorListener);
} }
p2PService.getNetworkNode().removeConnectionListener(connectionListener); p2PService.getNetworkNode().removeConnectionListener(connectionListener);
//isFeeSufficientSubscription.unsubscribe(); //isFeeSufficientSubscription.unsubscribe();