fixes when a deposit transaction does not confirm (#1892)

This commit is contained in:
woodser 2025-07-30 07:57:02 -04:00 committed by GitHub
parent 19acab4e25
commit c8fab5fb37
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 35 additions and 18 deletions

View file

@ -42,10 +42,15 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class DisputeValidation {
public static void validatePaymentAccountPayloads(Dispute dispute) throws ValidationException {
if (dispute.getSellerPaymentAccountPayload() == null) throw new ValidationException(dispute, "Seller's payment account payload is null in dispute opened for trade " + dispute.getTradeId());
if (!Arrays.equals(dispute.getSellerPaymentAccountPayload().getHash(), dispute.getContract().getSellerPaymentAccountPayloadHash())) throw new ValidationException(dispute, "Hash of seller's payment account payload does not match contract");
if (dispute.getSellerPaymentAccountPayload() != null) {
if (!Arrays.equals(dispute.getSellerPaymentAccountPayload().getHash(), dispute.getContract().getSellerPaymentAccountPayloadHash())) {
throw new ValidationException(dispute, "Hash of seller's payment account payload does not match contract");
}
}
if (dispute.getBuyerPaymentAccountPayload() != null) {
if (!Arrays.equals(dispute.getBuyerPaymentAccountPayload().getHash(), dispute.getContract().getBuyerPaymentAccountPayloadHash())) throw new ValidationException(dispute, "Hash of buyer's payment account payload does not match contract");
if (!Arrays.equals(dispute.getBuyerPaymentAccountPayload().getHash(), dispute.getContract().getBuyerPaymentAccountPayloadHash())) {
throw new ValidationException(dispute, "Hash of buyer's payment account payload does not match contract");
}
}
}

View file

@ -2727,39 +2727,45 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
}
}
setDepositTxs(txs);
if (!isPublished(getMaker().getDepositTx()) || (!hasBuyerAsTakerWithoutDeposit() && !isPublished(getTaker().getDepositTx()))) return; // skip if deposit txs not published successfully
setStateDepositsSeen();
// set actual security deposits
if (getBuyer().getDepositTx() != null) {
// set actual buyer security deposit
if (isSeen(getBuyer().getDepositTx())) {
BigInteger buyerSecurityDeposit = ((MoneroTxWallet) getBuyer().getDepositTx()).getIncomingAmount();
if (!getBuyer().getSecurityDeposit().equals(BigInteger.ZERO) && !getBuyer().getSecurityDeposit().equals(buyerSecurityDeposit)) {
if (!getBuyer().getSecurityDeposit().equals(BigInteger.ZERO) && !buyerSecurityDeposit.equals(getBuyer().getSecurityDeposit())) {
log.warn("Overwriting buyer security deposit for {} {}, old={}, new={}", getClass().getSimpleName(), getShortId(), getBuyer().getSecurityDeposit(), buyerSecurityDeposit);
}
getBuyer().setSecurityDeposit(buyerSecurityDeposit);
}
if (getSeller().getDepositTx() != null) {
// set actual seller security deposit
if (isSeen(getSeller().getDepositTx())) {
BigInteger sellerSecurityDeposit = ((MoneroTxWallet) getSeller().getDepositTx()).getIncomingAmount().subtract(getAmount());
if (!getSeller().getSecurityDeposit().equals(BigInteger.ZERO) && !getSeller().getSecurityDeposit().equals(sellerSecurityDeposit)) {
if (!getSeller().getSecurityDeposit().equals(BigInteger.ZERO) && !sellerSecurityDeposit.equals(getSeller().getSecurityDeposit())) {
log.warn("Overwriting seller security deposit for {} {}, old={}, new={}", getClass().getSimpleName(), getShortId(), getSeller().getSecurityDeposit(), sellerSecurityDeposit);
}
getSeller().setSecurityDeposit(sellerSecurityDeposit);
}
// check for deposit txs confirmation
if (getMaker().getDepositTx().isConfirmed() && (hasBuyerAsTakerWithoutDeposit() || getTaker().getDepositTx().isConfirmed())) setStateDepositsConfirmed();
// handle both deposits seen
if (isSeen(getMaker().getDepositTx()) && (hasBuyerAsTakerWithoutDeposit() || isSeen(getTaker().getDepositTx()))) {
setStateDepositsSeen();
// check for deposit txs unlocked
if (getMaker().getDepositTx().getNumConfirmations() >= XmrWalletService.NUM_BLOCKS_UNLOCK && (hasBuyerAsTakerWithoutDeposit() || getTaker().getDepositTx().getNumConfirmations() >= XmrWalletService.NUM_BLOCKS_UNLOCK)) {
setStateDepositsUnlocked();
// check for deposit txs confirmed
if (getMaker().getDepositTx().isConfirmed() && (hasBuyerAsTakerWithoutDeposit() || getTaker().getDepositTx().isConfirmed())) setStateDepositsConfirmed();
// check for deposit txs unlocked
if (getMaker().getDepositTx().getNumConfirmations() >= XmrWalletService.NUM_BLOCKS_UNLOCK && (hasBuyerAsTakerWithoutDeposit() || getTaker().getDepositTx().getNumConfirmations() >= XmrWalletService.NUM_BLOCKS_UNLOCK)) {
setStateDepositsUnlocked();
}
}
}
// check for payout tx
if (isDepositsUnlocked()) {
boolean hasUnlockedDeposit = isUnlocked(getMaker().getDepositTx()) || isUnlocked(getTaker().getDepositTx());
if (isDepositsUnlocked() || hasUnlockedDeposit) { // arbitrator idles so these may not be the same
// determine if payout tx expected
boolean isPayoutExpected = isPaymentReceived() || hasPaymentReceivedMessage() || hasDisputeClosedMessage() || disputeState.ordinal() >= DisputeState.ARBITRATOR_SENT_DISPUTE_CLOSED_MSG.ordinal();
boolean isPayoutExpected = isDepositsUnlocked() && isPaymentReceived() || hasPaymentReceivedMessage() || hasDisputeClosedMessage() || disputeState.ordinal() >= DisputeState.ARBITRATOR_SENT_DISPUTE_CLOSED_MSG.ordinal();
// sync wallet if payout expected or payout is published
if (isPayoutExpected || isPayoutPublished()) syncWalletIfBehind();
@ -2837,13 +2843,19 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
}
}
private static boolean isPublished(MoneroTx tx) {
private static boolean isSeen(MoneroTx tx) {
if (tx == null) return false;
if (Boolean.TRUE.equals(tx.isFailed())) return false;
if (!Boolean.TRUE.equals(tx.inTxPool()) && !Boolean.TRUE.equals(tx.isConfirmed())) return false;
return true;
}
private static boolean isUnlocked(MoneroTx tx) {
if (tx == null) return false;
if (tx.getNumConfirmations() == null || tx.getNumConfirmations() < XmrWalletService.NUM_BLOCKS_UNLOCK) return false;
return true;
}
private void syncWalletIfBehind() {
synchronized (walletLock) {
if (isWalletBehind()) {