From 1311a2ed050534558ef738ceb754bd9b3a5552a6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=BF=97=E5=AE=87?= Date: Wed, 17 Sep 2025 23:46:29 +0000 Subject: [PATCH] refactor(chain)!: Change trust_predicate to accept FullTxOut MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit BREAKING CHANGE: The trust_predicate parameter in CanonicalView::balance() now takes &FullTxOut 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 --- crates/chain/src/canonical_view.rs | 10 +- crates/chain/tests/test_canonical_view.rs | 113 +++++++++--------- crates/chain/tests/test_indexed_tx_graph.rs | 2 +- crates/chain/tests/test_tx_graph_conflicts.rs | 10 +- 4 files changed, 69 insertions(+), 66 deletions(-) diff --git a/crates/chain/src/canonical_view.rs b/crates/chain/src/canonical_view.rs index b24dbb2d..09b18e50 100644 --- a/crates/chain/src/canonical_view.rs +++ b/crates/chain/src/canonical_view.rs @@ -60,12 +60,12 @@ pub struct CanonicalTx { /// 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 { - /// Ordered list of transaction IDs in canonical order. + /// Ordered list of transaction IDs in in topological-spending order. order: Vec, /// Map of transaction IDs to their transaction data and chain position. txs: HashMap, ChainPosition)>, @@ -357,7 +357,7 @@ impl CanonicalView { pub fn balance<'v, O: Clone + 'v>( &'v self, outpoints: impl IntoIterator + 'v, - mut trust_predicate: impl FnMut(&O, ScriptBuf) -> bool, + mut trust_predicate: impl FnMut(&O, &FullTxOut) -> bool, min_confirmations: u32, ) -> Balance { let mut immature = Amount::ZERO; @@ -378,7 +378,7 @@ impl CanonicalView { 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 CanonicalView { } } 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; diff --git a/crates/chain/tests/test_canonical_view.rs b/crates/chain/tests/test_canonical_view.rs index 5d6740ac..3c0d5438 100644 --- a/crates/chain/tests/test_canonical_view.rs +++ b/crates/chain/tests/test_canonical_view.rs @@ -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 = [ + (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 = [ + (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 = [ + (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(); diff --git a/crates/chain/tests/test_indexed_tx_graph.rs b/crates/chain/tests/test_indexed_tx_graph.rs index 5b44cb16..7a2f8ea6 100644 --- a/crates/chain/tests/test_indexed_tx_graph.rs +++ b/crates/chain/tests/test_indexed_tx_graph.rs @@ -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, ); diff --git a/crates/chain/tests/test_tx_graph_conflicts.rs b/crates/chain/tests/test_tx_graph_conflicts.rs index f91a3a8d..70dc0188 100644 --- a/crates/chain/tests/test_tx_graph_conflicts.rs +++ b/crates/chain/tests/test_tx_graph_conflicts.rs @@ -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, -- 2.49.0