diff --git a/crates/chain/src/canonical_iter.rs b/crates/chain/src/canonical_iter.rs index 204ead451..2a3339073 100644 --- a/crates/chain/src/canonical_iter.rs +++ b/crates/chain/src/canonical_iter.rs @@ -85,19 +85,14 @@ impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> { } /// Mark transaction as canonical if it is anchored in the best chain. - fn scan_anchors( - &mut self, - txid: Txid, - tx: Arc, - anchors: &BTreeSet, - ) -> Result<(), C::Error> { + fn scan_anchors(&mut self, txid: Txid, tx: Arc, anchors: &BTreeSet) { for anchor in anchors { let in_chain_opt = self .chain - .is_block_in_chain(anchor.anchor_block(), self.chain_tip)?; + .is_block_in_chain(anchor.anchor_block(), self.chain_tip); if in_chain_opt == Some(true) { self.mark_canonical(txid, tx, CanonicalReason::from_anchor(anchor.clone())); - return Ok(()); + return; } } // cannot determine @@ -112,7 +107,6 @@ impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> { ) .confirmation_height_upper_bound(), )); - Ok(()) } /// Marks `tx` and it's ancestors as canonical and mark all conflicts of these as @@ -201,7 +195,7 @@ impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> { } impl Iterator for CanonicalIter<'_, A, C> { - type Item = Result<(Txid, Arc, CanonicalReason), C::Error>; + type Item = (Txid, Arc, CanonicalReason); fn next(&mut self) -> Option { loop { @@ -211,7 +205,7 @@ impl Iterator for CanonicalIter<'_, A, C> { .get(&txid) .cloned() .expect("reason must exist"); - return Some(Ok((txid, tx, reason))); + return Some((txid, tx, reason)); } if let Some((txid, tx)) = self.unprocessed_assumed_txs.next() { @@ -222,9 +216,7 @@ impl Iterator for CanonicalIter<'_, A, C> { if let Some((txid, tx, anchors)) = self.unprocessed_anchored_txs.next() { if !self.is_canonicalized(txid) { - if let Err(err) = self.scan_anchors(txid, tx, anchors) { - return Some(Err(err)); - } + self.scan_anchors(txid, tx, anchors); } continue; } diff --git a/crates/chain/src/chain_oracle.rs b/crates/chain/src/chain_oracle.rs index 08e697ed4..67f5eabb7 100644 --- a/crates/chain/src/chain_oracle.rs +++ b/crates/chain/src/chain_oracle.rs @@ -7,19 +7,12 @@ use crate::BlockId; /// /// [`is_block_in_chain`]: Self::is_block_in_chain pub trait ChainOracle { - /// Error type. - type Error: core::fmt::Debug; - /// Determines whether `block` of [`BlockId`] exists as an ancestor of `chain_tip`. /// /// If `None` is returned, it means the implementation cannot determine whether `block` exists /// under `chain_tip`. - fn is_block_in_chain( - &self, - block: BlockId, - chain_tip: BlockId, - ) -> Result, Self::Error>; + fn is_block_in_chain(&self, block: BlockId, chain_tip: BlockId) -> Option; /// Get the best chain's chain tip. - fn get_chain_tip(&self) -> Result; + fn get_chain_tip(&self) -> BlockId; } diff --git a/crates/chain/src/indexed_tx_graph.rs b/crates/chain/src/indexed_tx_graph.rs index f0c1d121d..419aac5ee 100644 --- a/crates/chain/src/indexed_tx_graph.rs +++ b/crates/chain/src/indexed_tx_graph.rs @@ -1,7 +1,6 @@ //! Contains the [`IndexedTxGraph`] and associated types. Refer to the //! [`IndexedTxGraph`] documentation for more. use core::{ - convert::Infallible, fmt::{self, Debug}, ops::RangeBounds, }; @@ -438,33 +437,6 @@ where /// /// /// The spk index range can be contrained with `range`. - /// - /// # Error - /// - /// If the [`ChainOracle`] implementation (`chain`) fails, an error will be returned with the - /// returned item. - /// - /// If the [`ChainOracle`] is infallible, - /// [`list_expected_spk_txids`](Self::list_expected_spk_txids) can be used instead. - pub fn try_list_expected_spk_txids<'a, C, I>( - &'a self, - chain: &'a C, - chain_tip: BlockId, - spk_index_range: impl RangeBounds + 'a, - ) -> impl Iterator> + 'a - where - C: ChainOracle, - X: AsRef> + 'a, - I: fmt::Debug + Clone + Ord + 'a, - { - self.graph - .try_list_expected_spk_txids(chain, chain_tip, &self.index, spk_index_range) - } - - /// List txids that are expected to exist under the given spks. - /// - /// This is the infallible version of - /// [`try_list_expected_spk_txids`](Self::try_list_expected_spk_txids). pub fn list_expected_spk_txids<'a, C, I>( &'a self, chain: &'a C, @@ -472,12 +444,12 @@ where spk_index_range: impl RangeBounds + 'a, ) -> impl Iterator + 'a where - C: ChainOracle, + C: ChainOracle, X: AsRef> + 'a, I: fmt::Debug + Clone + Ord + 'a, { - self.try_list_expected_spk_txids(chain, chain_tip, spk_index_range) - .map(|r| r.expect("infallible")) + self.graph + .list_expected_spk_txids(chain, chain_tip, &self.index, spk_index_range) } } diff --git a/crates/chain/src/local_chain.rs b/crates/chain/src/local_chain.rs index 81f4a1796..ee148026c 100644 --- a/crates/chain/src/local_chain.rs +++ b/crates/chain/src/local_chain.rs @@ -1,6 +1,5 @@ //! The [`LocalChain`] is a local implementation of [`ChainOracle`]. -use core::convert::Infallible; use core::fmt; use core::ops::RangeBounds; @@ -70,27 +69,20 @@ impl PartialEq for LocalChain { } impl ChainOracle for LocalChain { - type Error = Infallible; - - fn is_block_in_chain( - &self, - block: BlockId, - chain_tip: BlockId, - ) -> Result, Self::Error> { + fn is_block_in_chain(&self, block: BlockId, chain_tip: BlockId) -> Option { let chain_tip_cp = match self.tip.get(chain_tip.height) { // we can only determine whether `block` is in chain of `chain_tip` if `chain_tip` can // be identified in chain Some(cp) if cp.hash() == chain_tip.hash => cp, - _ => return Ok(None), + _ => return None, }; - match chain_tip_cp.get(block.height) { - Some(cp) => Ok(Some(cp.hash() == block.hash)), - None => Ok(None), - } + chain_tip_cp + .get(block.height) + .map(|cp| cp.hash() == block.hash) } - fn get_chain_tip(&self) -> Result { - Ok(self.tip.block_id()) + fn get_chain_tip(&self) -> BlockId { + self.tip.block_id() } } diff --git a/crates/chain/src/tx_graph.rs b/crates/chain/src/tx_graph.rs index 6b9a4cf96..31f5390b9 100644 --- a/crates/chain/src/tx_graph.rs +++ b/crates/chain/src/tx_graph.rs @@ -135,10 +135,7 @@ pub use bdk_core::TxUpdate; use bitcoin::{Amount, OutPoint, ScriptBuf, SignedAmount, Transaction, TxOut, Txid}; use core::fmt::{self, Formatter}; use core::ops::RangeBounds; -use core::{ - convert::Infallible, - ops::{Deref, RangeInclusive}, -}; +use core::ops::{Deref, RangeInclusive}; impl From> for TxUpdate { fn from(graph: TxGraph) -> Self { @@ -985,108 +982,79 @@ impl TxGraph { /// Each transaction is represented as a [`CanonicalTx`] that contains where the transaction is /// observed in-chain, and the [`TxNode`]. /// - /// # Error - /// - /// If the [`ChainOracle`] implementation (`chain`) fails, an error will be returned with the - /// returned item. - /// - /// If the [`ChainOracle`] is infallible, [`list_canonical_txs`] can be used instead. - /// - /// [`list_canonical_txs`]: Self::list_canonical_txs - pub fn try_list_canonical_txs<'a, C: ChainOracle + 'a>( + /// List graph transactions that are in `chain` with `chain_tip`. + pub fn list_canonical_txs<'a, C: ChainOracle + 'a>( &'a self, chain: &'a C, chain_tip: BlockId, params: CanonicalizationParams, - ) -> impl Iterator, A>, C::Error>> { + ) -> impl Iterator, A>> { fn find_direct_anchor( tx_node: &TxNode<'_, Arc, A>, chain: &C, chain_tip: BlockId, - ) -> Result, C::Error> { - tx_node - .anchors - .iter() - .find_map(|a| -> Option> { - match chain.is_block_in_chain(a.anchor_block(), chain_tip) { - Ok(Some(true)) => Some(Ok(a.clone())), - Ok(Some(false)) | Ok(None) => None, - Err(err) => Some(Err(err)), - } - }) - .transpose() + ) -> Option { + tx_node.anchors.iter().find_map(|a| { + match chain.is_block_in_chain(a.anchor_block(), chain_tip) { + Some(true) => Some(a.clone()), + Some(false) | None => None, + } + }) } self.canonical_iter(chain, chain_tip, params) - .flat_map(move |res| { - res.map(|(txid, _, canonical_reason)| { - let tx_node = self.get_tx_node(txid).expect("must contain tx"); - let chain_position = match canonical_reason { - CanonicalReason::Assumed { descendant } => match descendant { - Some(_) => match find_direct_anchor(&tx_node, chain, chain_tip)? { - Some(anchor) => ChainPosition::Confirmed { - anchor, - transitively: None, - }, - None => ChainPosition::Unconfirmed { - first_seen: tx_node.first_seen, - last_seen: tx_node.last_seen, - }, + .map(move |(txid, _, canonical_reason)| { + let tx_node = self.get_tx_node(txid).expect("must contain tx"); + let chain_position = match canonical_reason { + CanonicalReason::Assumed { descendant } => match descendant { + Some(_) => match find_direct_anchor(&tx_node, chain, chain_tip) { + Some(anchor) => ChainPosition::Confirmed { + anchor, + transitively: None, }, None => ChainPosition::Unconfirmed { first_seen: tx_node.first_seen, last_seen: tx_node.last_seen, }, }, - CanonicalReason::Anchor { anchor, descendant } => match descendant { - Some(_) => match find_direct_anchor(&tx_node, chain, chain_tip)? { - Some(anchor) => ChainPosition::Confirmed { - anchor, - transitively: None, - }, - None => ChainPosition::Confirmed { - anchor, - transitively: descendant, - }, + None => ChainPosition::Unconfirmed { + first_seen: tx_node.first_seen, + last_seen: tx_node.last_seen, + }, + }, + CanonicalReason::Anchor { anchor, descendant } => match descendant { + Some(_) => match find_direct_anchor(&tx_node, chain, chain_tip) { + Some(anchor) => ChainPosition::Confirmed { + anchor, + transitively: None, }, None => ChainPosition::Confirmed { anchor, - transitively: None, + transitively: descendant, }, }, - CanonicalReason::ObservedIn { observed_in, .. } => match observed_in { - ObservedIn::Mempool(last_seen) => ChainPosition::Unconfirmed { - first_seen: tx_node.first_seen, - last_seen: Some(last_seen), - }, - ObservedIn::Block(_) => ChainPosition::Unconfirmed { - first_seen: tx_node.first_seen, - last_seen: None, - }, + None => ChainPosition::Confirmed { + anchor, + transitively: None, }, - }; - Ok(CanonicalTx { - chain_position, - tx_node, - }) - }) + }, + CanonicalReason::ObservedIn { observed_in, .. } => match observed_in { + ObservedIn::Mempool(last_seen) => ChainPosition::Unconfirmed { + first_seen: tx_node.first_seen, + last_seen: Some(last_seen), + }, + ObservedIn::Block(_) => ChainPosition::Unconfirmed { + first_seen: tx_node.first_seen, + last_seen: None, + }, + }, + }; + CanonicalTx { + chain_position, + tx_node, + } }) } - /// List graph transactions that are in `chain` with `chain_tip`. - /// - /// This is the infallible version of [`try_list_canonical_txs`]. - /// - /// [`try_list_canonical_txs`]: Self::try_list_canonical_txs - pub fn list_canonical_txs<'a, C: ChainOracle + 'a>( - &'a self, - chain: &'a C, - chain_tip: BlockId, - params: CanonicalizationParams, - ) -> impl Iterator, A>> { - self.try_list_canonical_txs(chain, chain_tip, params) - .map(|res| res.expect("infallible")) - } - /// Get a filtered list of outputs from the given `outpoints` that are in `chain` with /// `chain_tip`. /// @@ -1096,27 +1064,16 @@ impl TxGraph { /// /// Floating outputs (i.e., outputs for which we don't have the full transaction in the graph) /// are ignored. - /// - /// # Error - /// - /// An [`Iterator::Item`] can be an [`Err`] if the [`ChainOracle`] implementation (`chain`) - /// fails. - /// - /// If the [`ChainOracle`] implementation is infallible, [`filter_chain_txouts`] can be used - /// instead. - /// - /// [`filter_chain_txouts`]: Self::filter_chain_txouts - pub fn try_filter_chain_txouts<'a, C: ChainOracle + 'a, OI: Clone + 'a>( + pub fn filter_chain_txouts<'a, C: ChainOracle + 'a, OI: Clone + 'a>( &'a self, chain: &'a C, chain_tip: BlockId, params: CanonicalizationParams, outpoints: impl IntoIterator + 'a, - ) -> Result)> + 'a, C::Error> { + ) -> impl Iterator)> + 'a { let mut canon_txs = HashMap::, A>>::new(); let mut canon_spends = HashMap::::new(); - for r in self.try_list_canonical_txs(chain, chain_tip, params) { - let canonical_tx = r?; + for canonical_tx in self.list_canonical_txs(chain, chain_tip, params) { let txid = canonical_tx.tx_node.txid; if !canonical_tx.tx_node.tx.is_coinbase() { @@ -1127,7 +1084,7 @@ impl TxGraph { } canon_txs.insert(txid, canonical_tx); } - Ok(outpoints.into_iter().filter_map(move |(spk_i, outpoint)| { + outpoints.into_iter().filter_map(move |(spk_i, outpoint)| { let canon_tx = canon_txs.get(&outpoint.txid)?; let txout = canon_tx .tx_node @@ -1154,7 +1111,7 @@ impl TxGraph { is_on_coinbase, }, )) - })) + }) } /// List txids by descending anchor height order. @@ -1192,23 +1149,6 @@ impl TxGraph { CanonicalIter::new(self, chain, chain_tip, params) } - /// Get a filtered list of outputs from the given `outpoints` that are in `chain` with - /// `chain_tip`. - /// - /// This is the infallible version of [`try_filter_chain_txouts`]. - /// - /// [`try_filter_chain_txouts`]: Self::try_filter_chain_txouts - pub fn filter_chain_txouts<'a, C: ChainOracle + 'a, OI: Clone + 'a>( - &'a self, - chain: &'a C, - chain_tip: BlockId, - params: CanonicalizationParams, - outpoints: impl IntoIterator + 'a, - ) -> impl Iterator)> + 'a { - self.try_filter_chain_txouts(chain, chain_tip, params, outpoints) - .expect("oracle is infallible") - } - /// Get a filtered list of unspent outputs (UTXOs) from the given `outpoints` that are in /// `chain` with `chain_tip`. /// @@ -1217,43 +1157,15 @@ impl TxGraph { /// [`Iterator::enumerate`] over a list of [`OutPoint`]s. /// /// Floating outputs are ignored. - /// - /// # Error - /// - /// An [`Iterator::Item`] can be an [`Err`] if the [`ChainOracle`] implementation (`chain`) - /// fails. - /// - /// If the [`ChainOracle`] implementation is infallible, [`filter_chain_unspents`] can be used - /// instead. - /// - /// [`filter_chain_unspents`]: Self::filter_chain_unspents - pub fn try_filter_chain_unspents<'a, C: ChainOracle + 'a, OI: Clone + 'a>( + pub fn filter_chain_unspents<'a, C: ChainOracle + 'a, OI: Clone + 'a>( &'a self, chain: &'a C, chain_tip: BlockId, params: CanonicalizationParams, outpoints: impl IntoIterator + 'a, - ) -> Result)> + 'a, C::Error> { - Ok(self - .try_filter_chain_txouts(chain, chain_tip, params, outpoints)? - .filter(|(_, full_txo)| full_txo.spent_by.is_none())) - } - - /// Get a filtered list of unspent outputs (UTXOs) from the given `outpoints` that are in - /// `chain` with `chain_tip`. - /// - /// This is the infallible version of [`try_filter_chain_unspents`]. - /// - /// [`try_filter_chain_unspents`]: Self::try_filter_chain_unspents - pub fn filter_chain_unspents<'a, C: ChainOracle + 'a, OI: Clone + 'a>( - &'a self, - chain: &'a C, - chain_tip: BlockId, - params: CanonicalizationParams, - txouts: impl IntoIterator + 'a, ) -> impl Iterator)> + 'a { - self.try_filter_chain_unspents(chain, chain_tip, params, txouts) - .expect("oracle is infallible") + self.filter_chain_txouts(chain, chain_tip, params, outpoints) + .filter(|(_, full_txo)| full_txo.spent_by.is_none()) } /// Get the total balance of `outpoints` that are in `chain` of `chain_tip`. @@ -1263,25 +1175,20 @@ impl TxGraph { /// `outpoints` is a list of outpoints we are interested in, coupled with an outpoint identifier /// (`OI`) for convenience. If `OI` is not necessary, the caller can use `()`, or /// [`Iterator::enumerate`] over a list of [`OutPoint`]s. - /// - /// If the provided [`ChainOracle`] implementation (`chain`) is infallible, [`balance`] can be - /// used instead. - /// - /// [`balance`]: Self::balance - pub fn try_balance( + pub fn balance( &self, chain: &C, chain_tip: BlockId, params: CanonicalizationParams, outpoints: impl IntoIterator, mut trust_predicate: impl FnMut(&OI, ScriptBuf) -> bool, - ) -> Result { + ) -> Balance { let mut immature = Amount::ZERO; let mut trusted_pending = Amount::ZERO; let mut untrusted_pending = Amount::ZERO; let mut confirmed = Amount::ZERO; - for (spk_i, txout) in self.try_filter_chain_unspents(chain, chain_tip, params, outpoints)? { + for (spk_i, txout) in self.filter_chain_unspents(chain, chain_tip, params, outpoints) { match &txout.chain_position { ChainPosition::Confirmed { .. } => { if txout.is_confirmed_and_spendable(chain_tip.height) { @@ -1300,17 +1207,14 @@ impl TxGraph { } } - Ok(Balance { + Balance { immature, trusted_pending, untrusted_pending, confirmed, - }) + } } - /// Get the total balance of `outpoints` that are in `chain` of `chain_tip`. - /// - /// This is the infallible version of [`try_balance`]. /// /// ### Minimum confirmations /// @@ -1375,19 +1279,6 @@ impl TxGraph { /// assert_eq!(balance.confirmed, Amount::from_sat(42_000)); /// ``` /// - /// [`try_balance`]: Self::try_balance - pub fn balance, OI: Clone>( - &self, - chain: &C, - chain_tip: BlockId, - params: CanonicalizationParams, - outpoints: impl IntoIterator, - trust_predicate: impl FnMut(&OI, ScriptBuf) -> bool, - ) -> Balance { - self.try_balance(chain, chain_tip, params, outpoints, trust_predicate) - .expect("oracle is infallible") - } - /// List txids that are expected to exist under the given spks. /// /// This is used to fill @@ -1395,61 +1286,30 @@ impl TxGraph { /// /// /// The spk index range can be constrained with `range`. - /// - /// # Error - /// - /// If the [`ChainOracle`] implementation (`chain`) fails, an error will be returned with the - /// returned item. - /// - /// If the [`ChainOracle`] is infallible, - /// [`list_expected_spk_txids`](Self::list_expected_spk_txids) can be used instead. - pub fn try_list_expected_spk_txids<'a, C, I>( + pub fn list_expected_spk_txids<'a, C, I>( &'a self, chain: &'a C, chain_tip: BlockId, indexer: &'a impl AsRef>, spk_index_range: impl RangeBounds + 'a, - ) -> impl Iterator> + 'a + ) -> impl Iterator + 'a where C: ChainOracle, I: fmt::Debug + Clone + Ord + 'a, { let indexer = indexer.as_ref(); - self.try_list_canonical_txs(chain, chain_tip, CanonicalizationParams::default()) - .flat_map(move |res| -> Vec> { + self.list_canonical_txs(chain, chain_tip, CanonicalizationParams::default()) + .flat_map(move |c_tx| { let range = &spk_index_range; - let c_tx = match res { - Ok(c_tx) => c_tx, - Err(err) => return vec![Err(err)], - }; let relevant_spks = indexer.relevant_spks_of_tx(&c_tx.tx_node); relevant_spks .into_iter() .filter(|(i, _)| range.contains(i)) - .map(|(_, spk)| Ok((spk, c_tx.tx_node.txid))) - .collect() + .map(|(_, spk)| (spk, c_tx.tx_node.txid)) + .collect::>() }) } - /// List txids that are expected to exist under the given spks. - /// - /// This is the infallible version of - /// [`try_list_expected_spk_txids`](Self::try_list_expected_spk_txids). - pub fn list_expected_spk_txids<'a, C, I>( - &'a self, - chain: &'a C, - chain_tip: BlockId, - indexer: &'a impl AsRef>, - spk_index_range: impl RangeBounds + 'a, - ) -> impl Iterator + 'a - where - C: ChainOracle, - I: fmt::Debug + Clone + Ord + 'a, - { - self.try_list_expected_spk_txids(chain, chain_tip, indexer, spk_index_range) - .map(|r| r.expect("infallible")) - } - /// Construct a `TxGraph` from a `changeset`. pub fn from_changeset(changeset: ChangeSet) -> Self { let mut graph = Self::default(); diff --git a/crates/chain/tests/test_tx_graph.rs b/crates/chain/tests/test_tx_graph.rs index 685b62c6e..3e5cb4b86 100644 --- a/crates/chain/tests/test_tx_graph.rs +++ b/crates/chain/tests/test_tx_graph.rs @@ -758,7 +758,7 @@ fn test_walk_ancestors() { let tx_node = graph.get_tx_node(tx.compute_txid())?; for block in tx_node.anchors { match local_chain.is_block_in_chain(block.anchor_block(), tip.block_id()) { - Ok(Some(true)) => return None, + Some(true) => return None, _ => continue, } } diff --git a/examples/example_cli/src/lib.rs b/examples/example_cli/src/lib.rs index 96a41802f..6e1f5ceff 100644 --- a/examples/example_cli/src/lib.rs +++ b/examples/example_cli/src/lib.rs @@ -268,10 +268,7 @@ pub fn create_tx( address: Address, value: u64, feerate: f32, -) -> anyhow::Result<(Psbt, Option)> -where - O::Error: std::error::Error + Send + Sync + 'static, -{ +) -> anyhow::Result<(Psbt, Option)> { let mut changeset = keychain_txout::ChangeSet::default(); // get planned utxos @@ -395,7 +392,7 @@ where lock_time: assets .absolute_timelock .unwrap_or(absolute::LockTime::from_height( - chain.get_chain_tip()?.height, + chain.get_chain_tip().height, )?), input: selected .iter() @@ -428,17 +425,17 @@ pub fn planned_utxos( graph: &KeychainTxGraph, chain: &O, assets: &Assets, -) -> Result, O::Error> { - let chain_tip = chain.get_chain_tip()?; +) -> anyhow::Result> { + let chain_tip = chain.get_chain_tip(); let outpoints = graph.index.outpoints(); graph .graph() - .try_filter_chain_unspents( + .filter_chain_unspents( chain, chain_tip, CanonicalizationParams::default(), outpoints.iter().cloned(), - )? + ) .filter_map(|((k, i), full_txo)| -> Option> { let desc = graph .index @@ -529,13 +526,13 @@ pub fn handle_commands( } } - let balance = graph.graph().try_balance( + let balance = graph.graph().balance( chain, - chain.get_chain_tip()?, + chain.get_chain_tip(), CanonicalizationParams::default(), graph.index.outpoints().iter().cloned(), |(k, _), _| k == &Keychain::Internal, - )?; + ); let confirmed_total = balance.confirmed + balance.immature; let unconfirmed_total = balance.untrusted_pending + balance.trusted_pending; @@ -562,7 +559,7 @@ pub fn handle_commands( Commands::TxOut { txout_cmd } => { let graph = &*graph.lock().unwrap(); let chain = &*chain.lock().unwrap(); - let chain_tip = chain.get_chain_tip()?; + let chain_tip = chain.get_chain_tip(); let outpoints = graph.index.outpoints(); match txout_cmd { @@ -574,12 +571,12 @@ pub fn handle_commands( } => { let txouts = graph .graph() - .try_filter_chain_txouts( + .filter_chain_txouts( chain, chain_tip, CanonicalizationParams::default(), outpoints.iter().cloned(), - )? + ) .filter(|(_, full_txo)| match (spent, unspent) { (true, false) => full_txo.spent_by.is_some(), (false, true) => full_txo.spent_by.is_none(),