mirror of
https://github.com/boldsuck/haveno.git
synced 2025-01-24 00:25:56 +00:00
refactor trade protocol latch and timeouts
This commit is contained in:
parent
3f25a756ea
commit
3dcaf67edd
22 changed files with 346 additions and 368 deletions
|
@ -186,27 +186,23 @@ public class XmrWalletService {
|
||||||
public MoneroWallet createMultisigWallet(String tradeId) {
|
public MoneroWallet createMultisigWallet(String tradeId) {
|
||||||
log.info("{}.createMultisigWallet({})", getClass().getSimpleName(), tradeId);
|
log.info("{}.createMultisigWallet({})", getClass().getSimpleName(), tradeId);
|
||||||
Trade trade = tradeManager.getOpenTrade(tradeId).get();
|
Trade trade = tradeManager.getOpenTrade(tradeId).get();
|
||||||
synchronized (trade) {
|
if (multisigWallets.containsKey(trade.getId())) return multisigWallets.get(trade.getId());
|
||||||
if (multisigWallets.containsKey(trade.getId())) return multisigWallets.get(trade.getId());
|
String path = MONERO_MULTISIG_WALLET_PREFIX + trade.getId();
|
||||||
String path = MONERO_MULTISIG_WALLET_PREFIX + trade.getId();
|
MoneroWallet multisigWallet = createWallet(new MoneroWalletConfig().setPath(path).setPassword(getWalletPassword()), null, false); // auto-assign port
|
||||||
MoneroWallet multisigWallet = createWallet(new MoneroWalletConfig().setPath(path).setPassword(getWalletPassword()), null); // auto-assign port
|
multisigWallets.put(trade.getId(), multisigWallet);
|
||||||
multisigWallets.put(trade.getId(), multisigWallet);
|
return multisigWallet;
|
||||||
return multisigWallet;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO (woodser): provide progress notifications during open?
|
// TODO (woodser): provide progress notifications during open?
|
||||||
public MoneroWallet getMultisigWallet(String tradeId) {
|
public MoneroWallet getMultisigWallet(String tradeId) {
|
||||||
log.info("{}.getMultisigWallet({})", getClass().getSimpleName(), tradeId);
|
log.info("{}.getMultisigWallet({})", getClass().getSimpleName(), tradeId);
|
||||||
Trade trade = tradeManager.getTrade(tradeId);
|
Trade trade = tradeManager.getTrade(tradeId);
|
||||||
synchronized (trade) {
|
if (multisigWallets.containsKey(trade.getId())) return multisigWallets.get(trade.getId());
|
||||||
if (multisigWallets.containsKey(trade.getId())) return multisigWallets.get(trade.getId());
|
String path = MONERO_MULTISIG_WALLET_PREFIX + trade.getId();
|
||||||
String path = MONERO_MULTISIG_WALLET_PREFIX + trade.getId();
|
if (!walletExists(path)) throw new RuntimeException("Multisig wallet does not exist for trade " + trade.getId());
|
||||||
if (!walletExists(path)) throw new RuntimeException("Multisig wallet does not exist for trade " + trade.getId());
|
MoneroWallet multisigWallet = openWallet(new MoneroWalletConfig().setPath(path).setPassword(getWalletPassword()), null);
|
||||||
MoneroWallet multisigWallet = openWallet(new MoneroWalletConfig().setPath(path).setPassword(getWalletPassword()), null);
|
multisigWallets.put(trade.getId(), multisigWallet);
|
||||||
multisigWallets.put(trade.getId(), multisigWallet);
|
return multisigWallet;
|
||||||
return multisigWallet;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveWallet(MoneroWallet wallet) {
|
public void saveWallet(MoneroWallet wallet) {
|
||||||
|
@ -216,24 +212,18 @@ public class XmrWalletService {
|
||||||
|
|
||||||
public void closeMultisigWallet(String tradeId) {
|
public void closeMultisigWallet(String tradeId) {
|
||||||
log.info("{}.closeMultisigWallet({})", getClass().getSimpleName(), tradeId);
|
log.info("{}.closeMultisigWallet({})", getClass().getSimpleName(), tradeId);
|
||||||
Trade trade = tradeManager.getTrade(tradeId);
|
if (!multisigWallets.containsKey(tradeId)) throw new RuntimeException("Multisig wallet to close was not previously opened for trade " + tradeId);
|
||||||
synchronized (trade) {
|
MoneroWallet wallet = multisigWallets.remove(tradeId);
|
||||||
if (!multisigWallets.containsKey(trade.getId())) throw new RuntimeException("Multisig wallet to close was not previously opened for trade " + trade.getId());
|
closeWallet(wallet, true);
|
||||||
MoneroWallet wallet = multisigWallets.remove(trade.getId());
|
|
||||||
closeWallet(wallet, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean deleteMultisigWallet(String tradeId) {
|
public boolean deleteMultisigWallet(String tradeId) {
|
||||||
log.info("{}.deleteMultisigWallet({})", getClass().getSimpleName(), tradeId);
|
log.info("{}.deleteMultisigWallet({})", getClass().getSimpleName(), tradeId);
|
||||||
Trade trade = tradeManager.getTrade(tradeId);
|
String walletName = MONERO_MULTISIG_WALLET_PREFIX + tradeId;
|
||||||
synchronized (trade) {
|
if (!walletExists(walletName)) return false;
|
||||||
String walletName = MONERO_MULTISIG_WALLET_PREFIX + tradeId;
|
if (multisigWallets.containsKey(tradeId)) closeMultisigWallet(tradeId); // TODO: synchronize
|
||||||
if (!walletExists(walletName)) return false;
|
deleteWallet(walletName);
|
||||||
if (multisigWallets.containsKey(trade.getId())) closeMultisigWallet(tradeId);
|
return true;
|
||||||
deleteWallet(walletName);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public MoneroTxWallet createTx(List<MoneroDestination> destinations) {
|
public MoneroTxWallet createTx(List<MoneroDestination> destinations) {
|
||||||
|
@ -407,7 +397,7 @@ public class XmrWalletService {
|
||||||
if (MoneroUtils.walletExists(xmrWalletFile.getPath())) {
|
if (MoneroUtils.walletExists(xmrWalletFile.getPath())) {
|
||||||
wallet = openWallet(walletConfig, rpcBindPort);
|
wallet = openWallet(walletConfig, rpcBindPort);
|
||||||
} else if (connectionsService.getConnection() != null && Boolean.TRUE.equals(connectionsService.getConnection().isConnected())) {
|
} else if (connectionsService.getConnection() != null && Boolean.TRUE.equals(connectionsService.getConnection().isConnected())) {
|
||||||
wallet = createWallet(walletConfig, rpcBindPort);
|
wallet = createWallet(walletConfig, rpcBindPort, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// wallet is not initialized until connected to a daemon
|
// wallet is not initialized until connected to a daemon
|
||||||
|
@ -437,10 +427,10 @@ public class XmrWalletService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private MoneroWalletRpc createWallet(MoneroWalletConfig config, Integer port) {
|
private MoneroWalletRpc createWallet(MoneroWalletConfig config, Integer port, boolean sync) {
|
||||||
|
|
||||||
// start monero-wallet-rpc instance
|
// start monero-wallet-rpc instance
|
||||||
MoneroWalletRpc walletRpc = startWalletRpcInstance(port);
|
MoneroWalletRpc walletRpc = startWalletRpcInstance(port, sync);
|
||||||
|
|
||||||
// must be connected to daemon
|
// must be connected to daemon
|
||||||
MoneroRpcConnection connection = connectionsService.getConnection();
|
MoneroRpcConnection connection = connectionsService.getConnection();
|
||||||
|
@ -449,9 +439,17 @@ public class XmrWalletService {
|
||||||
// create wallet
|
// create wallet
|
||||||
try {
|
try {
|
||||||
log.info("Creating wallet " + config.getPath());
|
log.info("Creating wallet " + config.getPath());
|
||||||
|
MoneroRpcConnection daemonConnection = config.getServer();
|
||||||
|
if (!sync) config.setServer(null);
|
||||||
walletRpc.createWallet(config);
|
walletRpc.createWallet(config);
|
||||||
log.info("Syncing wallet " + config.getPath() + " in background");
|
if (sync) {
|
||||||
walletRpc.startSyncing(connectionsService.getDefaultRefreshPeriodMs());
|
log.info("Syncing wallet " + config.getPath() + " in background");
|
||||||
|
walletRpc.startSyncing(connectionsService.getDefaultRefreshPeriodMs());
|
||||||
|
log.info("Done starting background wallet sync for " + config.getPath());
|
||||||
|
} else {
|
||||||
|
walletRpc.setDaemonConnection(daemonConnection);
|
||||||
|
}
|
||||||
|
log.info("Done creating wallet " + config.getPath());
|
||||||
return walletRpc;
|
return walletRpc;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -463,7 +461,7 @@ public class XmrWalletService {
|
||||||
private MoneroWalletRpc openWallet(MoneroWalletConfig config, Integer port) {
|
private MoneroWalletRpc openWallet(MoneroWalletConfig config, Integer port) {
|
||||||
|
|
||||||
// start monero-wallet-rpc instance
|
// start monero-wallet-rpc instance
|
||||||
MoneroWalletRpc walletRpc = startWalletRpcInstance(port);
|
MoneroWalletRpc walletRpc = startWalletRpcInstance(port, true);
|
||||||
|
|
||||||
// open wallet
|
// open wallet
|
||||||
try {
|
try {
|
||||||
|
@ -474,10 +472,6 @@ public class XmrWalletService {
|
||||||
// start syncing wallet in background
|
// start syncing wallet in background
|
||||||
log.info("Syncing wallet " + config.getPath() + " in background");
|
log.info("Syncing wallet " + config.getPath() + " in background");
|
||||||
walletRpc.startSyncing(connectionsService.getDefaultRefreshPeriodMs());
|
walletRpc.startSyncing(connectionsService.getDefaultRefreshPeriodMs());
|
||||||
|
|
||||||
// sync wallet (blocks)
|
|
||||||
log.info("Syncing wallet " + config.getPath());
|
|
||||||
walletRpc.sync(); // TODO: does this initiate 2 syncs back-to-back?
|
|
||||||
log.info("Done syncing wallet " + config.getPath());
|
log.info("Done syncing wallet " + config.getPath());
|
||||||
return walletRpc;
|
return walletRpc;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -487,7 +481,7 @@ public class XmrWalletService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private MoneroWalletRpc startWalletRpcInstance(Integer port) {
|
private MoneroWalletRpc startWalletRpcInstance(Integer port, boolean withConnection) {
|
||||||
|
|
||||||
// check if monero-wallet-rpc exists
|
// check if monero-wallet-rpc exists
|
||||||
if (!new File(MONERO_WALLET_RPC_PATH).exists()) throw new Error("monero-wallet-rpc executable doesn't exist at path " + MONERO_WALLET_RPC_PATH
|
if (!new File(MONERO_WALLET_RPC_PATH).exists()) throw new Error("monero-wallet-rpc executable doesn't exist at path " + MONERO_WALLET_RPC_PATH
|
||||||
|
@ -497,7 +491,7 @@ public class XmrWalletService {
|
||||||
List<String> cmd = new ArrayList<>(Arrays.asList( // modifiable list
|
List<String> cmd = new ArrayList<>(Arrays.asList( // modifiable list
|
||||||
MONERO_WALLET_RPC_PATH, "--" + MONERO_NETWORK_TYPE.toString().toLowerCase(), "--rpc-login",
|
MONERO_WALLET_RPC_PATH, "--" + MONERO_NETWORK_TYPE.toString().toLowerCase(), "--rpc-login",
|
||||||
MONERO_WALLET_RPC_USERNAME + ":" + getWalletPassword(), "--wallet-dir", walletDir.toString()));
|
MONERO_WALLET_RPC_USERNAME + ":" + getWalletPassword(), "--wallet-dir", walletDir.toString()));
|
||||||
MoneroRpcConnection connection = connectionsService.getConnection();
|
MoneroRpcConnection connection = withConnection ? connectionsService.getConnection() : null;
|
||||||
if (connection != null) {
|
if (connection != null) {
|
||||||
cmd.add("--daemon-address");
|
cmd.add("--daemon-address");
|
||||||
cmd.add(connection.getUri());
|
cmd.add(connection.getUri());
|
||||||
|
|
|
@ -132,7 +132,7 @@ public abstract class Trade implements Tradable, Model {
|
||||||
// We changes order in trade protocol of publishing deposit tx and sending it to the peer.
|
// We changes order in trade protocol of publishing deposit tx and sending it to the peer.
|
||||||
// Now we send it first to the peer and only if that succeeds we publish it to avoid likelihood of
|
// Now we send it first to the peer and only if that succeeds we publish it to avoid likelihood of
|
||||||
// failed trades. We do not want to change the order of the enum though so we keep it here as it was originally.
|
// failed trades. We do not want to change the order of the enum though so we keep it here as it was originally.
|
||||||
TAKER_PUBLISHED_DEPOSIT_TX(Phase.DEPOSIT_PUBLISHED),
|
ARBITRATOR_PUBLISHED_DEPOSIT_TX(Phase.DEPOSIT_PUBLISHED),
|
||||||
|
|
||||||
// DEPOSIT_TX_PUBLISHED_MSG
|
// DEPOSIT_TX_PUBLISHED_MSG
|
||||||
// taker perspective
|
// taker perspective
|
||||||
|
|
|
@ -67,6 +67,7 @@ import bisq.network.p2p.P2PService;
|
||||||
import bisq.network.p2p.network.TorNetworkNode;
|
import bisq.network.p2p.network.TorNetworkNode;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import bisq.common.ClockWatcher;
|
import bisq.common.ClockWatcher;
|
||||||
|
import bisq.common.UserThread;
|
||||||
import bisq.common.config.Config;
|
import bisq.common.config.Config;
|
||||||
import bisq.common.crypto.KeyRing;
|
import bisq.common.crypto.KeyRing;
|
||||||
import bisq.common.handlers.ErrorMessageHandler;
|
import bisq.common.handlers.ErrorMessageHandler;
|
||||||
|
@ -884,20 +885,22 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
||||||
|
|
||||||
private void updateTradePeriodState() {
|
private void updateTradePeriodState() {
|
||||||
getObservableList().forEach(trade -> {
|
getObservableList().forEach(trade -> {
|
||||||
if (!trade.isPayoutPublished()) {
|
UserThread.execute(() -> { // prevent concurrent modification error
|
||||||
Date maxTradePeriodDate = trade.getMaxTradePeriodDate();
|
if (!trade.isPayoutPublished()) {
|
||||||
Date halfTradePeriodDate = trade.getHalfTradePeriodDate();
|
Date maxTradePeriodDate = trade.getMaxTradePeriodDate();
|
||||||
if (maxTradePeriodDate != null && halfTradePeriodDate != null) {
|
Date halfTradePeriodDate = trade.getHalfTradePeriodDate();
|
||||||
Date now = new Date();
|
if (maxTradePeriodDate != null && halfTradePeriodDate != null) {
|
||||||
if (now.after(maxTradePeriodDate)) {
|
Date now = new Date();
|
||||||
trade.setPeriodState(Trade.TradePeriodState.TRADE_PERIOD_OVER);
|
if (now.after(maxTradePeriodDate)) {
|
||||||
requestPersistence();
|
trade.setPeriodState(Trade.TradePeriodState.TRADE_PERIOD_OVER);
|
||||||
} else if (now.after(halfTradePeriodDate)) {
|
requestPersistence();
|
||||||
trade.setPeriodState(Trade.TradePeriodState.SECOND_HALF);
|
} else if (now.after(halfTradePeriodDate)) {
|
||||||
requestPersistence();
|
trade.setPeriodState(Trade.TradePeriodState.SECOND_HALF);
|
||||||
|
requestPersistence();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1060,28 +1063,27 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
||||||
return closedTradableManager.getClosedTrades().stream().filter(e -> e.getId().equals(tradeId)).findFirst();
|
return closedTradableManager.getClosedTrades().stream().filter(e -> e.getId().equals(tradeId)).findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeTrade(Trade trade) {
|
private synchronized void removeTrade(Trade trade) {
|
||||||
log.info("TradeManager.removeTrade()");
|
log.info("TradeManager.removeTrade()");
|
||||||
synchronized(tradableList) {
|
synchronized(tradableList) {
|
||||||
if (!tradableList.contains(trade)) return;
|
if (!tradableList.contains(trade)) return;
|
||||||
|
|
||||||
synchronized (trade) {
|
// remove trade
|
||||||
|
tradableList.remove(trade);
|
||||||
|
|
||||||
// unreserve trade key images
|
// unreserve trade key images
|
||||||
if (trade instanceof TakerTrade && trade.getSelf().getReserveTxKeyImages() != null) {
|
if (trade instanceof TakerTrade && trade.getSelf().getReserveTxKeyImages() != null) {
|
||||||
for (String keyImage : trade.getSelf().getReserveTxKeyImages()) {
|
for (String keyImage : trade.getSelf().getReserveTxKeyImages()) {
|
||||||
xmrWalletService.getWallet().thawOutput(keyImage);
|
xmrWalletService.getWallet().thawOutput(keyImage);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete trade wallet when empty
|
|
||||||
deleteTradeWalletWhenEmpty(trade);
|
|
||||||
|
|
||||||
// unregister and persist
|
|
||||||
p2PService.removeDecryptedDirectMessageListener(getTradeProtocol(trade));
|
|
||||||
tradableList.remove(trade);
|
|
||||||
requestPersistence();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// delete trade wallet when empty
|
||||||
|
deleteTradeWalletWhenEmpty(trade);
|
||||||
|
|
||||||
|
// unregister and persist
|
||||||
|
p2PService.removeDecryptedDirectMessageListener(getTradeProtocol(trade));
|
||||||
|
requestPersistence();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,9 +33,9 @@ public class ArbitratorProtocol extends DisputeProtocol {
|
||||||
public void handleInitTradeRequest(InitTradeRequest message, NodeAddress peer, ErrorMessageHandler errorMessageHandler) {
|
public void handleInitTradeRequest(InitTradeRequest message, NodeAddress peer, ErrorMessageHandler errorMessageHandler) {
|
||||||
System.out.println("ArbitratorProtocol.handleInitTradeRequest()");
|
System.out.println("ArbitratorProtocol.handleInitTradeRequest()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
|
latchTrade();
|
||||||
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
|
||||||
latchTrade();
|
|
||||||
expect(phase(Trade.Phase.INIT)
|
expect(phase(Trade.Phase.INIT)
|
||||||
.with(message)
|
.with(message)
|
||||||
.from(peer))
|
.from(peer))
|
||||||
|
@ -46,11 +46,10 @@ public class ArbitratorProtocol extends DisputeProtocol {
|
||||||
ArbitratorSendsInitTradeAndMultisigRequests.class)
|
ArbitratorSendsInitTradeAndMultisigRequests.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerSuccess(peer, message);
|
handleTaskRunnerSuccess(peer, message);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(peer, message, errorMessage);
|
handleTaskRunnerFault(peer, message, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
|
@ -63,9 +62,9 @@ public class ArbitratorProtocol extends DisputeProtocol {
|
||||||
public void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress sender) {
|
public void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress sender) {
|
||||||
System.out.println("ArbitratorProtocol.handleInitMultisigRequest()");
|
System.out.println("ArbitratorProtocol.handleInitMultisigRequest()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
|
latchTrade();
|
||||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||||
processModel.setTradeMessage(request);
|
processModel.setTradeMessage(request);
|
||||||
latchTrade();
|
|
||||||
expect(anyPhase(Trade.Phase.INIT)
|
expect(anyPhase(Trade.Phase.INIT)
|
||||||
.with(request)
|
.with(request)
|
||||||
.from(sender))
|
.from(sender))
|
||||||
|
@ -73,11 +72,10 @@ public class ArbitratorProtocol extends DisputeProtocol {
|
||||||
ProcessInitMultisigRequest.class)
|
ProcessInitMultisigRequest.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerSuccess(sender, request);
|
handleTaskRunnerSuccess(sender, request);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(sender, request, errorMessage);
|
handleTaskRunnerFault(sender, request, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
|
@ -90,9 +88,9 @@ public class ArbitratorProtocol extends DisputeProtocol {
|
||||||
public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) {
|
public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) {
|
||||||
System.out.println("ArbitratorProtocol.handleSignContractRequest()");
|
System.out.println("ArbitratorProtocol.handleSignContractRequest()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
|
latchTrade();
|
||||||
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
|
||||||
latchTrade();
|
|
||||||
expect(anyPhase(Trade.Phase.INIT)
|
expect(anyPhase(Trade.Phase.INIT)
|
||||||
.with(message)
|
.with(message)
|
||||||
.from(sender))
|
.from(sender))
|
||||||
|
@ -101,11 +99,10 @@ public class ArbitratorProtocol extends DisputeProtocol {
|
||||||
ProcessSignContractRequest.class)
|
ProcessSignContractRequest.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerSuccess(sender, message);
|
handleTaskRunnerSuccess(sender, message);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(sender, message, errorMessage);
|
handleTaskRunnerFault(sender, message, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
|
@ -117,22 +114,23 @@ public class ArbitratorProtocol extends DisputeProtocol {
|
||||||
public void handleDepositRequest(DepositRequest request, NodeAddress sender) {
|
public void handleDepositRequest(DepositRequest request, NodeAddress sender) {
|
||||||
System.out.println("ArbitratorProtocol.handleDepositRequest()");
|
System.out.println("ArbitratorProtocol.handleDepositRequest()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
|
latchTrade();
|
||||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||||
processModel.setTradeMessage(request);
|
processModel.setTradeMessage(request);
|
||||||
latchTrade();
|
expect(phase(Trade.Phase.INIT)
|
||||||
expect(anyPhase(Trade.Phase.INIT)
|
|
||||||
.with(request)
|
.with(request)
|
||||||
.from(sender))
|
.from(sender))
|
||||||
.setup(tasks(
|
.setup(tasks(
|
||||||
ArbitratorProcessesDepositRequest.class)
|
ArbitratorProcessesDepositRequest.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
if (trade.getState() == Trade.State.ARBITRATOR_PUBLISHED_DEPOSIT_TX) {
|
||||||
stopTimeout();
|
stopTimeout();
|
||||||
|
this.errorMessageHandler = null;
|
||||||
|
}
|
||||||
handleTaskRunnerSuccess(sender, request);
|
handleTaskRunnerSuccess(sender, request);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(sender, request, errorMessage);
|
handleTaskRunnerFault(sender, request, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
|
|
|
@ -19,7 +19,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.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;
|
||||||
|
@ -77,8 +76,8 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||||
ErrorMessageHandler errorMessageHandler) {
|
ErrorMessageHandler errorMessageHandler) {
|
||||||
System.out.println(getClass().getCanonicalName() + ".handleInitTradeRequest()");
|
System.out.println(getClass().getCanonicalName() + ".handleInitTradeRequest()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
this.errorMessageHandler = errorMessageHandler;
|
|
||||||
latchTrade();
|
latchTrade();
|
||||||
|
this.errorMessageHandler = errorMessageHandler;
|
||||||
expect(phase(Trade.Phase.INIT)
|
expect(phase(Trade.Phase.INIT)
|
||||||
.with(message)
|
.with(message)
|
||||||
.from(peer))
|
.from(peer))
|
||||||
|
@ -89,11 +88,10 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||||
MakerSendsInitTradeRequestIfUnreserved.class)
|
MakerSendsInitTradeRequestIfUnreserved.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerSuccess(peer, message);
|
handleTaskRunnerSuccess(peer, message);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(peer, message, errorMessage);
|
handleTaskRunnerFault(peer, message, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
|
@ -106,9 +104,9 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||||
public void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress sender) {
|
public void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress sender) {
|
||||||
System.out.println(getClass().getCanonicalName() + ".handleInitMultisigRequest()");
|
System.out.println(getClass().getCanonicalName() + ".handleInitMultisigRequest()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
|
latchTrade();
|
||||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||||
processModel.setTradeMessage(request);
|
processModel.setTradeMessage(request);
|
||||||
latchTrade();
|
|
||||||
expect(anyPhase(Trade.Phase.INIT)
|
expect(anyPhase(Trade.Phase.INIT)
|
||||||
.with(request)
|
.with(request)
|
||||||
.from(sender))
|
.from(sender))
|
||||||
|
@ -117,13 +115,13 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||||
SendSignContractRequestAfterMultisig.class)
|
SendSignContractRequestAfterMultisig.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerSuccess(sender, request);
|
handleTaskRunnerSuccess(sender, request);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(sender, request, errorMessage);
|
handleTaskRunnerFault(sender, request, errorMessage);
|
||||||
})))
|
}))
|
||||||
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
|
@ -133,9 +131,9 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||||
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() + ".handleSignContractRequest()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
|
latchTrade();
|
||||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
processModel.setTradeMessage(message);
|
processModel.setTradeMessage(message);
|
||||||
latchTrade();
|
|
||||||
expect(anyPhase(Trade.Phase.INIT)
|
expect(anyPhase(Trade.Phase.INIT)
|
||||||
.with(message)
|
.with(message)
|
||||||
.from(sender))
|
.from(sender))
|
||||||
|
@ -144,13 +142,13 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||||
ProcessSignContractRequest.class)
|
ProcessSignContractRequest.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerSuccess(sender, message);
|
handleTaskRunnerSuccess(sender, message);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(sender, message, errorMessage);
|
handleTaskRunnerFault(sender, message, errorMessage);
|
||||||
})))
|
}))
|
||||||
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
|
@ -158,12 +156,13 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleSignContractResponse(SignContractResponse message, NodeAddress sender) {
|
public void handleSignContractResponse(SignContractResponse message, NodeAddress sender) {
|
||||||
System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse()");
|
System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse() " + trade.getId());
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
if (trade.getState() == State.CONTRACT_SIGNATURE_REQUESTED) {
|
if (trade.getState() == Trade.State.CONTRACT_SIGNATURE_REQUESTED) {
|
||||||
|
latchTrade();
|
||||||
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
processModel.setTradeMessage(message);
|
processModel.setTradeMessage(message);
|
||||||
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))
|
||||||
|
@ -172,11 +171,10 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||||
ProcessSignContractResponse.class)
|
ProcessSignContractResponse.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerSuccess(sender, message);
|
handleTaskRunnerSuccess(sender, message);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(sender, message, errorMessage);
|
handleTaskRunnerFault(sender, message, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
||||||
|
@ -184,7 +182,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
} else {
|
} else {
|
||||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||||
if (state == State.CONTRACT_SIGNATURE_REQUESTED) handleSignContractResponse(message, sender);
|
if (state == Trade.State.CONTRACT_SIGNATURE_REQUESTED) new Thread(() -> handleSignContractResponse(message, sender)).start(); // process notification without trade lock
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,10 +192,10 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||||
public void handleDepositResponse(DepositResponse response, NodeAddress sender) {
|
public void handleDepositResponse(DepositResponse response, NodeAddress sender) {
|
||||||
System.out.println(getClass().getCanonicalName() + ".handleDepositResponse()");
|
System.out.println(getClass().getCanonicalName() + ".handleDepositResponse()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
|
latchTrade();
|
||||||
Validator.checkTradeId(processModel.getOfferId(), response);
|
Validator.checkTradeId(processModel.getOfferId(), response);
|
||||||
processModel.setTradeMessage(response);
|
processModel.setTradeMessage(response);
|
||||||
latchTrade();
|
expect(state(Trade.State.MAKER_SENT_PUBLISH_DEPOSIT_TX_REQUEST)
|
||||||
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()
|
||||||
.setup(tasks(
|
.setup(tasks(
|
||||||
|
@ -205,11 +203,10 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||||
ProcessDepositResponse.class)
|
ProcessDepositResponse.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerSuccess(sender, response);
|
handleTaskRunnerSuccess(sender, response);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(sender, response, errorMessage);
|
handleTaskRunnerFault(sender, response, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
|
@ -220,12 +217,13 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handlePaymentAccountPayloadRequest(PaymentAccountPayloadRequest request, NodeAddress sender) {
|
public void handlePaymentAccountPayloadRequest(PaymentAccountPayloadRequest request, NodeAddress sender) {
|
||||||
System.out.println(getClass().getCanonicalName() + ".handlePaymentAccountPayloadRequest()");
|
System.out.println(getClass().getCanonicalName() + ".handlePaymentAccountPayloadRequest() " + trade.getId());
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||||
if (trade.getState() == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) {
|
if (trade.getState() == Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) {
|
||||||
|
latchTrade();
|
||||||
|
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||||
processModel.setTradeMessage(request);
|
processModel.setTradeMessage(request);
|
||||||
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()
|
||||||
|
@ -234,22 +232,20 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||||
ProcessPaymentAccountPayloadRequest.class,
|
ProcessPaymentAccountPayloadRequest.class,
|
||||||
MakerRemovesOpenOffer.class)
|
MakerRemovesOpenOffer.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
stopTimeout();
|
stopTimeout();
|
||||||
unlatchTrade();
|
this.errorMessageHandler = null;
|
||||||
this.errorMessageHandler = null;
|
handleTaskRunnerSuccess(sender, request);
|
||||||
handleTaskRunnerSuccess(sender, request);
|
},
|
||||||
},
|
errorMessage -> {
|
||||||
errorMessage -> {
|
handleTaskRunnerFault(sender, request, errorMessage);
|
||||||
handleError(errorMessage);
|
}))
|
||||||
handleTaskRunnerFault(sender, request, errorMessage);
|
|
||||||
}))
|
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
awaitTradeLatch();
|
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 == Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) new Thread(() -> handlePaymentAccountPayloadRequest(request, sender)).start(); // process notification without trade lock
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ package bisq.core.trade.protocol;
|
||||||
import bisq.core.offer.Offer;
|
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.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;
|
||||||
|
@ -94,9 +93,9 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
||||||
ErrorMessageHandler errorMessageHandler) {
|
ErrorMessageHandler errorMessageHandler) {
|
||||||
System.out.println(getClass().getCanonicalName() + ".onTakeOffer()");
|
System.out.println(getClass().getCanonicalName() + ".onTakeOffer()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
|
latchTrade();
|
||||||
this.tradeResultHandler = tradeResultHandler;
|
this.tradeResultHandler = tradeResultHandler;
|
||||||
this.errorMessageHandler = errorMessageHandler;
|
this.errorMessageHandler = errorMessageHandler;
|
||||||
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()))
|
||||||
|
@ -106,6 +105,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
||||||
TakerSendsInitTradeRequestToArbitrator.class)
|
TakerSendsInitTradeRequestToArbitrator.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
|
startTimeout(TRADE_TIMEOUT);
|
||||||
unlatchTrade();
|
unlatchTrade();
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
|
@ -121,9 +121,9 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
||||||
public void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress sender) {
|
public void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress sender) {
|
||||||
System.out.println(getClass().getCanonicalName() + ".handleInitMultisigRequest()");
|
System.out.println(getClass().getCanonicalName() + ".handleInitMultisigRequest()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
|
latchTrade();
|
||||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||||
processModel.setTradeMessage(request);
|
processModel.setTradeMessage(request);
|
||||||
latchTrade();
|
|
||||||
expect(anyPhase(Trade.Phase.INIT)
|
expect(anyPhase(Trade.Phase.INIT)
|
||||||
.with(request)
|
.with(request)
|
||||||
.from(sender))
|
.from(sender))
|
||||||
|
@ -132,26 +132,25 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
||||||
SendSignContractRequestAfterMultisig.class)
|
SendSignContractRequestAfterMultisig.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerSuccess(sender, request);
|
handleTaskRunnerSuccess(sender, request);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(sender, request, errorMessage);
|
handleTaskRunnerFault(sender, request, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
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() + ".handleSignContractRequest()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
|
latchTrade();
|
||||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
processModel.setTradeMessage(message);
|
processModel.setTradeMessage(message);
|
||||||
latchTrade();
|
|
||||||
expect(anyPhase(Trade.Phase.INIT)
|
expect(anyPhase(Trade.Phase.INIT)
|
||||||
.with(message)
|
.with(message)
|
||||||
.from(sender))
|
.from(sender))
|
||||||
|
@ -160,11 +159,10 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
||||||
ProcessSignContractRequest.class)
|
ProcessSignContractRequest.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerSuccess(sender, message);
|
handleTaskRunnerSuccess(sender, message);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(sender, message, errorMessage);
|
handleTaskRunnerFault(sender, message, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
|
@ -178,9 +176,10 @@ 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() == State.CONTRACT_SIGNATURE_REQUESTED) {
|
if (trade.getState() == Trade.State.CONTRACT_SIGNATURE_REQUESTED) {
|
||||||
|
latchTrade();
|
||||||
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
processModel.setTradeMessage(message);
|
processModel.setTradeMessage(message);
|
||||||
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))
|
||||||
|
@ -189,20 +188,18 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
||||||
ProcessSignContractResponse.class)
|
ProcessSignContractResponse.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerSuccess(sender, message);
|
handleTaskRunnerSuccess(sender, message);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(sender, message, errorMessage);
|
handleTaskRunnerFault(sender, message, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
} else {
|
} else {
|
||||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||||
if (state != State.CONTRACT_SIGNATURE_REQUESTED) return;
|
if (state == Trade.State.CONTRACT_SIGNATURE_REQUESTED) new Thread(() -> handleSignContractResponse(message, sender)).start(); // process notification without trade lock
|
||||||
handleSignContractResponse(message, sender);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,10 +209,10 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
||||||
public void handleDepositResponse(DepositResponse response, NodeAddress sender) {
|
public void handleDepositResponse(DepositResponse response, NodeAddress sender) {
|
||||||
System.out.println(getClass().getCanonicalName() + ".handleDepositResponse()");
|
System.out.println(getClass().getCanonicalName() + ".handleDepositResponse()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
|
latchTrade();
|
||||||
Validator.checkTradeId(processModel.getOfferId(), response);
|
Validator.checkTradeId(processModel.getOfferId(), response);
|
||||||
processModel.setTradeMessage(response);
|
processModel.setTradeMessage(response);
|
||||||
latchTrade();
|
expect(state(Trade.State.MAKER_SENT_PUBLISH_DEPOSIT_TX_REQUEST)
|
||||||
expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED)
|
|
||||||
.with(response)
|
.with(response)
|
||||||
.from(sender))
|
.from(sender))
|
||||||
.setup(tasks(
|
.setup(tasks(
|
||||||
|
@ -223,11 +220,10 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
||||||
ProcessDepositResponse.class)
|
ProcessDepositResponse.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerSuccess(sender, response);
|
handleTaskRunnerSuccess(sender, response);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(sender, response, errorMessage);
|
handleTaskRunnerFault(sender, response, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
|
@ -241,10 +237,11 @@ 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);
|
||||||
if (tradeLatch == null) latchTrade(); // may be initialized from previous message
|
if (trade.getState() == Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) {
|
||||||
if (trade.getState() == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) {
|
latchTrade();
|
||||||
|
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||||
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)
|
||||||
.with(request)
|
.with(request)
|
||||||
.from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress()
|
.from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress()
|
||||||
.setup(tasks(
|
.setup(tasks(
|
||||||
|
@ -253,13 +250,11 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
stopTimeout();
|
stopTimeout();
|
||||||
unlatchTrade();
|
|
||||||
this.errorMessageHandler = null;
|
this.errorMessageHandler = null;
|
||||||
handleTaskRunnerSuccess(sender, request);
|
|
||||||
tradeResultHandler.handleResult(trade); // trade is initialized
|
tradeResultHandler.handleResult(trade); // trade is initialized
|
||||||
|
handleTaskRunnerSuccess(sender, request);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(sender, request, errorMessage);
|
handleTaskRunnerFault(sender, request, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
|
@ -267,7 +262,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
||||||
awaitTradeLatch();
|
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 == Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) new Thread(() -> handlePaymentAccountPayloadRequest(request, sender)).start(); // process notification without trade lock
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,8 @@ import bisq.core.trade.protocol.tasks.buyer.BuyerPreparesPaymentSentMessage;
|
||||||
import bisq.core.trade.protocol.tasks.buyer.BuyerProcessesPaymentReceivedMessage;
|
import bisq.core.trade.protocol.tasks.buyer.BuyerProcessesPaymentReceivedMessage;
|
||||||
import bisq.core.trade.protocol.tasks.buyer.BuyerSendsPaymentSentMessage;
|
import bisq.core.trade.protocol.tasks.buyer.BuyerSendsPaymentSentMessage;
|
||||||
import bisq.core.trade.protocol.tasks.buyer.BuyerSetupPayoutTxListener;
|
import bisq.core.trade.protocol.tasks.buyer.BuyerSetupPayoutTxListener;
|
||||||
|
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;
|
||||||
|
|
||||||
|
@ -127,9 +126,8 @@ public abstract class BuyerProtocol extends DisputeProtocol {
|
||||||
|
|
||||||
public void onPaymentStarted(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
public void onPaymentStarted(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
||||||
System.out.println("BuyerProtocol.onPaymentStarted()");
|
System.out.println("BuyerProtocol.onPaymentStarted()");
|
||||||
synchronized (trade) { // TODO (woodser): UpdateMultisigWithTradingPeer sends UpdateMultisigRequest and waits for UpdateMultisigResponse which is new thread, so synchronized (trade) in subsequent pipeline blocks forever if we hold on with countdown latch in this function
|
synchronized (trade) {
|
||||||
BuyerEvent event = BuyerEvent.PAYMENT_SENT;
|
BuyerEvent event = BuyerEvent.PAYMENT_SENT;
|
||||||
CountDownLatch latch = new CountDownLatch(1);
|
|
||||||
expect(phase(Trade.Phase.DEPOSIT_UNLOCKED)
|
expect(phase(Trade.Phase.DEPOSIT_UNLOCKED)
|
||||||
.with(event)
|
.with(event)
|
||||||
.preCondition(trade.confirmPermitted()))
|
.preCondition(trade.confirmPermitted()))
|
||||||
|
@ -138,21 +136,19 @@ public abstract class BuyerProtocol extends DisputeProtocol {
|
||||||
//UpdateMultisigWithTradingPeer.class, // TODO (woodser): can use this to test protocol with updated multisig from peer. peer should attempt to send updated multisig hex earlier as part of protocol. cannot use with countdown latch because response comes back in a separate thread and blocks on trade
|
//UpdateMultisigWithTradingPeer.class, // TODO (woodser): can use this to test protocol with updated multisig from peer. peer should attempt to send updated multisig hex earlier as part of protocol. cannot use with countdown latch because response comes back in a separate thread and blocks on trade
|
||||||
BuyerPreparesPaymentSentMessage.class,
|
BuyerPreparesPaymentSentMessage.class,
|
||||||
//BuyerSetupPayoutTxListener.class,
|
//BuyerSetupPayoutTxListener.class,
|
||||||
BuyerSendsPaymentSentMessage.class)
|
BuyerSendsPaymentSentMessage.class) // don't latch trade because this blocks and runs in background
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
latch.countDown();
|
resultHandler.handleResult();
|
||||||
resultHandler.handleResult();
|
handleTaskRunnerSuccess(event);
|
||||||
handleTaskRunnerSuccess(event);
|
},
|
||||||
},
|
(errorMessage) -> {
|
||||||
(errorMessage) -> {
|
errorMessageHandler.handleErrorMessage(errorMessage);
|
||||||
latch.countDown();
|
handleTaskRunnerFault(event, errorMessage);
|
||||||
errorMessageHandler.handleErrorMessage(errorMessage);
|
})))
|
||||||
handleTaskRunnerFault(event, errorMessage);
|
|
||||||
})))
|
|
||||||
.run(() -> trade.setState(Trade.State.BUYER_CONFIRMED_IN_UI_PAYMENT_SENT))
|
.run(() -> trade.setState(Trade.State.BUYER_CONFIRMED_IN_UI_PAYMENT_SENT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -162,8 +158,9 @@ public abstract class BuyerProtocol extends DisputeProtocol {
|
||||||
protected void handle(PaymentReceivedMessage message, NodeAddress peer) {
|
protected void handle(PaymentReceivedMessage message, NodeAddress peer) {
|
||||||
log.info("BuyerProtocol.handle(PaymentReceivedMessage)");
|
log.info("BuyerProtocol.handle(PaymentReceivedMessage)");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
processModel.setTradeMessage(message);
|
|
||||||
latchTrade();
|
latchTrade();
|
||||||
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
|
processModel.setTradeMessage(message);
|
||||||
expect(anyPhase(Trade.Phase.PAYMENT_SENT, Trade.Phase.PAYOUT_PUBLISHED)
|
expect(anyPhase(Trade.Phase.PAYMENT_SENT, Trade.Phase.PAYOUT_PUBLISHED)
|
||||||
.with(message)
|
.with(message)
|
||||||
.from(peer))
|
.from(peer))
|
||||||
|
@ -172,13 +169,14 @@ public abstract class BuyerProtocol extends DisputeProtocol {
|
||||||
BuyerProcessesPaymentReceivedMessage.class)
|
BuyerProcessesPaymentReceivedMessage.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
stopTimeout();
|
||||||
handleTaskRunnerSuccess(peer, message);
|
handleTaskRunnerSuccess(peer, message);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
stopTimeout();
|
||||||
handleTaskRunnerFault(peer, message, errorMessage);
|
handleTaskRunnerFault(peer, message, errorMessage);
|
||||||
})))
|
}))
|
||||||
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,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.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;
|
||||||
|
@ -77,8 +76,8 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
||||||
ErrorMessageHandler errorMessageHandler) {
|
ErrorMessageHandler errorMessageHandler) {
|
||||||
System.out.println(getClass().getCanonicalName() + ".handleInitTradeRequest()");
|
System.out.println(getClass().getCanonicalName() + ".handleInitTradeRequest()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
this.errorMessageHandler = errorMessageHandler;
|
|
||||||
latchTrade();
|
latchTrade();
|
||||||
|
this.errorMessageHandler = errorMessageHandler;
|
||||||
expect(phase(Trade.Phase.INIT)
|
expect(phase(Trade.Phase.INIT)
|
||||||
.with(message)
|
.with(message)
|
||||||
.from(peer))
|
.from(peer))
|
||||||
|
@ -89,11 +88,10 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
||||||
MakerSendsInitTradeRequestIfUnreserved.class)
|
MakerSendsInitTradeRequestIfUnreserved.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerSuccess(peer, message);
|
handleTaskRunnerSuccess(peer, message);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(peer, message, errorMessage);
|
handleTaskRunnerFault(peer, message, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
|
@ -106,9 +104,9 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
||||||
public void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress sender) {
|
public void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress sender) {
|
||||||
System.out.println(getClass().getCanonicalName() + ".handleInitMultisigRequest()");
|
System.out.println(getClass().getCanonicalName() + ".handleInitMultisigRequest()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
|
latchTrade();
|
||||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||||
processModel.setTradeMessage(request);
|
processModel.setTradeMessage(request);
|
||||||
latchTrade();
|
|
||||||
expect(anyPhase(Trade.Phase.INIT)
|
expect(anyPhase(Trade.Phase.INIT)
|
||||||
.with(request)
|
.with(request)
|
||||||
.from(sender))
|
.from(sender))
|
||||||
|
@ -117,11 +115,10 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
||||||
SendSignContractRequestAfterMultisig.class)
|
SendSignContractRequestAfterMultisig.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerSuccess(sender, request);
|
handleTaskRunnerSuccess(sender, request);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(sender, request, errorMessage);
|
handleTaskRunnerFault(sender, request, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
|
@ -134,9 +131,9 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
||||||
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() + ".handleSignContractRequest()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
|
latchTrade();
|
||||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
processModel.setTradeMessage(message);
|
processModel.setTradeMessage(message);
|
||||||
latchTrade();
|
|
||||||
expect(anyPhase(Trade.Phase.INIT)
|
expect(anyPhase(Trade.Phase.INIT)
|
||||||
.with(message)
|
.with(message)
|
||||||
.from(sender))
|
.from(sender))
|
||||||
|
@ -145,11 +142,10 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
||||||
ProcessSignContractRequest.class)
|
ProcessSignContractRequest.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerSuccess(sender, message);
|
handleTaskRunnerSuccess(sender, message);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(sender, message, errorMessage);
|
handleTaskRunnerFault(sender, message, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
|
@ -163,9 +159,10 @@ 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() == State.CONTRACT_SIGNATURE_REQUESTED) {
|
if (trade.getState() == Trade.State.CONTRACT_SIGNATURE_REQUESTED) {
|
||||||
|
latchTrade();
|
||||||
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
processModel.setTradeMessage(message);
|
processModel.setTradeMessage(message);
|
||||||
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))
|
||||||
|
@ -174,19 +171,18 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
||||||
ProcessSignContractResponse.class)
|
ProcessSignContractResponse.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerSuccess(sender, message);
|
handleTaskRunnerSuccess(sender, message);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(sender, message, errorMessage);
|
handleTaskRunnerFault(sender, message, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
} else {
|
} else {
|
||||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||||
if (state == State.CONTRACT_SIGNATURE_REQUESTED) handleSignContractResponse(message, sender);
|
if (state == Trade.State.CONTRACT_SIGNATURE_REQUESTED) new Thread(() -> handleSignContractResponse(message, sender)).start(); // process notification without trade lock
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,10 +192,10 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
||||||
public void handleDepositResponse(DepositResponse response, NodeAddress sender) {
|
public void handleDepositResponse(DepositResponse response, NodeAddress sender) {
|
||||||
System.out.println(getClass().getCanonicalName() + ".handleDepositResponse()");
|
System.out.println(getClass().getCanonicalName() + ".handleDepositResponse()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
|
latchTrade();
|
||||||
Validator.checkTradeId(processModel.getOfferId(), response);
|
Validator.checkTradeId(processModel.getOfferId(), response);
|
||||||
processModel.setTradeMessage(response);
|
processModel.setTradeMessage(response);
|
||||||
latchTrade();
|
expect(state(Trade.State.MAKER_SENT_PUBLISH_DEPOSIT_TX_REQUEST)
|
||||||
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()
|
||||||
.setup(tasks(
|
.setup(tasks(
|
||||||
|
@ -207,11 +203,10 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
||||||
ProcessDepositResponse.class)
|
ProcessDepositResponse.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerSuccess(sender, response);
|
handleTaskRunnerSuccess(sender, response);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(sender, response, errorMessage);
|
handleTaskRunnerFault(sender, response, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
|
@ -225,9 +220,10 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
||||||
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);
|
||||||
if (trade.getState() == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) {
|
if (trade.getState() == Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) {
|
||||||
|
latchTrade();
|
||||||
|
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||||
processModel.setTradeMessage(request);
|
processModel.setTradeMessage(request);
|
||||||
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()
|
||||||
|
@ -236,22 +232,20 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
||||||
ProcessPaymentAccountPayloadRequest.class,
|
ProcessPaymentAccountPayloadRequest.class,
|
||||||
MakerRemovesOpenOffer.class)
|
MakerRemovesOpenOffer.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
stopTimeout();
|
stopTimeout();
|
||||||
unlatchTrade();
|
this.errorMessageHandler = null;
|
||||||
this.errorMessageHandler = null;
|
handleTaskRunnerSuccess(sender, request);
|
||||||
handleTaskRunnerSuccess(sender, request);
|
},
|
||||||
},
|
errorMessage -> {
|
||||||
errorMessage -> {
|
handleTaskRunnerFault(sender, request, errorMessage);
|
||||||
handleError(errorMessage);
|
}))
|
||||||
handleTaskRunnerFault(sender, request, errorMessage);
|
|
||||||
}))
|
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
awaitTradeLatch();
|
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 == Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) new Thread(() -> handlePaymentAccountPayloadRequest(request, sender)).start(); // process notification without trade lock
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ package bisq.core.trade.protocol;
|
||||||
import bisq.core.offer.Offer;
|
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.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;
|
||||||
|
@ -87,9 +86,9 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
||||||
ErrorMessageHandler errorMessageHandler) {
|
ErrorMessageHandler errorMessageHandler) {
|
||||||
System.out.println(getClass().getCanonicalName() + ".onTakeOffer()");
|
System.out.println(getClass().getCanonicalName() + ".onTakeOffer()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
|
latchTrade();
|
||||||
this.tradeResultHandler = tradeResultHandler;
|
this.tradeResultHandler = tradeResultHandler;
|
||||||
this.errorMessageHandler = errorMessageHandler;
|
this.errorMessageHandler = errorMessageHandler;
|
||||||
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()))
|
||||||
|
@ -99,6 +98,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
||||||
TakerSendsInitTradeRequestToArbitrator.class)
|
TakerSendsInitTradeRequestToArbitrator.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
|
startTimeout(TRADE_TIMEOUT);
|
||||||
unlatchTrade();
|
unlatchTrade();
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
|
@ -114,9 +114,9 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
||||||
public void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress sender) {
|
public void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress sender) {
|
||||||
System.out.println(getClass().getCanonicalName() + ".handleInitMultisigRequest()");
|
System.out.println(getClass().getCanonicalName() + ".handleInitMultisigRequest()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
|
latchTrade();
|
||||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||||
processModel.setTradeMessage(request);
|
processModel.setTradeMessage(request);
|
||||||
latchTrade();
|
|
||||||
expect(anyPhase(Trade.Phase.INIT)
|
expect(anyPhase(Trade.Phase.INIT)
|
||||||
.with(request)
|
.with(request)
|
||||||
.from(sender))
|
.from(sender))
|
||||||
|
@ -125,11 +125,10 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
||||||
SendSignContractRequestAfterMultisig.class)
|
SendSignContractRequestAfterMultisig.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerSuccess(sender, request);
|
handleTaskRunnerSuccess(sender, request);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(sender, request, errorMessage);
|
handleTaskRunnerFault(sender, request, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
|
@ -142,9 +141,9 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
||||||
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() + ".handleSignContractRequest()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
|
latchTrade();
|
||||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
processModel.setTradeMessage(message);
|
processModel.setTradeMessage(message);
|
||||||
latchTrade();
|
|
||||||
expect(anyPhase(Trade.Phase.INIT)
|
expect(anyPhase(Trade.Phase.INIT)
|
||||||
.with(message)
|
.with(message)
|
||||||
.from(sender))
|
.from(sender))
|
||||||
|
@ -153,11 +152,10 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
||||||
ProcessSignContractRequest.class)
|
ProcessSignContractRequest.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerSuccess(sender, message);
|
handleTaskRunnerSuccess(sender, message);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(sender, message, errorMessage);
|
handleTaskRunnerFault(sender, message, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
|
@ -168,12 +166,13 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleSignContractResponse(SignContractResponse message, NodeAddress sender) {
|
public void handleSignContractResponse(SignContractResponse message, NodeAddress sender) {
|
||||||
System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse()");
|
System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse() " + trade.getId());
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
if (trade.getState() == State.CONTRACT_SIGNATURE_REQUESTED) {
|
if (trade.getState() == Trade.State.CONTRACT_SIGNATURE_REQUESTED) {
|
||||||
|
latchTrade();
|
||||||
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
processModel.setTradeMessage(message);
|
processModel.setTradeMessage(message);
|
||||||
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))
|
||||||
|
@ -182,20 +181,18 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
||||||
ProcessSignContractResponse.class)
|
ProcessSignContractResponse.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerSuccess(sender, message);
|
handleTaskRunnerSuccess(sender, message);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(sender, message, errorMessage);
|
handleTaskRunnerFault(sender, message, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
} else {
|
} else {
|
||||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||||
if (state != State.CONTRACT_SIGNATURE_REQUESTED) return;
|
if (state == Trade.State.CONTRACT_SIGNATURE_REQUESTED) new Thread(() -> handleSignContractResponse(message, sender)).start(); // process notification without trade lock
|
||||||
handleSignContractResponse(message, sender);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,10 +202,10 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
||||||
public void handleDepositResponse(DepositResponse response, NodeAddress sender) {
|
public void handleDepositResponse(DepositResponse response, NodeAddress sender) {
|
||||||
System.out.println(getClass().getCanonicalName() + ".handleDepositResponse()");
|
System.out.println(getClass().getCanonicalName() + ".handleDepositResponse()");
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
|
latchTrade();
|
||||||
Validator.checkTradeId(processModel.getOfferId(), response);
|
Validator.checkTradeId(processModel.getOfferId(), response);
|
||||||
processModel.setTradeMessage(response);
|
processModel.setTradeMessage(response);
|
||||||
latchTrade();
|
expect(state(Trade.State.MAKER_SENT_PUBLISH_DEPOSIT_TX_REQUEST)
|
||||||
expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED)
|
|
||||||
.with(response)
|
.with(response)
|
||||||
.from(sender))
|
.from(sender))
|
||||||
.setup(tasks(
|
.setup(tasks(
|
||||||
|
@ -216,11 +213,10 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
||||||
ProcessDepositResponse.class)
|
ProcessDepositResponse.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
unlatchTrade();
|
startTimeout(TRADE_TIMEOUT);
|
||||||
handleTaskRunnerSuccess(sender, response);
|
handleTaskRunnerSuccess(sender, response);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(sender, response, errorMessage);
|
handleTaskRunnerFault(sender, response, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
|
@ -231,13 +227,14 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handlePaymentAccountPayloadRequest(PaymentAccountPayloadRequest request, NodeAddress sender) {
|
public void handlePaymentAccountPayloadRequest(PaymentAccountPayloadRequest request, NodeAddress sender) {
|
||||||
System.out.println(getClass().getCanonicalName() + ".handlePaymentAccountPayloadRequest()");
|
System.out.println(getClass().getCanonicalName() + ".handlePaymentAccountPayloadRequest() " + trade.getId());
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||||
if (tradeLatch == null) latchTrade(); // may be initialized from previous message
|
if (trade.getState() == Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) {
|
||||||
if (trade.getState() == State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) {
|
latchTrade();
|
||||||
|
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||||
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)
|
||||||
.with(request)
|
.with(request)
|
||||||
.from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress()
|
.from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress()
|
||||||
.setup(tasks(
|
.setup(tasks(
|
||||||
|
@ -246,13 +243,11 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
stopTimeout();
|
stopTimeout();
|
||||||
unlatchTrade();
|
|
||||||
this.errorMessageHandler = null;
|
this.errorMessageHandler = null;
|
||||||
handleTaskRunnerSuccess(sender, request);
|
|
||||||
tradeResultHandler.handleResult(trade); // trade is initialized
|
tradeResultHandler.handleResult(trade); // trade is initialized
|
||||||
|
handleTaskRunnerSuccess(sender, request);
|
||||||
},
|
},
|
||||||
errorMessage -> {
|
errorMessage -> {
|
||||||
handleError(errorMessage);
|
|
||||||
handleTaskRunnerFault(sender, request, errorMessage);
|
handleTaskRunnerFault(sender, request, errorMessage);
|
||||||
}))
|
}))
|
||||||
.withTimeout(TRADE_TIMEOUT))
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
|
@ -260,7 +255,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
||||||
awaitTradeLatch();
|
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 == Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) new Thread(() -> handlePaymentAccountPayloadRequest(request, sender)).start(); // process notification without trade lock
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,11 @@ public abstract class SellerProtocol extends DisputeProtocol {
|
||||||
// TODO A better fix would be to add a listener for the wallet sync state and process
|
// TODO A better fix would be to add a listener for the wallet sync state and process
|
||||||
// the mailbox msg once wallet is ready and trade state set.
|
// the mailbox msg once wallet is ready and trade state set.
|
||||||
synchronized (trade) {
|
synchronized (trade) {
|
||||||
//CountDownLatch latch = new CountDownLatch(1); // TODO: apply latch countdown
|
if (trade.getPhase().ordinal() >= Trade.Phase.PAYMENT_SENT.ordinal()) {
|
||||||
|
log.warn("Ignoring PaymentSentMessage which was already processed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
latchTrade();
|
||||||
expect(anyPhase(Trade.Phase.DEPOSIT_UNLOCKED, Trade.Phase.DEPOSIT_PUBLISHED)
|
expect(anyPhase(Trade.Phase.DEPOSIT_UNLOCKED, Trade.Phase.DEPOSIT_PUBLISHED)
|
||||||
.with(message)
|
.with(message)
|
||||||
.from(peer)
|
.from(peer)
|
||||||
|
@ -98,8 +102,19 @@ public abstract class SellerProtocol extends DisputeProtocol {
|
||||||
.setup(tasks(
|
.setup(tasks(
|
||||||
SellerProcessesPaymentSentMessage.class,
|
SellerProcessesPaymentSentMessage.class,
|
||||||
ApplyFilter.class,
|
ApplyFilter.class,
|
||||||
getVerifyPeersFeePaymentClass()))
|
getVerifyPeersFeePaymentClass())
|
||||||
|
.using(new TradeTaskRunner(trade,
|
||||||
|
() -> {
|
||||||
|
stopTimeout();
|
||||||
|
handleTaskRunnerSuccess(peer, message);
|
||||||
|
},
|
||||||
|
(errorMessage) -> {
|
||||||
|
stopTimeout();
|
||||||
|
handleTaskRunnerFault(peer, message, errorMessage);
|
||||||
|
}))
|
||||||
|
.withTimeout(TRADE_TIMEOUT))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +126,6 @@ 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;
|
||||||
// CountDownLatch latch = new CountDownLatch(1); // TODO (woodser): user countdown latch, but freezes legacy app
|
|
||||||
expect(anyPhase(Trade.Phase.PAYMENT_SENT)
|
expect(anyPhase(Trade.Phase.PAYMENT_SENT)
|
||||||
.with(event)
|
.with(event)
|
||||||
.preCondition(trade.confirmPermitted()))
|
.preCondition(trade.confirmPermitted()))
|
||||||
|
|
|
@ -107,7 +107,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onWithdrawCompleted() {
|
public void onWithdrawCompleted() {
|
||||||
cleanup();
|
log.info("Withdraw completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onMailboxMessage(TradeMessage message, NodeAddress peerNodeAddress) {
|
protected void onMailboxMessage(TradeMessage message, NodeAddress peerNodeAddress) {
|
||||||
|
@ -218,27 +218,23 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||||
|
|
||||||
// TODO (woodser): update to use fluent for consistency
|
// TODO (woodser): update to use fluent for consistency
|
||||||
public void handleUpdateMultisigRequest(UpdateMultisigRequest message, NodeAddress peer, ErrorMessageHandler errorMessageHandler) {
|
public void handleUpdateMultisigRequest(UpdateMultisigRequest message, NodeAddress peer, ErrorMessageHandler errorMessageHandler) {
|
||||||
synchronized (trade) {
|
latchTrade();
|
||||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||||
processModel.setTradeMessage(message);
|
processModel.setTradeMessage(message);
|
||||||
latchTrade();
|
TradeTaskRunner taskRunner = new TradeTaskRunner(trade,
|
||||||
TradeTaskRunner taskRunner = new TradeTaskRunner(trade,
|
() -> {
|
||||||
() -> {
|
stopTimeout();
|
||||||
unlatchTrade();
|
handleTaskRunnerSuccess(peer, message, "handleUpdateMultisigRequest");
|
||||||
stopTimeout();
|
},
|
||||||
handleTaskRunnerSuccess(peer, message, "handleUpdateMultisigRequest");
|
errorMessage -> {
|
||||||
},
|
handleTaskRunnerFault(peer, message, errorMessage);
|
||||||
errorMessage -> {
|
});
|
||||||
handleError(errorMessage);
|
taskRunner.addTasks(
|
||||||
handleTaskRunnerFault(peer, message, errorMessage);
|
ProcessUpdateMultisigRequest.class
|
||||||
});
|
);
|
||||||
taskRunner.addTasks(
|
startTimeout(TRADE_TIMEOUT);
|
||||||
ProcessUpdateMultisigRequest.class
|
taskRunner.run();
|
||||||
);
|
awaitTradeLatch();
|
||||||
startTimeout(TRADE_TIMEOUT);
|
|
||||||
taskRunner.run();
|
|
||||||
awaitTradeLatch();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -365,32 +361,6 @@ 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
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -478,6 +448,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||||
// again.
|
// again.
|
||||||
removeMailboxMessageAfterProcessing(message);
|
removeMailboxMessageAfterProcessing(message);
|
||||||
}
|
}
|
||||||
|
unlatchTrade();
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleTaskRunnerFault(NodeAddress ackReceiver, @Nullable TradeMessage message, String source, String errorMessage) {
|
void handleTaskRunnerFault(NodeAddress ackReceiver, @Nullable TradeMessage message, String source, String errorMessage) {
|
||||||
|
@ -486,7 +457,33 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||||
if (message != null) {
|
if (message != null) {
|
||||||
sendAckMessage(ackReceiver, message, false, errorMessage);
|
sendAckMessage(ackReceiver, message, false, errorMessage);
|
||||||
}
|
}
|
||||||
cleanup();
|
|
||||||
|
handleError(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void handleError(String errorMessage) {
|
||||||
|
stopTimeout();
|
||||||
|
log.error(errorMessage);
|
||||||
|
trade.setErrorMessage(errorMessage);
|
||||||
|
processModel.getTradeManager().requestPersistence();
|
||||||
|
if (errorMessageHandler != null) errorMessageHandler.handleErrorMessage(errorMessage);
|
||||||
|
unlatchTrade();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void latchTrade() {
|
||||||
|
if (tradeLatch != null) throw new RuntimeException("Trade latch is not null. That 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isMyMessage(NetworkEnvelope message) {
|
private boolean isMyMessage(NetworkEnvelope message) {
|
||||||
|
@ -501,10 +498,4 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cleanup() {
|
|
||||||
stopTimeout();
|
|
||||||
// We do not remove the decryptedDirectMessageListener as in case of not critical failures we want allow to receive
|
|
||||||
// follow-up messages still
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ import bisq.common.taskrunner.TaskRunner;
|
||||||
import bisq.core.btc.wallet.XmrWalletService;
|
import bisq.core.btc.wallet.XmrWalletService;
|
||||||
import bisq.core.offer.Offer;
|
import bisq.core.offer.Offer;
|
||||||
import bisq.core.offer.OfferDirection;
|
import bisq.core.offer.OfferDirection;
|
||||||
import bisq.core.offer.OfferPayload;
|
|
||||||
import bisq.core.trade.Trade;
|
import bisq.core.trade.Trade;
|
||||||
import bisq.core.trade.messages.DepositRequest;
|
import bisq.core.trade.messages.DepositRequest;
|
||||||
import bisq.core.trade.messages.DepositResponse;
|
import bisq.core.trade.messages.DepositResponse;
|
||||||
|
@ -112,6 +111,10 @@ public class ArbitratorProcessesDepositRequest extends TradeTask {
|
||||||
daemon.submitTxHex(processModel.getMaker().getDepositTxHex()); // TODO (woodser): check that result is good. will need to release funds if one is submitted
|
daemon.submitTxHex(processModel.getMaker().getDepositTxHex()); // TODO (woodser): check that result is good. will need to release funds if one is submitted
|
||||||
daemon.submitTxHex(processModel.getTaker().getDepositTxHex());
|
daemon.submitTxHex(processModel.getTaker().getDepositTxHex());
|
||||||
|
|
||||||
|
// update trade state
|
||||||
|
log.info("Arbitrator submitted deposit txs for trade " + trade.getId());
|
||||||
|
trade.setState(Trade.State.ARBITRATOR_PUBLISHED_DEPOSIT_TX);
|
||||||
|
|
||||||
// create deposit response
|
// create deposit response
|
||||||
DepositResponse response = new DepositResponse(
|
DepositResponse response = new DepositResponse(
|
||||||
trade.getOffer().getId(),
|
trade.getOffer().getId(),
|
||||||
|
@ -124,6 +127,8 @@ public class ArbitratorProcessesDepositRequest extends TradeTask {
|
||||||
// send deposit response to maker and taker
|
// send deposit response to maker and taker
|
||||||
sendDepositResponse(trade.getMakerNodeAddress(), trade.getMakerPubKeyRing(), response);
|
sendDepositResponse(trade.getMakerNodeAddress(), trade.getMakerPubKeyRing(), response);
|
||||||
sendDepositResponse(trade.getTakerNodeAddress(), trade.getTakerPubKeyRing(), response);
|
sendDepositResponse(trade.getTakerNodeAddress(), trade.getTakerPubKeyRing(), response);
|
||||||
|
} else {
|
||||||
|
log.info("Arbitrator waiting for deposit request from maker and taker for trade " + trade.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO (woodser): request persistence?
|
// TODO (woodser): request persistence?
|
||||||
|
@ -134,6 +139,7 @@ public class ArbitratorProcessesDepositRequest extends TradeTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendDepositResponse(NodeAddress nodeAddress, PubKeyRing pubKeyRing, DepositResponse response) {
|
private void sendDepositResponse(NodeAddress nodeAddress, PubKeyRing pubKeyRing, DepositResponse response) {
|
||||||
|
log.info("Sending deposit response to trader={}; offerId={}", nodeAddress, trade.getId());
|
||||||
processModel.getP2PService().sendEncryptedDirectMessage(nodeAddress, pubKeyRing, response, new SendDirectMessageListener() {
|
processModel.getP2PService().sendEncryptedDirectMessage(nodeAddress, pubKeyRing, response, new SendDirectMessageListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onArrived() {
|
public void onArrived() {
|
||||||
|
|
|
@ -170,7 +170,7 @@ public class ArbitratorSendsInitTradeAndMultisigRequests extends TradeTask {
|
||||||
new SendDirectMessageListener() {
|
new SendDirectMessageListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onArrived() {
|
public void onArrived() {
|
||||||
log.info("{} arrived at arbitrator: offerId={}; uid={}", initMultisigRequest.getClass().getSimpleName(), initMultisigRequest.getTradeId(), initMultisigRequest.getUid());
|
log.info("{} arrived at maker: offerId={}; uid={}", initMultisigRequest.getClass().getSimpleName(), initMultisigRequest.getTradeId(), initMultisigRequest.getUid());
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onFault(String errorMessage) {
|
public void onFault(String errorMessage) {
|
||||||
|
@ -190,7 +190,7 @@ public class ArbitratorSendsInitTradeAndMultisigRequests extends TradeTask {
|
||||||
new SendDirectMessageListener() {
|
new SendDirectMessageListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onArrived() {
|
public void onArrived() {
|
||||||
log.info("{} arrived at peer: offerId={}; uid={}", initMultisigRequest.getClass().getSimpleName(), initMultisigRequest.getTradeId(), initMultisigRequest.getUid());
|
log.info("{} arrived at taker: offerId={}; uid={}", initMultisigRequest.getClass().getSimpleName(), initMultisigRequest.getTradeId(), initMultisigRequest.getUid());
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onFault(String errorMessage) {
|
public void onFault(String errorMessage) {
|
||||||
|
|
|
@ -82,9 +82,9 @@ public class ProcessInitMultisigRequest extends TradeTask {
|
||||||
|
|
||||||
// reconcile peer's established multisig hex with message
|
// reconcile peer's established multisig hex with message
|
||||||
if (multisigParticipant.getPreparedMultisigHex() == null) multisigParticipant.setPreparedMultisigHex(request.getPreparedMultisigHex());
|
if (multisigParticipant.getPreparedMultisigHex() == null) multisigParticipant.setPreparedMultisigHex(request.getPreparedMultisigHex());
|
||||||
else if (!multisigParticipant.getPreparedMultisigHex().equals(request.getPreparedMultisigHex())) throw new RuntimeException("Message's prepared multisig differs from previous messages, previous: " + multisigParticipant.getPreparedMultisigHex() + ", message: " + request.getPreparedMultisigHex());
|
else if (request.getPreparedMultisigHex() != null && !multisigParticipant.getPreparedMultisigHex().equals(request.getPreparedMultisigHex())) throw new RuntimeException("Message's prepared multisig differs from previous messages, previous: " + multisigParticipant.getPreparedMultisigHex() + ", message: " + request.getPreparedMultisigHex());
|
||||||
if (multisigParticipant.getMadeMultisigHex() == null) multisigParticipant.setMadeMultisigHex(request.getMadeMultisigHex());
|
if (multisigParticipant.getMadeMultisigHex() == null) multisigParticipant.setMadeMultisigHex(request.getMadeMultisigHex());
|
||||||
else if (!multisigParticipant.getMadeMultisigHex().equals(request.getMadeMultisigHex())) throw new RuntimeException("Message's made multisig differs from previous messages: " + request.getMadeMultisigHex() + " versus " + multisigParticipant.getMadeMultisigHex());
|
else if (request.getMadeMultisigHex() != null && !multisigParticipant.getMadeMultisigHex().equals(request.getMadeMultisigHex())) throw new RuntimeException("Message's made multisig differs from previous messages: " + request.getMadeMultisigHex() + " versus " + multisigParticipant.getMadeMultisigHex());
|
||||||
|
|
||||||
// prepare multisig if applicable
|
// prepare multisig if applicable
|
||||||
boolean updateParticipants = false;
|
boolean updateParticipants = false;
|
||||||
|
@ -217,6 +217,6 @@ public class ProcessInitMultisigRequest extends TradeTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void completeAux() {
|
private void completeAux() {
|
||||||
complete();
|
complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,19 +18,14 @@
|
||||||
package bisq.core.trade.protocol.tasks;
|
package bisq.core.trade.protocol.tasks;
|
||||||
|
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
|
||||||
|
|
||||||
import bisq.common.UserThread;
|
|
||||||
import bisq.common.taskrunner.TaskRunner;
|
import bisq.common.taskrunner.TaskRunner;
|
||||||
import bisq.core.btc.model.XmrAddressEntry;
|
|
||||||
import bisq.core.payment.payload.PaymentAccountPayload;
|
import bisq.core.payment.payload.PaymentAccountPayload;
|
||||||
import bisq.core.trade.MakerTrade;
|
import bisq.core.trade.MakerTrade;
|
||||||
import bisq.core.trade.Trade;
|
import bisq.core.trade.Trade;
|
||||||
|
import bisq.core.trade.Trade.State;
|
||||||
import bisq.core.trade.messages.PaymentAccountPayloadRequest;
|
import bisq.core.trade.messages.PaymentAccountPayloadRequest;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import monero.wallet.MoneroWallet;
|
|
||||||
import monero.wallet.model.MoneroTxWallet;
|
|
||||||
import org.fxmisc.easybind.EasyBind;
|
import org.fxmisc.easybind.EasyBind;
|
||||||
import org.fxmisc.easybind.Subscription;
|
import org.fxmisc.easybind.Subscription;
|
||||||
|
|
||||||
|
@ -49,15 +44,15 @@ public class ProcessPaymentAccountPayloadRequest extends TradeTask {
|
||||||
try {
|
try {
|
||||||
runInterceptHook();
|
runInterceptHook();
|
||||||
if (trade.getTradingPeer().getPaymentAccountPayload() != null) throw new RuntimeException("Peer's payment account payload has already been set");
|
if (trade.getTradingPeer().getPaymentAccountPayload() != null) throw new RuntimeException("Peer's payment account payload has already been set");
|
||||||
|
|
||||||
// get peer's payment account payload
|
// get peer's payment account payload
|
||||||
PaymentAccountPayloadRequest request = (PaymentAccountPayloadRequest) processModel.getTradeMessage(); // TODO (woodser): verify request
|
PaymentAccountPayloadRequest request = (PaymentAccountPayloadRequest) processModel.getTradeMessage(); // TODO (woodser): verify request
|
||||||
PaymentAccountPayload paymentAccountPayload = request.getPaymentAccountPayload();
|
PaymentAccountPayload paymentAccountPayload = request.getPaymentAccountPayload();
|
||||||
|
|
||||||
// verify hash of payment account payload
|
// verify hash of payment account payload
|
||||||
byte[] peerPaymentAccountPayloadHash = trade instanceof MakerTrade ? trade.getContract().getTakerPaymentAccountPayloadHash() : trade.getContract().getMakerPaymentAccountPayloadHash();
|
byte[] peerPaymentAccountPayloadHash = trade instanceof MakerTrade ? trade.getContract().getTakerPaymentAccountPayloadHash() : trade.getContract().getMakerPaymentAccountPayloadHash();
|
||||||
if (!Arrays.equals(paymentAccountPayload.getHash(), peerPaymentAccountPayloadHash)) throw new RuntimeException("Hash of peer's payment account payload does not match contract");
|
if (!Arrays.equals(paymentAccountPayload.getHash(), peerPaymentAccountPayloadHash)) throw new RuntimeException("Hash of peer's payment account payload does not match contract");
|
||||||
|
|
||||||
// set payment account payload
|
// set payment account payload
|
||||||
trade.getTradingPeer().setPaymentAccountPayload(paymentAccountPayload);
|
trade.getTradingPeer().setPaymentAccountPayload(paymentAccountPayload);
|
||||||
|
|
||||||
|
@ -68,8 +63,4 @@ public class ProcessPaymentAccountPayloadRequest extends TradeTask {
|
||||||
failed(t);
|
failed(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void unSubscribe() {
|
|
||||||
if (tradeStateSubscription != null) tradeStateSubscription.unsubscribe();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ import bisq.common.app.Version;
|
||||||
import bisq.common.crypto.PubKeyRing;
|
import bisq.common.crypto.PubKeyRing;
|
||||||
import bisq.common.crypto.Sig;
|
import bisq.common.crypto.Sig;
|
||||||
import bisq.common.taskrunner.TaskRunner;
|
import bisq.common.taskrunner.TaskRunner;
|
||||||
import bisq.common.util.Utilities;
|
|
||||||
import bisq.core.trade.ArbitratorTrade;
|
import bisq.core.trade.ArbitratorTrade;
|
||||||
import bisq.core.trade.Contract;
|
import bisq.core.trade.Contract;
|
||||||
import bisq.core.trade.Trade;
|
import bisq.core.trade.Trade;
|
||||||
|
@ -102,7 +101,7 @@ public class ProcessSignContractRequest extends TradeTask {
|
||||||
public void onArrived() {
|
public void onArrived() {
|
||||||
log.info("{} arrived: trading peer={}; offerId={}; uid={}", response.getClass().getSimpleName(), recipient1, trade.getId());
|
log.info("{} arrived: trading peer={}; offerId={}; uid={}", response.getClass().getSimpleName(), recipient1, trade.getId());
|
||||||
ack1 = true;
|
ack1 = true;
|
||||||
if (ack1 && (recipient2 == null || ack2)) complete();
|
if (ack1 && (recipient2 == null || ack2)) completeAux();
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onFault(String errorMessage) {
|
public void onFault(String errorMessage) {
|
||||||
|
@ -119,7 +118,7 @@ public class ProcessSignContractRequest extends TradeTask {
|
||||||
public void onArrived() {
|
public void onArrived() {
|
||||||
log.info("{} arrived: trading peer={}; offerId={}; uid={}", response.getClass().getSimpleName(), recipient2, trade.getId());
|
log.info("{} arrived: trading peer={}; offerId={}; uid={}", response.getClass().getSimpleName(), recipient2, trade.getId());
|
||||||
ack2 = true;
|
ack2 = true;
|
||||||
if (ack1 && ack2) complete();
|
if (ack1 && ack2) completeAux();
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onFault(String errorMessage) {
|
public void onFault(String errorMessage) {
|
||||||
|
@ -129,11 +128,14 @@ public class ProcessSignContractRequest extends TradeTask {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// update trade state
|
|
||||||
trade.setState(State.CONTRACT_SIGNATURE_REQUESTED);
|
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
failed(t);
|
failed(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void completeAux() {
|
||||||
|
trade.setState(State.CONTRACT_SIGNATURE_REQUESTED); // TODO: rename to contract_signature_request_received
|
||||||
|
processModel.getTradeManager().requestPersistence();
|
||||||
|
complete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,67 +42,69 @@ public class ProcessSignContractResponse extends TradeTask {
|
||||||
@Override
|
@Override
|
||||||
protected void run() {
|
protected void run() {
|
||||||
try {
|
try {
|
||||||
runInterceptHook();
|
runInterceptHook();
|
||||||
|
|
||||||
// get contract and signature
|
// get contract and signature
|
||||||
String contractAsJson = trade.getContractAsJson();
|
String contractAsJson = trade.getContractAsJson();
|
||||||
SignContractResponse response = (SignContractResponse) processModel.getTradeMessage(); // TODO (woodser): verify response
|
SignContractResponse response = (SignContractResponse) processModel.getTradeMessage(); // TODO (woodser): verify response
|
||||||
String signature = response.getContractSignature();
|
String signature = response.getContractSignature();
|
||||||
|
|
||||||
// get peer info
|
// get peer info
|
||||||
// TODO (woodser): make these utilities / refactor model
|
// TODO (woodser): make these utilities / refactor model
|
||||||
PubKeyRing peerPubKeyRing;
|
PubKeyRing peerPubKeyRing;
|
||||||
TradingPeer peer = trade.getTradingPeer(response.getSenderNodeAddress());
|
TradingPeer peer = trade.getTradingPeer(response.getSenderNodeAddress());
|
||||||
if (peer == processModel.getArbitrator()) peerPubKeyRing = trade.getArbitratorPubKeyRing();
|
if (peer == processModel.getArbitrator()) peerPubKeyRing = trade.getArbitratorPubKeyRing();
|
||||||
else if (peer == processModel.getMaker()) peerPubKeyRing = trade.getMakerPubKeyRing();
|
else if (peer == processModel.getMaker()) peerPubKeyRing = trade.getMakerPubKeyRing();
|
||||||
else if (peer == processModel.getTaker()) peerPubKeyRing = trade.getTakerPubKeyRing();
|
else if (peer == processModel.getTaker()) peerPubKeyRing = trade.getTakerPubKeyRing();
|
||||||
else throw new RuntimeException(response.getClass().getSimpleName() + " is not from maker, taker, or arbitrator");
|
else throw new RuntimeException(response.getClass().getSimpleName() + " is not from maker, taker, or arbitrator");
|
||||||
|
|
||||||
// verify signature
|
// verify signature
|
||||||
// TODO (woodser): transfer contract for convenient comparison?
|
// TODO (woodser): transfer contract for convenient comparison?
|
||||||
if (!Sig.verify(peerPubKeyRing.getSignaturePubKey(), contractAsJson, signature)) throw new RuntimeException("Peer's contract signature is invalid");
|
if (!Sig.verify(peerPubKeyRing.getSignaturePubKey(), contractAsJson, signature)) throw new RuntimeException("Peer's contract signature is invalid");
|
||||||
|
|
||||||
// set peer's signature
|
// set peer's signature
|
||||||
peer.setContractSignature(signature);
|
peer.setContractSignature(signature);
|
||||||
|
|
||||||
// send deposit request when all contract signatures received
|
// send deposit request when all contract signatures received
|
||||||
if (processModel.getArbitrator().getContractSignature() != null && processModel.getMaker().getContractSignature() != null && processModel.getTaker().getContractSignature() != null) {
|
if (processModel.getArbitrator().getContractSignature() != null && processModel.getMaker().getContractSignature() != null && processModel.getTaker().getContractSignature() != null) {
|
||||||
|
|
||||||
// start listening for deposit txs
|
// start listening for deposit txs
|
||||||
trade.listenForDepositTxs();
|
trade.listenForDepositTxs();
|
||||||
|
|
||||||
// create request for arbitrator to deposit funds to multisig
|
// create request for arbitrator to deposit funds to multisig
|
||||||
DepositRequest request = new DepositRequest(
|
DepositRequest request = new DepositRequest(
|
||||||
trade.getOffer().getId(),
|
trade.getOffer().getId(),
|
||||||
processModel.getMyNodeAddress(),
|
processModel.getMyNodeAddress(),
|
||||||
processModel.getPubKeyRing(),
|
processModel.getPubKeyRing(),
|
||||||
UUID.randomUUID().toString(),
|
UUID.randomUUID().toString(),
|
||||||
Version.getP2PMessageVersion(),
|
Version.getP2PMessageVersion(),
|
||||||
new Date().getTime(),
|
new Date().getTime(),
|
||||||
trade.getSelf().getContractSignature(),
|
trade.getSelf().getContractSignature(),
|
||||||
processModel.getDepositTxXmr().getFullHex(),
|
processModel.getDepositTxXmr().getFullHex(),
|
||||||
processModel.getDepositTxXmr().getKey());
|
processModel.getDepositTxXmr().getKey());
|
||||||
|
|
||||||
// send request to arbitrator
|
// send request to arbitrator
|
||||||
processModel.getP2PService().sendEncryptedDirectMessage(trade.getArbitratorNodeAddress(), trade.getArbitratorPubKeyRing(), request, new SendDirectMessageListener() {
|
processModel.getP2PService().sendEncryptedDirectMessage(trade.getArbitratorNodeAddress(), trade.getArbitratorPubKeyRing(), request, new SendDirectMessageListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onArrived() {
|
public void onArrived() {
|
||||||
log.info("{} arrived: trading peer={}; offerId={}; uid={}", request.getClass().getSimpleName(), trade.getArbitratorNodeAddress(), trade.getId());
|
log.info("{} arrived: arbitrator={}; offerId={}; uid={}", request.getClass().getSimpleName(), trade.getArbitratorNodeAddress(), trade.getId(), request.getUid());
|
||||||
processModel.getTradeManager().requestPersistence();
|
trade.setState(Trade.State.MAKER_SENT_PUBLISH_DEPOSIT_TX_REQUEST); // TODO: rename to DEPOSIT_REQUESTED
|
||||||
complete();
|
processModel.getTradeManager().requestPersistence();
|
||||||
}
|
complete();
|
||||||
@Override
|
}
|
||||||
public void onFault(String errorMessage) {
|
@Override
|
||||||
log.error("Sending {} failed: uid={}; peer={}; error={}", request.getClass().getSimpleName(), trade.getArbitratorNodeAddress(), trade.getId(), errorMessage);
|
public void onFault(String errorMessage) {
|
||||||
appendToErrorMessage("Sending message failed: message=" + request + "\nerrorMessage=" + errorMessage);
|
log.error("Sending {} failed: uid={}; peer={}; error={}", request.getClass().getSimpleName(), trade.getArbitratorNodeAddress(), trade.getId(), errorMessage);
|
||||||
failed();
|
appendToErrorMessage("Sending message failed: message=" + request + "\nerrorMessage=" + errorMessage);
|
||||||
}
|
failed();
|
||||||
});
|
}
|
||||||
} else {
|
});
|
||||||
complete(); // does not yet have needed signatures
|
} else {
|
||||||
}
|
log.info("Waiting for more contract signatures to send deposit request");
|
||||||
|
complete(); // does not yet have needed signatures
|
||||||
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
failed(t);
|
failed(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,6 +124,7 @@ public class SendSignContractRequestAfterMultisig extends TradeTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void completeAux() {
|
private void completeAux() {
|
||||||
|
processModel.getTradeManager().requestPersistence();
|
||||||
processModel.getXmrWalletService().saveWallet(processModel.getXmrWalletService().getWallet());
|
processModel.getXmrWalletService().saveWallet(processModel.getXmrWalletService().getWallet());
|
||||||
complete();
|
complete();
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,6 @@ import javafx.beans.value.ChangeListener;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import monero.wallet.MoneroWallet;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We send the seller the BuyerSendPaymentSentMessage.
|
* We send the seller the BuyerSendPaymentSentMessage.
|
||||||
|
|
|
@ -237,8 +237,8 @@ class GrpcTradesService extends TradesImplBase {
|
||||||
put(getGetTradeMethod().getFullMethodName(), new GrpcCallRateMeter(10, SECONDS));
|
put(getGetTradeMethod().getFullMethodName(), new GrpcCallRateMeter(10, SECONDS));
|
||||||
put(getGetTradesMethod().getFullMethodName(), new GrpcCallRateMeter(10, SECONDS));
|
put(getGetTradesMethod().getFullMethodName(), new GrpcCallRateMeter(10, SECONDS));
|
||||||
put(getTakeOfferMethod().getFullMethodName(), new GrpcCallRateMeter(10, SECONDS));
|
put(getTakeOfferMethod().getFullMethodName(), new GrpcCallRateMeter(10, SECONDS));
|
||||||
put(getConfirmPaymentStartedMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
|
put(getConfirmPaymentStartedMethod().getFullMethodName(), new GrpcCallRateMeter(10, SECONDS));
|
||||||
put(getConfirmPaymentReceivedMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
|
put(getConfirmPaymentReceivedMethod().getFullMethodName(), new GrpcCallRateMeter(10, SECONDS));
|
||||||
put(getKeepFundsMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES));
|
put(getKeepFundsMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES));
|
||||||
put(getWithdrawFundsMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES));
|
put(getWithdrawFundsMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES));
|
||||||
put(getGetChatMessagesMethod().getFullMethodName(), new GrpcCallRateMeter(10, SECONDS));
|
put(getGetChatMessagesMethod().getFullMethodName(), new GrpcCallRateMeter(10, SECONDS));
|
||||||
|
|
|
@ -428,7 +428,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||||
|
|
||||||
|
|
||||||
// #################### Phase DEPOSIT_PAID
|
// #################### Phase DEPOSIT_PAID
|
||||||
case TAKER_PUBLISHED_DEPOSIT_TX:
|
case ARBITRATOR_PUBLISHED_DEPOSIT_TX:
|
||||||
case TAKER_SAW_DEPOSIT_TX_IN_NETWORK:
|
case TAKER_SAW_DEPOSIT_TX_IN_NETWORK:
|
||||||
|
|
||||||
// DEPOSIT_TX_PUBLISHED_MSG
|
// DEPOSIT_TX_PUBLISHED_MSG
|
||||||
|
|
|
@ -1632,7 +1632,7 @@ message Trade {
|
||||||
MAKER_STORED_IN_MAILBOX_PUBLISH_DEPOSIT_TX_REQUEST = 7;
|
MAKER_STORED_IN_MAILBOX_PUBLISH_DEPOSIT_TX_REQUEST = 7;
|
||||||
MAKER_SEND_FAILED_PUBLISH_DEPOSIT_TX_REQUEST = 8;
|
MAKER_SEND_FAILED_PUBLISH_DEPOSIT_TX_REQUEST = 8;
|
||||||
TAKER_RECEIVED_PUBLISH_DEPOSIT_TX_REQUEST = 9;
|
TAKER_RECEIVED_PUBLISH_DEPOSIT_TX_REQUEST = 9;
|
||||||
TAKER_PUBLISHED_DEPOSIT_TX = 10;
|
ARBITRATOR_PUBLISHED_DEPOSIT_TX = 10;
|
||||||
TAKER_SAW_DEPOSIT_TX_IN_NETWORK = 11;
|
TAKER_SAW_DEPOSIT_TX_IN_NETWORK = 11;
|
||||||
TAKER_SENT_DEPOSIT_TX_PUBLISHED_MSG = 12;
|
TAKER_SENT_DEPOSIT_TX_PUBLISHED_MSG = 12;
|
||||||
TAKER_SAW_ARRIVED_DEPOSIT_TX_PUBLISHED_MSG = 13;
|
TAKER_SAW_ARRIVED_DEPOSIT_TX_PUBLISHED_MSG = 13;
|
||||||
|
|
Loading…
Reference in a new issue