From: Wei Chen Date: Thu, 7 Aug 2025 05:50:27 +0000 (+0000) Subject: docs(chain): add doctest for min confirmation balance filtering X-Git-Tag: core-0.6.2~2^2 X-Git-Url: http://internal-gitweb-vhost/?a=commitdiff_plain;h=657a044370a102259eb1b7f5abdfee2dde998bc2;p=bdk docs(chain): add doctest for min confirmation balance filtering --- diff --git a/crates/chain/src/tx_graph.rs b/crates/chain/src/tx_graph.rs index 1e2b7ced..7bbdef63 100644 --- a/crates/chain/src/tx_graph.rs +++ b/crates/chain/src/tx_graph.rs @@ -1315,6 +1315,69 @@ impl TxGraph { /// /// This is the infallible version of [`try_balance`]. /// + /// ### Minimum confirmations + /// + /// To filter for transactions with at least `N` confirmations, pass a `chain_tip` that is + /// `N - 1` blocks below the actual tip. This ensures that only transactions with at least `N` + /// confirmations are counted as confirmed in the returned [`Balance`]. + /// + /// ``` + /// # use bdk_chain::tx_graph::TxGraph; + /// # use bdk_chain::{local_chain::LocalChain, CanonicalizationParams, ConfirmationBlockTime}; + /// # use bdk_testenv::{hash, utils::new_tx}; + /// # use bitcoin::{Amount, OutPoint, ScriptBuf, Transaction, TxIn, TxOut}; + /// + /// # let spk = ScriptBuf::from_hex("0014c692ecf13534982a9a2834565cbd37add8027140").unwrap(); + /// # let chain = + /// # LocalChain::from_blocks((0..=15).map(|i| (i as u32, hash!("h"))).collect()).unwrap(); + /// # let mut graph: TxGraph = TxGraph::default(); + /// # let coinbase_tx = Transaction { + /// # input: vec![TxIn { + /// # previous_output: OutPoint::null(), + /// # ..Default::default() + /// # }], + /// # output: vec![TxOut { + /// # value: Amount::from_sat(70000), + /// # script_pubkey: spk.clone(), + /// # }], + /// # ..new_tx(0) + /// # }; + /// # let tx = Transaction { + /// # input: vec![TxIn { + /// # previous_output: OutPoint::new(coinbase_tx.compute_txid(), 0), + /// # ..Default::default() + /// # }], + /// # output: vec![TxOut { + /// # value: Amount::from_sat(42_000), + /// # script_pubkey: spk.clone(), + /// # }], + /// # ..new_tx(1) + /// # }; + /// # let txid = tx.compute_txid(); + /// # let _ = graph.insert_tx(tx.clone()); + /// # let _ = graph.insert_anchor( + /// # txid, + /// # ConfirmationBlockTime { + /// # block_id: chain.get(10).unwrap().block_id(), + /// # confirmation_time: 123456, + /// # }, + /// # ); + /// + /// let minimum_confirmations = 6; + /// let target_tip = chain + /// .tip() + /// .floor_below(minimum_confirmations - 1) + /// .expect("checkpoint from local chain must have genesis"); + /// let balance = graph.balance( + /// &chain, + /// target_tip.block_id(), + /// CanonicalizationParams::default(), + /// std::iter::once(((), OutPoint::new(txid, 0))), + /// |_: &(), _| true, + /// ); + /// assert_eq!(balance.confirmed, Amount::from_sat(42_000)); + /// ``` + /// /// [`try_balance`]: Self::try_balance pub fn balance, OI: Clone>( &self, diff --git a/crates/core/src/checkpoint.rs b/crates/core/src/checkpoint.rs index bb6bb9fe..01b36e25 100644 --- a/crates/core/src/checkpoint.rs +++ b/crates/core/src/checkpoint.rs @@ -192,6 +192,30 @@ impl CheckPoint { }) } + /// Returns the checkpoint at `height` if one exists, otherwise the nearest checkpoint at a + /// lower height. + /// + /// This is equivalent to taking the "floor" of `height` over this checkpoint chain. + /// + /// Returns `None` if no checkpoint exists at or below the given height. + pub fn floor_at(&self, height: u32) -> Option { + self.range(..=height).next() + } + + /// Returns the checkpoint located a number of heights below this one. + /// + /// This is a convenience wrapper for [`CheckPoint::floor_at`], subtracting `to_subtract` from + /// the current height. + /// + /// - If a checkpoint exists exactly `offset` heights below, it is returned. + /// - Otherwise, the nearest checkpoint *below that target height* is returned. + /// + /// Returns `None` if `to_subtract` is greater than the current height, or if there is no + /// checkpoint at or below the target height. + pub fn floor_below(&self, offset: u32) -> Option { + self.floor_at(self.height().checked_sub(offset)?) + } + /// Inserts `block_id` at its height within the chain. /// /// The effect of `insert` depends on whether a height already exists. If it doesn't the