Skip to content

docs(chain,core): document how evictions are inferred - #2362

Open
soma-enyi wants to merge 1 commit into
bitcoindevkit:masterfrom
soma-enyi:docs/document-eviction-inference
Open

soma-enyi wants to merge 1 commit into
bitcoindevkit:masterfrom
soma-enyi:docs/document-eviction-inference

Conversation

@soma-enyi

@soma-enyi soma-enyi commented Oct 9, 2026 •

Copy link
Copy Markdown

Description

The Electrum and Esplora clients record an eviction for every expected txid that is missing from its script's history in a single response. They can't tell "the transaction left the mempool" apart from "the source did not list it". Once last_evicted >= last_seen, the transaction leaves the canonical view and drops out of balances, and the outputs it spent appear unspent again. That includes the wallet's own broadcast transactions. None of this was documented, so callers deciding whether to pass expected txids, or how to treat is_evicted() == true, had to infer the trust placed in the chain source from the implementation.

This PR documents it. Documentation only: no code, signature or behaviour changes.

Fixes #2303

What changed:

  • SyncRequestBuilder::expected_spk_txids: new "Eviction inference" section covering how evictions are inferred, the trust placed in the source, and the trade-off of not passing expected txids.
  • TxUpdate::evicted_ats: an entry means "not observed", not a verified eviction. Notes that bdk_bitcoind_rpc infers evictions differently (it compares getrawmempool results).
  • TxNode::is_evicted: trust in the chain source, effect on the canonical view, balances and spendable outputs, and how a transaction comes back.
  • TxGraph::insert_evicted_at, batch_insert_relevant_evicted_at, their IndexedTxGraph counterparts, list_expected_spk_txids and the tx_graph module docs: cross-references and consistent wording.

Notes to the reviewers

Two statements come from reading the implementation, not from the issue text, so please check them:

  • A tie between last_evicted and last_seen still counts as evicted (>= in TxNode::is_evicted), so a transaction returns only when it is recorded as seen strictly later.
  • An evicted transaction stays canonical if it is anchored, or if it is an ancestor of another canonical transaction (mark_canonical marks ancestors transitively).

Whether the inference should be more conservative (for example requiring an omission across more than one sync) is a behaviour change and out of scope here. I'm happy to follow up separately.

Verified locally:

  • cargo +nightly fmt --all -- --check
  • cargo check --workspace --all-features
  • cargo clippy --all-features --all-targets -- -D warnings
  • RUSTDOCFLAGS='-D warnings' cargo doc --workspace --no-deps

Changelog notice

None. Documentation only.

Checklists

All Submissions:

Bugfixes:

  • This pull request breaks the existing API
  • I've added tests to reproduce the issue which are now passing (nonly)
  • I'm linking the issue being fixed by this PR

@soma-enyi
soma-enyi requested a review from a team as a code owner October 9, 2026 15:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Triage

Development

Successfully merging this pull request may close these issues.

Document that eviction is inferred from a single omission by the chain source

1 participant