Skip to content

fix: queue SwapConfirm on tx_not_found instead of rejecting#333

Open
LandynDev wants to merge 1 commit into
testfrom
fix/queue-tx-not-found-on-confirm
Open

fix: queue SwapConfirm on tx_not_found instead of rejecting#333
LandynDev wants to merge 1 commit into
testfrom
fix/queue-tx-not-found-on-confirm

Conversation

@LandynDev
Copy link
Copy Markdown
Collaborator

Summary

  • Validators previously hard-rejected SwapConfirm when the source tx wasn't yet visible to the local BTC node + Esplora at axon time. A user who broadcast and immediately confirmed (a 20s reserve→confirm window) raced propagation and got bounced with Source transaction not found, amount or sender mismatch, forcing a retry.
  • This change queues that case the same way we already queue "found but not yet confirmed" — the forward.py drain re-verifies on each step, and PENDING_CONFIRM_NULL_RETRY_LIMIT bounds bogus entries so the abuse surface is unchanged.
  • Improves the silent-None paths in BitcoinProvider: DEBUG when neither RPC nor Esplora has the tx, WARNING when the tx exists but no vout matches recipient + amount. Sender-mismatch already warns in base.py. The previous catchall log conflated all three failure modes.

Reasoning

Real incident: reservation at 15:02:25ZSwapConfirm 20s later → rejected at 15:02:46Z → tx confirmed in block at 15:58:36Z. The tx was real and valid; the validator just couldn't see it yet. The CLI already softens the rejection to "yellow" + a "usually propagation lag, retry" message (cli/validator_rejections.py:217-232), which is itself an admission that this rejection should be a queue.

The new "Queued — source tx not yet visible..." response is accepted=True, so the existing CLI renderer treats it as queued (validator_rejections.py:340) — no client-side change required, and old-validator rejection text continues to map to the legacy tx_not_found rule for backward compatibility.

Test plan

  • pytest tests/test_axon_handlers.py tests/test_validator_rejections.py tests/test_pending_confirm_queue.py — 42 passed
  • pytest — full suite, 472 passed
  • ruff format + ruff check — clean
  • E2E smoke (./tests/run.sh --chains btc --suite 02) on dev environment to confirm the queued path drains correctly when the tx eventually lands
  • Manual: broadcast a BTC tx, immediately call alw swap with the matching reservation, confirm validator logs show queued: source tx not yet visible and the swap initiates once the tx propagates

Validators previously rejected SwapConfirm outright when the source tx
wasn't visible to the local BTC node + Esplora at axon time, forcing
users to retry across a propagation race they had no control over.

Treat tx_info=None the same as "found but not yet confirmed" — enqueue
into pending_confirms and let the forward drain re-verify, bounded by
PENDING_CONFIRM_NULL_RETRY_LIMIT for bogus entries. The user gets a
"Queued — source tx not yet visible" response that the CLI already
renders as queued, so no client change is required.

Logging: split the silent None paths in BitcoinProvider so operators can
distinguish "tx not in RPC/Esplora" (DEBUG) from "tx returned but no vout
matches recipient + amount" (WARNING). Sender-mismatch already warns at
the base class.
@xiao-xiao-mao xiao-xiao-mao Bot added the bug Something isn't working label May 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant