add validation and self correct recorded security deposits (#1872)

This commit is contained in:
woodser 2025-07-20 16:33:35 -04:00 committed by GitHub
parent 0b04d34909
commit f722ca4cd4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 39 additions and 19 deletions

View file

@ -2695,10 +2695,18 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
setStateDepositsSeen(); setStateDepositsSeen();
// set actual security deposits // set actual security deposits
if (getBuyer().getSecurityDeposit().longValueExact() == 0) { if (getBuyer().getDepositTx() != null) {
BigInteger buyerSecurityDeposit = hasBuyerAsTakerWithoutDeposit() ? BigInteger.ZERO : ((MoneroTxWallet) getBuyer().getDepositTx()).getIncomingAmount(); BigInteger buyerSecurityDeposit = ((MoneroTxWallet) getBuyer().getDepositTx()).getIncomingAmount();
BigInteger sellerSecurityDeposit = ((MoneroTxWallet) getSeller().getDepositTx()).getIncomingAmount().subtract(getAmount()); if (!getBuyer().getSecurityDeposit().equals(BigInteger.ZERO) && !getBuyer().getSecurityDeposit().equals(buyerSecurityDeposit)) {
log.warn("Overwriting buyer security deposit for {} {}, old={}, new={}", getClass().getSimpleName(), getShortId(), getBuyer().getSecurityDeposit(), buyerSecurityDeposit);
}
getBuyer().setSecurityDeposit(buyerSecurityDeposit); getBuyer().setSecurityDeposit(buyerSecurityDeposit);
}
if (getSeller().getDepositTx() != null) {
BigInteger sellerSecurityDeposit = ((MoneroTxWallet) getSeller().getDepositTx()).getIncomingAmount().subtract(getAmount());
if (!getSeller().getSecurityDeposit().equals(BigInteger.ZERO) && !getSeller().getSecurityDeposit().equals(sellerSecurityDeposit)) {
log.warn("Overwriting seller security deposit for {} {}, old={}, new={}", getClass().getSimpleName(), getShortId(), getSeller().getSecurityDeposit(), sellerSecurityDeposit);
}
getSeller().setSecurityDeposit(sellerSecurityDeposit); getSeller().setSecurityDeposit(sellerSecurityDeposit);
} }

View file

@ -120,9 +120,8 @@ public class ArbitratorProcessDepositRequest extends TradeTask {
// verify deposit tx // verify deposit tx
boolean isFromBuyerAsTakerWithoutDeposit = isFromBuyer && isFromTaker && trade.hasBuyerAsTakerWithoutDeposit(); boolean isFromBuyerAsTakerWithoutDeposit = isFromBuyer && isFromTaker && trade.hasBuyerAsTakerWithoutDeposit();
if (!isFromBuyerAsTakerWithoutDeposit) { if (!isFromBuyerAsTakerWithoutDeposit) {
MoneroTx verifiedTx;
try { try {
verifiedTx = trade.getXmrWalletService().verifyDepositTx( MoneroTx verifiedTx = trade.getXmrWalletService().verifyDepositTx(
offer.getId(), offer.getId(),
tradeFee, tradeFee,
trade.getProcessModel().getTradeFeeAddress(), trade.getProcessModel().getTradeFeeAddress(),
@ -133,8 +132,12 @@ public class ArbitratorProcessDepositRequest extends TradeTask {
request.getDepositTxHex(), request.getDepositTxHex(),
request.getDepositTxKey(), request.getDepositTxKey(),
null); null);
} catch (Exception e) {
throw new RuntimeException("Error processing deposit tx from " + (isFromTaker ? "taker " : "maker ") + sender.getNodeAddress() + ", offerId=" + offer.getId() + ": " + e.getMessage()); // TODO: it seems a deposit tx had 0 fee once?
if (BigInteger.ZERO.equals(verifiedTx.getFee())) {
String errorMessage = "Deposit transaction from " + (isFromTaker ? "taker" : "maker") + " has 0 fee for trade " + trade.getId() + ". This should never happen.";
log.warn(errorMessage + "\n" + verifiedTx);
throw new RuntimeException(errorMessage);
} }
// update trade state // update trade state
@ -142,6 +145,9 @@ public class ArbitratorProcessDepositRequest extends TradeTask {
sender.setDepositTxFee(verifiedTx.getFee()); sender.setDepositTxFee(verifiedTx.getFee());
sender.setDepositTxHex(request.getDepositTxHex()); sender.setDepositTxHex(request.getDepositTxHex());
sender.setDepositTxKey(request.getDepositTxKey()); sender.setDepositTxKey(request.getDepositTxKey());
} catch (Exception e) {
throw new RuntimeException("Error processing deposit tx from " + (isFromTaker ? "taker " : "maker ") + sender.getNodeAddress() + ", offerId=" + offer.getId() + ": " + e.getMessage());
}
} }
// update trade state // update trade state

View file

@ -67,9 +67,8 @@ public class ArbitratorProcessReserveTx extends TradeTask {
BigInteger penaltyFee = HavenoUtils.multiply(isFromMaker ? offer.getAmount() : trade.getAmount(), offer.getPenaltyFeePct()); BigInteger penaltyFee = HavenoUtils.multiply(isFromMaker ? offer.getAmount() : trade.getAmount(), offer.getPenaltyFeePct());
BigInteger tradeFee = isFromMaker ? offer.getMaxMakerFee() : trade.getTakerFee(); BigInteger tradeFee = isFromMaker ? offer.getMaxMakerFee() : trade.getTakerFee();
BigInteger sendAmount = isFromBuyer ? BigInteger.ZERO : isFromMaker ? offer.getAmount() : trade.getAmount(); // maker reserve tx is for offer amount BigInteger sendAmount = isFromBuyer ? BigInteger.ZERO : isFromMaker ? offer.getAmount() : trade.getAmount(); // maker reserve tx is for offer amount
MoneroTx verifiedTx;
try { try {
verifiedTx = trade.getXmrWalletService().verifyReserveTx( MoneroTx verifiedTx = trade.getXmrWalletService().verifyReserveTx(
offer.getId(), offer.getId(),
penaltyFee, penaltyFee,
tradeFee, tradeFee,
@ -80,9 +79,12 @@ public class ArbitratorProcessReserveTx extends TradeTask {
request.getReserveTxHex(), request.getReserveTxHex(),
request.getReserveTxKey(), request.getReserveTxKey(),
null); null);
} catch (Exception e) {
log.error(ExceptionUtils.getStackTrace(e)); // TODO: it seems a deposit tx had 0 fee once?
throw new RuntimeException("Error processing reserve tx from " + (isFromMaker ? "maker " : "taker ") + processModel.getTempTradePeerNodeAddress() + ", offerId=" + offer.getId() + ": " + e.getMessage()); if (BigInteger.ZERO.equals(verifiedTx.getFee())) {
String errorMessage = "Reserve transaction from " + (isFromMaker ? "maker" : "taker") + " has 0 fee for trade " + trade.getId() + ". This should never happen.";
log.warn(errorMessage + "\n" + verifiedTx);
throw new RuntimeException(errorMessage);
} }
// save reserve tx to model // save reserve tx to model
@ -90,6 +92,10 @@ public class ArbitratorProcessReserveTx extends TradeTask {
sender.setReserveTxHash(request.getReserveTxHash()); sender.setReserveTxHash(request.getReserveTxHash());
sender.setReserveTxHex(request.getReserveTxHex()); sender.setReserveTxHex(request.getReserveTxHex());
sender.setReserveTxKey(request.getReserveTxKey()); sender.setReserveTxKey(request.getReserveTxKey());
} catch (Exception e) {
log.error(ExceptionUtils.getStackTrace(e));
throw new RuntimeException("Error processing reserve tx from " + (isFromMaker ? "maker " : "taker ") + processModel.getTempTradePeerNodeAddress() + ", offerId=" + offer.getId() + ": " + e.getMessage());
}
} }
// persist trade // persist trade