mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-01-03 17:40:10 +00:00
close arbitrator trade by sending PayoutTxPublishedMessage
This commit is contained in:
parent
9975d7398b
commit
64925d0137
17 changed files with 385 additions and 121 deletions
|
@ -770,14 +770,15 @@ public abstract class Trade implements Tradable, Model {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify and sign a payout tx.
|
* Verify a payout tx.
|
||||||
*
|
*
|
||||||
* @param payoutTxHex is the payout tx hex to verify
|
* @param payoutTxHex is the payout tx hex to verify
|
||||||
* @return String the signed payout tx hex
|
* @param sign signs the payout tx if true
|
||||||
|
* @param publish publishes the signed payout tx if true
|
||||||
*/
|
*/
|
||||||
public void verifySignAndPublishPayoutTx(String payoutTxHex) {
|
public void verifyPayoutTx(String payoutTxHex, boolean sign, boolean publish) {
|
||||||
log.info("Verifying payout tx");
|
log.info("Verifying payout tx");
|
||||||
|
|
||||||
// gather relevant info
|
// gather relevant info
|
||||||
XmrWalletService walletService = processModel.getProvider().getXmrWalletService();
|
XmrWalletService walletService = processModel.getProvider().getXmrWalletService();
|
||||||
MoneroWallet multisigWallet = walletService.getMultisigWallet(getId());
|
MoneroWallet multisigWallet = walletService.getMultisigWallet(getId());
|
||||||
|
@ -787,9 +788,9 @@ public abstract class Trade implements Tradable, Model {
|
||||||
BigInteger tradeAmount = ParsingUtils.coinToAtomicUnits(getAmount());
|
BigInteger tradeAmount = ParsingUtils.coinToAtomicUnits(getAmount());
|
||||||
|
|
||||||
// parse payout tx
|
// parse payout tx
|
||||||
MoneroTxSet parsedTxSet = multisigWallet.describeTxSet(new MoneroTxSet().setMultisigTxHex(payoutTxHex));
|
MoneroTxSet describedTxSet = multisigWallet.describeTxSet(new MoneroTxSet().setMultisigTxHex(payoutTxHex));
|
||||||
if (parsedTxSet.getTxs() == null || parsedTxSet.getTxs().size() != 1) throw new RuntimeException("Bad payout tx"); // TODO (woodser): test nack
|
if (describedTxSet.getTxs() == null || describedTxSet.getTxs().size() != 1) throw new RuntimeException("Bad payout tx"); // TODO (woodser): test nack
|
||||||
MoneroTxWallet payoutTx = parsedTxSet.getTxs().get(0);
|
MoneroTxWallet payoutTx = describedTxSet.getTxs().get(0);
|
||||||
|
|
||||||
// verify payout tx has exactly 2 destinations
|
// verify payout tx has exactly 2 destinations
|
||||||
if (payoutTx.getOutgoingTransfer() == null || payoutTx.getOutgoingTransfer().getDestinations() == null || payoutTx.getOutgoingTransfer().getDestinations().size() != 2) throw new RuntimeException("Payout tx does not have exactly two destinations");
|
if (payoutTx.getOutgoingTransfer() == null || payoutTx.getOutgoingTransfer().getDestinations() == null || payoutTx.getOutgoingTransfer().getDestinations().size() != 2) throw new RuntimeException("Payout tx does not have exactly two destinations");
|
||||||
|
@ -819,21 +820,25 @@ public abstract class Trade implements Tradable, Model {
|
||||||
if (!sellerPayoutDestination.getAmount().equals(expectedSellerPayout)) throw new RuntimeException("Seller destination amount is not deposit amount - trade amount - 1/2 tx costs, " + sellerPayoutDestination.getAmount() + " vs " + expectedSellerPayout);
|
if (!sellerPayoutDestination.getAmount().equals(expectedSellerPayout)) throw new RuntimeException("Seller destination amount is not deposit amount - trade amount - 1/2 tx costs, " + sellerPayoutDestination.getAmount() + " vs " + expectedSellerPayout);
|
||||||
|
|
||||||
// TODO (woodser): verify fee is reasonable (e.g. within 2x of fee estimate tx)
|
// TODO (woodser): verify fee is reasonable (e.g. within 2x of fee estimate tx)
|
||||||
|
|
||||||
// sign payout tx
|
// sign payout tx
|
||||||
MoneroMultisigSignResult result = multisigWallet.signMultisigTxHex(payoutTxHex);
|
if (sign) {
|
||||||
if (result.getSignedMultisigTxHex() == null) throw new RuntimeException("Error signing payout tx");
|
MoneroMultisigSignResult result = multisigWallet.signMultisigTxHex(payoutTxHex);
|
||||||
String signedPayoutTxHex = result.getSignedMultisigTxHex();
|
if (result.getSignedMultisigTxHex() == null) throw new RuntimeException("Error signing payout tx");
|
||||||
|
payoutTxHex = result.getSignedMultisigTxHex();
|
||||||
// submit payout tx
|
}
|
||||||
multisigWallet.submitMultisigTxHex(signedPayoutTxHex);
|
|
||||||
walletService.closeMultisigWallet(getId());
|
|
||||||
|
|
||||||
// update trade state
|
// update trade state
|
||||||
getSelf().setPayoutTxHex(signedPayoutTxHex);
|
getSelf().setPayoutTxHex(payoutTxHex);
|
||||||
setPayoutTx(parsedTxSet.getTxs().get(0));
|
setPayoutTx(describedTxSet.getTxs().get(0));
|
||||||
setPayoutTxId(parsedTxSet.getTxs().get(0).getHash());
|
setPayoutTxId(describedTxSet.getTxs().get(0).getHash());
|
||||||
setState(isBuyer() ? Trade.State.BUYER_PUBLISHED_PAYOUT_TX : Trade.State.SELLER_PUBLISHED_PAYOUT_TX);
|
|
||||||
|
// submit payout tx
|
||||||
|
if (publish) {
|
||||||
|
multisigWallet.submitMultisigTxHex(payoutTxHex);
|
||||||
|
setState(isArbitrator() ? Trade.State.WITHDRAW_COMPLETED : isBuyer() ? Trade.State.BUYER_PUBLISHED_PAYOUT_TX : Trade.State.SELLER_PUBLISHED_PAYOUT_TX);
|
||||||
|
}
|
||||||
|
walletService.closeMultisigWallet(getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1114,6 +1119,10 @@ public abstract class Trade implements Tradable, Model {
|
||||||
// Getter
|
// Getter
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public boolean isArbitrator() {
|
||||||
|
return this instanceof ArbitratorTrade;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isBuyer() {
|
public boolean isBuyer() {
|
||||||
return getBuyer() == getSelf();
|
return getBuyer() == getSelf();
|
||||||
}
|
}
|
||||||
|
|
|
@ -541,7 +541,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
||||||
//System.out.println("TradeManager trade.setTradingPeerNodeAddress(): " + sender);
|
//System.out.println("TradeManager trade.setTradingPeerNodeAddress(): " + sender);
|
||||||
//trade.setTradingPeerNodeAddress(sender);
|
//trade.setTradingPeerNodeAddress(sender);
|
||||||
// TODO (woodser): what if maker's address changes while offer open, or taker's address changes after multisig deposit available? need to verify and update. see OpenOfferManager.maybeUpdatePersistedOffers()
|
// TODO (woodser): what if maker's address changes while offer open, or taker's address changes after multisig deposit available? need to verify and update. see OpenOfferManager.maybeUpdatePersistedOffers()
|
||||||
trade.setArbitratorPubKeyRing(user.getAcceptedArbitratorByAddress(sender).getPubKeyRing());
|
trade.setArbitratorPubKeyRing(arbitrator.getPubKeyRing());
|
||||||
trade.setMakerPubKeyRing(trade.getOffer().getPubKeyRing());
|
trade.setMakerPubKeyRing(trade.getOffer().getPubKeyRing());
|
||||||
initTradeAndProtocol(trade, getTradeProtocol(trade));
|
initTradeAndProtocol(trade, getTradeProtocol(trade));
|
||||||
trade.getSelf().setReserveTxHash(openOffer.getReserveTxHash()); // TODO (woodser): initialize in initTradeAndProtocol?
|
trade.getSelf().setReserveTxHash(openOffer.getReserveTxHash()); // TODO (woodser): initialize in initTradeAndProtocol?
|
||||||
|
|
|
@ -74,8 +74,8 @@ public class TradeUtils {
|
||||||
/**
|
/**
|
||||||
* Check if the arbitrator signature for an offer is valid.
|
* Check if the arbitrator signature for an offer is valid.
|
||||||
*
|
*
|
||||||
* @param arbitrator is the possible original arbitrator
|
|
||||||
* @param signedOfferPayload is a signed offer payload
|
* @param signedOfferPayload is a signed offer payload
|
||||||
|
* @param arbitrator is the possible original arbitrator
|
||||||
* @return true if the arbitrator's signature is valid for the offer
|
* @return true if the arbitrator's signature is valid for the offer
|
||||||
*/
|
*/
|
||||||
public static boolean isArbitratorSignatureValid(OfferPayload signedOfferPayload, Arbitrator arbitrator) {
|
public static boolean isArbitratorSignatureValid(OfferPayload signedOfferPayload, Arbitrator arbitrator) {
|
||||||
|
|
|
@ -38,7 +38,7 @@ import javax.annotation.Nullable;
|
||||||
@Value
|
@Value
|
||||||
public final class PayoutTxPublishedMessage extends TradeMailboxMessage {
|
public final class PayoutTxPublishedMessage extends TradeMailboxMessage {
|
||||||
private final NodeAddress senderNodeAddress;
|
private final NodeAddress senderNodeAddress;
|
||||||
private final String payoutTxHex;
|
private final String signedPayoutTxHex;
|
||||||
|
|
||||||
// Added in v1.4.0
|
// Added in v1.4.0
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -47,13 +47,13 @@ public final class PayoutTxPublishedMessage extends TradeMailboxMessage {
|
||||||
public PayoutTxPublishedMessage(String tradeId,
|
public PayoutTxPublishedMessage(String tradeId,
|
||||||
NodeAddress senderNodeAddress,
|
NodeAddress senderNodeAddress,
|
||||||
@Nullable SignedWitness signedWitness,
|
@Nullable SignedWitness signedWitness,
|
||||||
String payoutTxHex) {
|
String signedPayoutTxHex) {
|
||||||
this(tradeId,
|
this(tradeId,
|
||||||
senderNodeAddress,
|
senderNodeAddress,
|
||||||
signedWitness,
|
signedWitness,
|
||||||
UUID.randomUUID().toString(),
|
UUID.randomUUID().toString(),
|
||||||
Version.getP2PMessageVersion(),
|
Version.getP2PMessageVersion(),
|
||||||
payoutTxHex);
|
signedPayoutTxHex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -66,11 +66,11 @@ public final class PayoutTxPublishedMessage extends TradeMailboxMessage {
|
||||||
@Nullable SignedWitness signedWitness,
|
@Nullable SignedWitness signedWitness,
|
||||||
String uid,
|
String uid,
|
||||||
String messageVersion,
|
String messageVersion,
|
||||||
String payoutTxHex) {
|
String signedPayoutTxHex) {
|
||||||
super(messageVersion, tradeId, uid);
|
super(messageVersion, tradeId, uid);
|
||||||
this.senderNodeAddress = senderNodeAddress;
|
this.senderNodeAddress = senderNodeAddress;
|
||||||
this.signedWitness = signedWitness;
|
this.signedWitness = signedWitness;
|
||||||
this.payoutTxHex = payoutTxHex;
|
this.signedPayoutTxHex = signedPayoutTxHex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -79,7 +79,7 @@ public final class PayoutTxPublishedMessage extends TradeMailboxMessage {
|
||||||
.setTradeId(tradeId)
|
.setTradeId(tradeId)
|
||||||
.setSenderNodeAddress(senderNodeAddress.toProtoMessage())
|
.setSenderNodeAddress(senderNodeAddress.toProtoMessage())
|
||||||
.setUid(uid)
|
.setUid(uid)
|
||||||
.setPayoutTxHex(payoutTxHex);
|
.setSignedPayoutTxHex(signedPayoutTxHex);
|
||||||
Optional.ofNullable(signedWitness).ifPresent(signedWitness -> builder.setSignedWitness(signedWitness.toProtoSignedWitness()));
|
Optional.ofNullable(signedWitness).ifPresent(signedWitness -> builder.setSignedWitness(signedWitness.toProtoSignedWitness()));
|
||||||
return getNetworkEnvelopeBuilder().setPayoutTxPublishedMessage(builder).build();
|
return getNetworkEnvelopeBuilder().setPayoutTxPublishedMessage(builder).build();
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ public final class PayoutTxPublishedMessage extends TradeMailboxMessage {
|
||||||
signedWitness,
|
signedWitness,
|
||||||
proto.getUid(),
|
proto.getUid(),
|
||||||
messageVersion,
|
messageVersion,
|
||||||
proto.getPayoutTxHex());
|
proto.getSignedPayoutTxHex());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -104,7 +104,7 @@ public final class PayoutTxPublishedMessage extends TradeMailboxMessage {
|
||||||
return "PayoutTxPublishedMessage{" +
|
return "PayoutTxPublishedMessage{" +
|
||||||
"\n senderNodeAddress=" + senderNodeAddress +
|
"\n senderNodeAddress=" + senderNodeAddress +
|
||||||
",\n signedWitness=" + signedWitness +
|
",\n signedWitness=" + signedWitness +
|
||||||
",\n payoutTxHex=" + payoutTxHex +
|
",\n signedPayoutTxHex=" + signedPayoutTxHex +
|
||||||
"\n} " + super.toString();
|
"\n} " + super.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package bisq.core.trade.protocol;
|
package bisq.core.trade.protocol;
|
||||||
|
|
||||||
|
import bisq.common.handlers.ErrorMessageHandler;
|
||||||
import bisq.core.trade.ArbitratorTrade;
|
import bisq.core.trade.ArbitratorTrade;
|
||||||
import bisq.core.trade.Trade;
|
import bisq.core.trade.Trade;
|
||||||
import bisq.core.trade.messages.DepositRequest;
|
import bisq.core.trade.messages.DepositRequest;
|
||||||
|
@ -7,17 +8,18 @@ import bisq.core.trade.messages.DepositResponse;
|
||||||
import bisq.core.trade.messages.InitTradeRequest;
|
import bisq.core.trade.messages.InitTradeRequest;
|
||||||
import bisq.core.trade.messages.PaymentAccountKeyRequest;
|
import bisq.core.trade.messages.PaymentAccountKeyRequest;
|
||||||
import bisq.core.trade.messages.SignContractResponse;
|
import bisq.core.trade.messages.SignContractResponse;
|
||||||
|
import bisq.core.trade.messages.PayoutTxPublishedMessage;
|
||||||
|
import bisq.core.trade.messages.TradeMessage;
|
||||||
import bisq.core.trade.protocol.FluentProtocol.Condition;
|
import bisq.core.trade.protocol.FluentProtocol.Condition;
|
||||||
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
||||||
import bisq.core.trade.protocol.tasks.ArbitratorSendsInitTradeOrMultisigRequests;
|
|
||||||
import bisq.core.trade.protocol.tasks.ArbitratorProcessesDepositRequest;
|
import bisq.core.trade.protocol.tasks.ArbitratorProcessesDepositRequest;
|
||||||
import bisq.core.trade.protocol.tasks.ArbitratorProcessesPaymentAccountKeyRequest;
|
import bisq.core.trade.protocol.tasks.ArbitratorProcessesPaymentAccountKeyRequest;
|
||||||
import bisq.core.trade.protocol.tasks.ArbitratorProcessesReserveTx;
|
import bisq.core.trade.protocol.tasks.ArbitratorProcessesReserveTx;
|
||||||
|
import bisq.core.trade.protocol.tasks.ArbitratorProcessPayoutTxPublishedMessage;
|
||||||
|
import bisq.core.trade.protocol.tasks.ArbitratorSendsInitTradeOrMultisigRequests;
|
||||||
import bisq.core.trade.protocol.tasks.ProcessInitTradeRequest;
|
import bisq.core.trade.protocol.tasks.ProcessInitTradeRequest;
|
||||||
import bisq.core.util.Validator;
|
import bisq.core.util.Validator;
|
||||||
import bisq.network.p2p.NodeAddress;
|
import bisq.network.p2p.NodeAddress;
|
||||||
import bisq.common.handlers.ErrorMessageHandler;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -27,6 +29,22 @@ public class ArbitratorProtocol extends DisputeProtocol {
|
||||||
super(trade);
|
super(trade);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onTradeMessage(TradeMessage message, NodeAddress peer) {
|
||||||
|
super.onTradeMessage(message, peer);
|
||||||
|
if (message instanceof PayoutTxPublishedMessage) {
|
||||||
|
handle((PayoutTxPublishedMessage) message, peer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMailboxMessage(TradeMessage message, NodeAddress peer) {
|
||||||
|
super.onMailboxMessage(message, peer);
|
||||||
|
if (message instanceof PayoutTxPublishedMessage) {
|
||||||
|
handle((PayoutTxPublishedMessage) message, peer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Incoming messages
|
// Incoming messages
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -94,7 +112,7 @@ public class ArbitratorProtocol extends DisputeProtocol {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleDepositResponse(DepositResponse response, NodeAddress sender) {
|
public void handleDepositResponse(DepositResponse response, NodeAddress sender) {
|
||||||
log.warn("Arbitrator ignoring DepositResponse");
|
log.warn("Arbitrator ignoring DepositResponse for trade " + response.getTradeId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handlePaymentAccountKeyRequest(PaymentAccountKeyRequest request, NodeAddress sender) {
|
public void handlePaymentAccountKeyRequest(PaymentAccountKeyRequest request, NodeAddress sender) {
|
||||||
|
@ -121,15 +139,30 @@ public class ArbitratorProtocol extends DisputeProtocol {
|
||||||
awaitTradeLatch();
|
awaitTradeLatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
protected void handle(PayoutTxPublishedMessage request, NodeAddress peer) {
|
||||||
// Message dispatcher
|
System.out.println("ArbitratorProtocol.handle(PayoutTxPublishedMessage)");
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
new Thread(() -> {
|
||||||
|
synchronized (trade) {
|
||||||
// @Override
|
if (trade.isCompleted()) return; // ignore subsequent requests
|
||||||
// protected void onTradeMessage(TradeMessage message, NodeAddress peer) {
|
latchTrade();
|
||||||
// if (message instanceof InitTradeRequest) {
|
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||||
// handleInitTradeRequest((InitTradeRequest) message, peer);
|
processModel.setTradeMessage(request);
|
||||||
// }
|
expect(phase(Trade.Phase.DEPOSITS_PUBLISHED)
|
||||||
// }
|
.with(request)
|
||||||
|
.from(peer))
|
||||||
|
.setup(tasks(
|
||||||
|
ArbitratorProcessPayoutTxPublishedMessage.class)
|
||||||
|
.using(new TradeTaskRunner(trade,
|
||||||
|
() -> {
|
||||||
|
handleTaskRunnerSuccess(peer, request);
|
||||||
|
},
|
||||||
|
errorMessage -> {
|
||||||
|
handleTaskRunnerFault(peer, request, errorMessage);
|
||||||
|
})))
|
||||||
|
.executeTasks(true);
|
||||||
|
awaitTradeLatch();
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import bisq.core.trade.messages.SignContractResponse;
|
||||||
import bisq.core.trade.messages.TradeMessage;
|
import bisq.core.trade.messages.TradeMessage;
|
||||||
import bisq.core.trade.protocol.FluentProtocol.Condition;
|
import bisq.core.trade.protocol.FluentProtocol.Condition;
|
||||||
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
||||||
|
import bisq.core.trade.protocol.tasks.BuyerSendsPayoutTxPublishedMessage;
|
||||||
import bisq.core.trade.protocol.tasks.BuyerPreparesPaymentSentMessage;
|
import bisq.core.trade.protocol.tasks.BuyerPreparesPaymentSentMessage;
|
||||||
import bisq.core.trade.protocol.tasks.BuyerProcessesPaymentReceivedMessage;
|
import bisq.core.trade.protocol.tasks.BuyerProcessesPaymentReceivedMessage;
|
||||||
import bisq.core.trade.protocol.tasks.BuyerSendsPaymentAccountKeyRequestToArbitrator;
|
import bisq.core.trade.protocol.tasks.BuyerSendsPaymentAccountKeyRequestToArbitrator;
|
||||||
|
@ -189,7 +190,8 @@ public abstract class BuyerProtocol extends DisputeProtocol {
|
||||||
.with(message)
|
.with(message)
|
||||||
.from(peer))
|
.from(peer))
|
||||||
.setup(tasks(
|
.setup(tasks(
|
||||||
BuyerProcessesPaymentReceivedMessage.class)
|
BuyerProcessesPaymentReceivedMessage.class,
|
||||||
|
BuyerSendsPayoutTxPublishedMessage.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
handleTaskRunnerSuccess(peer, message);
|
handleTaskRunnerSuccess(peer, message);
|
||||||
|
|
|
@ -51,6 +51,31 @@ public abstract class DisputeProtocol extends TradeProtocol {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Dispatcher
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onTradeMessage(TradeMessage message, NodeAddress peer) {
|
||||||
|
super.onTradeMessage(message, peer);
|
||||||
|
if (message instanceof MediatedPayoutTxSignatureMessage) {
|
||||||
|
handle((MediatedPayoutTxSignatureMessage) message, peer);
|
||||||
|
} else if (message instanceof MediatedPayoutTxPublishedMessage) {
|
||||||
|
handle((MediatedPayoutTxPublishedMessage) message, peer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMailboxMessage(TradeMessage message, NodeAddress peer) {
|
||||||
|
super.onMailboxMessage(message, peer);
|
||||||
|
if (message instanceof MediatedPayoutTxSignatureMessage) {
|
||||||
|
handle((MediatedPayoutTxSignatureMessage) message, peer);
|
||||||
|
} else if (message instanceof MediatedPayoutTxPublishedMessage) {
|
||||||
|
handle((MediatedPayoutTxPublishedMessage) message, peer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// User interaction: Trader accepts mediation result
|
// User interaction: Trader accepts mediation result
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -131,53 +156,4 @@ public abstract class DisputeProtocol extends TradeProtocol {
|
||||||
.setup(tasks(ProcessMediatedPayoutTxPublishedMessage.class))
|
.setup(tasks(ProcessMediatedPayoutTxPublishedMessage.class))
|
||||||
.executeTasks();
|
.executeTasks();
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Delayed payout tx
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// public void onPublishDelayedPayoutTx(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
|
||||||
// DisputeEvent event = DisputeEvent.ARBITRATION_REQUESTED;
|
|
||||||
// expect(anyPhase(Trade.Phase.DEPOSITS_CONFIRMED,
|
|
||||||
// Trade.Phase.FIAT_SENT,
|
|
||||||
// Trade.Phase.FIAT_RECEIVED)
|
|
||||||
// .with(event)
|
|
||||||
// .preCondition(trade.getDelayedPayoutTx() != null))
|
|
||||||
// .setup(tasks(PublishedDelayedPayoutTx.class,
|
|
||||||
// SendPeerPublishedDelayedPayoutTxMessage.class)
|
|
||||||
// .using(new TradeTaskRunner(trade,
|
|
||||||
// () -> {
|
|
||||||
// resultHandler.handleResult();
|
|
||||||
// handleTaskRunnerSuccess(event);
|
|
||||||
// },
|
|
||||||
// errorMessage -> {
|
|
||||||
// errorMessageHandler.handleErrorMessage(errorMessage);
|
|
||||||
// handleTaskRunnerFault(event, errorMessage);
|
|
||||||
// })))
|
|
||||||
// .executeTasks();
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Dispatcher
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onTradeMessage(TradeMessage message, NodeAddress peer) {
|
|
||||||
if (message instanceof MediatedPayoutTxSignatureMessage) {
|
|
||||||
handle((MediatedPayoutTxSignatureMessage) message, peer);
|
|
||||||
} else if (message instanceof MediatedPayoutTxPublishedMessage) {
|
|
||||||
handle((MediatedPayoutTxPublishedMessage) message, peer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onMailboxMessage(TradeMessage message, NodeAddress peer) {
|
|
||||||
super.onMailboxMessage(message, peer);
|
|
||||||
if (message instanceof MediatedPayoutTxSignatureMessage) {
|
|
||||||
handle((MediatedPayoutTxSignatureMessage) message, peer);
|
|
||||||
} else if (message instanceof MediatedPayoutTxPublishedMessage) {
|
|
||||||
handle((MediatedPayoutTxPublishedMessage) message, peer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,12 @@ package bisq.core.trade.protocol;
|
||||||
|
|
||||||
import bisq.core.trade.SellerTrade;
|
import bisq.core.trade.SellerTrade;
|
||||||
import bisq.core.trade.Trade;
|
import bisq.core.trade.Trade;
|
||||||
import bisq.core.trade.messages.DepositResponse;
|
|
||||||
import bisq.core.trade.messages.PaymentSentMessage;
|
import bisq.core.trade.messages.PaymentSentMessage;
|
||||||
import bisq.core.trade.messages.SignContractResponse;
|
import bisq.core.trade.messages.SignContractResponse;
|
||||||
import bisq.core.trade.messages.TradeMessage;
|
import bisq.core.trade.messages.TradeMessage;
|
||||||
import bisq.core.trade.protocol.FluentProtocol.Condition;
|
import bisq.core.trade.protocol.FluentProtocol.Condition;
|
||||||
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
||||||
|
import bisq.core.trade.protocol.tasks.SellerMaybeSendsPayoutTxPublishedMessage;
|
||||||
import bisq.core.trade.protocol.tasks.SellerPreparesPaymentReceivedMessage;
|
import bisq.core.trade.protocol.tasks.SellerPreparesPaymentReceivedMessage;
|
||||||
import bisq.core.trade.protocol.tasks.SellerProcessesPaymentSentMessage;
|
import bisq.core.trade.protocol.tasks.SellerProcessesPaymentSentMessage;
|
||||||
import bisq.core.trade.protocol.tasks.SellerSendsPaymentReceivedMessage;
|
import bisq.core.trade.protocol.tasks.SellerSendsPaymentReceivedMessage;
|
||||||
|
@ -155,6 +155,7 @@ public abstract class SellerProtocol extends DisputeProtocol {
|
||||||
.setup(tasks(
|
.setup(tasks(
|
||||||
ApplyFilter.class,
|
ApplyFilter.class,
|
||||||
SellerPreparesPaymentReceivedMessage.class,
|
SellerPreparesPaymentReceivedMessage.class,
|
||||||
|
SellerMaybeSendsPayoutTxPublishedMessage.class,
|
||||||
SellerSendsPaymentReceivedMessage.class)
|
SellerSendsPaymentReceivedMessage.class)
|
||||||
.using(new TradeTaskRunner(trade, () -> {
|
.using(new TradeTaskRunner(trade, () -> {
|
||||||
this.errorMessageHandler = null;
|
this.errorMessageHandler = null;
|
||||||
|
|
|
@ -86,6 +86,19 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Dispatcher
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
protected void onTradeMessage(TradeMessage message, NodeAddress peerNodeAddress) {
|
||||||
|
log.info("Received {} as TradeMessage from {} with tradeId {} and uid {}", message.getClass().getSimpleName(), peerNodeAddress, message.getTradeId(), message.getUid());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onMailboxMessage(TradeMessage message, NodeAddress peerNodeAddress) {
|
||||||
|
log.info("Received {} as MailboxMessage from {} with tradeId {} and uid {}", message.getClass().getSimpleName(), peerNodeAddress, message.getTradeId(), message.getUid());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// API
|
// API
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -116,11 +129,6 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||||
log.info("Withdraw completed");
|
log.info("Withdraw completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onMailboxMessage(TradeMessage message, NodeAddress peerNodeAddress) {
|
|
||||||
log.info("Received {} as MailboxMessage from {} with tradeId {} and uid {}",
|
|
||||||
message.getClass().getSimpleName(), peerNodeAddress, message.getTradeId(), message.getUid());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// DecryptedDirectMessageListener
|
// DecryptedDirectMessageListener
|
||||||
|
@ -218,8 +226,6 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||||
// Abstract
|
// Abstract
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
protected abstract void onTradeMessage(TradeMessage message, NodeAddress peer);
|
|
||||||
|
|
||||||
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) {
|
||||||
|
|
|
@ -147,8 +147,7 @@ public final class TradingPeer implements PersistablePayload {
|
||||||
Optional.ofNullable(signature).ifPresent(e -> builder.setSignature(ByteString.copyFrom(e)));
|
Optional.ofNullable(signature).ifPresent(e -> builder.setSignature(ByteString.copyFrom(e)));
|
||||||
Optional.ofNullable(pubKeyRing).ifPresent(e -> builder.setPubKeyRing(e.toProtoMessage()));
|
Optional.ofNullable(pubKeyRing).ifPresent(e -> builder.setPubKeyRing(e.toProtoMessage()));
|
||||||
Optional.ofNullable(multiSigPubKey).ifPresent(e -> builder.setMultiSigPubKey(ByteString.copyFrom(e)));
|
Optional.ofNullable(multiSigPubKey).ifPresent(e -> builder.setMultiSigPubKey(ByteString.copyFrom(e)));
|
||||||
Optional.ofNullable(rawTransactionInputs).ifPresent(e -> builder.addAllRawTransactionInputs(
|
Optional.ofNullable(rawTransactionInputs).ifPresent(e -> builder.addAllRawTransactionInputs(ProtoUtil.collectionToProto(e, protobuf.RawTransactionInput.class)));
|
||||||
ProtoUtil.collectionToProto(e, protobuf.RawTransactionInput.class)));
|
|
||||||
Optional.ofNullable(changeOutputAddress).ifPresent(builder::setChangeOutputAddress);
|
Optional.ofNullable(changeOutputAddress).ifPresent(builder::setChangeOutputAddress);
|
||||||
Optional.ofNullable(accountAgeWitnessNonce).ifPresent(e -> builder.setAccountAgeWitnessNonce(ByteString.copyFrom(e)));
|
Optional.ofNullable(accountAgeWitnessNonce).ifPresent(e -> builder.setAccountAgeWitnessNonce(ByteString.copyFrom(e)));
|
||||||
Optional.ofNullable(accountAgeWitnessSignature).ifPresent(e -> builder.setAccountAgeWitnessSignature(ByteString.copyFrom(e)));
|
Optional.ofNullable(accountAgeWitnessSignature).ifPresent(e -> builder.setAccountAgeWitnessSignature(ByteString.copyFrom(e)));
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Haveno.
|
||||||
|
*
|
||||||
|
* Haveno is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* Haveno is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||||
|
* License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with Haveno. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package bisq.core.trade.protocol.tasks;
|
||||||
|
|
||||||
|
|
||||||
|
import bisq.common.taskrunner.TaskRunner;
|
||||||
|
import bisq.core.trade.Trade;
|
||||||
|
import bisq.core.trade.messages.PayoutTxPublishedMessage;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class ArbitratorProcessPayoutTxPublishedMessage extends TradeTask {
|
||||||
|
|
||||||
|
@SuppressWarnings({"unused"})
|
||||||
|
public ArbitratorProcessPayoutTxPublishedMessage(TaskRunner taskHandler, Trade trade) {
|
||||||
|
super(taskHandler, trade);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void run() {
|
||||||
|
try {
|
||||||
|
runInterceptHook();
|
||||||
|
PayoutTxPublishedMessage request = (PayoutTxPublishedMessage) processModel.getTradeMessage();
|
||||||
|
|
||||||
|
// verify and publish payout tx
|
||||||
|
trade.verifyPayoutTx(request.getSignedPayoutTxHex(), false, true);
|
||||||
|
|
||||||
|
// TODO: publish signed witness data?
|
||||||
|
//request.getSignedWitness()
|
||||||
|
|
||||||
|
// close arbitrator trade
|
||||||
|
processModel.getTradeManager().onTradeCompleted(trade);
|
||||||
|
complete();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
failed(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -71,7 +71,7 @@ public class BuyerProcessesPaymentReceivedMessage extends TradeTask {
|
||||||
walletService.closeMultisigWallet(trade.getId());
|
walletService.closeMultisigWallet(trade.getId());
|
||||||
} else {
|
} else {
|
||||||
log.info("Buyer verifying, signing, and publishing seller's payout tx");
|
log.info("Buyer verifying, signing, and publishing seller's payout tx");
|
||||||
trade.verifySignAndPublishPayoutTx(message.getPayoutTxHex());
|
trade.verifyPayoutTx(message.getPayoutTxHex(), true, true);
|
||||||
trade.setState(Trade.State.BUYER_PUBLISHED_PAYOUT_TX);
|
trade.setState(Trade.State.BUYER_PUBLISHED_PAYOUT_TX);
|
||||||
// TODO (woodser): send PayoutTxPublishedMessage to arbitrator and seller
|
// TODO (woodser): send PayoutTxPublishedMessage to arbitrator and seller
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,7 @@ public class BuyerProcessesPaymentReceivedMessage extends TradeTask {
|
||||||
log.info("We got the payout tx already set from BuyerSetupPayoutTxListener and do nothing here. trade ID={}", trade.getId());
|
log.info("We got the payout tx already set from BuyerSetupPayoutTxListener and do nothing here. trade ID={}", trade.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove witness
|
||||||
SignedWitness signedWitness = message.getSignedWitness();
|
SignedWitness signedWitness = message.getSignedWitness();
|
||||||
if (signedWitness != null) {
|
if (signedWitness != null) {
|
||||||
// We received the signedWitness from the seller and publish the data to the network.
|
// We received the signedWitness from the seller and publish the data to the network.
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Haveno.
|
||||||
|
*
|
||||||
|
* Haveno is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* Haveno is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||||
|
* License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with Haveno. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package bisq.core.trade.protocol.tasks;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import bisq.common.crypto.PubKeyRing;
|
||||||
|
import bisq.common.taskrunner.TaskRunner;
|
||||||
|
import bisq.core.payment.PaymentAccount;
|
||||||
|
import bisq.core.trade.Trade;
|
||||||
|
import bisq.core.trade.messages.PayoutTxPublishedMessage;
|
||||||
|
import bisq.core.trade.messages.TradeMailboxMessage;
|
||||||
|
import bisq.network.p2p.NodeAddress;
|
||||||
|
import java.util.UUID;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Slf4j
|
||||||
|
public class BuyerSendsPayoutTxPublishedMessage extends SendMailboxMessageTask {
|
||||||
|
|
||||||
|
public BuyerSendsPayoutTxPublishedMessage(TaskRunner<Trade> taskHandler, Trade trade) {
|
||||||
|
super(taskHandler, trade);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected NodeAddress getReceiverNodeAddress() {
|
||||||
|
return trade.getArbitratorNodeAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PubKeyRing getReceiverPubKeyRing() {
|
||||||
|
return trade.getArbitratorPubKeyRing();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TradeMailboxMessage getTradeMailboxMessage(String tradeId) {
|
||||||
|
checkNotNull(trade.getSelf().getPayoutTxHex(), "Payout tx must not be null");
|
||||||
|
return new PayoutTxPublishedMessage(
|
||||||
|
tradeId,
|
||||||
|
processModel.getMyNodeAddress(),
|
||||||
|
null, // TODO: send witness data?
|
||||||
|
trade.getSelf().getPayoutTxHex()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setStateSent() {
|
||||||
|
log.info("Buyer sent PayoutTxPublishedMessage: tradeId={} at arbitrator {}", trade.getId(), getReceiverNodeAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setStateArrived() {
|
||||||
|
log.info("Buyer's PayoutTxPublishedMessage arrived: tradeId={} at arbitrator {}", trade.getId(), getReceiverNodeAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setStateStoredInMailbox() {
|
||||||
|
log.info("Buyer's PayoutTxPublishedMessage stored in mailbox: tradeId={} at arbitrator {}", trade.getId(), getReceiverNodeAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setStateFault() {
|
||||||
|
log.error("Buyer's PayoutTxPublishedMessage failed: tradeId={} at arbitrator {}", trade.getId(), getReceiverNodeAddress());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Haveno.
|
||||||
|
*
|
||||||
|
* Haveno is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* Haveno is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||||
|
* License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with Haveno. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package bisq.core.trade.protocol.tasks;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import bisq.common.crypto.PubKeyRing;
|
||||||
|
import bisq.common.taskrunner.TaskRunner;
|
||||||
|
import bisq.core.trade.Trade;
|
||||||
|
import bisq.core.trade.messages.PayoutTxPublishedMessage;
|
||||||
|
import bisq.core.trade.messages.TradeMailboxMessage;
|
||||||
|
import bisq.network.p2p.NodeAddress;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Slf4j
|
||||||
|
public class SellerMaybeSendsPayoutTxPublishedMessage extends SendMailboxMessageTask {
|
||||||
|
|
||||||
|
public SellerMaybeSendsPayoutTxPublishedMessage(TaskRunner<Trade> taskHandler, Trade trade) {
|
||||||
|
super(taskHandler, trade);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void run() {
|
||||||
|
try {
|
||||||
|
runInterceptHook();
|
||||||
|
|
||||||
|
// skip if payout tx not published
|
||||||
|
if (trade.getPhase().ordinal() < Trade.Phase.PAYOUT_PUBLISHED.ordinal()) {
|
||||||
|
complete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.run();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
failed(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected NodeAddress getReceiverNodeAddress() {
|
||||||
|
return trade.getArbitratorNodeAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PubKeyRing getReceiverPubKeyRing() {
|
||||||
|
return trade.getArbitratorPubKeyRing();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TradeMailboxMessage getTradeMailboxMessage(String tradeId) {
|
||||||
|
checkNotNull(trade.getSelf().getPayoutTxHex(), "Payout tx must not be null");
|
||||||
|
return new PayoutTxPublishedMessage(
|
||||||
|
tradeId,
|
||||||
|
processModel.getMyNodeAddress(),
|
||||||
|
null, // TODO: send witness data?
|
||||||
|
trade.getSelf().getPayoutTxHex()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setStateSent() {
|
||||||
|
log.info("Seller sent PayoutTxPublishedMessage: tradeId={} at arbitrator {}", trade.getId(), getReceiverNodeAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setStateArrived() {
|
||||||
|
log.info("Seller's PayoutTxPublishedMessage arrived: tradeId={} at arbitrator {}", trade.getId(), getReceiverNodeAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setStateStoredInMailbox() {
|
||||||
|
log.info("Seller's PayoutTxPublishedMessage stored in mailbox: tradeId={} at arbitrator {}", trade.getId(), getReceiverNodeAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setStateFault() {
|
||||||
|
log.error("Seller's PayoutTxPublishedMessage failed: tradeId={} at arbitrator {}", trade.getId(), getReceiverNodeAddress());
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,7 +40,7 @@ public class SellerPreparesPaymentReceivedMessage extends TradeTask {
|
||||||
// verify, sign, and publish payout tx if given. otherwise create payout tx
|
// verify, sign, and publish payout tx if given. otherwise create payout tx
|
||||||
if (trade.getBuyer().getPayoutTxHex() != null) {
|
if (trade.getBuyer().getPayoutTxHex() != null) {
|
||||||
log.info("Seller verifying, signing, and publishing payout tx");
|
log.info("Seller verifying, signing, and publishing payout tx");
|
||||||
trade.verifySignAndPublishPayoutTx(trade.getBuyer().getPayoutTxHex());
|
trade.verifyPayoutTx(trade.getBuyer().getPayoutTxHex(), true, true);
|
||||||
} else {
|
} else {
|
||||||
log.info("Seller creating unsigned payout tx");
|
log.info("Seller creating unsigned payout tx");
|
||||||
MoneroTxWallet payoutTx = trade.createPayoutTx();
|
MoneroTxWallet payoutTx = trade.createPayoutTx();
|
||||||
|
|
|
@ -23,7 +23,7 @@ import bisq.core.trade.messages.TradeMessage;
|
||||||
|
|
||||||
import bisq.network.p2p.NodeAddress;
|
import bisq.network.p2p.NodeAddress;
|
||||||
import bisq.network.p2p.SendMailboxMessageListener;
|
import bisq.network.p2p.SendMailboxMessageListener;
|
||||||
|
import bisq.common.crypto.PubKeyRing;
|
||||||
import bisq.common.taskrunner.TaskRunner;
|
import bisq.common.taskrunner.TaskRunner;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
@ -34,7 +34,15 @@ public abstract class SendMailboxMessageTask extends TradeTask {
|
||||||
super(taskHandler, trade);
|
super(taskHandler, trade);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract TradeMailboxMessage getTradeMailboxMessage(String id);
|
protected NodeAddress getReceiverNodeAddress() {
|
||||||
|
return trade.getTradingPeerNodeAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected PubKeyRing getReceiverPubKeyRing() {
|
||||||
|
return trade.getTradingPeer().getPubKeyRing();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract TradeMailboxMessage getTradeMailboxMessage(String tradeId);
|
||||||
|
|
||||||
protected abstract void setStateSent();
|
protected abstract void setStateSent();
|
||||||
|
|
||||||
|
@ -51,34 +59,31 @@ public abstract class SendMailboxMessageTask extends TradeTask {
|
||||||
String id = processModel.getOfferId();
|
String id = processModel.getOfferId();
|
||||||
TradeMailboxMessage message = getTradeMailboxMessage(id);
|
TradeMailboxMessage message = getTradeMailboxMessage(id);
|
||||||
setStateSent();
|
setStateSent();
|
||||||
NodeAddress peersNodeAddress = trade.getTradingPeerNodeAddress();
|
NodeAddress peersNodeAddress = getReceiverNodeAddress();
|
||||||
log.info("Send {} to peer {}. tradeId={}, uid={}",
|
log.info("Send {} to peer {}. tradeId={}, uid={}",
|
||||||
message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid());
|
message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid());
|
||||||
|
|
||||||
processModel.getP2PService().getMailboxMessageService().sendEncryptedMailboxMessage(
|
processModel.getP2PService().getMailboxMessageService().sendEncryptedMailboxMessage(
|
||||||
peersNodeAddress,
|
peersNodeAddress,
|
||||||
trade.getTradingPeer().getPubKeyRing(),
|
getReceiverPubKeyRing(),
|
||||||
message,
|
message,
|
||||||
new SendMailboxMessageListener() {
|
new SendMailboxMessageListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onArrived() {
|
public void onArrived() {
|
||||||
log.info("{} arrived at peer {}. tradeId={}, uid={}",
|
log.info("{} arrived at peer {}. tradeId={}, uid={}", message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid());
|
||||||
message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid());
|
|
||||||
setStateArrived();
|
setStateArrived();
|
||||||
complete();
|
complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStoredInMailbox() {
|
public void onStoredInMailbox() {
|
||||||
log.info("{} stored in mailbox for peer {}. tradeId={}, uid={}",
|
log.info("{} stored in mailbox for peer {}. tradeId={}, uid={}", message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid());
|
||||||
message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid());
|
|
||||||
SendMailboxMessageTask.this.onStoredInMailbox();
|
SendMailboxMessageTask.this.onStoredInMailbox();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFault(String errorMessage) {
|
public void onFault(String errorMessage) {
|
||||||
log.error("{} failed: Peer {}. tradeId={}, uid={}, errorMessage={}",
|
log.error("{} failed: Peer {}. tradeId={}, uid={}, errorMessage={}", message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid(), errorMessage);
|
||||||
message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid(), errorMessage);
|
|
||||||
SendMailboxMessageTask.this.onFault(errorMessage, message);
|
SendMailboxMessageTask.this.onFault(errorMessage, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,10 +79,12 @@ message NetworkEnvelope {
|
||||||
PaymentSentMessage payment_sent_message = 1011;
|
PaymentSentMessage payment_sent_message = 1011;
|
||||||
PaymentReceivedMessage payment_received_message = 1012;
|
PaymentReceivedMessage payment_received_message = 1012;
|
||||||
PayoutTxPublishedMessage payout_tx_published_message = 1013;
|
PayoutTxPublishedMessage payout_tx_published_message = 1013;
|
||||||
UpdateMultisigRequest update_multisig_request = 1014;
|
|
||||||
UpdateMultisigResponse update_multisig_response = 1015;
|
|
||||||
ArbitratorPayoutTxRequest arbitrator_payout_tx_request = 1016;
|
ArbitratorPayoutTxRequest arbitrator_payout_tx_request = 1016;
|
||||||
ArbitratorPayoutTxResponse arbitrator_payout_tx_response = 1017;
|
ArbitratorPayoutTxResponse arbitrator_payout_tx_response = 1017;
|
||||||
|
|
||||||
|
// TODO: delete these
|
||||||
|
UpdateMultisigRequest update_multisig_request = 1018;
|
||||||
|
UpdateMultisigResponse update_multisig_response = 1019;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,8 +461,8 @@ message PayoutTxPublishedMessage {
|
||||||
string trade_id = 1;
|
string trade_id = 1;
|
||||||
NodeAddress sender_node_address = 2;
|
NodeAddress sender_node_address = 2;
|
||||||
string uid = 3;
|
string uid = 3;
|
||||||
SignedWitness signed_witness = 4; // Added in v1.4.0
|
SignedWitness signed_witness = 4;
|
||||||
string payout_tx_hex = 5;
|
string signed_payout_tx_hex = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ArbitratorPayoutTxRequest {
|
message ArbitratorPayoutTxRequest {
|
||||||
|
|
Loading…
Reference in a new issue