Skip to content

fix(electrum,esplora): retain only unobserved txids in evicted_ats - #2467

Open
AlphaSparrow wants to merge 1 commit into
bitcoindevkit:masterfrom
AlphaSparrow:fix/prevent-false-evictions-on-seen-tx
Open

AlphaSparrow wants to merge 1 commit into
bitcoindevkit:masterfrom
AlphaSparrow:fix/prevent-false-evictions-on-seen-tx

Conversation

@AlphaSparrow

Copy link
Copy Markdown

Description

Fixes #2271.

When multiple script pubkeys in a SyncRequest or FullScanRequest expect a transaction (e.g. from an unconfirmed incoming transaction or wallet history), scripts that do not observe the transaction in their history populate tx_update.evicted_ats with (txid, start_time). If another script within the same sync pass observes the transaction, tx_update.seen_ats (or tx_update.anchors) is also populated with (txid, start_time).

Because TxNode::is_evicted() evaluates last_evicted >= last_seen, emitting equal timestamps for both seen and evicted marks the transaction as evicted, causing it to be hidden from canonical_view and unconfirmed transaction listings even though it was observed during that sync pass.

This PR ensures that bdk_electrum and bdk_esplora sanitize tx_update.evicted_ats before returning: any transaction observed in seen_ats or anchors during the sync pass is removed from evicted_ats.

Notes to the reviewers

  • Added integration test test_sync_does_not_evict_tx_seen_on_another_spk in crates/electrum/tests/test_electrum.rs. It reproduces the failure when two SPKs expect the same txid and only one observes it.
  • Note on Esplora: I could not get the esplora integration tests to build locally, so the esplora change is covered only by the same logic as the Electrum test. Happy to add a test if someone can point me to the right setup.
  • Producer-side sanitization prevents clients from emitting contradictory TxUpdates without requiring modifications to TxGraph tie semantics in bdk_chain.

Test output:

running 1 test
test test_sync_does_not_evict_tx_seen_on_another_spk ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 12 filtered out; finished in 6.96s

Changelog notice

Fixed

Checklists

All Submissions:

Bugfixes:

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

When multiple SPKs in a sync or full_scan request expect a transaction, an SPK that does not find the transaction in its history populates evicted_ats with (txid, start_time). If another SPK in the same sync pass finds the transaction, seen_ats (or anchors) is also populated with the same timestamp.

Because TxNode::is_evicted() treats last_evicted >= last_seen as evicted, emitting equal timestamps marks the transaction as evicted, causing it to be hidden from canonical_view and unconfirmed transaction lists.

This prunes any transactions present in seen_ats or anchors from evicted_ats before returning the response in both bdk_electrum and bdk_esplora.

Fixes bitcoindevkit#2271
@AlphaSparrow
AlphaSparrow requested a review from a team as a code owner November 11, 2026 06:25
@github-project-automation github-project-automation Bot moved this to Triage in BDK Chain Nov 11, 2026
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.

Equal seen_at and evicted_at within one sync hides present tx

1 participant