Skip to content

fix(electrum): refresh header cache with headers fetched for the chain update - #2319

Open
evanlinjin wants to merge 2 commits into
bitcoindevkit:release/chain-0.23.xfrom
evanlinjin:fix/electrum-stale-header-cache
Open

evanlinjin wants to merge 2 commits into
bitcoindevkit:release/chain-0.23.xfrom
evanlinjin:fix/electrum-stale-header-cache

Conversation

@evanlinjin

Copy link
Copy Markdown
Member

Description

block_header_cache was only written by batch_fetch_anchors, so after a reorg it kept the pre-reorg header for that height. A tx re-mined at the same height then hit the anchor cache under the stale block hash, skipped proof validation, and was never re-anchored to the replacement block. This happens even for a 1-block reorg.

fetch_tip_and_latest_blocks now writes the headers it fetches (the chain suffix and the agreement-walk checkpoints) into the header cache.

Notes to the reviewers

The test covers two cases: syncing right after the reorg (header is in the suffix), and syncing after 20 more blocks (header comes from the agreement walk). Both fail on the base branch. The 20-block case also fails if only the agreement-walk insert is removed.

Related: #2312. That issue points at chain_update, but checkpoints are already corrected by the agreement walk. The stale header cache is what leaves the anchor wrong.

Changelog notice

  • Fixed bdk_electrum returning a stale anchor for a transaction re-mined at the same height after a reorg.

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

🤖 Generated with Claude Code

evanlinjin and others added 2 commits September 18, 2026 09:36
…n update

`block_header_cache` was only written by `batch_fetch_anchors`, so after a
reorg it kept serving the pre-reorg header for that height. The anchor
cache is keyed by `(txid, hash)` from that header, so a tx re-mined at the
same height hit the anchor cache with the stale hash, skipped proof
validation, and was never re-anchored to the replacement block.

`fetch_tip_and_latest_blocks` now writes the headers it fetches (the
chain suffix and the agreement-walk checkpoints) into the header cache.
Checks the tx is re-anchored to the replacement block both when the
reorged height is still in the synced chain suffix and when 20 blocks are
mined before the next sync.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant