1
1
use crate :: collections:: { HashMap , HashSet , VecDeque } ;
2
- use crate :: tx_graph:: { TxAncestors , TxDescendants , TxNode } ;
2
+ use crate :: tx_graph:: { TxAncestors , TxDescendants } ;
3
3
use crate :: { Anchor , ChainOracle , TxGraph } ;
4
4
use alloc:: boxed:: Box ;
5
5
use alloc:: collections:: BTreeSet ;
@@ -213,20 +213,17 @@ impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> {
213
213
self . not_canonical . remove ( & txid) ;
214
214
}
215
215
} else {
216
- // TODO: (@oleonardolima) Can this be optimized somehow ?
217
- // Can we just do a simple lookup on the `canonical_ancestors` field ?
218
216
for txid in staged_queue {
219
217
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 {
230
227
self . canonical_roots . push_back ( txid) ;
231
228
}
232
229
}
@@ -271,12 +268,18 @@ impl<A: Anchor, C: ChainOracle> Iterator for CanonicalIter<'_, A, C> {
271
268
}
272
269
273
270
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 (
278
272
& self . canonical_ancestors ,
279
273
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
+ } ,
280
283
) ;
281
284
self . queue . extend ( topological_iter) ;
282
285
}
@@ -383,97 +386,65 @@ impl<A: Clone> CanonicalReason<A> {
383
386
}
384
387
}
385
388
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
+ {
391
393
current_level : Vec < Txid > ,
392
394
next_level : Vec < Txid > ,
393
395
394
396
adj_list : HashMap < Txid , Vec < Txid > > ,
395
- parent_count : HashMap < Txid , usize > ,
397
+ inputs_count : HashMap < Txid , usize > ,
396
398
397
399
current_index : usize ,
400
+
401
+ sort_by : F ,
398
402
}
399
403
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 ( ) ;
409
410
let mut adj_list: HashMap < Txid , Vec < Txid > > = HashMap :: new ( ) ;
410
411
411
- for ( txid, ancestors) in ancestors_by_txid {
412
+ for ( txid, ancestors) in ancestors {
412
413
for ancestor in ancestors {
413
414
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 ;
415
416
}
416
417
}
417
418
418
419
let mut current_level: Vec < Txid > = roots. to_vec ( ) ;
419
420
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) ) ;
428
423
429
424
Self {
430
425
current_level,
431
426
next_level : Vec :: new ( ) ,
432
427
adj_list,
433
- parent_count ,
428
+ inputs_count ,
434
429
current_index : 0 ,
435
- tx_graph,
436
- chain,
437
- chain_tip,
430
+ sort_by,
438
431
}
439
432
}
440
433
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
-
459
434
fn advance_to_next_level ( & mut self ) {
460
435
self . current_level = core:: mem:: take ( & mut self . next_level ) ;
461
436
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) ) ;
471
439
472
440
self . current_index = 0 ;
473
441
}
474
442
}
475
443
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
+ {
477
448
type Item = Txid ;
478
449
479
450
fn next ( & mut self ) -> Option < Self :: Item > {
@@ -494,7 +465,7 @@ impl<'a, A: Anchor, C: ChainOracle> Iterator for TopologicalIteratorWithLevels<'
494
465
for & tx in & self . current_level {
495
466
if let Some ( dependents) = self . adj_list . get ( & tx) {
496
467
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) {
498
469
* degree -= 1 ;
499
470
if * degree == 0 {
500
471
self . next_level . push ( dependent) ;
0 commit comments