Skip to content

Make bdk_bitcoind_rpc emitters support any checkpoint data type#2105

Draft
evanlinjin wants to merge 3 commits intobitcoindevkit:masterfrom
evanlinjin:feature/bitcoind_rpc_emit_header
Draft

Make bdk_bitcoind_rpc emitters support any checkpoint data type#2105
evanlinjin wants to merge 3 commits intobitcoindevkit:masterfrom
evanlinjin:feature/bitcoind_rpc_emit_header

Conversation

@evanlinjin
Copy link
Member

@evanlinjin evanlinjin commented Jan 26, 2026

Description

Make bdk_bitcoind_rpc emitters support emitting CheckPoint updates with both BlockHash and Header data. To make this easier to implement, a bdk_core::fromBlockHash trait is introduced.

Rationale

I think BDK should move towards making Header the most-used checkpoint data type (so chain-sources should be able to output that!). This allows us to accurately calculate time (MTP), provides the merkle root for verification (maybe anchors in the future can include the merkle proof), and provides the prev_blockhash value.

However, we cannot force this change as users may want persisted data to be compatible with newer versions of BDK (and retain their BlockId-based persistence data).

Changelog notice

Added
- `FromBlockHash` trait which `BlockHash` and `Header` implement. This makes it easier for chain-sources to output `CheckPoint` updates with both types of data (and more in the future).
- `bdk_bitcoind_rpc` emitters now have new methods for emitting events with custom "checkpoint data" types.

Changed
- `bdk_bitcoind_rpc` emitters now have generic types for "checkpoint data" with backwards compatible defaults.

Checklists

All Submissions:

New Features:

  • I've added tests for the new feature
  • I've added docs for the new feature

@luisschwab
Copy link
Member

This couples nicely with Floresta, since we already keep a chain of headers. Cool idea.

…dress

Refactor block mining in `TestEnv` to use `getblocktemplate` RPC properly:

- Add `MineParams` struct to configure mining (empty blocks, custom
  timestamp, custom coinbase address)
- Add `mine_block()` method that builds blocks from the template with
  proper BIP34 coinbase scriptSig, witness commitment, and merkle root
- Add `min_time_for_next_block()` and `get_block_template()` helpers
- Refactor `mine_empty_block()` to use the new `mine_block()` API
- Include mempool transactions when `empty: false`
@ValuedMammal
Copy link
Collaborator

Proposal - Make FilterIter generic over the checkpoint data type D

Add fetch_data member field to FilterIter

pub struct FilterIter<'a, D> {
    /// User provided closure which defines the method of fetching checkpoint data `D`.
    fetch_data: Box<FetchData<D>>,
    
    // ...
}

/// Type representing the "fetch data" closure.
type FetchData<D> = dyn Fn(&Client, &BlockHash) -> Result<D, Error> + 'static;

Change constructor to take a user-provided fetch_data closure.

pub fn new(
    client: &'a bitcoincore_rpc::Client,
    cp: CheckPoint<D>,
    spks: impl IntoIterator<Item = ScriptBuf>,
    fetch_data: impl Fn(&Client, &BlockHash) -> Result<D, Error> + 'static,
) -> Self {
    Self {
        client,
        spks: spks.into_iter().collect(),
        cp,
        header: None,
        fetch_data: Box::new(fetch_data),
    }
}

Update next function to fetch the checkpoint data D given a reference to the RPC client and the next block hash.

let next_data = (self.fetch_data)(self.client, &next_hash)?;
cp = cp.insert(next_height, next_data);

For example

The current, non-generic implementation can be achieved by passing a function that simply returns the next hash unchanged. For more complex data types, e.g. Header, the RPC client can be used to fetch it.

fn fetch_blockhash() -> impl Fn(&Client, &BlockHash) -> Result<BlockHash, Error> {
    |_client, &hash| Ok(hash)
}

fn fetch_header() -> impl Fn(&Client, &BlockHash) -> Result<Header, Error> {
    |client, hash| client.get_block_header(hash).map_err(Error::Rpc)
}

This allows us to use any subset of a `Header` to construct checkpoint
data. Currently, only `BlockHash` and `Header` implement this.

Chain sources can bound the checkpoint data generic to this trait, so all
checkpoint data types that implement `FromBlockHeader` is supported by
the chain source.
@evanlinjin evanlinjin force-pushed the feature/bitcoind_rpc_emit_header branch from cd404c6 to 912d0f7 Compare January 29, 2026 03:57
@evanlinjin evanlinjin force-pushed the feature/bitcoind_rpc_emit_header branch from 912d0f7 to b76cb25 Compare January 29, 2026 10:07
@oleonardolima oleonardolima moved this to In Progress in BDK Chain Feb 2, 2026
@oleonardolima oleonardolima added module-blockchain api A breaking API change labels Feb 2, 2026
@oleonardolima oleonardolima self-requested a review February 2, 2026 15:37
Comment on lines +58 to +62
/// Trait that converts [`Header`] to subset data.
pub trait FromBlockHeader {
/// Returns the subset data from a block `header`.
fn from_blockheader(header: Header) -> Self;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@evanlinjin Can you clarify why the new trait it's really need ? Can't we achieve the same by just implementing ToBlockHash for Header ? (I'll do another round to better understand it)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want Header -> checkpoint data. So a chain-source crate can provide the Header, and the checkpoint data can be made from that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api A breaking API change module-blockchain

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

4 participants