]> Untitled Git - bdk/commitdiff
refactor(chain)!: Change trust_predicate to accept FullTxOut
author志宇 <hello@evanlinjin.me>
Wed, 17 Sep 2025 23:46:29 +0000 (23:46 +0000)
committerLeonardo Lima <oleonardolima@users.noreply.github.com>
Wed, 24 Sep 2025 01:22:59 +0000 (11:22 +1000)
BREAKING CHANGE: The trust_predicate parameter in CanonicalView::balance()
now takes &FullTxOut<A> instead of ScriptBuf as its second argument.

This provides more context to the predicate function.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
crates/chain/src/canonical_view.rs
crates/chain/tests/test_canonical_view.rs
crates/chain/tests/test_indexed_tx_graph.rs
crates/chain/tests/test_tx_graph_conflicts.rs

index b24dbb2d83da5ca345e15e56dd5e2857f41fec7b..09b18e50a19dd054da8a5ac8b9ed797b6a69f7f7 100644 (file)
@@ -60,12 +60,12 @@ pub struct CanonicalTx<A> {
 /// provides methods to query transaction data, unspent outputs, and balances.
 ///
 /// The view maintains:
-/// - An ordered list of canonical transactions (WIP)
+/// - An ordered list of canonical transactions in topological-spending order
 /// - A mapping of outpoints to the transactions that spend them
 /// - The chain tip used for canonicalization
 #[derive(Debug)]
 pub struct CanonicalView<A> {
-    /// Ordered list of transaction IDs in canonical order.
+    /// Ordered list of transaction IDs in in topological-spending order.
     order: Vec<Txid>,
     /// Map of transaction IDs to their transaction data and chain position.
     txs: HashMap<Txid, (Arc<Transaction>, ChainPosition<A>)>,
@@ -357,7 +357,7 @@ impl<A: Anchor> CanonicalView<A> {
     pub fn balance<'v, O: Clone + 'v>(
         &'v self,
         outpoints: impl IntoIterator<Item = (O, OutPoint)> + 'v,
-        mut trust_predicate: impl FnMut(&O, ScriptBuf) -> bool,
+        mut trust_predicate: impl FnMut(&O, &FullTxOut<A>) -> bool,
         min_confirmations: u32,
     ) -> Balance {
         let mut immature = Amount::ZERO;
@@ -378,7 +378,7 @@ impl<A: Anchor> CanonicalView<A> {
 
                     if confirmations < min_confirmations {
                         // Not enough confirmations, treat as trusted/untrusted pending
-                        if trust_predicate(&spk_i, txout.txout.script_pubkey) {
+                        if trust_predicate(&spk_i, &txout) {
                             trusted_pending += txout.txout.value;
                         } else {
                             untrusted_pending += txout.txout.value;
@@ -390,7 +390,7 @@ impl<A: Anchor> CanonicalView<A> {
                     }
                 }
                 ChainPosition::Unconfirmed { .. } => {
-                    if trust_predicate(&spk_i, txout.txout.script_pubkey) {
+                    if trust_predicate(&spk_i, &txout) {
                         trusted_pending += txout.txout.value;
                     } else {
                         untrusted_pending += txout.txout.value;
index 5d6740ac56929fc707da0021cda0edaf038fe3c4..3c0d54381c263a81079b48d568da9d7b6c156292 100644 (file)
@@ -1,29 +1,30 @@
 #![cfg(feature = "miniscript")]
 
+use std::collections::BTreeMap;
+
 use bdk_chain::{local_chain::LocalChain, CanonicalizationParams, ConfirmationBlockTime, TxGraph};
 use bdk_testenv::{hash, utils::new_tx};
-use bitcoin::{Amount, OutPoint, ScriptBuf, Transaction, TxIn, TxOut};
+use bitcoin::{Amount, BlockHash, OutPoint, ScriptBuf, Transaction, TxIn, TxOut};
 
 #[test]
 fn test_min_confirmations_parameter() {
     // Create a local chain with several blocks
-    let chain = LocalChain::from_blocks(
-        [
-            (0, hash!("block0")),
-            (1, hash!("block1")),
-            (2, hash!("block2")),
-            (3, hash!("block3")),
-            (4, hash!("block4")),
-            (5, hash!("block5")),
-            (6, hash!("block6")),
-            (7, hash!("block7")),
-            (8, hash!("block8")),
-            (9, hash!("block9")),
-            (10, hash!("block10")),
-        ]
-        .into(),
-    )
-    .unwrap();
+    let blocks: BTreeMap<u32, BlockHash> = [
+        (0, hash!("block0")),
+        (1, hash!("block1")),
+        (2, hash!("block2")),
+        (3, hash!("block3")),
+        (4, hash!("block4")),
+        (5, hash!("block5")),
+        (6, hash!("block6")),
+        (7, hash!("block7")),
+        (8, hash!("block8")),
+        (9, hash!("block9")),
+        (10, hash!("block10")),
+    ]
+    .into_iter()
+    .collect();
+    let chain = LocalChain::from_blocks(blocks).unwrap();
 
     let mut tx_graph = TxGraph::default();
 
@@ -98,23 +99,22 @@ fn test_min_confirmations_parameter() {
 #[test]
 fn test_min_confirmations_with_untrusted_tx() {
     // Create a local chain
-    let chain = LocalChain::from_blocks(
-        [
-            (0, hash!("genesis")),
-            (1, hash!("b1")),
-            (2, hash!("b2")),
-            (3, hash!("b3")),
-            (4, hash!("b4")),
-            (5, hash!("b5")),
-            (6, hash!("b6")),
-            (7, hash!("b7")),
-            (8, hash!("b8")),
-            (9, hash!("b9")),
-            (10, hash!("tip")),
-        ]
-        .into(),
-    )
-    .unwrap();
+    let blocks: BTreeMap<u32, BlockHash> = [
+        (0, hash!("genesis")),
+        (1, hash!("b1")),
+        (2, hash!("b2")),
+        (3, hash!("b3")),
+        (4, hash!("b4")),
+        (5, hash!("b5")),
+        (6, hash!("b6")),
+        (7, hash!("b7")),
+        (8, hash!("b8")),
+        (9, hash!("b9")),
+        (10, hash!("tip")),
+    ]
+    .into_iter()
+    .collect();
+    let chain = LocalChain::from_blocks(blocks).unwrap();
 
     let mut tx_graph = TxGraph::default();
 
@@ -164,28 +164,27 @@ fn test_min_confirmations_with_untrusted_tx() {
 #[test]
 fn test_min_confirmations_multiple_transactions() {
     // Create a local chain
-    let chain = LocalChain::from_blocks(
-        [
-            (0, hash!("genesis")),
-            (1, hash!("b1")),
-            (2, hash!("b2")),
-            (3, hash!("b3")),
-            (4, hash!("b4")),
-            (5, hash!("b5")),
-            (6, hash!("b6")),
-            (7, hash!("b7")),
-            (8, hash!("b8")),
-            (9, hash!("b9")),
-            (10, hash!("b10")),
-            (11, hash!("b11")),
-            (12, hash!("b12")),
-            (13, hash!("b13")),
-            (14, hash!("b14")),
-            (15, hash!("tip")),
-        ]
-        .into(),
-    )
-    .unwrap();
+    let blocks: BTreeMap<u32, BlockHash> = [
+        (0, hash!("genesis")),
+        (1, hash!("b1")),
+        (2, hash!("b2")),
+        (3, hash!("b3")),
+        (4, hash!("b4")),
+        (5, hash!("b5")),
+        (6, hash!("b6")),
+        (7, hash!("b7")),
+        (8, hash!("b8")),
+        (9, hash!("b9")),
+        (10, hash!("b10")),
+        (11, hash!("b11")),
+        (12, hash!("b12")),
+        (13, hash!("b13")),
+        (14, hash!("b14")),
+        (15, hash!("tip")),
+    ]
+    .into_iter()
+    .collect();
+    let chain = LocalChain::from_blocks(blocks).unwrap();
 
     let mut tx_graph = TxGraph::default();
 
index 5b44cb1634d31af8dcaebbf7a3c47b0317b8bb43..7a2f8ea60ff66a58c00f3a81bbf614b0dfd36948 100644 (file)
@@ -473,7 +473,7 @@ fn test_list_owned_txouts() {
                 .canonical_view(&local_chain, chain_tip, CanonicalizationParams::default())
                 .balance(
                     graph.index.outpoints().iter().cloned(),
-                    |_, spk: ScriptBuf| trusted_spks.contains(&spk),
+                    |_, txout| trusted_spks.contains(&txout.txout.script_pubkey),
                     1,
                 );
 
index f91a3a8d356dd641756284eb8f503f089e2ea4b9..70dc01884b7a916e6f354c7dff47683c1c046a9a 100644 (file)
@@ -5,7 +5,7 @@ mod common;
 
 use bdk_chain::{local_chain::LocalChain, Balance, BlockId};
 use bdk_testenv::{block_id, hash, local_chain};
-use bitcoin::{Amount, BlockHash, OutPoint, ScriptBuf};
+use bitcoin::{Amount, BlockHash, OutPoint};
 use common::*;
 use std::collections::{BTreeSet, HashSet};
 
@@ -1032,8 +1032,12 @@ fn test_tx_conflict_handling() {
             .canonical_view(&local_chain, chain_tip, env.canonicalization_params.clone())
             .balance(
                 env.indexer.outpoints().iter().cloned(),
-                |_, spk: ScriptBuf| env.indexer.index_of_spk(spk).is_some(),
-                1,
+                |_, txout| {
+                    env.indexer
+                        .index_of_spk(txout.txout.script_pubkey.clone())
+                        .is_some()
+                },
+                0,
             );
         assert_eq!(
             balance, scenario.exp_balance,