diff --git a/crates/chain/src/canonical_iter.rs b/crates/chain/src/canonical_iter.rs index 204ead451..3de08e663 100644 --- a/crates/chain/src/canonical_iter.rs +++ b/crates/chain/src/canonical_iter.rs @@ -1,6 +1,6 @@ use crate::collections::{HashMap, HashSet, VecDeque}; use crate::tx_graph::{TxAncestors, TxDescendants}; -use crate::{Anchor, ChainOracle, TxGraph}; +use crate::{Anchor, TxGraph}; use alloc::boxed::Box; use alloc::collections::BTreeSet; use alloc::sync::Arc; @@ -22,10 +22,12 @@ pub struct CanonicalizationParams { } /// Iterates over canonical txs. -pub struct CanonicalIter<'g, A, C> { +pub struct CanonicalIter<'g, A, F> +where + F: FnMut(BlockId) -> Option, +{ tx_graph: &'g TxGraph, - chain: &'g C, - chain_tip: BlockId, + is_block_in_chain: F, unprocessed_assumed_txs: Box)> + 'g>, unprocessed_anchored_txs: @@ -39,13 +41,15 @@ pub struct CanonicalIter<'g, A, C> { queue: VecDeque, } -impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> { +impl<'g, A: Anchor, F> CanonicalIter<'g, A, F> +where + F: FnMut(BlockId) -> Option, +{ /// Constructs [`CanonicalIter`]. pub fn new( tx_graph: &'g TxGraph, - chain: &'g C, - chain_tip: BlockId, params: CanonicalizationParams, + is_block_in_chain: F, ) -> Self { let anchors = tx_graph.all_anchors(); let unprocessed_assumed_txs = Box::new( @@ -67,8 +71,7 @@ impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> { ); Self { tx_graph, - chain, - chain_tip, + is_block_in_chain, unprocessed_assumed_txs, unprocessed_anchored_txs, unprocessed_seen_txs, @@ -85,19 +88,13 @@ 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)?; - if in_chain_opt == Some(true) { + let block_id = anchor.anchor_block(); + let is_block_in_chain = (self.is_block_in_chain)(block_id); + if is_block_in_chain == Some(true) { self.mark_canonical(txid, tx, CanonicalReason::from_anchor(anchor.clone())); - return Ok(()); + return; } } // cannot determine @@ -112,7 +109,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 @@ -200,8 +196,11 @@ impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> { } } -impl Iterator for CanonicalIter<'_, A, C> { - type Item = Result<(Txid, Arc, CanonicalReason), C::Error>; +impl Iterator for CanonicalIter<'_, A, F> +where + F: FnMut(BlockId) -> Option, +{ + type Item = (Txid, Arc, CanonicalReason); fn next(&mut self) -> Option { loop { @@ -211,7 +210,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 +221,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/tx_graph.rs b/crates/chain/src/tx_graph.rs index 6b9a4cf96..2f0b9822d 100644 --- a/crates/chain/src/tx_graph.rs +++ b/crates/chain/src/tx_graph.rs @@ -998,7 +998,7 @@ impl TxGraph { 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, @@ -1016,60 +1016,61 @@ impl TxGraph { }) .transpose() } - 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, - }, - }, - None => ChainPosition::Unconfirmed { - first_seen: tx_node.first_seen, - last_seen: tx_node.last_seen, - }, + self.canonical_iter(params, move |block_id: BlockId| -> Option { + // FIXME: (@leonardolima) how should we handle the error from ChainOracle ? + chain.is_block_in_chain(block_id, chain_tip).unwrap_or_default() + }) + .flat_map(move |(txid, _, canonical_reason)| -> Result, A>, C::Error> { + 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, }, - 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::Confirmed { - anchor, - transitively: None, - }, + None => ChainPosition::Unconfirmed { + first_seen: tx_node.first_seen, + last_seen: tx_node.last_seen, }, - 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::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, }, - }; - Ok(CanonicalTx { - chain_position, - tx_node, - }) - }) + None => ChainPosition::Confirmed { + anchor, + transitively: descendant, + }, + }, + None => ChainPosition::Confirmed { + anchor, + transitively: None, + }, + }, + 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, + }, + }, + }; + Ok(CanonicalTx { + chain_position, + tx_node, }) + }) } /// List graph transactions that are in `chain` with `chain_tip`. @@ -1084,7 +1085,6 @@ impl TxGraph { 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 @@ -1116,7 +1116,7 @@ impl TxGraph { 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?; + let canonical_tx = r; let txid = canonical_tx.tx_node.txid; if !canonical_tx.tx_node.tx.is_coinbase() { @@ -1183,13 +1183,15 @@ impl TxGraph { } /// Returns a [`CanonicalIter`]. - pub fn canonical_iter<'a, C: ChainOracle>( + pub fn canonical_iter<'a, F>( &'a self, - chain: &'a C, - chain_tip: BlockId, params: CanonicalizationParams, - ) -> CanonicalIter<'a, A, C> { - CanonicalIter::new(self, chain, chain_tip, params) + is_block_in_chain: F, + ) -> CanonicalIter<'a, A, F> + where + F: FnMut(BlockId) -> Option, + { + CanonicalIter::new(self, params, is_block_in_chain) } /// Get a filtered list of outputs from the given `outpoints` that are in `chain` with @@ -1416,12 +1418,13 @@ impl TxGraph { { let indexer = indexer.as_ref(); self.try_list_canonical_txs(chain, chain_tip, CanonicalizationParams::default()) - .flat_map(move |res| -> Vec> { + .flat_map(move |c_tx| -> Vec> { let range = &spk_index_range; - let c_tx = match res { - Ok(c_tx) => c_tx, - Err(err) => return vec![Err(err)], - }; + // FIXME: (@oleonardolima) should we handle the error here somehow ? + // 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()