mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-10-01 01:35:48 -04:00
add multisig wallet state and wait for multisig to complete
refactor trade protocol
This commit is contained in:
parent
f61fd09127
commit
50126874a0
@ -107,7 +107,10 @@ public abstract class Trade implements Tradable, Model {
|
||||
// #################### Phase INIT
|
||||
// When trade protocol starts no funds are on stake
|
||||
PREPARATION(Phase.INIT),
|
||||
CONTRACT_SIGNATURE_REQUESTED(Phase.INIT), // TODO (woodser): add more states for initializing multisig, etc to support trade initialization notifications
|
||||
MULTISIG_PREPARED(Phase.INIT),
|
||||
MULTISIG_MADE(Phase.INIT),
|
||||
MULTISIG_COMPLETED(Phase.INIT),
|
||||
CONTRACT_SIGNATURE_REQUESTED(Phase.INIT),
|
||||
CONTRACT_SIGNED(Phase.INIT),
|
||||
|
||||
// At first part maker/taker have different roles
|
||||
@ -894,7 +897,6 @@ public abstract class Trade implements Tradable, Model {
|
||||
|
||||
// create block listener
|
||||
depositTxListener = new MoneroWalletListener() {
|
||||
|
||||
Long unlockHeight = null;
|
||||
|
||||
@Override
|
||||
@ -903,6 +905,9 @@ public abstract class Trade implements Tradable, Model {
|
||||
// ignore if no longer listening
|
||||
if (depositTxListener == null) return;
|
||||
|
||||
// use latest height
|
||||
height = havenoWallet.getHeight();
|
||||
|
||||
// ignore if before unlock height
|
||||
if (unlockHeight != null && height < unlockHeight) return;
|
||||
|
||||
@ -921,7 +926,7 @@ public abstract class Trade implements Tradable, Model {
|
||||
if (unlockHeight == null && txs.size() == 2 && txs.get(0).isConfirmed() && txs.get(1).isConfirmed()) {
|
||||
unlockHeight = Math.max(txs.get(0).getHeight(), txs.get(1).getHeight()) + XmrWalletService.NUM_BLOCKS_UNLOCK;
|
||||
}
|
||||
|
||||
|
||||
// check if deposit txs unlocked
|
||||
if (unlockHeight != null && height >= unlockHeight) {
|
||||
log.info("Multisig deposits unlocked for trade {}", getId());
|
||||
|
@ -3,16 +3,15 @@ package bisq.core.trade.protocol;
|
||||
import bisq.core.trade.ArbitratorTrade;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.messages.DepositRequest;
|
||||
import bisq.core.trade.messages.InitMultisigRequest;
|
||||
import bisq.core.trade.messages.DepositResponse;
|
||||
import bisq.core.trade.messages.InitTradeRequest;
|
||||
import bisq.core.trade.messages.SignContractRequest;
|
||||
import bisq.core.trade.messages.PaymentAccountPayloadRequest;
|
||||
import bisq.core.trade.messages.SignContractResponse;
|
||||
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
||||
import bisq.core.trade.protocol.tasks.ArbitratorSendsInitTradeAndMultisigRequests;
|
||||
import bisq.core.trade.protocol.tasks.ArbitratorProcessesDepositRequest;
|
||||
import bisq.core.trade.protocol.tasks.ProcessInitMultisigRequest;
|
||||
import bisq.core.trade.protocol.tasks.ArbitratorProcessesReserveTx;
|
||||
import bisq.core.trade.protocol.tasks.ProcessInitTradeRequest;
|
||||
import bisq.core.trade.protocol.tasks.ProcessSignContractRequest;
|
||||
import bisq.core.util.Validator;
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
import bisq.common.handlers.ErrorMessageHandler;
|
||||
@ -59,60 +58,12 @@ public class ArbitratorProtocol extends DisputeProtocol {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress sender) {
|
||||
System.out.println("ArbitratorProtocol.handleInitMultisigRequest()");
|
||||
synchronized (trade) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||
processModel.setTradeMessage(request);
|
||||
expect(anyPhase(Trade.Phase.INIT)
|
||||
.with(request)
|
||||
.from(sender))
|
||||
.setup(tasks(
|
||||
ProcessInitMultisigRequest.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, request);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, request, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT))
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) {
|
||||
System.out.println("ArbitratorProtocol.handleSignContractRequest()");
|
||||
synchronized (trade) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||
processModel.setTradeMessage(message); // TODO (woodser): synchronize access since concurrent requests processed
|
||||
expect(anyPhase(Trade.Phase.INIT)
|
||||
.with(message)
|
||||
.from(sender))
|
||||
.setup(tasks(
|
||||
// TODO (woodser): validate request
|
||||
ProcessSignContractRequest.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, message);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, message, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT))
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
}
|
||||
public void handleSignContractResponse(SignContractResponse message, NodeAddress sender) {
|
||||
log.warn("Arbitrator ignoring SignContractResponse");
|
||||
}
|
||||
|
||||
public void handleDepositRequest(DepositRequest request, NodeAddress sender) {
|
||||
System.out.println("ArbitratorProtocol.handleDepositRequest()");
|
||||
System.out.println("ArbitratorProtocol.handleDepositRequest() " + trade.getId());
|
||||
synchronized (trade) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||
@ -138,6 +89,16 @@ public class ArbitratorProtocol extends DisputeProtocol {
|
||||
awaitTradeLatch();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleDepositResponse(DepositResponse response, NodeAddress sender) {
|
||||
log.warn("Arbitrator ignoring DepositResponse");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePaymentAccountPayloadRequest(PaymentAccountPayloadRequest request, NodeAddress sender) {
|
||||
log.warn("Arbitrator ignoring PaymentAccountPayloadRequest");
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Message dispatcher
|
||||
|
@ -28,30 +28,22 @@ import bisq.core.trade.messages.PaymentAccountPayloadRequest;
|
||||
import bisq.core.trade.messages.PaymentReceivedMessage;
|
||||
import bisq.core.trade.messages.SignContractRequest;
|
||||
import bisq.core.trade.messages.SignContractResponse;
|
||||
import bisq.core.trade.protocol.tasks.ProcessDepositResponse;
|
||||
import bisq.core.trade.protocol.tasks.ProcessInitMultisigRequest;
|
||||
import bisq.core.trade.protocol.tasks.ProcessInitTradeRequest;
|
||||
import bisq.core.trade.protocol.tasks.ProcessPaymentAccountPayloadRequest;
|
||||
import bisq.core.trade.protocol.tasks.ProcessSignContractRequest;
|
||||
import bisq.core.trade.protocol.tasks.ProcessSignContractResponse;
|
||||
import bisq.core.trade.protocol.tasks.SendSignContractRequestAfterMultisig;
|
||||
import bisq.core.trade.protocol.tasks.TradeTask;
|
||||
import bisq.core.trade.protocol.tasks.buyer.BuyerFinalizesDelayedPayoutTx;
|
||||
import bisq.core.trade.protocol.tasks.buyer.BuyerProcessDelayedPayoutTxSignatureRequest;
|
||||
import bisq.core.trade.protocol.tasks.buyer.BuyerSendsDelayedPayoutTxSignatureResponse;
|
||||
import bisq.core.trade.protocol.tasks.buyer.BuyerSignsDelayedPayoutTx;
|
||||
import bisq.core.trade.protocol.tasks.buyer.BuyerVerifiesPreparedDelayedPayoutTx;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerRemovesOpenOffer;
|
||||
import bisq.core.trade.protocol.tasks.maker.MaybeRemoveOpenOffer;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerSendsInitTradeRequestIfUnreserved;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerVerifyTakerFeePayment;
|
||||
import bisq.core.util.Validator;
|
||||
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
import bisq.common.handlers.ErrorMessageHandler;
|
||||
import bisq.common.handlers.ResultHandler;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
|
||||
@Slf4j
|
||||
public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol {
|
||||
@ -68,8 +60,6 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||
// MakerProtocol
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// TODO (woodser): these methods are duplicated with SellerAsMakerProtocol due to single inheritance
|
||||
|
||||
@Override
|
||||
public void handleInitTradeRequest(InitTradeRequest message,
|
||||
NodeAddress peer,
|
||||
@ -99,165 +89,30 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||
awaitTradeLatch();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handleInitMultisigRequest()");
|
||||
synchronized (trade) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||
processModel.setTradeMessage(request);
|
||||
expect(anyPhase(Trade.Phase.INIT)
|
||||
.with(request)
|
||||
.from(sender))
|
||||
.setup(tasks(
|
||||
ProcessInitMultisigRequest.class,
|
||||
SendSignContractRequestAfterMultisig.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, request);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, request, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT))
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
}
|
||||
super.handleInitMultisigRequest(request, sender);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse() " + trade.getId());
|
||||
synchronized (trade) {
|
||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||
if (trade.getState() == Trade.State.CONTRACT_SIGNATURE_REQUESTED) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||
processModel.setTradeMessage(message);
|
||||
expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED)
|
||||
.with(message)
|
||||
.from(sender))
|
||||
.setup(tasks(
|
||||
// TODO (woodser): validate request
|
||||
ProcessSignContractRequest.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, message);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, message, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
} else {
|
||||
// process sign contract request after contract signature requested
|
||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||
if (state == Trade.State.CONTRACT_SIGNATURE_REQUESTED) new Thread(() -> handleSignContractRequest(message, sender)).start(); // process notification without trade lock
|
||||
});
|
||||
}
|
||||
}
|
||||
super.handleSignContractRequest(message, sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSignContractResponse(SignContractResponse message, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse() " + trade.getId());
|
||||
synchronized (trade) {
|
||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||
if (trade.getState() == Trade.State.CONTRACT_SIGNED) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||
processModel.setTradeMessage(message);
|
||||
expect(state(Trade.State.CONTRACT_SIGNED)
|
||||
.with(message)
|
||||
.from(sender))
|
||||
.setup(tasks(
|
||||
// TODO (woodser): validate request
|
||||
ProcessSignContractResponse.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, message);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, message, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
} else {
|
||||
// process sign contract response after contract signed
|
||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||
if (state == Trade.State.CONTRACT_SIGNED) new Thread(() -> handleSignContractResponse(message, sender)).start(); // process notification without trade lock
|
||||
});
|
||||
}
|
||||
}
|
||||
super.handleSignContractResponse(message, sender);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handleDepositResponse(DepositResponse response, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handleDepositResponse()");
|
||||
synchronized (trade) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), response);
|
||||
processModel.setTradeMessage(response);
|
||||
expect(state(Trade.State.MAKER_SENT_PUBLISH_DEPOSIT_TX_REQUEST)
|
||||
.with(response)
|
||||
.from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress()
|
||||
.setup(tasks(
|
||||
// TODO (woodser): validate request
|
||||
ProcessDepositResponse.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, response);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, response, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT))
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
}
|
||||
super.handleDepositResponse(response, sender);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handlePaymentAccountPayloadRequest(PaymentAccountPayloadRequest request, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handlePaymentAccountPayloadRequest() " + trade.getId());
|
||||
synchronized (trade) {
|
||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||
if (trade.getState() == Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||
processModel.setTradeMessage(request);
|
||||
expect(state(Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG)
|
||||
.with(request)
|
||||
.from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress()
|
||||
.setup(tasks(
|
||||
// TODO (woodser): validate request
|
||||
ProcessPaymentAccountPayloadRequest.class,
|
||||
MakerRemovesOpenOffer.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
stopTimeout();
|
||||
this.errorMessageHandler = null;
|
||||
handleTaskRunnerSuccess(sender, request);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, request, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT))
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
} else {
|
||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||
if (state == Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) new Thread(() -> handlePaymentAccountPayloadRequest(request, sender)).start(); // process notification without trade lock
|
||||
});
|
||||
}
|
||||
}
|
||||
super.handlePaymentAccountPayloadRequest(request, sender);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -297,7 +152,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
|
||||
.with(message)
|
||||
.from(peer))
|
||||
.setup(tasks(
|
||||
MakerRemovesOpenOffer.class,
|
||||
MaybeRemoveOpenOffer.class,
|
||||
BuyerProcessDelayedPayoutTxSignatureRequest.class,
|
||||
BuyerVerifiesPreparedDelayedPayoutTx.class,
|
||||
BuyerSignsDelayedPayoutTx.class,
|
||||
|
@ -33,12 +33,6 @@ import bisq.core.trade.messages.SignContractRequest;
|
||||
import bisq.core.trade.messages.SignContractResponse;
|
||||
import bisq.core.trade.messages.TradeMessage;
|
||||
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
||||
import bisq.core.trade.protocol.tasks.ProcessDepositResponse;
|
||||
import bisq.core.trade.protocol.tasks.ProcessInitMultisigRequest;
|
||||
import bisq.core.trade.protocol.tasks.ProcessPaymentAccountPayloadRequest;
|
||||
import bisq.core.trade.protocol.tasks.ProcessSignContractRequest;
|
||||
import bisq.core.trade.protocol.tasks.ProcessSignContractResponse;
|
||||
import bisq.core.trade.protocol.tasks.SendSignContractRequestAfterMultisig;
|
||||
import bisq.core.trade.protocol.tasks.TradeTask;
|
||||
import bisq.core.trade.protocol.tasks.VerifyPeersAccountAgeWitness;
|
||||
import bisq.core.trade.protocol.tasks.buyer.BuyerFinalizesDelayedPayoutTx;
|
||||
@ -54,13 +48,11 @@ import bisq.core.trade.protocol.tasks.taker.TakerPublishFeeTx;
|
||||
import bisq.core.trade.protocol.tasks.taker.TakerReservesTradeFunds;
|
||||
import bisq.core.trade.protocol.tasks.taker.TakerSendsInitTradeRequestToArbitrator;
|
||||
import bisq.core.trade.protocol.tasks.taker.TakerVerifyMakerFeePayment;
|
||||
import bisq.core.util.Validator;
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
import bisq.common.handlers.ErrorMessageHandler;
|
||||
import bisq.common.handlers.ResultHandler;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@ -86,8 +78,6 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
||||
// Take offer
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// TODO (woodser): these methods are duplicated with SellerAsTakerProtocol due to single inheritance
|
||||
|
||||
@Override
|
||||
public void onTakeOffer(TradeResultHandler tradeResultHandler,
|
||||
ErrorMessageHandler errorMessageHandler) {
|
||||
@ -119,161 +109,27 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
|
||||
|
||||
@Override
|
||||
public void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handleInitMultisigRequest()");
|
||||
synchronized (trade) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||
processModel.setTradeMessage(request);
|
||||
expect(anyPhase(Trade.Phase.INIT)
|
||||
.with(request)
|
||||
.from(sender))
|
||||
.setup(tasks(
|
||||
ProcessInitMultisigRequest.class,
|
||||
SendSignContractRequestAfterMultisig.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, request);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, request, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT))
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
}
|
||||
super.handleInitMultisigRequest(request, sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse() " + trade.getId());
|
||||
synchronized (trade) {
|
||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||
if (trade.getState() == Trade.State.CONTRACT_SIGNATURE_REQUESTED) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||
processModel.setTradeMessage(message);
|
||||
expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED)
|
||||
.with(message)
|
||||
.from(sender))
|
||||
.setup(tasks(
|
||||
// TODO (woodser): validate request
|
||||
ProcessSignContractRequest.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, message);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, message, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
} else {
|
||||
// process sign contract request after contract signature requested
|
||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||
if (state == Trade.State.CONTRACT_SIGNATURE_REQUESTED) new Thread(() -> handleSignContractRequest(message, sender)).start(); // process notification without trade lock
|
||||
});
|
||||
}
|
||||
}
|
||||
super.handleSignContractRequest(message, sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSignContractResponse(SignContractResponse message, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse()");
|
||||
synchronized (trade) {
|
||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||
if (trade.getState() == Trade.State.CONTRACT_SIGNED) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||
processModel.setTradeMessage(message);
|
||||
expect(state(Trade.State.CONTRACT_SIGNED)
|
||||
.with(message)
|
||||
.from(sender))
|
||||
.setup(tasks(
|
||||
// TODO (woodser): validate request
|
||||
ProcessSignContractResponse.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, message);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, message, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
} else {
|
||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||
if (state == Trade.State.CONTRACT_SIGNED) new Thread(() -> handleSignContractResponse(message, sender)).start(); // process notification without trade lock
|
||||
});
|
||||
}
|
||||
}
|
||||
super.handleSignContractResponse(message, sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleDepositResponse(DepositResponse response, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handleDepositResponse()");
|
||||
synchronized (trade) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), response);
|
||||
processModel.setTradeMessage(response);
|
||||
expect(state(Trade.State.MAKER_SENT_PUBLISH_DEPOSIT_TX_REQUEST)
|
||||
.with(response)
|
||||
.from(sender))
|
||||
.setup(tasks(
|
||||
// TODO (woodser): validate request
|
||||
ProcessDepositResponse.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, response);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, response, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT))
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
}
|
||||
super.handleDepositResponse(response, sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePaymentAccountPayloadRequest(PaymentAccountPayloadRequest request, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handlePaymentAccountPayloadRequest()");
|
||||
synchronized (trade) {
|
||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||
if (trade.getState() == Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||
processModel.setTradeMessage(request);
|
||||
expect(state(Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG)
|
||||
.with(request)
|
||||
.from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress()
|
||||
.setup(tasks(
|
||||
// TODO (woodser): validate request
|
||||
ProcessPaymentAccountPayloadRequest.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
stopTimeout();
|
||||
this.errorMessageHandler = null;
|
||||
tradeResultHandler.handleResult(trade); // trade is initialized
|
||||
handleTaskRunnerSuccess(sender, request);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, request, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT))
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
} else {
|
||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||
if (state == Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) new Thread(() -> handlePaymentAccountPayloadRequest(request, sender)).start(); // process notification without trade lock
|
||||
});
|
||||
}
|
||||
}
|
||||
super.handlePaymentAccountPayloadRequest(request, sender);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -142,8 +142,8 @@ public abstract class BuyerProtocol extends DisputeProtocol {
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
this.errorMessageHandler = null;
|
||||
resultHandler.handleResult();
|
||||
handleTaskRunnerSuccess(event);
|
||||
resultHandler.handleResult();
|
||||
},
|
||||
(errorMessage) -> {
|
||||
handleTaskRunnerFault(event, errorMessage);
|
||||
|
@ -183,10 +183,6 @@ public class ProcessModel implements Model, PersistablePayload {
|
||||
@Setter
|
||||
private String multisigAddress;
|
||||
@Nullable
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean multisigSetupComplete; // TODO (woodser): redundant with multisigAddress existing, remove
|
||||
|
||||
|
||||
// We want to indicate the user the state of the message delivery of the
|
||||
// PaymentSentMessage. As well we do an automatic re-send in case it was not ACKed yet.
|
||||
@ -247,7 +243,6 @@ public class ProcessModel implements Model, PersistablePayload {
|
||||
Optional.ofNullable(preparedMultisigHex).ifPresent(e -> builder.setPreparedMultisigHex(preparedMultisigHex));
|
||||
Optional.ofNullable(madeMultisigHex).ifPresent(e -> builder.setMadeMultisigHex(madeMultisigHex));
|
||||
Optional.ofNullable(multisigAddress).ifPresent(e -> builder.setMultisigAddress(multisigAddress));
|
||||
Optional.ofNullable(multisigSetupComplete).ifPresent(e -> builder.setMultisigSetupComplete(multisigSetupComplete));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@ -279,7 +274,6 @@ public class ProcessModel implements Model, PersistablePayload {
|
||||
processModel.setPreparedMultisigHex(ProtoUtil.stringOrNullFromProto(proto.getPreparedMultisigHex()));
|
||||
processModel.setMadeMultisigHex(ProtoUtil.stringOrNullFromProto(proto.getMadeMultisigHex()));
|
||||
processModel.setMultisigAddress(ProtoUtil.stringOrNullFromProto(proto.getMultisigAddress()));
|
||||
processModel.setMultisigSetupComplete(proto.getMultisigSetupComplete());
|
||||
|
||||
String paymentStartedMessageStateString = ProtoUtil.stringOrNullFromProto(proto.getPaymentStartedMessageState());
|
||||
MessageState paymentStartedMessageState = ProtoUtil.enumFromProto(MessageState.class, paymentStartedMessageStateString);
|
||||
|
@ -21,23 +21,17 @@ package bisq.core.trade.protocol;
|
||||
import bisq.core.trade.SellerAsMakerTrade;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.messages.PaymentSentMessage;
|
||||
import bisq.core.trade.messages.SignContractRequest;
|
||||
import bisq.core.trade.messages.SignContractResponse;
|
||||
import bisq.core.trade.messages.DepositResponse;
|
||||
import bisq.core.trade.messages.DepositTxMessage;
|
||||
import bisq.core.trade.messages.InitMultisigRequest;
|
||||
import bisq.core.trade.messages.InitTradeRequest;
|
||||
import bisq.core.trade.messages.PaymentAccountPayloadRequest;
|
||||
import bisq.core.trade.messages.SignContractRequest;
|
||||
import bisq.core.trade.messages.SignContractResponse;
|
||||
import bisq.core.trade.messages.TradeMessage;
|
||||
import bisq.core.trade.protocol.tasks.ProcessDepositResponse;
|
||||
import bisq.core.trade.protocol.tasks.ProcessInitMultisigRequest;
|
||||
import bisq.core.trade.protocol.tasks.ProcessInitTradeRequest;
|
||||
import bisq.core.trade.protocol.tasks.ProcessPaymentAccountPayloadRequest;
|
||||
import bisq.core.trade.protocol.tasks.ProcessSignContractRequest;
|
||||
import bisq.core.trade.protocol.tasks.ProcessSignContractResponse;
|
||||
import bisq.core.trade.protocol.tasks.SendSignContractRequestAfterMultisig;
|
||||
import bisq.core.trade.protocol.tasks.TradeTask;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerRemovesOpenOffer;
|
||||
import bisq.core.trade.protocol.tasks.maker.MaybeRemoveOpenOffer;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerSendsInitTradeRequestIfUnreserved;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerVerifyTakerFeePayment;
|
||||
import bisq.core.trade.protocol.tasks.seller.SellerCreatesDelayedPayoutTx;
|
||||
@ -45,13 +39,11 @@ import bisq.core.trade.protocol.tasks.seller.SellerSendDelayedPayoutTxSignatureR
|
||||
import bisq.core.trade.protocol.tasks.seller.SellerSignsDelayedPayoutTx;
|
||||
import bisq.core.trade.protocol.tasks.seller_as_maker.SellerAsMakerFinalizesDepositTx;
|
||||
import bisq.core.trade.protocol.tasks.seller_as_maker.SellerAsMakerProcessDepositTxMessage;
|
||||
import bisq.core.util.Validator;
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
import bisq.common.handlers.ErrorMessageHandler;
|
||||
import bisq.common.handlers.ResultHandler;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
|
||||
@Slf4j
|
||||
public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtocol {
|
||||
@ -68,8 +60,6 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
||||
// MakerProtocol
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// TODO (woodser): these methods are duplicated with BuyerAsMakerProtocol due to single inheritance
|
||||
|
||||
@Override
|
||||
public void handleInitTradeRequest(InitTradeRequest message,
|
||||
NodeAddress peer,
|
||||
@ -99,164 +89,30 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
||||
awaitTradeLatch();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handleInitMultisigRequest()");
|
||||
synchronized (trade) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||
processModel.setTradeMessage(request);
|
||||
expect(anyPhase(Trade.Phase.INIT)
|
||||
.with(request)
|
||||
.from(sender))
|
||||
.setup(tasks(
|
||||
ProcessInitMultisigRequest.class,
|
||||
SendSignContractRequestAfterMultisig.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, request);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, request, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT))
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
}
|
||||
super.handleInitMultisigRequest(request, sender);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse() " + trade.getId());
|
||||
synchronized (trade) {
|
||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||
if (trade.getState() == Trade.State.CONTRACT_SIGNATURE_REQUESTED) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||
processModel.setTradeMessage(message);
|
||||
expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED)
|
||||
.with(message)
|
||||
.from(sender))
|
||||
.setup(tasks(
|
||||
// TODO (woodser): validate request
|
||||
ProcessSignContractRequest.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, message);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, message, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
} else {
|
||||
// process sign contract request after contract signature requested
|
||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||
if (state == Trade.State.CONTRACT_SIGNATURE_REQUESTED) new Thread(() -> handleSignContractRequest(message, sender)).start(); // process notification without trade lock
|
||||
});
|
||||
}
|
||||
}
|
||||
super.handleSignContractRequest(message, sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSignContractResponse(SignContractResponse message, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse()");
|
||||
synchronized (trade) {
|
||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||
if (trade.getState() == Trade.State.CONTRACT_SIGNED) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||
processModel.setTradeMessage(message);
|
||||
expect(state(Trade.State.CONTRACT_SIGNED)
|
||||
.with(message)
|
||||
.from(sender))
|
||||
.setup(tasks(
|
||||
// TODO (woodser): validate request
|
||||
ProcessSignContractResponse.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, message);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, message, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
} else {
|
||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||
if (state == Trade.State.CONTRACT_SIGNED) new Thread(() -> handleSignContractResponse(message, sender)).start(); // process notification without trade lock
|
||||
});
|
||||
}
|
||||
}
|
||||
super.handleSignContractResponse(message, sender);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handleDepositResponse(DepositResponse response, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handleDepositResponse()");
|
||||
synchronized (trade) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), response);
|
||||
processModel.setTradeMessage(response);
|
||||
expect(state(Trade.State.MAKER_SENT_PUBLISH_DEPOSIT_TX_REQUEST)
|
||||
.with(response)
|
||||
.from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress()
|
||||
.setup(tasks(
|
||||
// TODO (woodser): validate request
|
||||
ProcessDepositResponse.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, response);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, response, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT))
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
}
|
||||
super.handleDepositResponse(response, sender);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handlePaymentAccountPayloadRequest(PaymentAccountPayloadRequest request, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handlePaymentAccountPayloadRequest()");
|
||||
synchronized (trade) {
|
||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||
if (trade.getState() == Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||
processModel.setTradeMessage(request);
|
||||
expect(state(Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG)
|
||||
.with(request)
|
||||
.from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress()
|
||||
.setup(tasks(
|
||||
// TODO (woodser): validate request
|
||||
ProcessPaymentAccountPayloadRequest.class,
|
||||
MakerRemovesOpenOffer.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
stopTimeout();
|
||||
this.errorMessageHandler = null;
|
||||
handleTaskRunnerSuccess(sender, request);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, request, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT))
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
} else {
|
||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||
if (state == Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) new Thread(() -> handlePaymentAccountPayloadRequest(request, sender)).start(); // process notification without trade lock
|
||||
});
|
||||
}
|
||||
}
|
||||
super.handlePaymentAccountPayloadRequest(request, sender);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -301,7 +157,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
|
||||
.with(message)
|
||||
.from(peer))
|
||||
.setup(tasks(
|
||||
MakerRemovesOpenOffer.class,
|
||||
MaybeRemoveOpenOffer.class,
|
||||
SellerAsMakerProcessDepositTxMessage.class,
|
||||
SellerAsMakerFinalizesDepositTx.class,
|
||||
SellerCreatesDelayedPayoutTx.class,
|
||||
|
@ -23,20 +23,14 @@ import bisq.core.trade.SellerAsTakerTrade;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.handlers.TradeResultHandler;
|
||||
import bisq.core.trade.messages.PaymentSentMessage;
|
||||
import bisq.core.trade.messages.SignContractRequest;
|
||||
import bisq.core.trade.messages.SignContractResponse;
|
||||
import bisq.core.trade.messages.DepositResponse;
|
||||
import bisq.core.trade.messages.InitMultisigRequest;
|
||||
import bisq.core.trade.messages.InputsForDepositTxResponse;
|
||||
import bisq.core.trade.messages.PaymentAccountPayloadRequest;
|
||||
import bisq.core.trade.messages.SignContractRequest;
|
||||
import bisq.core.trade.messages.SignContractResponse;
|
||||
import bisq.core.trade.messages.TradeMessage;
|
||||
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
||||
import bisq.core.trade.protocol.tasks.ProcessDepositResponse;
|
||||
import bisq.core.trade.protocol.tasks.ProcessInitMultisigRequest;
|
||||
import bisq.core.trade.protocol.tasks.ProcessPaymentAccountPayloadRequest;
|
||||
import bisq.core.trade.protocol.tasks.ProcessSignContractRequest;
|
||||
import bisq.core.trade.protocol.tasks.ProcessSignContractResponse;
|
||||
import bisq.core.trade.protocol.tasks.SendSignContractRequestAfterMultisig;
|
||||
import bisq.core.trade.protocol.tasks.TradeTask;
|
||||
import bisq.core.trade.protocol.tasks.VerifyPeersAccountAgeWitness;
|
||||
import bisq.core.trade.protocol.tasks.seller.SellerCreatesDelayedPayoutTx;
|
||||
@ -48,14 +42,12 @@ import bisq.core.trade.protocol.tasks.taker.TakerPublishFeeTx;
|
||||
import bisq.core.trade.protocol.tasks.taker.TakerReservesTradeFunds;
|
||||
import bisq.core.trade.protocol.tasks.taker.TakerSendsInitTradeRequestToArbitrator;
|
||||
import bisq.core.trade.protocol.tasks.taker.TakerVerifyMakerFeePayment;
|
||||
import bisq.core.util.Validator;
|
||||
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
import bisq.common.handlers.ErrorMessageHandler;
|
||||
import bisq.common.handlers.ResultHandler;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@ -79,8 +71,6 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
||||
// Take offer
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// TODO (woodser): these methods are duplicated with BuyerAsTakerProtocol due to single inheritance
|
||||
|
||||
@Override
|
||||
public void onTakeOffer(TradeResultHandler tradeResultHandler,
|
||||
ErrorMessageHandler errorMessageHandler) {
|
||||
@ -112,164 +102,29 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
|
||||
|
||||
@Override
|
||||
public void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handleInitMultisigRequest()");
|
||||
synchronized (trade) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||
processModel.setTradeMessage(request);
|
||||
expect(anyPhase(Trade.Phase.INIT)
|
||||
.with(request)
|
||||
.from(sender))
|
||||
.setup(tasks(
|
||||
ProcessInitMultisigRequest.class,
|
||||
SendSignContractRequestAfterMultisig.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, request);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, request, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT))
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
}
|
||||
super.handleInitMultisigRequest(request, sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse() " + trade.getId());
|
||||
synchronized (trade) {
|
||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||
if (trade.getState() == Trade.State.CONTRACT_SIGNATURE_REQUESTED) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||
processModel.setTradeMessage(message);
|
||||
expect(state(Trade.State.CONTRACT_SIGNATURE_REQUESTED)
|
||||
.with(message)
|
||||
.from(sender))
|
||||
.setup(tasks(
|
||||
// TODO (woodser): validate request
|
||||
ProcessSignContractRequest.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, message);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, message, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
} else {
|
||||
// process sign contract request after contract signature requested
|
||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||
if (state == Trade.State.CONTRACT_SIGNATURE_REQUESTED) new Thread(() -> handleSignContractRequest(message, sender)).start(); // process notification without trade lock
|
||||
});
|
||||
}
|
||||
}
|
||||
super.handleSignContractRequest(message, sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSignContractResponse(SignContractResponse message, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse() " + trade.getId());
|
||||
synchronized (trade) {
|
||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||
if (trade.getState() == Trade.State.CONTRACT_SIGNED) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||
processModel.setTradeMessage(message);
|
||||
expect(state(Trade.State.CONTRACT_SIGNED)
|
||||
.with(message)
|
||||
.from(sender))
|
||||
.setup(tasks(
|
||||
// TODO (woodser): validate request
|
||||
ProcessSignContractResponse.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, message);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, message, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
} else {
|
||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||
if (state == Trade.State.CONTRACT_SIGNED) new Thread(() -> handleSignContractResponse(message, sender)).start(); // process notification without trade lock
|
||||
});
|
||||
}
|
||||
}
|
||||
super.handleSignContractResponse(message, sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleDepositResponse(DepositResponse response, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handleDepositResponse()");
|
||||
synchronized (trade) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), response);
|
||||
processModel.setTradeMessage(response);
|
||||
expect(state(Trade.State.MAKER_SENT_PUBLISH_DEPOSIT_TX_REQUEST)
|
||||
.with(response)
|
||||
.from(sender))
|
||||
.setup(tasks(
|
||||
// TODO (woodser): validate request
|
||||
ProcessDepositResponse.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, response);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, response, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT))
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
}
|
||||
super.handleDepositResponse(response, sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePaymentAccountPayloadRequest(PaymentAccountPayloadRequest request, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handlePaymentAccountPayloadRequest() " + trade.getId());
|
||||
synchronized (trade) {
|
||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||
if (trade.getState() == Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||
processModel.setTradeMessage(request);
|
||||
expect(state(Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG)
|
||||
.with(request)
|
||||
.from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress()
|
||||
.setup(tasks(
|
||||
// TODO (woodser): validate request
|
||||
ProcessPaymentAccountPayloadRequest.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
stopTimeout();
|
||||
this.errorMessageHandler = null;
|
||||
tradeResultHandler.handleResult(trade); // trade is initialized
|
||||
handleTaskRunnerSuccess(sender, request);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, request, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT))
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
} else {
|
||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||
if (state == Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) new Thread(() -> handlePaymentAccountPayloadRequest(request, sender)).start(); // process notification without trade lock
|
||||
});
|
||||
}
|
||||
}
|
||||
super.handlePaymentAccountPayloadRequest(request, sender);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Incoming message when buyer has clicked payment started button
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -136,13 +136,13 @@ public abstract class SellerProtocol extends DisputeProtocol {
|
||||
getVerifyPeersFeePaymentClass(),
|
||||
SellerPreparesPaymentReceivedMessage.class,
|
||||
SellerSendsPaymentReceivedMessage.class)
|
||||
.using(new TradeTaskRunner(trade, () -> {
|
||||
this.errorMessageHandler = null;
|
||||
resultHandler.handleResult();
|
||||
handleTaskRunnerSuccess(event);
|
||||
}, (errorMessage) -> {
|
||||
handleTaskRunnerFault(event, errorMessage);
|
||||
})))
|
||||
.using(new TradeTaskRunner(trade, () -> {
|
||||
this.errorMessageHandler = null;
|
||||
handleTaskRunnerSuccess(event);
|
||||
resultHandler.handleResult();
|
||||
}, (errorMessage) -> {
|
||||
handleTaskRunnerFault(event, errorMessage);
|
||||
})))
|
||||
.run(() -> trade.setState(Trade.State.SELLER_CONFIRMED_IN_UI_PAYMENT_RECEIPT))
|
||||
.executeTasks();
|
||||
awaitTradeLatch();
|
||||
|
@ -23,12 +23,22 @@ import bisq.core.trade.TradeManager;
|
||||
import bisq.core.trade.TradeUtils;
|
||||
import bisq.core.trade.handlers.TradeResultHandler;
|
||||
import bisq.core.trade.messages.PaymentSentMessage;
|
||||
import bisq.core.trade.messages.DepositResponse;
|
||||
import bisq.core.trade.messages.DepositTxAndDelayedPayoutTxMessage;
|
||||
import bisq.core.trade.messages.InitMultisigRequest;
|
||||
import bisq.core.trade.messages.PaymentAccountPayloadRequest;
|
||||
import bisq.core.trade.messages.SignContractRequest;
|
||||
import bisq.core.trade.messages.SignContractResponse;
|
||||
import bisq.core.trade.messages.TradeMessage;
|
||||
import bisq.core.trade.messages.UpdateMultisigRequest;
|
||||
import bisq.core.trade.protocol.tasks.MaybeSendSignContractRequest;
|
||||
import bisq.core.trade.protocol.tasks.ProcessDepositResponse;
|
||||
import bisq.core.trade.protocol.tasks.ProcessInitMultisigRequest;
|
||||
import bisq.core.trade.protocol.tasks.ProcessPaymentAccountPayloadRequest;
|
||||
import bisq.core.trade.protocol.tasks.ProcessSignContractRequest;
|
||||
import bisq.core.trade.protocol.tasks.ProcessSignContractResponse;
|
||||
import bisq.core.trade.protocol.tasks.ProcessUpdateMultisigRequest;
|
||||
import bisq.core.trade.protocol.tasks.maker.MaybeRemoveOpenOffer;
|
||||
import bisq.core.util.Validator;
|
||||
|
||||
import bisq.network.p2p.AckMessage;
|
||||
@ -54,7 +64,7 @@ import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@Slf4j
|
||||
@ -213,8 +223,162 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected abstract void onTradeMessage(TradeMessage message, NodeAddress peer);
|
||||
public abstract void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress peer);
|
||||
public abstract void handleSignContractRequest(SignContractRequest request, NodeAddress peer);
|
||||
|
||||
public void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handleInitMultisigRequest()");
|
||||
synchronized (trade) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||
processModel.setTradeMessage(request);
|
||||
expect(anyPhase(Trade.Phase.INIT)
|
||||
.with(request)
|
||||
.from(sender))
|
||||
.setup(tasks(
|
||||
ProcessInitMultisigRequest.class,
|
||||
MaybeSendSignContractRequest.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, request);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, request, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT))
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
}
|
||||
}
|
||||
|
||||
public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse() " + trade.getId());
|
||||
synchronized (trade) {
|
||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||
if (trade.getState() == Trade.State.MULTISIG_COMPLETED || trade.getState() == Trade.State.CONTRACT_SIGNATURE_REQUESTED) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||
processModel.setTradeMessage(message);
|
||||
expect(anyState(Trade.State.MULTISIG_COMPLETED, Trade.State.CONTRACT_SIGNATURE_REQUESTED)
|
||||
.with(message)
|
||||
.from(sender))
|
||||
.setup(tasks(
|
||||
// TODO (woodser): validate request
|
||||
ProcessSignContractRequest.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, message);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, message, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
} else {
|
||||
// process sign contract request after multisig created
|
||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||
if (state == Trade.State.MULTISIG_COMPLETED) new Thread(() -> handleSignContractRequest(message, sender)).start(); // process notification without trade lock
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleSignContractResponse(SignContractResponse message, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handleSignContractResponse() " + trade.getId());
|
||||
synchronized (trade) {
|
||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||
if (trade.getState() == Trade.State.CONTRACT_SIGNED) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), message);
|
||||
processModel.setTradeMessage(message);
|
||||
expect(state(Trade.State.CONTRACT_SIGNED)
|
||||
.with(message)
|
||||
.from(sender))
|
||||
.setup(tasks(
|
||||
// TODO (woodser): validate request
|
||||
ProcessSignContractResponse.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, message);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, message, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT)) // extend timeout
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
} else {
|
||||
// process sign contract response after contract signed
|
||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||
if (state == Trade.State.CONTRACT_SIGNED) new Thread(() -> handleSignContractResponse(message, sender)).start(); // process notification without trade lock
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleDepositResponse(DepositResponse response, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handleDepositResponse()");
|
||||
synchronized (trade) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), response);
|
||||
processModel.setTradeMessage(response);
|
||||
expect(state(Trade.State.MAKER_SENT_PUBLISH_DEPOSIT_TX_REQUEST)
|
||||
.with(response)
|
||||
.from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress()
|
||||
.setup(tasks(
|
||||
// TODO (woodser): validate request
|
||||
ProcessDepositResponse.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
startTimeout(TRADE_TIMEOUT);
|
||||
handleTaskRunnerSuccess(sender, response);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, response, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT))
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
}
|
||||
}
|
||||
|
||||
public void handlePaymentAccountPayloadRequest(PaymentAccountPayloadRequest request, NodeAddress sender) {
|
||||
System.out.println(getClass().getCanonicalName() + ".handlePaymentAccountPayloadRequest()");
|
||||
synchronized (trade) {
|
||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||
if (trade.getState() == Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) {
|
||||
latchTrade();
|
||||
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||
processModel.setTradeMessage(request);
|
||||
expect(state(Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG)
|
||||
.with(request)
|
||||
.from(sender)) // TODO (woodser): ensure this asserts sender == response.getSenderNodeAddress()
|
||||
.setup(tasks(
|
||||
// TODO (woodser): validate request
|
||||
ProcessPaymentAccountPayloadRequest.class,
|
||||
MaybeRemoveOpenOffer.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
stopTimeout();
|
||||
this.errorMessageHandler = null;
|
||||
handleTaskRunnerSuccess(sender, request);
|
||||
if (tradeResultHandler != null) tradeResultHandler.handleResult(trade); // trade is initialized
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, request, errorMessage);
|
||||
}))
|
||||
.withTimeout(TRADE_TIMEOUT))
|
||||
.executeTasks(true);
|
||||
awaitTradeLatch();
|
||||
} else {
|
||||
EasyBind.subscribe(trade.stateProperty(), state -> {
|
||||
if (state == Trade.State.MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) new Thread(() -> handlePaymentAccountPayloadRequest(request, sender)).start(); // process notification without trade lock
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO (woodser): update to use fluent for consistency
|
||||
public void handleUpdateMultisigRequest(UpdateMultisigRequest message, NodeAddress peer, ErrorMessageHandler errorMessageHandler) {
|
||||
@ -237,7 +401,6 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||
awaitTradeLatch();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FluentProtocol
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -20,6 +20,7 @@ package bisq.core.trade.protocol.tasks;
|
||||
import bisq.common.app.Version;
|
||||
import bisq.common.taskrunner.TaskRunner;
|
||||
import bisq.core.btc.model.XmrAddressEntry;
|
||||
import bisq.core.trade.ArbitratorTrade;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.Trade.State;
|
||||
import bisq.core.trade.messages.SignContractRequest;
|
||||
@ -32,13 +33,13 @@ import monero.wallet.model.MoneroTxWallet;
|
||||
|
||||
// TODO (woodser): separate classes for deposit tx creation and contract request, or combine into ProcessInitMultisigRequest
|
||||
@Slf4j
|
||||
public class SendSignContractRequestAfterMultisig extends TradeTask {
|
||||
public class MaybeSendSignContractRequest extends TradeTask {
|
||||
|
||||
private boolean ack1 = false; // TODO (woodser) these represent onArrived(), not the ack
|
||||
private boolean ack2 = false;
|
||||
|
||||
@SuppressWarnings({"unused"})
|
||||
public SendSignContractRequestAfterMultisig(TaskRunner taskHandler, Trade trade) {
|
||||
public MaybeSendSignContractRequest(TaskRunner taskHandler, Trade trade) {
|
||||
super(taskHandler, trade);
|
||||
}
|
||||
|
||||
@ -46,11 +47,17 @@ public class SendSignContractRequestAfterMultisig extends TradeTask {
|
||||
protected void run() {
|
||||
try {
|
||||
runInterceptHook();
|
||||
|
||||
// skip if arbitrator
|
||||
if (trade instanceof ArbitratorTrade) {
|
||||
complete();
|
||||
return;
|
||||
}
|
||||
|
||||
// skip if multisig wallet not complete
|
||||
if (!processModel.isMultisigSetupComplete()) {
|
||||
if (processModel.getMultisigAddress() == null) {
|
||||
complete();
|
||||
return; // TODO: woodser: this does not ack original request?
|
||||
return;
|
||||
}
|
||||
|
||||
// skip if deposit tx already created
|
||||
@ -71,7 +78,7 @@ public class SendSignContractRequestAfterMultisig extends TradeTask {
|
||||
// TODO (woodser): save frozen key images and unfreeze if trade fails before deposited to multisig
|
||||
|
||||
// save process state
|
||||
processModel.setDepositTxXmr(depositTx);
|
||||
processModel.setDepositTxXmr(depositTx); // TODO: trade.getSelf().setDepositTx()
|
||||
trade.getSelf().setDepositTxHash(depositTx.getHash());
|
||||
trade.getSelf().setPayoutAddressString(trade.getXmrWalletService().getAddressEntry(processModel.getOffer().getId(), XmrAddressEntry.Context.TRADE_PAYOUT).get().getAddressString()); // TODO (woodser): allow custom payout address?
|
||||
|
@ -23,9 +23,7 @@ import bisq.core.trade.MakerTrade;
|
||||
import bisq.core.trade.TakerTrade;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.messages.InitMultisigRequest;
|
||||
import bisq.core.trade.protocol.TradeListener;
|
||||
import bisq.core.trade.protocol.TradingPeer;
|
||||
import bisq.network.p2p.AckMessage;
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
import bisq.network.p2p.SendDirectMessageListener;
|
||||
|
||||
@ -92,8 +90,9 @@ public class ProcessInitMultisigRequest extends TradeTask {
|
||||
log.info("Preparing multisig wallet for trade {}", trade.getId());
|
||||
multisigWallet = xmrWalletService.createMultisigWallet(trade.getId());
|
||||
processModel.setPreparedMultisigHex(multisigWallet.prepareMultisig());
|
||||
trade.setStateIfValidTransitionTo(Trade.State.MULTISIG_PREPARED);
|
||||
updateParticipants = true;
|
||||
} else if (!processModel.isMultisigSetupComplete()) {
|
||||
} else if (processModel.getMultisigAddress() == null) {
|
||||
multisigWallet = xmrWalletService.getMultisigWallet(trade.getId());
|
||||
}
|
||||
|
||||
@ -103,15 +102,16 @@ public class ProcessInitMultisigRequest extends TradeTask {
|
||||
log.info("Making multisig wallet for trade {}", trade.getId());
|
||||
MoneroMultisigInitResult result = multisigWallet.makeMultisig(Arrays.asList(peers[0].getPreparedMultisigHex(), peers[1].getPreparedMultisigHex()), 2, xmrWalletService.getWalletPassword()); // TODO (woodser): xmrWalletService.makeMultisig(tradeId, multisigHexes, threshold)?
|
||||
processModel.setMadeMultisigHex(result.getMultisigHex());
|
||||
trade.setStateIfValidTransitionTo(Trade.State.MULTISIG_MADE);
|
||||
updateParticipants = true;
|
||||
}
|
||||
|
||||
// exchange multisig keys if applicable
|
||||
if (!processModel.isMultisigSetupComplete() && peers[0].getMadeMultisigHex() != null && peers[1].getMadeMultisigHex() != null) {
|
||||
if (processModel.getMultisigAddress() == null && peers[0].getMadeMultisigHex() != null && peers[1].getMadeMultisigHex() != null) {
|
||||
log.info("Exchanging multisig wallet keys for trade {}", trade.getId());
|
||||
multisigWallet.exchangeMultisigKeys(Arrays.asList(peers[0].getMadeMultisigHex(), peers[1].getMadeMultisigHex()), xmrWalletService.getWalletPassword());
|
||||
processModel.setMultisigSetupComplete(true); // TODO: (woodser): remove this field?
|
||||
processModel.setMultisigAddress(multisigWallet.getPrimaryAddress());
|
||||
trade.setStateIfValidTransitionTo(Trade.State.MULTISIG_COMPLETED);
|
||||
processModel.getProvider().getXmrWalletService().closeMultisigWallet(trade.getId()); // save and close multisig wallet once it's created
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
package bisq.core.trade.protocol.tasks.maker;
|
||||
|
||||
import bisq.core.trade.MakerTrade;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.protocol.tasks.TradeTask;
|
||||
|
||||
@ -27,8 +28,8 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@Slf4j
|
||||
public class MakerRemovesOpenOffer extends TradeTask {
|
||||
public MakerRemovesOpenOffer(TaskRunner<Trade> taskHandler, Trade trade) {
|
||||
public class MaybeRemoveOpenOffer extends TradeTask {
|
||||
public MaybeRemoveOpenOffer(TaskRunner<Trade> taskHandler, Trade trade) {
|
||||
super(taskHandler, trade);
|
||||
}
|
||||
|
||||
@ -36,8 +37,10 @@ public class MakerRemovesOpenOffer extends TradeTask {
|
||||
protected void run() {
|
||||
try {
|
||||
runInterceptHook();
|
||||
|
||||
processModel.getOpenOfferManager().closeOpenOffer(checkNotNull(trade.getOffer()));
|
||||
|
||||
if (trade instanceof MakerTrade) {
|
||||
processModel.getOpenOfferManager().closeOpenOffer(checkNotNull(trade.getOffer()));
|
||||
}
|
||||
|
||||
complete();
|
||||
} catch (Throwable t) {
|
@ -128,8 +128,7 @@ class GrpcTradesService extends TradesImplBase {
|
||||
responseObserver.onCompleted();
|
||||
},
|
||||
errorMessage -> {
|
||||
if (!errorMessageHandler.isErrorHandled())
|
||||
errorMessageHandler.handleErrorMessage(errorMessage);
|
||||
if (!errorMessageHandler.isErrorHandled()) errorMessageHandler.handleErrorMessage(errorMessage);
|
||||
});
|
||||
} catch (Throwable cause) {
|
||||
cause.printStackTrace();
|
||||
@ -169,7 +168,7 @@ class GrpcTradesService extends TradesImplBase {
|
||||
responseObserver.onCompleted();
|
||||
},
|
||||
errorMessage -> {
|
||||
if (!errorMessageHandler.isErrorHandled()) errorMessageHandler.handleErrorMessage(errorMessage);
|
||||
if (!errorMessageHandler.isErrorHandled()) errorMessageHandler.handleErrorMessage(errorMessage);
|
||||
});
|
||||
} catch (Throwable cause) {
|
||||
cause.printStackTrace();
|
||||
|
@ -43,7 +43,7 @@ import bisq.core.trade.protocol.tasks.buyer_as_maker.BuyerAsMakerSendsInputsForD
|
||||
import bisq.core.trade.protocol.tasks.buyer_as_taker.BuyerAsTakerCreatesDepositTxInputs;
|
||||
import bisq.core.trade.protocol.tasks.buyer_as_taker.BuyerAsTakerSendsDepositTxMessage;
|
||||
import bisq.core.trade.protocol.tasks.buyer_as_taker.BuyerAsTakerSignsDepositTx;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerRemovesOpenOffer;
|
||||
import bisq.core.trade.protocol.tasks.maker.MaybeRemoveOpenOffer;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerSetsLockTime;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerVerifyTakerFeePayment;
|
||||
import bisq.core.trade.protocol.tasks.seller.SellerCreatesDelayedPayoutTx;
|
||||
@ -157,7 +157,7 @@ public class DebugView extends InitializableView<GridPane, Void> {
|
||||
BuyerAsMakerSendsInputsForDepositTxResponse.class,
|
||||
|
||||
BuyerProcessDelayedPayoutTxSignatureRequest.class,
|
||||
MakerRemovesOpenOffer.class,
|
||||
MaybeRemoveOpenOffer.class,
|
||||
BuyerVerifiesPreparedDelayedPayoutTx.class,
|
||||
BuyerSignsDelayedPayoutTx.class,
|
||||
BuyerSendsDelayedPayoutTxSignatureResponse.class,
|
||||
@ -215,7 +215,7 @@ public class DebugView extends InitializableView<GridPane, Void> {
|
||||
SellerAsMakerSendsInputsForDepositTxResponse.class,
|
||||
|
||||
//SellerAsMakerProcessDepositTxMessage.class,
|
||||
MakerRemovesOpenOffer.class,
|
||||
MaybeRemoveOpenOffer.class,
|
||||
SellerAsMakerFinalizesDepositTx.class,
|
||||
SellerCreatesDelayedPayoutTx.class,
|
||||
SellerSendDelayedPayoutTxSignatureRequest.class,
|
||||
|
@ -403,6 +403,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||
// #################### Phase PREPARATION
|
||||
case PREPARATION:
|
||||
case CONTRACT_SIGNATURE_REQUESTED:
|
||||
case CONTRACT_SIGNED:
|
||||
sellerState.set(UNDEFINED);
|
||||
buyerState.set(BuyerState.UNDEFINED);
|
||||
break;
|
||||
|
@ -1624,43 +1624,46 @@ message Trade {
|
||||
enum State {
|
||||
PB_ERROR_STATE = 0;
|
||||
PREPARATION = 1;
|
||||
CONTRACT_SIGNATURE_REQUESTED = 2;
|
||||
CONTRACT_SIGNED = 3;
|
||||
TAKER_PUBLISHED_TAKER_FEE_TX = 4;
|
||||
MAKER_SENT_PUBLISH_DEPOSIT_TX_REQUEST = 5;
|
||||
MAKER_SAW_ARRIVED_PUBLISH_DEPOSIT_TX_REQUEST = 6;
|
||||
MAKER_STORED_IN_MAILBOX_PUBLISH_DEPOSIT_TX_REQUEST = 7;
|
||||
MAKER_SEND_FAILED_PUBLISH_DEPOSIT_TX_REQUEST = 8;
|
||||
TAKER_RECEIVED_PUBLISH_DEPOSIT_TX_REQUEST = 9;
|
||||
ARBITRATOR_PUBLISHED_DEPOSIT_TX = 10;
|
||||
TAKER_SAW_DEPOSIT_TX_IN_NETWORK = 11;
|
||||
TAKER_SENT_DEPOSIT_TX_PUBLISHED_MSG = 12;
|
||||
TAKER_SAW_ARRIVED_DEPOSIT_TX_PUBLISHED_MSG = 13;
|
||||
TAKER_STORED_IN_MAILBOX_DEPOSIT_TX_PUBLISHED_MSG = 14;
|
||||
TAKER_SEND_FAILED_DEPOSIT_TX_PUBLISHED_MSG = 15;
|
||||
MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG = 16;
|
||||
MAKER_SAW_DEPOSIT_TX_IN_NETWORK = 17;
|
||||
DEPOSIT_UNLOCKED_IN_BLOCK_CHAIN = 18;
|
||||
BUYER_CONFIRMED_IN_UI_PAYMENT_SENT = 19;
|
||||
BUYER_SENT_PAYMENT_SENT_MSG = 20;
|
||||
BUYER_SAW_ARRIVED_PAYMENT_SENT_MSG = 21;
|
||||
BUYER_STORED_IN_MAILBOX_PAYMENT_SENT_MSG = 22;
|
||||
BUYER_SEND_FAILED_PAYMENT_SENT_MSG = 23;
|
||||
SELLER_RECEIVED_PAYMENT_SENT_MSG = 24;
|
||||
SELLER_CONFIRMED_IN_UI_PAYMENT_RECEIPT = 25;
|
||||
SELLER_SENT_PAYMENT_RECEIVED_MSG = 26;
|
||||
SELLER_SAW_ARRIVED_PAYMENT_RECEIVED_MSG = 27;
|
||||
SELLER_STORED_IN_MAILBOX_PAYMENT_RECEIVED_MSG = 28;
|
||||
SELLER_SEND_FAILED_PAYMENT_RECEIVED_MSG = 29;
|
||||
SELLER_PUBLISHED_PAYOUT_TX = 30;
|
||||
SELLER_SENT_PAYOUT_TX_PUBLISHED_MSG = 31;
|
||||
SELLER_SAW_ARRIVED_PAYOUT_TX_PUBLISHED_MSG = 32;
|
||||
SELLER_STORED_IN_MAILBOX_PAYOUT_TX_PUBLISHED_MSG = 33;
|
||||
SELLER_SEND_FAILED_PAYOUT_TX_PUBLISHED_MSG = 34;
|
||||
BUYER_RECEIVED_PAYOUT_TX_PUBLISHED_MSG = 35;
|
||||
BUYER_SAW_PAYOUT_TX_IN_NETWORK = 36;
|
||||
BUYER_PUBLISHED_PAYOUT_TX = 37;
|
||||
WITHDRAW_COMPLETED = 38;
|
||||
MULTISIG_PREPARED = 2;
|
||||
MULTISIG_MADE = 3;
|
||||
MULTISIG_COMPLETED = 4;
|
||||
CONTRACT_SIGNATURE_REQUESTED = 5;
|
||||
CONTRACT_SIGNED = 6;
|
||||
TAKER_PUBLISHED_TAKER_FEE_TX = 7;
|
||||
MAKER_SENT_PUBLISH_DEPOSIT_TX_REQUEST = 8;
|
||||
MAKER_SAW_ARRIVED_PUBLISH_DEPOSIT_TX_REQUEST = 9;
|
||||
MAKER_STORED_IN_MAILBOX_PUBLISH_DEPOSIT_TX_REQUEST = 10;
|
||||
MAKER_SEND_FAILED_PUBLISH_DEPOSIT_TX_REQUEST = 11;
|
||||
TAKER_RECEIVED_PUBLISH_DEPOSIT_TX_REQUEST = 12;
|
||||
ARBITRATOR_PUBLISHED_DEPOSIT_TX = 13;
|
||||
TAKER_SAW_DEPOSIT_TX_IN_NETWORK = 14;
|
||||
TAKER_SENT_DEPOSIT_TX_PUBLISHED_MSG = 15;
|
||||
TAKER_SAW_ARRIVED_DEPOSIT_TX_PUBLISHED_MSG = 16;
|
||||
TAKER_STORED_IN_MAILBOX_DEPOSIT_TX_PUBLISHED_MSG = 17;
|
||||
TAKER_SEND_FAILED_DEPOSIT_TX_PUBLISHED_MSG = 18;
|
||||
MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG = 19;
|
||||
MAKER_SAW_DEPOSIT_TX_IN_NETWORK = 20;
|
||||
DEPOSIT_UNLOCKED_IN_BLOCK_CHAIN = 21;
|
||||
BUYER_CONFIRMED_IN_UI_PAYMENT_SENT = 22;
|
||||
BUYER_SENT_PAYMENT_SENT_MSG = 23;
|
||||
BUYER_SAW_ARRIVED_PAYMENT_SENT_MSG = 24;
|
||||
BUYER_STORED_IN_MAILBOX_PAYMENT_SENT_MSG = 25;
|
||||
BUYER_SEND_FAILED_PAYMENT_SENT_MSG = 26;
|
||||
SELLER_RECEIVED_PAYMENT_SENT_MSG = 27;
|
||||
SELLER_CONFIRMED_IN_UI_PAYMENT_RECEIPT = 28;
|
||||
SELLER_SENT_PAYMENT_RECEIVED_MSG = 29;
|
||||
SELLER_SAW_ARRIVED_PAYMENT_RECEIVED_MSG = 30;
|
||||
SELLER_STORED_IN_MAILBOX_PAYMENT_RECEIVED_MSG = 31;
|
||||
SELLER_SEND_FAILED_PAYMENT_RECEIVED_MSG = 32;
|
||||
SELLER_PUBLISHED_PAYOUT_TX = 33;
|
||||
SELLER_SENT_PAYOUT_TX_PUBLISHED_MSG = 34;
|
||||
SELLER_SAW_ARRIVED_PAYOUT_TX_PUBLISHED_MSG = 35;
|
||||
SELLER_STORED_IN_MAILBOX_PAYOUT_TX_PUBLISHED_MSG = 36;
|
||||
SELLER_SEND_FAILED_PAYOUT_TX_PUBLISHED_MSG = 37;
|
||||
BUYER_RECEIVED_PAYOUT_TX_PUBLISHED_MSG = 38;
|
||||
BUYER_SAW_PAYOUT_TX_IN_NETWORK = 39;
|
||||
BUYER_PUBLISHED_PAYOUT_TX = 40;
|
||||
WITHDRAW_COMPLETED = 41;
|
||||
}
|
||||
|
||||
enum Phase {
|
||||
@ -1789,7 +1792,6 @@ message ProcessModel {
|
||||
string prepared_multisig_hex = 1007;
|
||||
string made_multisig_hex = 1008;
|
||||
string multisig_address = 1009;
|
||||
bool multisig_setup_complete = 1010; // TODO: remove this field
|
||||
}
|
||||
|
||||
message TradingPeer {
|
||||
|
Loading…
Reference in New Issue
Block a user