11use crate :: collections:: { HashMap , HashSet , VecDeque } ;
2- use crate :: tx_graph:: { TxAncestors , TxDescendants , TxNode } ;
2+ use crate :: tx_graph:: { TxAncestors , TxDescendants } ;
33use crate :: { Anchor , ChainOracle , TxGraph } ;
44use alloc:: boxed:: Box ;
55use alloc:: collections:: BTreeSet ;
@@ -213,20 +213,17 @@ impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> {
213213 self . not_canonical . remove ( & txid) ;
214214 }
215215 } else {
216- // TODO: (@oleonardolima) Can this be optimized somehow ?
217- // Can we just do a simple lookup on the `canonical_ancestors` field ?
218216 for txid in staged_queue {
219217 let tx = self . tx_graph . get_tx ( txid) . expect ( "tx must exist" ) ;
220- let ancestors = tx
221- . input
222- . iter ( )
223- . map ( |txin| txin. previous_output . txid )
224- . filter_map ( |prev_txid| self . tx_graph . get_tx ( prev_txid) )
225- . collect :: < Vec < _ > > ( ) ;
226-
227- // check if it's a root: it's either a coinbase transaction or has not known
228- // ancestors in the tx_graph
229- if tx. is_coinbase ( ) || ancestors. is_empty ( ) {
218+ let has_no_ancestors = self
219+ . canonical_ancestors
220+ . get ( & txid)
221+ . expect ( "should exist" )
222+ . is_empty ( ) ;
223+
224+ // check if it's a root: it's either a coinbase transaction or has no known
225+ // ancestors in the tx_graph.
226+ if tx. is_coinbase ( ) || has_no_ancestors {
230227 self . canonical_roots . push_back ( txid) ;
231228 }
232229 }
@@ -271,12 +268,18 @@ impl<A: Anchor, C: ChainOracle> Iterator for CanonicalIter<'_, A, C> {
271268 }
272269
273270 if !self . canonical_roots . is_empty ( ) {
274- let topological_iter = TopologicalIteratorWithLevels :: new (
275- self . tx_graph ,
276- self . chain ,
277- self . chain_tip ,
271+ let topological_iter = TopologicalIter :: new (
278272 & self . canonical_ancestors ,
279273 self . canonical_roots . drain ( ..) . collect ( ) ,
274+ |txid| {
275+ let tx_node = self . tx_graph . get_tx_node ( txid) . expect ( "tx should exist" ) ;
276+ self . tx_graph
277+ . find_direct_anchor ( & tx_node, self . chain , self . chain_tip )
278+ . expect ( "should not fail" )
279+ . map ( |anchor| anchor. confirmation_height_upper_bound ( ) )
280+ . unwrap_or ( u32:: MAX ) // FIXME: (@oleonardo) should we use the `first_seen`
281+ // instead ?
282+ } ,
280283 ) ;
281284 self . queue . extend ( topological_iter) ;
282285 }
@@ -383,97 +386,65 @@ impl<A: Clone> CanonicalReason<A> {
383386 }
384387}
385388
386- struct TopologicalIteratorWithLevels < ' a , A , C > {
387- tx_graph : & ' a TxGraph < A > ,
388- chain : & ' a C ,
389- chain_tip : BlockId ,
390-
389+ struct TopologicalIter < F >
390+ where
391+ F : FnMut ( Txid ) -> u32 ,
392+ {
391393 current_level : Vec < Txid > ,
392394 next_level : Vec < Txid > ,
393395
394396 adj_list : HashMap < Txid , Vec < Txid > > ,
395- parent_count : HashMap < Txid , usize > ,
397+ inputs_count : HashMap < Txid , usize > ,
396398
397399 current_index : usize ,
400+
401+ sort_by : F ,
398402}
399403
400- impl < ' a , A : Anchor , C : ChainOracle > TopologicalIteratorWithLevels < ' a , A , C > {
401- fn new (
402- tx_graph : & ' a TxGraph < A > ,
403- chain : & ' a C ,
404- chain_tip : BlockId ,
405- ancestors_by_txid : & HashMap < Txid , Vec < Txid > > ,
406- roots : Vec < Txid > ,
407- ) -> Self {
408- let mut parent_count = HashMap :: new ( ) ;
404+ impl < F > TopologicalIter < F >
405+ where
406+ F : FnMut ( bitcoin:: Txid ) -> u32 ,
407+ {
408+ fn new ( ancestors : & HashMap < Txid , Vec < Txid > > , roots : Vec < Txid > , mut sort_by : F ) -> Self {
409+ let mut inputs_count = HashMap :: new ( ) ;
409410 let mut adj_list: HashMap < Txid , Vec < Txid > > = HashMap :: new ( ) ;
410411
411- for ( txid, ancestors) in ancestors_by_txid {
412+ for ( txid, ancestors) in ancestors {
412413 for ancestor in ancestors {
413414 adj_list. entry ( * ancestor) . or_default ( ) . push ( * txid) ;
414- * parent_count . entry ( * txid) . or_insert ( 0 ) += 1 ;
415+ * inputs_count . entry ( * txid) . or_insert ( 0 ) += 1 ;
415416 }
416417 }
417418
418419 let mut current_level: Vec < Txid > = roots. to_vec ( ) ;
419420
420- // Sort the initial level by confirmation height
421- current_level. sort_by_key ( |& txid| {
422- let tx_node = tx_graph. get_tx_node ( txid) . expect ( "tx should exist" ) ;
423- Self :: find_direct_anchor ( & tx_node, chain, chain_tip)
424- . expect ( "should not fail" )
425- . map ( |anchor| anchor. confirmation_height_upper_bound ( ) )
426- . unwrap_or ( u32:: MAX )
427- } ) ;
421+ // sort the level by confirmation height
422+ current_level. sort_by_key ( |txid| sort_by ( * txid) ) ;
428423
429424 Self {
430425 current_level,
431426 next_level : Vec :: new ( ) ,
432427 adj_list,
433- parent_count ,
428+ inputs_count ,
434429 current_index : 0 ,
435- tx_graph,
436- chain,
437- chain_tip,
430+ sort_by,
438431 }
439432 }
440433
441- fn find_direct_anchor (
442- tx_node : & TxNode < ' _ , Arc < Transaction > , A > ,
443- chain : & C ,
444- chain_tip : BlockId ,
445- ) -> Result < Option < A > , C :: Error > {
446- tx_node
447- . anchors
448- . iter ( )
449- . find_map ( |a| -> Option < Result < A , C :: Error > > {
450- match chain. is_block_in_chain ( a. anchor_block ( ) , chain_tip) {
451- Ok ( Some ( true ) ) => Some ( Ok ( a. clone ( ) ) ) ,
452- Ok ( Some ( false ) ) | Ok ( None ) => None ,
453- Err ( err) => Some ( Err ( err) ) ,
454- }
455- } )
456- . transpose ( )
457- }
458-
459434 fn advance_to_next_level ( & mut self ) {
460435 self . current_level = core:: mem:: take ( & mut self . next_level ) ;
461436
462- // Sort by confirmation height
463- self . current_level . sort_by_key ( |& txid| {
464- let tx_node = self . tx_graph . get_tx_node ( txid) . expect ( "tx should exist" ) ;
465-
466- Self :: find_direct_anchor ( & tx_node, self . chain , self . chain_tip )
467- . expect ( "should not fail" )
468- . map ( |anchor| anchor. confirmation_height_upper_bound ( ) )
469- . unwrap_or ( u32:: MAX )
470- } ) ;
437+ // sort the level by confirmation height
438+ self . current_level . sort_by_key ( |& txid| ( self . sort_by ) ( txid) ) ;
471439
472440 self . current_index = 0 ;
473441 }
474442}
475443
476- impl < ' a , A : Anchor , C : ChainOracle > Iterator for TopologicalIteratorWithLevels < ' a , A , C > {
444+ impl < F > Iterator for TopologicalIter < F >
445+ where
446+ F : FnMut ( bitcoin:: Txid ) -> u32 ,
447+ {
477448 type Item = Txid ;
478449
479450 fn next ( & mut self ) -> Option < Self :: Item > {
@@ -494,7 +465,7 @@ impl<'a, A: Anchor, C: ChainOracle> Iterator for TopologicalIteratorWithLevels<'
494465 for & tx in & self . current_level {
495466 if let Some ( dependents) = self . adj_list . get ( & tx) {
496467 for & dependent in dependents {
497- if let Some ( degree) = self . parent_count . get_mut ( & dependent) {
468+ if let Some ( degree) = self . inputs_count . get_mut ( & dependent) {
498469 * degree -= 1 ;
499470 if * degree == 0 {
500471 self . next_level . push ( dependent) ;
0 commit comments