Skip to content

Optionally emit prev-11 block headers per confirmation block and chain tip (for MTP) #2199

Description

@evanlinjin

Depends on #2200 — the on-demand height fetch primitive. The opt-in mode described here can be implemented in terms of that primitive.

Context

LocalChain<Header>::canonicalize_with_mtp computes median-time-past (MTP) for each confirmed transaction and for the chain tip (Canonical::tip_mtp). MTP at height N is the median of timestamps from the 11 blocks preceding N, so the local chain must contain headers for heights N-11..N at minimum. If those headers aren't present, MTP can't be computed for that block.

Today, the chain source crates only emit the confirmation block when reporting a confirmed tx, and only the tip itself for the chain tip. Downstream callers wanting MTP have to fetch the preceding 11 headers themselves, which is awkward and easy to get wrong.

Goal

Add an opt-in mode to each chain source that also emits the 11 blocks preceding:

  1. Every confirmation block (so per-tx MTP is computable), and
  2. The chain tip (so tip_mtp is computable).

A LocalChain<Header> populated from the source should then have everything canonicalize_with_mtp needs without extra caller-side fetches.

Scope

  • bdk_electrum
  • bdk_esplora
  • bdk_bitcoind_rpc

Design notes

  • Opt-in via builder/constructor flag. Most callers don't need MTP and shouldn't pay the extra round-trips. Each crate should expose this through whatever builder or constructor API it already has.
  • Dedup overlapping windows. A confirmation near the tip will share most of its prev-11 window with the tip's prev-11. Ditto two confirmations close in height. The source should fetch and emit each prev header at most once per sync.
  • Already-known headers. If a header is already in the caller's LocalChain, it shouldn't be refetched — accept a "known heights" filter or expose enough that the caller can dedupe.
  • Reorg safety. Prev-11 headers must be tied to the same chain as the block they're preceding; if the confirmation or tip reorgs, the prev-11 emission for the old branch must be invalidated too.

Acceptance criteria

  • Each crate exposes a builder/constructor flag to enable prev-11 emission.
  • With it enabled, populating a LocalChain<Header> from the source is sufficient to call canonicalize_with_mtp and get Some(_) MTPs for all confirmed txs and for the tip.
  • Test covering: a confirmation at height N results in headers N-11..N present in the resulting chain.
  • Test covering: a chain tip at height T results in headers T-11..T present in the resulting chain.
  • Test covering: two confirmations within 11 blocks of each other (or a confirmation within 11 blocks of the tip) don't trigger duplicate header fetches.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Discussion

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions