Skip to content

release: 0.6.0, the tracker hosted (the served poll gone, the spender bound, the gift claim the wallet's own); the toolbox 0.6.0 - #11

Merged
Calgooon merged 8 commits into
mainfrom
cli-0.6.0/release
Oct 9, 2026
Merged

Calgooon merged 8 commits into
mainfrom
cli-0.6.0/release

Conversation

@Calgooon

@Calgooon Calgooon commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

The owner's calls of 2026-10-09 (bsv-stack-lean docs/RULINGS-2026-10-09.md, E1 to E4, decided by the captain after the north star): the CLI hosts bsv-tracker 0.1.0 from crates.io with the four host things, the state in the wallet database and tracker-tick; the served loop's 60 s chain-index probe is gone; a spender named by a provider is bound to the outpoint by its own bytes before the proof; gift-claim --force holds a not-final claim as the tracker's and re-asks at the lock time; gift-claim records its own claim and the gift flow names no chain scan. The toolbox pin moves to 0.6.0 (a stranger's spend only by proof; an unspent answer a hint): the probe reads UnspentHint, a SpentHint names no spender and is left to the cadence. 323 tests, clippy, fmt at f4b4273 on the captain's host (bsv-stack-lean docs/p0/cli-0.6.0-tracker.md). serve no longer retires a transaction a broadcaster accepted but the network never showed; reconcile-broadcasts by hand stays the explicit act.

🤖 Generated with Claude Code

Calgooon and others added 8 commits October 9, 2026 13:08
The manifest and the lock only. The tracker is at Calhooon/bsv-tracker main
99a9ae9, not yet on crates.io; the CLI takes it from the local clone until it
publishes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tes (E1)

A provider's "spent by X" is a word. Before X is asked for a proof and before
`confirmed`, X's bytes are read through `get_raw_tx`: they must hash to X and
hold the outpoint among their inputs. Bytes that could not be read leave
`Unknown` (never released); bytes that spend something else mean the provider
named no spender, and the probe falls through to the unspent question.

Witness: a_named_spender_is_bound_to_the_outpoint_by_its_own_bytes. Red at
9235de5: SpentBy { confirmed: true } for a mined transaction that spends
another outpoint. Green.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…l is gone (E3)

The served loop asked WhatsOnChain and Bitails every 60 s about every unproven
transaction. The answer it waited for was "mined", and that is a proof. The
loop now runs the transaction tracker's pass in its place and asks no chain
index.

The host (src/tracker_host.rs) supplies the tracker's four things: Headers
(a snapshot of the header service's tip and the headers a pass names, failing
closed), ProofFetcher (get_merkle_path for one named transaction), HintSource
(the wallet's broadcast memory rows, each word fed once) and Clock. The state
is in the wallet's own database (tracker_states): the hints heard and the raw
merkle path, never a trusted word; a stored path is checked again against the
active header every time its row is read. A checked proof is handed to the
wallet's storage through its one proof funnel (ingest_merkle_proof).

A pass tracks the wallet's own unproven transactions, feeds the new hints,
ticks the clock, and runs the re-asks that are due: one proof request for one
transaction, the pause doubling between two asks (TRACKER_AGE_SECS, default
600; TRACKER_MAX_ASKS, default 20). A mined row is read again only when a
header at or below its height moved (the last twelve tips are kept) or when
the spend guard is run for it.

New: `bsv-wallet tracker-tick`, one pass. `serve` and `serve-fleet` run the
same pass every 60 s, then the sweep of the verdicts already in storage and
the locked-input re-checks.

No longer routine: retiring a transaction because the chain indexes do not
know it. `reconcile-broadcasts` (by hand) is the one caller left of that
probe. BROADCAST_RECONCILE_MAX_PROBES and BROADCAST_RECONCILE_MAX_LOCKED_CHECKS
are no longer read by the served loop.

Witness: the_served_pass_asks_for_a_proof_and_never_a_chain_index. Red at
9235de5: the served pass requested /tx/hash/{txid} of the chain index. Green,
with four tests of the host, the tracker README's wallet spend guard run as
the host among them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sks at the lock time (E2)

A forced claim went to the wallet's broadcasters, and a broadcaster that
called it not final (ARC and Arcade's 476) made the command fail with nothing
kept. The claim is a transaction this wallet built, so the tracker now holds
it from the moment it is handed over, and the command prints the tracker's
word in place of an explorer link.

- Accepted: the acceptance is a hint, the word is `announced`. Before the
  lock time no proof can exist, so nothing is asked about it until then.
- Called not final, with --force, before the lock time: not a failure. The
  refusal is a hint (the word stays `built`, with a re-ask); the claim is
  kept with its BEEF and handed to the broadcasters again at the lock time by
  the tracker's pass (`serve`'s loop, or `tracker-tick`). "Not final" again
  waits one pause (the node reads the median time past, behind our clock),
  sixteen times at most.
- Any other refusal, or "not final" without --force or past the lock time:
  the error it was, saying what they said.

gift-claim's JSON gains word, reask, heldUntil and notFinal; broadcast is
null when no broadcaster took the claim.

Witness: a_forced_claim_called_not_final_is_tracked_and_re_asked_at_the_lock_time.
Red at 980b1e9: "broadcast rejected by every broadcaster (Arcade: 476
non-final)". Green, with the host's own test of the re-announce.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The gift flow sent the recipient to `bsv-wallet sync`, an address scan of the
chain, to learn that a claim this wallet had just made had landed. The
wallet's storage is the verdict for its own actions: gift-claim now
internalizes the claim from the BEEF it already holds (the deposit with its
checked proof, and the claim), naming every output that pays the deposit
script as a payment to the deposit key. The coins are spendable balance the
moment a broadcaster takes the claim.

