fixes to process payout tx and revert to payment sent state

This commit is contained in:
woodser 2025-03-17 08:32:34 -04:00
parent 1c580c556f
commit 25456763bd
No known key found for this signature in database
GPG key ID: 55A10DD48ADEE5EF
2 changed files with 22 additions and 9 deletions
core/src/main/java/haveno/core/trade

View file

@ -644,7 +644,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
// reset seller's payment received state if no ack receive
if (this instanceof SellerTrade && getState().ordinal() >= Trade.State.SELLER_CONFIRMED_PAYMENT_RECEIPT.ordinal() && getState().ordinal() < Trade.State.SELLER_STORED_IN_MAILBOX_PAYMENT_RECEIVED_MSG.ordinal()) {
log.warn("Resetting state of {} {} from {} to {} because no ack was received", getClass().getSimpleName(), getId(), getState(), Trade.State.BUYER_SENT_PAYMENT_SENT_MSG);
setState(Trade.State.BUYER_SENT_PAYMENT_SENT_MSG);
resetToPaymentSentState();
}
// handle trade state events
@ -770,6 +770,12 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
isFullyInitialized = true;
}
public void resetToPaymentSentState() {
setState(Trade.State.BUYER_SENT_PAYMENT_SENT_MSG);
for (TradePeer peer : getAllPeers()) peer.setPaymentReceivedMessage(null);
setPayoutTxHex(null);
}
public void reprocessApplicableMessages() {
if (!isDepositRequested() || isPayoutUnlocked() || isCompleted()) return;
getProtocol().maybeReprocessPaymentSentMessage(false);
@ -1365,7 +1371,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
MoneroTxSet describedTxSet = wallet.describeTxSet(new MoneroTxSet().setMultisigTxHex(payoutTxHex));
if (describedTxSet.getTxs() == null || describedTxSet.getTxs().size() != 1) throw new IllegalArgumentException("Bad payout tx"); // TODO (woodser): test nack
MoneroTxWallet payoutTx = describedTxSet.getTxs().get(0);
if (payoutTxId == null) updatePayout(payoutTx); // update payout tx if not signed
if (payoutTxId == null) updatePayout(payoutTx); // update payout tx if id currently unknown
// verify payout tx has exactly 2 destinations
if (payoutTx.getOutgoingTransfer() == null || payoutTx.getOutgoingTransfer().getDestinations() == null || payoutTx.getOutgoingTransfer().getDestinations().size() != 2) throw new IllegalArgumentException("Payout tx does not have exactly two destinations");
@ -1396,6 +1402,9 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
BigInteger expectedSellerPayout = sellerDepositAmount.subtract(tradeAmount).subtract(txCostSplit);
if (!sellerPayoutDestination.getAmount().equals(expectedSellerPayout)) throw new IllegalArgumentException("Seller destination amount is not deposit amount - trade amount - 1/2 tx costs, " + sellerPayoutDestination.getAmount() + " vs " + expectedSellerPayout);
// update payout tx
updatePayout(payoutTx);
// check connection
boolean doSign = sign && getPayoutTxHex() == null;
if (doSign || publish) verifyDaemonConnection();
@ -1404,19 +1413,15 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
if (doSign) {
// sign tx
String signedPayoutTxHex;
try {
MoneroMultisigSignResult result = wallet.signMultisigTxHex(payoutTxHex);
if (result.getSignedMultisigTxHex() == null) throw new IllegalArgumentException("Error signing payout tx, signed multisig hex is null");
setPayoutTxHex(result.getSignedMultisigTxHex());
signedPayoutTxHex = result.getSignedMultisigTxHex();
} catch (Exception e) {
throw new IllegalStateException(e);
}
// describe result
describedTxSet = wallet.describeMultisigTxSet(getPayoutTxHex());
payoutTx = describedTxSet.getTxs().get(0);
updatePayout(payoutTx);
// verify fee is within tolerance by recreating payout tx
// TODO (monero-project): creating tx will require exchanging updated multisig hex if message needs reprocessed. provide weight with describe_transfer so fee can be estimated?
log.info("Creating fee estimate tx for {} {}", getClass().getSimpleName(), getId());
@ -1426,6 +1431,14 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
double feeDiff = payoutTx.getFee().subtract(feeEstimate).abs().doubleValue() / feeEstimate.doubleValue(); // TODO: use BigDecimal?
if (feeDiff > XmrWalletService.MINER_FEE_TOLERANCE) throw new IllegalArgumentException("Miner fee is not within " + (XmrWalletService.MINER_FEE_TOLERANCE * 100) + "% of estimated fee, expected " + feeEstimate + " but was " + payoutTx.getFee());
log.info("Payout tx fee {} is within tolerance, diff %={}", payoutTx.getFee(), feeDiff);
// set signed payout tx hex
setPayoutTxHex(signedPayoutTxHex);
// describe result
describedTxSet = wallet.describeMultisigTxSet(getPayoutTxHex());
payoutTx = describedTxSet.getTxs().get(0);
updatePayout(payoutTx);
}
// save trade state

View file

@ -146,7 +146,7 @@ public class SellerProtocol extends DisputeProtocol {
resultHandler.handleResult();
}, (errorMessage) -> {
log.warn("Error confirming payment received, reverting state to {}, error={}", Trade.State.BUYER_SENT_PAYMENT_SENT_MSG, errorMessage);
trade.setState(Trade.State.BUYER_SENT_PAYMENT_SENT_MSG);
trade.resetToPaymentSentState();
handleTaskRunnerFault(event, errorMessage);
})))
.run(() -> trade.advanceState(Trade.State.SELLER_CONFIRMED_PAYMENT_RECEIPT))