]> Untitled Git - bdk/commit
Merge bitcoindevkit/bdk#2038: refactor(chain,core)!: replace `CanonicalIter` with... master github/master
authormerge-script <oleonardolima@users.noreply.github.com>
Mon, 15 Jun 2026 12:42:14 +0000 (09:42 -0300)
committermerge-script <oleonardolima@users.noreply.github.com>
Mon, 15 Jun 2026 12:42:14 +0000 (09:42 -0300)
commit023fdf0fa7ad89e34035bdcc49af3748761d56a7
treebd3c4fe703b61015b1f69c9a01819b85a4b86a6f
parent47556ab7094c6af5c500eda9c9fa43f6d1804563
parent555f774169ea934dbb2934f2fbe6763908e86670
Merge bitcoindevkit/bdk#2038: refactor(chain,core)!: replace `CanonicalIter` with sans-IO `CanonicalTask` + `ChainQuery` trait

555f774169ea934dbb2934f2fbe6763908e86670 fix(chain): position resolution for assumed txs (Leonardo Lima)
4f10cdef4d55139ee7f608d9cf90ff8d9c0b3037 chore(chain,example)!: remove `ChainOracle`, update docs (志宇)
a3c73e4685f3381b5b1ae799c2279009b6f7d1ea refactor(chain)!: split `canonical_view` into `canonical`,`canonical_view_task` (志宇)
22b04c33dc0b75e5a247f99087ad36f41e99a0ed refactor(chain)!: split canonicalization into two tasks with generic `Canonical<A, P>` (志宇)
a9f5ca4415af36b42cca43551414ad0644d627b8 refactor(chain)!: remove `CanonicalIter` APIs (Leonardo Lima)
bb83da8260fb167fa548f31c12710153095e9064 chore(workspace): use new `LocalChain::canonical_view` API (Leonardo Lima)
987da73fce7b7f4e015aa05cc8fa4e36deebf4df feat(core,chain): introduce `CanonicalizationTask` and `ChainQuery` (Leonardo Lima)

Pull request description:

  fixes #1816

  ### Description

  Replaces the iterator-based `CanonicalIter` with a two-phase sans-IO canonicalization pipeline, and introduces a generic `ChainQuery` trait in `bdk_core` to decouple canonicalization from chain sources.

  **Old API:**
  ```rust
  // Direct coupling between canonicalization logic and ChainOracle
  let view = tx_graph.canonical_view(&chain, chain_tip, params)?;
  ```

  **New API:**
  ```rust
  // Option A: Two-phase (full control)
  let canonical_txs = chain.canonicalize(tx_graph.canonical_task(tip, params));
  let view = chain.canonicalize(canonical_txs.view_task(&tx_graph));

  // Option B: Convenience method
  let view = chain.canonical_view(&tx_graph, tip, params);
  ```

  #### Phase 1: `CanonicalTask`
  Determines which transactions are canonical by processing them in stages:
  1. **Assumed txs** — transactions assumed canonical via `CanonicalParams`
  2. **Anchored txs** — transactions anchored in the best chain (descending height)
  3. **Seen txs** — unconfirmed transactions by descending last-seen time
  4. **Remaining txs** — leftover anchored transactions not in the best chain

  Produces a `CanonicalTxs<A>` containing each canonical transaction with its `CanonicalReason`.

  #### Phase 2: `CanonicalViewTask`
  Resolves `CanonicalReason`s into concrete `ChainPosition`s (confirmed height or unconfirmed with last-seen), producing the final `CanonicalView<A>`.

  Both phases implement the `ChainQuery` trait, so any chain source can drive them via the same `next_query`/`resolve_query` loop.

  #### Key structural changes

  - **`ChainQuery` trait** added to `bdk_core` — a generic sans-IO interface (`next_query` → `resolve_query` → `finish`) for any algorithm that needs to verify blocks against a chain source.
  - **`ChainOracle` trait removed** — replaced by `ChainQuery`. `LocalChain::canonicalize()` now drives any `ChainQuery` implementor.
  - **`Canonical<A, P>` generic container** — `CanonicalTxs<A>` (phase 1 output) and `CanonicalView<A>` (phase 2 output) are type aliases over `Canonical<A, P>`.
  - **Module split** — `canonical_view.rs` split into `canonical.rs` (types: `Canonical`, `CanonicalTx`, `CanonicalTxOut`) and `canonical_view_task.rs` (phase 2 task). `canonical_iter.rs` replaced by `canonical_task.rs`.

  ### Notes to the reviewers

  The changes are split into multiple commits for easier review. Also depends on #2029.

  ### Changelog notice

  ```
    ### Added
    - `bdk_core::ChainQuery` trait — generic sans-IO interface for chain verification queries
    - `bdk_core::ChainRequest` / `ChainResponse` type aliases
    - `CanonicalTask` — phase 1 sans-IO canonicalization (determines canonical txs)
    - `CanonicalViewTask` — phase 2 sans-IO canonicalization (resolves chain positions)
    - `Canonical<A, P>` generic container with `CanonicalTxs<A>` and `CanonicalView<A>` aliases
    - `LocalChain::canonicalize()` — drives any `ChainQuery` implementor
    - `LocalChain::canonical_view()` — convenience method for full two-phase canonicalization

    ### Changed
    - **Breaking:** Replace `TxGraph::canonical_iter()` / `TxGraph::canonical_view()` with `TxGraph::canonical_task()`
    - **Breaking:** Canonicalization now uses a two-phase sans-IO process via `ChainQuery`
    - **Breaking:** `ChainQuery`, `ChainRequest`, `ChainResponse` have no generics (use `BlockId` directly)
    - **Breaking:** Chain tip moved from `ChainRequest` to `ChainQuery::tip()`

    ### Removed
    - **Breaking:** `ChainOracle` trait and all implementations
    - **Breaking:** `CanonicalIter` type and `canonical_iter` module
    - **Breaking:** `TxGraph::try_canonical_view()` and `TxGraph::canonical_view()` methods
    - **Breaking:** `CanonicalView::new()` public constructor
  ```

  ### Checklists

  #### All Submissions:

  * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)

  #### New Features:

  * [x] I've added tests for the new feature
  * [x] I've added docs for the new feature

ACKs for top commit:
  evanlinjin:
    ACK 555f774169ea934dbb2934f2fbe6763908e86670

Tree-SHA512: ce466a623a1f8df20dedd3e4e68460892bd369567db44e6ba391c3d9ae1d10bca6204ebdcdb7b1376a9c97f3155b89e991846af4122e200d1fa15d998deb7830