A claim held as not final (--force before the lock time) is not out, so it is
not recorded then: its internalize arguments are kept with its BEEF, and the
caller that holds the wallet (`serve`'s loop, `tracker-tick`) records it when
a re-announce is accepted.

If the wallet cannot record the claim (a deposit whose proof no courier
delivered), the claim is still out; the command says so and names
`bsv-wallet receive <claim txid>`, by txid, never the scan.

gift-claim's JSON gains recorded and recordError. gift-inspect, the deposit
key's doc and GIFT.md no longer name `sync`; GIFT.md's funding step names
`receive <txid>`.

Witness: gift_claim_records_its_own_claim_and_the_flow_names_no_chain_scan.
Red at 8243dfd: 0 satoshis in the wallet's storage after the claim (5844
expected). Green, with the held claim's test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… bound, the gift claim the wallet's own)

The CLI hosts the transaction tracker (bsv-tracker 0.1.0). Needs
bsv-wallet-toolbox-rs 0.5.0, as 0.5.0 did.

1. The spend probe binds a named spender to the outpoint by the spender's
   own bytes before it asks for the proof and before `confirmed`
   (cleanup-abandoned, reconcile-outputs, the daemon's sweep,
   sync --reconcile-spent). A provider naming some other mined transaction
   no longer relinquishes an output.
2. `serve` and `serve-fleet` no longer ask WhatsOnChain and Bitails every
   60 s about every unproven transaction. The loop runs the tracker's pass:
   each of the wallet's unproven transactions holds a word; a broadcaster's
   word is a hint; a merkle proof is asked for one named transaction when a
   hint disagrees or its age is due, and only a proof checked against the
   header service writes `mined`. New command: `bsv-wallet tracker-tick`.
   New settings: TRACKER_AGE_SECS (600), TRACKER_MAX_ASKS (20).
3. `gift-claim --force`: a broadcaster calling the claim not final is not a
   failure. The claim is kept and announced again at the lock time by the
   tracker's pass. The command prints the tracker's word.
4. `gift-claim` records its own claim in the wallet. The gift flow no
   longer names `sync`.

What an operator sees:

- The wallet database gains two tables, tracker_states and tracker_meta,
  created on the first pass. 0.5.0 ignores them.
- `serve` no longer retires a transaction because the chain indexes do not
  know it. `bsv-wallet reconcile-broadcasts` does that, by hand; each pass
  lists the transactions it asked a proof for and got none.
- BROADCAST_RECONCILE_MAX_PROBES and BROADCAST_RECONCILE_MAX_LOCKED_CHECKS
  are no longer read by the served loop (the sweep re-checks 20 locked
  inputs a pass, the default it had).
- gift-claim's JSON: `broadcast` is null when no broadcaster took the
  claim; new fields word, reask, heldUntil, notFinal, recorded, recordError.

Rollback: install 0.5.0; the two tables are left unread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… answer a hint): the probe reads UnspentHint, a SpentHint names no spender and is left to the cadence

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@Calgooon
Calgooon merged commit 7d48f5c into main Oct 9, 2026
6 checks passed
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