Skip to content

CLI: detect stale pending_swap.json when miner is re-reserved#226

Merged
anderdc merged 2 commits into
testfrom
cli/reservation-staleness-probe
Apr 28, 2026
Merged

CLI: detect stale pending_swap.json when miner is re-reserved#226
anderdc merged 2 commits into
testfrom
cli/reservation-staleness-probe

Conversation

@LandynDev

Copy link
Copy Markdown
Collaborator

Summary

alw swap now and alw view reservation were treating any local pending_swap.json as live whenever the saved miner had an on-chain reserved_until > now. That conflates "this miner is reserved by anyone" with "our reservation is still live" — so when a swap completed and another user (or another process) re-reserved the same miner, the stale local row was reported as ACTIVE.

Reported case: user completed swap #3, came back later, alw swap now warned about a pending reservation, alw view reservation showed it ACTIVE with ~16 blocks remaining and the old BTC tx attached, but alw view swap 3 --watch correctly said the swap was already resolved.

Approach

New probe_pending_reservation helper in swap_commands/helpers.py decides among five outcomes:

  1. our_swapget_miner_active_swaps has a swap on this miner whose (user_from_address, receive_address) match ours. Strongest signal; survives vote_extend_reservation and into FULFILLED.
  2. expired — no swap match and no reservation row.
  3. replaced — reservation amounts differ from saved.
  4. replaced — amounts match but reserved_until is more than reservation_ttl past our saved value (a single extension can't push it that far, and chained extensions would have shown up as a swap in step 1).
  5. ours_active — within tolerance.

Three call sites consume it: swap.py (start-new prompt), view.py (full table), status.py (dashboard row). Each clears pending_swap.json and prints a one-line resolution when the saved state is no longer ours.

Tradeoffs

The amount-tuple match in step 4 is almost unique-per-reservation but technically could collide if a different user re-reserves the same miner with the same exact amounts. The contract doesn't expose Reservation.from_addr, so the amount tuple plus the ttl-bounded drift check is the best disambiguator without a contract change. In practice, step 1 catches every "stale local file" case once a tx is broadcast (the reservation transitions into a swap and the swap match wins). A contract getter for from_addr would close the residual hole — deferring until the collision actually surfaces.

Test plan

  • pytest tests/test_probe_pending_reservation.py — 9 cases covering all 5 branches, including the exact stale-after-completed-swap case
  • Full unit suite (pytest tests/) green — 330 passed
  • ruff format . + ruff check . clean
  • Manual reproduction: complete a swap on dev environment, leave pending_swap.json behind, re-reserve same miner with another wallet, verify alw swap now / alw view reservation / alw status all auto-clear instead of showing ACTIVE

The "you have a pending reservation" check trusted reserved_until > now,
which conflates "miner is reserved by anyone" with "our reservation is
still live". After a swap completed and another user re-reserved the same
miner, the local file was reported as ACTIVE.

probe_pending_reservation now (1) probes get_miner_active_swaps for our
user addresses first — survives extension and into FULFILLED — then
(2) compares reservation amounts and bounds reserved_until drift by ttl
to distinguish a legitimate extension from a fresh replacement.
probe_pending_reservation was hitting get_miner_active_swaps on every
call from alw status / swap now / view reservation. That helper scans the
swap-id range backward up to max_gap=50 — wasted RPCs for the common case
where the miner has no active swap. Gate it on get_miner_has_active_swap
(single bool read).

Also drop dead try/except around subtensor.get_current_block() in the
two callers that wrapped it: the probe right above already exercised
substrate via client.get_* calls, so the bare read can't fail in
isolation.
@LandynDev LandynDev force-pushed the cli/reservation-staleness-probe branch from f667f26 to 1d75d2c Compare April 28, 2026 20:54
@anderdc anderdc merged commit 7ad2193 into test Apr 28, 2026
3 checks passed
@anderdc anderdc deleted the cli/reservation-staleness-probe branch April 28, 2026 21:02
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.

2 participants