fix: refuse BTC source send when reservation TTL is too short to extend (#315)#328
Open
Khaostica wants to merge 4 commits into
Open
fix: refuse BTC source send when reservation TTL is too short to extend (#315)#328Khaostica wants to merge 4 commits into
Khaostica wants to merge 4 commits into
Conversation
…nd (entrius#315) PR entrius#316 added validator-side auto-extension of reservations on tx visibility, but the CLI never refused to broadcast when the remaining TTL was already below the floor required for that extension flow to fire. Users could (and did, per entrius#315) send BTC into a reservation that was mechanically doomed to expire before any propose tx could clear its challenge window — losing funds when the swap never initiated. Add a preflight check that reads current_block at send-time and classifies remaining TTL into ok / extension_required / too_short against EXTEND_THRESHOLD_BLOCKS + a small propagation buffer. The new swap and resume-reservation flows hard-refuse below the floor and soft-warn (require explicit confirm) when validators will need to auto-extend. Implements solutions entrius#3 and entrius#5 from entrius#315. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Originally the gate lived inside swap.py, which transitively imports bittensor — so unit tests covering the click.confirm wiring couldn't be written without spinning up the whole CLI stack. Moves the function to allways/cli/preflight.py (outside swap_commands/ so importing it doesn't trigger that package's eager command-registration __init__.py) and adds tests/test_preflight_send_runway.py covering the seven branch combinations: ok / too_short / extension_required × skip_confirm. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Stronger version of test_ok_runway_passes_silently — the previous assertion only covered click.confirm. Now also patches the module's _console and asserts .print was never called, so the test catches any future regression that adds chatter to the happy-path swap. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CONTRIBUTING.md requires ruff with E/F/I rules and ruff format. The new allways.cli.preflight import in swap.py and resume.py wasn't in the right alphabetical slot, and the new preflight module + test file had a few multi-line statements the formatter wanted collapsed onto one line. No behavior change — purely cosmetic. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add a CLI-side preflight that classifies remaining reservation TTL at send time and refuses to broadcast source funds into a reservation the validator auto-extension flow cannot rescue. Closes #315.
Problem
alw swap now --from btc --to taocould successfully reserve a miner and broadcast the BTC source transaction, then fail to initiate any on-chain swap because the reservation expired before the required BTC confirmations arrived. Per #315, a user sent 0.00018 BTC against a 50-block (~10 min) reservation — BTC needs 2 confirmations (~20 min), so the reservation expired before the tx confirmed and no TAO was delivered.#316 addressed two of the five proposed mitigations: it dropped BTC
min_confirmationsfrom 3 → 2 and added validator-side auto-extension that fires when the source tx becomes visible. But the auto-extension has a hard prerequisite — validators need at leastEXTEND_THRESHOLD_BLOCKS(~18 blocks ≈ 3.6 min) of runway to land their propose tx and let its challenge window close (allways/validator/optimistic_extensions.py:97). Below that the propose is mechanically doomed and the reservation expires anyway. The CLI never checked this, so users could broadcast into a reservation no validator could rescue.What Changed
classify_send_runway()inallways/chains.py— pure classifier returningok/extension_required/too_shortbased on remaining TTL vsEXTEND_THRESHOLD_BLOCKSplus a 5-block (~1 min) propagation buffer.preflight_send_runway()in a newallways/cli/preflight.pymodule (placed outsideswap_commands/so importing it doesn't trigger that package's eager command-registration__init__.pychain, which pulls inbittensorviahelpers).alw swap now(after the "Send now?" confirmation) andalw swap resume-reservation --send, re-readingcurrent_blockat send time so an idle user at the summary panel doesn't bypass the check.too_short: hard refusal, suggests starting fresh — overrides--yesto avoid scripted callers silently losing funds.extension_required: warns the validator auto-extension will need to kick in, requires explicit re-confirm (default no) in interactive mode, passes through in--yes.ok: silent passthrough (no prompt, no print).Implements solutions #3 ("prevent auto-send when required confirmations cannot fit inside reservation TTL") and #5 ("surface a hard preflight error instead of a warning") from #315.
Tests
tests/test_chains.py::TestClassifySendRunway— 7 cases covering the classifier's three bands, the BTC vs TAO confirmation-window difference, exact-floor boundary, zero remaining, and already-expired (negative remaining).tests/test_preflight_send_runway.py— 7 cases covering the wiring: subtensor re-read at send time, branch routing per band, and theskip_confirmcontract (refuses ontoo_shorteven in--yes; passes throughextension_requiredin--yes). The OK band asserts bothclick.confirmandconsole.printare untouched, so any future regression that adds chatter to the happy-path swap fails the test.Verification: