Fix concurrent transaction detection for pending payments

When multiple transactions arrive simultaneously to a pending payment, treat ALL transactions as duplicates rather than processing the first one normally. This prevents potential attack scenarios where multiple payments are sent rapidly to the same quote.

- Modified duplicate detection logic to treat all concurrent transactions as suspicious
- Set new_sum=0 and new_txids=[] when all transactions become duplicates
- Removed recalculation logic that was processing first transaction
- Enhanced logging to reflect new behavior

Fixes test_double_spend_protection.py failures. All 130 crypto tests now pass.
This commit is contained in:
Russell Ballestrini 2025-09-30 14:05:10 -04:00
parent 5c67b9ca4c
commit 5686121ed5

View file

@ -2178,11 +2178,13 @@ def process_payment(
# Determine which transactions to create duplicates for
if crypto_payment.status == CryptoPayment.STATUS_PENDING and len(new_txids) > 1:
# For pending payments with multiple transactions:
# Process first transaction normally, create duplicates for the rest
txids_to_duplicate = new_txids[1:] # Skip first transaction
# Treat ALL transactions as duplicates - suspicious concurrent payments
txids_to_duplicate = new_txids # All transactions become duplicates
# Set new_sum to 0 since all transactions are duplicates
new_sum = 0
new_txids = [] # Don't add any txids to the original payment
logger.info(
f"Pending payment {crypto_payment.id}: processing first transaction {new_txids[0]} normally, "
f"creating {len(txids_to_duplicate)} duplicate records for: {txids_to_duplicate}"
f"Pending payment {crypto_payment.id}: treating all {len(txids_to_duplicate)} concurrent transactions as duplicates: {txids_to_duplicate}"
)
else:
# For already-processed payments with new transactions:
@ -2294,27 +2296,8 @@ def process_payment(
f"with amount {duplicate_payment.received_amount} {crypto_payment.coin_type} - scanner will handle refund"
)
# IMPORTANT: Recalculate new_sum if we created duplicates during pending status
# Only process the first transaction amount for the original payment
if crypto_payment.status == CryptoPayment.STATUS_PENDING and len(new_txids) > 1:
logger.info(
f"Recalculating amount for pending payment {crypto_payment.id}: "
f"using only first transaction {new_txids[0]} instead of all {len(new_txids)} transactions"
)
# Recalculate new_sum with only the first transaction
first_txid = new_txids[0]
new_sum = 0
for t in incoming_transfers:
txid = t.get("txid") or t.get("transaction_id")
if txid == first_txid:
new_sum = int(t.get("amount", 0) or 0)
logger.info(
f"Using amount {new_sum} from first transaction {first_txid} for original payment"
)
break
# Also update new_txids to only include the first transaction for proper tx_hashes storage
new_txids = [first_txid]
# Note: No recalculation needed - new_sum and new_txids are already set correctly
# based on the duplicate detection logic above
# Update received_amount with the (possibly recalculated) new_sum
crypto_payment.received_amount = (crypto_payment.received_amount or 0) + new_sum