Skip to content

Commit 2c6c10b

Browse files
committed
docs(chain): add doctest for min confirmation balance filtering
1 parent 333cc2a commit 2c6c10b

File tree

2 files changed

+87
-0
lines changed

2 files changed

+87
-0
lines changed

crates/chain/src/tx_graph.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1315,6 +1315,69 @@ impl<A: Anchor> TxGraph<A> {
13151315
///
13161316
/// This is the infallible version of [`try_balance`].
13171317
///
1318+
/// ### Minimum confirmations
1319+
///
1320+
/// To filter for transactions with at least `N` confirmations, pass a `chain_tip` that is
1321+
/// `N - 1` blocks below the actual tip. This ensures that only transactions with at least `N`
1322+
/// confirmations are counted as confirmed in the returned [`Balance`].
1323+
///
1324+
/// ```
1325+
/// # use bdk_chain::tx_graph::TxGraph;
1326+
/// # use bdk_chain::{local_chain::LocalChain, CanonicalizationParams, ConfirmationBlockTime};
1327+
/// # use bdk_testenv::{hash, utils::new_tx};
1328+
/// # use bitcoin::{Amount, OutPoint, ScriptBuf, Transaction, TxIn, TxOut};
1329+
///
1330+
/// # let spk = ScriptBuf::from_hex("0014c692ecf13534982a9a2834565cbd37add8027140").unwrap();
1331+
/// # let chain =
1332+
/// # LocalChain::from_blocks((0..=15).map(|i| (i as u32, hash!("h"))).collect()).unwrap();
1333+
/// # let mut graph: TxGraph = TxGraph::default();
1334+
/// # let coinbase_tx = Transaction {
1335+
/// # input: vec![TxIn {
1336+
/// # previous_output: OutPoint::null(),
1337+
/// # ..Default::default()
1338+
/// # }],
1339+
/// # output: vec![TxOut {
1340+
/// # value: Amount::from_sat(70000),
1341+
/// # script_pubkey: spk.clone(),
1342+
/// # }],
1343+
/// # ..new_tx(0)
1344+
/// # };
1345+
/// # let tx = Transaction {
1346+
/// # input: vec![TxIn {
1347+
/// # previous_output: OutPoint::new(coinbase_tx.compute_txid(), 0),
1348+
/// # ..Default::default()
1349+
/// # }],
1350+
/// # output: vec![TxOut {
1351+
/// # value: Amount::from_sat(42_000),
1352+
/// # script_pubkey: spk.clone(),
1353+
/// # }],
1354+
/// # ..new_tx(1)
1355+
/// # };
1356+
/// # let txid = tx.compute_txid();
1357+
/// # let _ = graph.insert_tx(tx.clone());
1358+
/// # let _ = graph.insert_anchor(
1359+
/// # txid,
1360+
/// # ConfirmationBlockTime {
1361+
/// # block_id: chain.get(10).unwrap().block_id(),
1362+
/// # confirmation_time: 123456,
1363+
/// # },
1364+
/// # );
1365+
///
1366+
/// let minimum_confirmations = 6;
1367+
/// let target_tip = chain
1368+
/// .tip()
1369+
/// .floor_below(minimum_confirmations - 1)
1370+
/// .expect("checkpoint from local chain must have genesis");
1371+
/// let balance = graph.balance(
1372+
/// &chain,
1373+
/// target_tip.block_id(),
1374+
/// CanonicalizationParams::default(),
1375+
/// std::iter::once(((), OutPoint::new(txid, 0))),
1376+
/// |_: &(), _| true,
1377+
/// );
1378+
/// assert_eq!(balance.confirmed, Amount::from_sat(42_000));
1379+
/// ```
1380+
///
13181381
/// [`try_balance`]: Self::try_balance
13191382
pub fn balance<C: ChainOracle<Error = Infallible>, OI: Clone>(
13201383
&self,

crates/core/src/checkpoint.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,30 @@ impl CheckPoint {
192192
})
193193
}
194194

195+
/// Returns the checkpoint at `height` if one exists, otherwise the nearest checkpoint at a
196+
/// lower height.
197+
///
198+
/// This is equivalent to taking the "floor" of `height` over this checkpoint chain.
199+
///
200+
/// Returns `None` if no checkpoint exists at or below the given height.
201+
pub fn floor_at(&self, height: u32) -> Option<Self> {
202+
self.range(..=height).next()
203+
}
204+
205+
/// Returns the checkpoint located a number of heights below this one.
206+
///
207+
/// This is a convenience wrapper for [`CheckPoint::floor_at`], subtracting `to_subtract` from
208+
/// the current height.
209+
///
210+
/// - If a checkpoint exists exactly `offset` heights below, it is returned.
211+
/// - Otherwise, the nearest checkpoint *below that target height* is returned.
212+
///
213+
/// Returns `None` if `to_subtract` is greater than the current height, or if there is no
214+
/// checkpoint at or below the target height.
215+
pub fn floor_below(&self, offset: u32) -> Option<Self> {
216+
self.floor_at(self.height().checked_sub(offset)?)
217+
}
218+
195219
/// Inserts `block_id` at its height within the chain.
196220
///
197221
/// The effect of `insert` depends on whether a height already exists. If it doesn't the

0 commit comments

Comments
 (0)