trade completion fixes with payment key and multisig hex on confirmation

preserve peer multisig hex when arbitrator provides payment key
process payment received using persistent, non-transient data
payout_tx_published_msg represents payment_received_msg after payout
update arbitrator's peer address on payout published
schedule payment account key request after deposit request
This commit is contained in:
woodser 2022-09-20 10:48:27 -04:00
parent c21ebe6a9d
commit d698555c9a
11 changed files with 33 additions and 21 deletions

View File

@ -831,7 +831,6 @@ public abstract class Trade implements Tradable, Model {
// update trade state
getSelf().setPayoutTxHex(payoutTxHex);
setPayoutTx(describedTxSet.getTxs().get(0));
setPayoutTxId(describedTxSet.getTxs().get(0).getHash());
// submit payout tx
if (publish) {

View File

@ -38,6 +38,7 @@ import javax.annotation.Nullable;
@Value
public final class PayoutTxPublishedMessage extends TradeMailboxMessage {
private final NodeAddress senderNodeAddress;
private final boolean isMaker;
private final String signedPayoutTxHex;
// Added in v1.4.0
@ -46,10 +47,12 @@ public final class PayoutTxPublishedMessage extends TradeMailboxMessage {
public PayoutTxPublishedMessage(String tradeId,
NodeAddress senderNodeAddress,
boolean isMaker,
@Nullable SignedWitness signedWitness,
String signedPayoutTxHex) {
this(tradeId,
senderNodeAddress,
isMaker,
signedWitness,
UUID.randomUUID().toString(),
Version.getP2PMessageVersion(),
@ -63,12 +66,14 @@ public final class PayoutTxPublishedMessage extends TradeMailboxMessage {
private PayoutTxPublishedMessage(String tradeId,
NodeAddress senderNodeAddress,
boolean isMaker,
@Nullable SignedWitness signedWitness,
String uid,
String messageVersion,
String signedPayoutTxHex) {
super(messageVersion, tradeId, uid);
this.senderNodeAddress = senderNodeAddress;
this.isMaker = isMaker;
this.signedWitness = signedWitness;
this.signedPayoutTxHex = signedPayoutTxHex;
}
@ -78,6 +83,7 @@ public final class PayoutTxPublishedMessage extends TradeMailboxMessage {
protobuf.PayoutTxPublishedMessage.Builder builder = protobuf.PayoutTxPublishedMessage.newBuilder()
.setTradeId(tradeId)
.setSenderNodeAddress(senderNodeAddress.toProtoMessage())
.setIsMaker(isMaker)
.setUid(uid)
.setSignedPayoutTxHex(signedPayoutTxHex);
Optional.ofNullable(signedWitness).ifPresent(signedWitness -> builder.setSignedWitness(signedWitness.toProtoSignedWitness()));
@ -93,6 +99,7 @@ public final class PayoutTxPublishedMessage extends TradeMailboxMessage {
null;
return new PayoutTxPublishedMessage(proto.getTradeId(),
NodeAddress.fromProto(proto.getSenderNodeAddress()),
proto.getIsMaker(),
signedWitness,
proto.getUid(),
messageVersion,
@ -103,6 +110,7 @@ public final class PayoutTxPublishedMessage extends TradeMailboxMessage {
public String toString() {
return "PayoutTxPublishedMessage{" +
"\n senderNodeAddress=" + senderNodeAddress +
",\n isMaker=" + isMaker +
",\n signedWitness=" + signedWitness +
",\n signedPayoutTxHex=" + signedPayoutTxHex +
"\n} " + super.toString();

View File

@ -109,8 +109,8 @@ public abstract class BuyerProtocol extends DisputeProtocol {
@Override
public void handleSignContractResponse(SignContractResponse response, NodeAddress sender) {
sendPaymentAccountKeyRequestIfWhenNeeded(BuyerEvent.DEPOSIT_TXS_CONFIRMED, true);
super.handleSignContractResponse(response, sender);
sendPaymentAccountKeyRequestIfWhenNeeded(BuyerEvent.DEPOSIT_TXS_CONFIRMED, true);
}
public void handle(PaymentAccountKeyResponse response, NodeAddress sender) {

View File

@ -40,6 +40,10 @@ public class ArbitratorProcessPayoutTxPublishedMessage extends TradeTask {
// verify and publish payout tx
trade.verifyPayoutTx(request.getSignedPayoutTxHex(), false, true);
// update latest peer address
if (request.isMaker()) trade.setMakerNodeAddress(processModel.getTempTradingPeerNodeAddress());
else trade.setTakerNodeAddress(processModel.getTempTradingPeerNodeAddress());
// TODO: publish signed witness data?
//request.getSignedWitness()

View File

@ -41,18 +41,14 @@ public class BuyerProcessPaymentAccountKeyResponse extends TradeTask {
trade.setTradingPeerNodeAddress(processModel.getTempTradingPeerNodeAddress());
}
// buyer may already have decrypted payment account payload from arbitrator request
if (trade.getTradingPeer().getPaymentAccountPayload() != null) {
complete();
return;
}
// decrypt peer's payment account payload
PaymentAccountKeyResponse request = (PaymentAccountKeyResponse) processModel.getTradeMessage();
trade.decryptPeersPaymentAccountPayload(request.getPaymentAccountKey());
if (trade.getTradingPeer().getPaymentAccountPayload() == null) {
trade.decryptPeersPaymentAccountPayload(request.getPaymentAccountKey());
}
// store updated multisig hex for processing on payment sent
trade.getTradingPeer().setUpdatedMultisigHex(request.getUpdatedMultisigHex());
if (request.getUpdatedMultisigHex() != null) trade.getTradingPeer().setUpdatedMultisigHex(request.getUpdatedMultisigHex());
// persist and complete
processModel.getTradeManager().requestPersistence();

View File

@ -56,11 +56,11 @@ public class BuyerProcessPaymentReceivedMessage extends TradeTask {
trade.setTradingPeerNodeAddress(processModel.getTempTradingPeerNodeAddress());
// handle if payout tx is not seen on network
if (trade.getPayoutTx() == null) {
if (trade.getPhase().ordinal() < Trade.Phase.PAYOUT_PUBLISHED.ordinal()) {
// publish payout tx if signed. otherwise verify, sign, and publish payout tx
boolean fullySigned = trade.getSelf().getPayoutTx() != null;
if (fullySigned) {
boolean previouslySigned = trade.getBuyer().getPayoutTxHex() != null;
if (previouslySigned) {
log.info("Buyer publishing signed payout tx from seller");
XmrWalletService walletService = processModel.getProvider().getXmrWalletService();
MoneroWallet multisigWallet = walletService.getMultisigWallet(trade.getId());

View File

@ -54,6 +54,7 @@ public class BuyerSendPayoutTxPublishedMessage extends SendMailboxMessageTask {
return new PayoutTxPublishedMessage(
tradeId,
processModel.getMyNodeAddress(),
trade.isMaker(),
null, // TODO: send witness data?
trade.getSelf().getPayoutTxHex()
);

View File

@ -69,6 +69,7 @@ public class SellerMaybeSendPayoutTxPublishedMessage extends SendMailboxMessageT
return new PayoutTxPublishedMessage(
tradeId,
processModel.getMyNodeAddress(),
trade.isMaker(),
null, // TODO: send witness data?
trade.getSelf().getPayoutTxHex()
);

View File

@ -57,7 +57,7 @@ public class SellerProcessPaymentSentMessage extends TradeTask {
walletService.closeMultisigWallet(trade.getId());
}
// update to the latest peer address of our peer if the message is correct // TODO (woodser): update to latest peer addresses where needed
// update latest peer address
trade.setTradingPeerNodeAddress(processModel.getTempTradingPeerNodeAddress());
String counterCurrencyTxId = message.getCounterCurrencyTxId();

View File

@ -65,9 +65,11 @@ public class SellerSendPaymentReceivedMessage extends SendMailboxMessageTask {
);
}
// TODO: using PAYOUT_TX_PUBLISHED_MSG to represent PAYMENT_RECEIVED_MSG after payout, but PAYOUT_TX_PUBLISHED_MSG is specifically for arbitrator. delete *PAYOUT_TX_PUBLISHED* messages and check payout field manually?
@Override
protected void setStateSent() {
trade.setState(trade.getState() == Trade.State.SELLER_PUBLISHED_PAYOUT_TX ? Trade.State.SELLER_SENT_PAYOUT_TX_PUBLISHED_MSG : Trade.State.SELLER_SENT_PAYMENT_RECEIVED_MSG);
trade.setState(trade.getState().ordinal() >= Trade.State.SELLER_PUBLISHED_PAYOUT_TX.ordinal() ? Trade.State.SELLER_SENT_PAYOUT_TX_PUBLISHED_MSG : Trade.State.SELLER_SENT_PAYMENT_RECEIVED_MSG);
log.info("Sent SellerReceivedPaymentMessage: tradeId={} at peer {} SignedWitness {}",
trade.getId(), trade.getTradingPeerNodeAddress(), signedWitness);
processModel.getTradeManager().requestPersistence();
@ -75,7 +77,7 @@ public class SellerSendPaymentReceivedMessage extends SendMailboxMessageTask {
@Override
protected void setStateArrived() {
trade.setState(trade.getState() == Trade.State.SELLER_SENT_PAYOUT_TX_PUBLISHED_MSG ? Trade.State.SELLER_SAW_ARRIVED_PAYOUT_TX_PUBLISHED_MSG : Trade.State.SELLER_SAW_ARRIVED_PAYMENT_RECEIVED_MSG);
trade.setState(trade.getState().ordinal() >= Trade.State.SELLER_PUBLISHED_PAYOUT_TX.ordinal() ? Trade.State.SELLER_SAW_ARRIVED_PAYOUT_TX_PUBLISHED_MSG : Trade.State.SELLER_SAW_ARRIVED_PAYMENT_RECEIVED_MSG);
log.info("Seller's PaymentReceivedMessage arrived: tradeId={} at peer {} SignedWitness {}",
trade.getId(), trade.getTradingPeerNodeAddress(), signedWitness);
processModel.getTradeManager().requestPersistence();
@ -83,7 +85,7 @@ public class SellerSendPaymentReceivedMessage extends SendMailboxMessageTask {
@Override
protected void setStateStoredInMailbox() {
trade.setState(trade.getState() == Trade.State.SELLER_PUBLISHED_PAYOUT_TX ? Trade.State.SELLER_STORED_IN_MAILBOX_PAYOUT_TX_PUBLISHED_MSG : Trade.State.SELLER_STORED_IN_MAILBOX_PAYMENT_RECEIVED_MSG);
trade.setState(trade.getState().ordinal() >= Trade.State.SELLER_PUBLISHED_PAYOUT_TX.ordinal() ? Trade.State.SELLER_STORED_IN_MAILBOX_PAYOUT_TX_PUBLISHED_MSG : Trade.State.SELLER_STORED_IN_MAILBOX_PAYMENT_RECEIVED_MSG);
log.info("Seller's PaymentReceivedMessage stored in mailbox: tradeId={} at peer {} SignedWitness {}",
trade.getId(), trade.getTradingPeerNodeAddress(), signedWitness);
processModel.getTradeManager().requestPersistence();
@ -91,7 +93,7 @@ public class SellerSendPaymentReceivedMessage extends SendMailboxMessageTask {
@Override
protected void setStateFault() {
trade.setState(trade.getState() == Trade.State.SELLER_PUBLISHED_PAYOUT_TX ? Trade.State.SELLER_SEND_FAILED_PAYOUT_TX_PUBLISHED_MSG : Trade.State.SELLER_SEND_FAILED_PAYMENT_RECEIVED_MSG);
trade.setState(trade.getState().ordinal() >= Trade.State.SELLER_PUBLISHED_PAYOUT_TX.ordinal() ? Trade.State.SELLER_SEND_FAILED_PAYOUT_TX_PUBLISHED_MSG : Trade.State.SELLER_SEND_FAILED_PAYMENT_RECEIVED_MSG);
log.error("SellerReceivedPaymentMessage failed: tradeId={} at peer {} SignedWitness {}",
trade.getId(), trade.getTradingPeerNodeAddress(), signedWitness);
processModel.getTradeManager().requestPersistence();

View File

@ -461,9 +461,10 @@ message PaymentReceivedMessage {
message PayoutTxPublishedMessage {
string trade_id = 1;
NodeAddress sender_node_address = 2;
string uid = 3;
SignedWitness signed_witness = 4;
string signed_payout_tx_hex = 5;
bool is_maker = 3;
string uid = 4;
SignedWitness signed_witness = 5;
string signed_payout_tx_hex = 6;
}
message ArbitratorPayoutTxRequest {