Skip to content

fix(cli): refuse post-tx inside reservation extension dead-zone#355

Closed
anderdc wants to merge 1 commit into
testfrom
fix/user-post-tx-cushion
Closed

fix(cli): refuse post-tx inside reservation extension dead-zone#355
anderdc wants to merge 1 commit into
testfrom
fix/user-post-tx-cushion

Conversation

@anderdc
Copy link
Copy Markdown
Collaborator

@anderdc anderdc commented May 20, 2026

Summary

User-side analogue of the miner timeout cushion. Validators refuse propose_extend_reservation once current_block + CHALLENGE_WINDOW_BLOCKS >= reserved_until (optimistic_extensions.py:97), so a confirm broadcast inside that 8-block window has no extension rescue path. On tao→btc the source TAO is already sent to the miner before the swap row exists — a failed reservation inside that window is an unrecoverable loss (no escrow, no slash-to-user).

Today alw swap post-tx and alw swap resume-reservation only check reserved_until > current_block, so a user can ship a confirm with ~1 block of runway and silently lose funds.

This change:

  • Adds USER_POST_TX_CUSHION_BLOCKS = CHALLENGE_WINDOW_BLOCKS in constants.py.
  • Adds safe_reservation_remaining() helper in cli/swap_commands/helpers.py — returns remaining blocks if safe, else None after printing a user-facing reason.
  • Wires the helper into post_tx.py and resume.py, replacing the existing "expired or not" check.
  • Unit test for the cushion boundary, zero, and post-expiry cases.

Counterpart ticket on the miner side (raising DEFAULT_MINER_TIMEOUT_CUSHION_BLOCKS from 5 → ≥ CHALLENGE_WINDOW_BLOCKS) is left for a separate PR — that one affects operators and warrants its own announcement.

Test plan

  • pytest tests/test_safe_reservation_remaining.py — 5/5 pass
  • pytest tests/test_probe_pending_reservation.py — neighbouring suite still green
  • Imports clean on post_tx, resume, helpers, constants
  • Manual: run alw swap post-tx against a near-expiry reservation and confirm the new abort message fires; against a healthy reservation, confirm normal flow proceeds.

User-side analogue of MINER_TIMEOUT_CUSHION_BLOCKS. Validators refuse
propose_extend_reservation once current + CHALLENGE_WINDOW_BLOCKS >=
reserved_until, so a confirm broadcast inside that 8-block window has no
extension rescue path. On tao→btc the source TAO is already sent to the
miner before the swap row exists — a failed reservation in that window
is an unrecoverable loss.

Adds USER_POST_TX_CUSHION_BLOCKS (= CHALLENGE_WINDOW_BLOCKS) and a shared
helper used by `alw swap post-tx` and `alw swap resume-reservation` to
abort with a clear message when runway is inside the cushion.
@anderdc
Copy link
Copy Markdown
Collaborator Author

anderdc commented May 20, 2026

Superseded by #328 which gates upstream of this (before source funds are broadcast) and uses a more conservative threshold (EXTEND_THRESHOLD_BLOCKS + buffer vs CHALLENGE_WINDOW_BLOCKS). Closing in favor of that PR.

@anderdc anderdc closed this May 20, 2026
@anderdc anderdc deleted the fix/user-post-tx-cushion branch May 20, 2026 21:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant