/// This constructor analyzes the given [`TxGraph`] and creates a canonical view of all
/// transactions, resolving conflicts and ordering them according to their chain position.
///
- /// # Arguments
- ///
- /// * `tx_graph` - The transaction graph containing all known transactions
- /// * `chain` - A chain oracle for determining block inclusion
- /// * `chain_tip` - The current chain tip to use for canonicalization
- /// * `params` - Parameters controlling the canonicalization process
- ///
/// # Returns
///
/// Returns `Ok(CanonicalView)` on success, or an error if the chain oracle fails.
- ///
- /// # Example
- ///
- /// ```
- /// # use bdk_chain::{CanonicalView, TxGraph, CanonicalizationParams, local_chain::LocalChain};
- /// # use bdk_core::BlockId;
- /// # use bitcoin::hashes::Hash;
- /// # let tx_graph = TxGraph::<BlockId>::default();
- /// # let chain = LocalChain::from_blocks([(0, bitcoin::BlockHash::all_zeros())].into_iter().collect()).unwrap();
- /// let chain_tip = chain.tip().block_id();
- /// let params = CanonicalizationParams::default();
- ///
- /// let view = CanonicalView::new(&tx_graph, &chain, chain_tip, params)?;
- /// # Ok::<_, Box<dyn std::error::Error>>(())
- /// ```
pub fn new<'g, C>(
tx_graph: &'g TxGraph<A>,
chain: &'g C,
///
/// Returns `Some(CanonicalViewTx)` if the transaction exists in the canonical view,
/// or `None` if the transaction doesn't exist or was excluded due to conflicts.
- ///
- /// # Example
- ///
- /// ```
- /// # use bdk_chain::{CanonicalView, TxGraph, local_chain::LocalChain};
- /// # use bdk_core::BlockId;
- /// # use bitcoin::hashes::Hash;
- /// # let tx_graph = TxGraph::<BlockId>::default();
- /// # let chain = LocalChain::from_blocks([(0, bitcoin::BlockHash::all_zeros())].into_iter().collect()).unwrap();
- /// # let view = CanonicalView::new(&tx_graph, &chain, chain.tip().block_id(), Default::default()).unwrap();
- /// # let txid = bitcoin::Txid::all_zeros();
- /// if let Some(canonical_tx) = view.tx(txid) {
- /// println!("Found tx {} at position {:?}", canonical_tx.txid, canonical_tx.pos);
- /// }
- /// ```
pub fn tx(&self, txid: Txid) -> Option<CanonicalTx<A>> {
self.txs
.get(&txid)
/// - The transaction doesn't exist in the canonical view
/// - The output index is out of bounds
/// - The transaction was excluded due to conflicts
- ///
- /// # Example
- ///
- /// ```
- /// # use bdk_chain::{CanonicalView, TxGraph, local_chain::LocalChain};
- /// # use bdk_core::BlockId;
- /// # use bitcoin::{OutPoint, hashes::Hash};
- /// # let tx_graph = TxGraph::<BlockId>::default();
- /// # let chain = LocalChain::from_blocks([(0, bitcoin::BlockHash::all_zeros())].into_iter().collect()).unwrap();
- /// # let view = CanonicalView::new(&tx_graph, &chain, chain.tip().block_id(), Default::default()).unwrap();
- /// # let outpoint = OutPoint::default();
- /// if let Some(txout) = view.txout(outpoint) {
- /// if txout.spent_by.is_some() {
- /// println!("Output is spent");
- /// } else {
- /// println!("Output is unspent with value: {}", txout.txout.value);
- /// }
- /// }
- /// ```
pub fn txout(&self, op: OutPoint) -> Option<FullTxOut<A>> {
let (tx, pos) = self.txs.get(&op.txid)?;
let vout: usize = op.vout.try_into().ok()?;
/// of `(identifier, full_txout)` pairs for outpoints that exist in the canonical view.
/// Non-existent outpoints are silently filtered out.
///
- /// The identifier type `O` can be any cloneable type and is passed through unchanged.
- /// This is useful for tracking which outpoints correspond to which addresses or keys.
- ///
- /// # Arguments
- ///
- /// * `outpoints` - An iterator of `(identifier, outpoint)` pairs to look up
+ /// The identifier type `O` is useful for tracking which outpoints correspond to which addresses
+ /// or keys.
///
/// # Example
///
/// # let view = CanonicalView::new(&tx_graph, &chain, chain.tip().block_id(), Default::default()).unwrap();
/// # let indexer = KeychainTxOutIndex::<&str>::default();
/// // Get all outputs from an indexer
- /// for (keychain, txout) in view.filter_outpoints(indexer.outpoints().into_iter().map(|(k, op)| (k.clone(), *op))) {
+ /// for (keychain, txout) in view.filter_outpoints(indexer.outpoints().clone()) {
/// println!("{}: {} sats", keychain.0, txout.txout.value);
/// }
/// ```
/// Similar to [`filter_outpoints`](Self::filter_outpoints), but only returns outputs that
/// have not been spent. This is useful for finding available UTXOs for spending.
///
- /// # Arguments
- ///
- /// * `outpoints` - An iterator of `(identifier, outpoint)` pairs to look up
- ///
/// # Example
///
/// ```
/// # let view = CanonicalView::new(&tx_graph, &chain, chain.tip().block_id(), Default::default()).unwrap();
/// # let indexer = KeychainTxOutIndex::<&str>::default();
/// // Get unspent outputs (UTXOs) from an indexer
- /// for (keychain, utxo) in view.filter_unspent_outpoints(indexer.outpoints().into_iter().map(|(k, op)| (k.clone(), *op))) {
+ /// for (keychain, utxo) in view.filter_unspent_outpoints(indexer.outpoints().clone()) {
/// println!("{} UTXO: {} sats", keychain.0, utxo.txout.value);
/// }
/// ```
///
/// # Minimum Confirmations
///
- /// The `min_confirmations` parameter controls when outputs are considered confirmed:
- ///
- /// - `0` or `1`: Standard behavior - require at least 1 confirmation
- /// - `6`: Conservative - require 6 confirmations (often used for high-value transactions)
- /// - `100+`: May be used for coinbase outputs which require 100 confirmations
+ /// The `min_confirmations` parameter controls when outputs are considered confirmed. A
+ /// `min_confirmations` value of `0` is equivalent to `1` (require at least 1 confirmation).
///
/// Outputs with fewer than `min_confirmations` are categorized as pending (trusted or
/// untrusted based on the trust predicate).
///
- /// # Balance Categories
- ///
- /// The returned [`Balance`] contains four categories:
- ///
- /// - `confirmed`: Outputs with ≥ `min_confirmations` and spendable
- /// - `trusted_pending`: Unconfirmed or insufficiently confirmed outputs from trusted scripts
- /// - `untrusted_pending`: Unconfirmed or insufficiently confirmed outputs from untrusted
- /// scripts
- /// - `immature`: Coinbase outputs that haven't reached maturity (100 confirmations)
- ///
/// # Example
///
/// ```
/// |_keychain, _script| true, // Trust all outputs
/// 6, // Require 6 confirmations
/// );
- ///
- /// // Or calculate balance trusting no outputs
- /// let untrusted_balance = view.balance(
- /// indexer.outpoints().into_iter().map(|(k, op)| (k.clone(), *op)),
- /// |_keychain, _script| false, // Trust no outputs
- /// 1,
- /// );
/// ```
pub fn balance<'v, O: Clone + 'v>(
&'v self,
/// commonly used with
/// [`SyncRequestBuilder::expected_spk_txids`](bdk_core::spk_client::SyncRequestBuilder::expected_spk_txids)
/// to inform sync operations about known transactions.
- ///
- /// # Arguments
- ///
- /// * `indexer` - A script pubkey indexer (e.g., `KeychainTxOutIndex`) that tracks which scripts
- /// are relevant
- /// * `spk_index_range` - A range bound to constrain which script indices to include. Use `..`
- /// for all indices.
- ///
- /// # Returns
- ///
- /// An iterator of `(script_pubkey, txid)` pairs for all canonical transactions that involve
- /// the specified scripts.
- ///
- /// # Example
- ///
- /// ```
- /// # use bdk_chain::{CanonicalView, TxGraph, local_chain::LocalChain, spk_txout::SpkTxOutIndex};
- /// # use bdk_core::BlockId;
- /// # use bitcoin::hashes::Hash;
- /// # let tx_graph = TxGraph::<BlockId>::default();
- /// # let chain = LocalChain::from_blocks([(0, bitcoin::BlockHash::all_zeros())].into_iter().collect()).unwrap();
- /// # let view = CanonicalView::new(&tx_graph, &chain, chain.tip().block_id(), Default::default()).unwrap();
- /// # let indexer = SpkTxOutIndex::<u32>::default();
- /// // List all expected transactions for script indices 0-100
- /// for (script, txid) in view.list_expected_spk_txids(&indexer, 0..100) {
- /// println!("Script {:?} appears in transaction {}", script, txid);
- /// }
- ///
- /// // List all expected transactions (no range constraint)
- /// for (script, txid) in view.list_expected_spk_txids(&indexer, ..) {
- /// println!("Found transaction {} for script", txid);
- /// }
- /// ```
pub fn list_expected_spk_txids<'v, I>(
&'v self,
indexer: &'v impl AsRef<SpkTxOutIndex<I>>,