---
# System prepended metadata

title: Evan's `bdk_chain` Redesign Analysis and Proposal

---

# Evan's `bdk_chain` Redesign Analysis and Proposal

Consider this an extension of [bdk #895](https://github.com/bitcoindevkit/bdk/issues/895).

## Objectives

* Ensure the redesign allows for better sync integration with LDK. According to @tnull ([on Discord](https://discord.com/channels/753336465005608961/999098651383189554/1087285168491995156)) the most difficult part is Esplora/Electrum sync due to the assumptions about the order of data that is passed on to LDK (refer to the [docs about Order of the `Confirm` trait](https://docs.rs/lightning/0.0.114/lightning/chain/trait.Confirm.html#order)).
* Ensure the redesigned structures allow for an intuitive sync flow for Esplora/Electrum.
* Ensure the redesign still allows for us to keep a copy of "blockchain checkpoint" data locally in a manner that is intuitive.

## How does BDK fit in with LDK?

The diagram below is a subset of the LDK architecture (and the only portion that we should care about now).

![](https://i.imgur.com/W4bKzRM.png)

The *Chain Monitor* implements the [`Confirm`](https://docs.rs/lightning/0.0.114/lightning/chain/trait.Confirm.html) and [`Listen`](https://docs.rs/lightning/0.0.114/lightning/chain/trait.Listen.html) traits which provides methods that *Chain Source* should invoke to notify *Chain Monitor* of chain data.

* [`Confirm`](https://docs.rs/lightning/0.0.114/lightning/chain/trait.Confirm.html) is geared towards transaction-oriented APIs (esplora and electrum).
* [`Listen`](https://docs.rs/lightning/0.0.114/lightning/chain/trait.Listen.html) is geared towards block-oriented APIs (CBF, Bitcoin Core Chain).

*Chain source* is the component that may use BDK internally (whether it be `bdk_chain`, `bdk_esplora`, `bdk_electrum`, etc.).

[`Filter`](https://docs.rs/lightning/0.0.114/lightning/chain/trait.Filter.html) is a trait that *Chain Source* should implement if it sources from a light client. This way, *Chain Monitor* can invoke `Filter` methods to inform *Chain Source* what data to filter for.

### Syncing from `bitcoind` RPC

This should be straight-forward. We stream block events from `bitcoind` into both BDK's `bdk_chain` structures and LDK's `Listen` methods.

### Syncing from CBF (with Nakamoto)

This is similar to `bitcoind` RPC, except we should "listen" for `Filter` invocations that we use to construct block filters that is pass on to the Nakamoto client. We can then pass filtered blocks into `Listen::filtered_block_connected`.

It may make sense to use separate compact block filters for BDK vs LDK data.

### Syncing from Electrum/Esplora

Looking at [`lightning_transaction_sync::esplora::EsploraSyncClient`](https://github.com/lightningdevkit/rust-lightning/blob/main/lightning-transaction-sync/src/esplora.rs), it will be ideal to have a version of this that also collects data for BDK in the same loop.

Essentially, proper LDK and BDK integration does not rely on special features with `bdk_chain`. LDK already keeps note of txids and outpoints that it wants updates for.

## `LocalChainOracle`

This is essentially a super-simplified version of the current `SparseChain` (or [`#895`'s](https://github.com/bitcoindevkit/bdk/issues/895) `SparseChain2` as mentioned in the work plan).

The intention of this design is to ensure Esplora/Electrum sync works smoothly with the redesigned workflow. However, any data source can update this structure if the user intends on not depending on an external `ChainOracle`.

```rust
struct LocalChainOracle { /* internal fields */ }

impl ChainOracle for LocalChainOracle { /* todo */ }

impl LocalChainOracle {
    
}
```

~~TODO: I'm just too tired to finish this. At least we know that the redesign will work fine with LDK.~~ I thought about it over night, we are reusing the `SparseChain` logic with checkpoints only. This is an ultimate simplification and good as it is as we do not need to check for conflicting transactions, or invalid "transaction movements".

## Syncing in detail

### Electrum: Full Scan

1. Collect all heights of `LocalChain`. Collect all `txid`s from `TxGraph`.
    ```rust
    pub fn scan(heights: BTreeSet<u32>, txids: HashSet<Txid>) -> ElectrumUpdate { todo!() }
    ```
3. Get chain tip from Electrum.
4. Collect transactions into structure:
    ```rust
    struct ElectrumUpdate {
        /// Txids to confirmation height (if any).
        pub txs: HashMap<Txid, Option<u32>>,
        
        /// Used for updating `LocalChain`.
        ///
        /// Blocks with at least one relevant tx confirmed must be included here, unless if height is lower than `heights.last() - 10` and height is included in `heights`.
        pub blocks: BTreeMap<u32, BlockHash>,
    }
    ```
5. Ensure chain tip still exists in best chain after `ElectrumUpdate` is finalized.