@@ -6,7 +6,7 @@ use alloc::collections::BTreeSet;
66use  alloc:: sync:: Arc ; 
77use  alloc:: vec:: Vec ; 
88use  bdk_core:: BlockId ; 
9- use  bitcoin:: { Transaction ,  Txid } ; 
9+ use  bitcoin:: { OutPoint ,   Transaction ,  Txid } ; 
1010
1111type  CanonicalMap < A >  = HashMap < Txid ,  ( Arc < Transaction > ,  CanonicalReason < A > ) > ; 
1212type  NotCanonicalSet  = HashSet < Txid > ; 
@@ -36,7 +36,7 @@ pub struct CanonicalIter<'g, A, C> {
3636    canonical :  CanonicalMap < A > , 
3737    not_canonical :  NotCanonicalSet , 
3838
39-     canonical_ancestors :  HashMap < Txid ,   Vec < Txid > > , 
39+     canonical_spends :  HashMap < OutPoint ,   Txid > , 
4040    canonical_roots :  VecDeque < Txid > , 
4141
4242    queue :  VecDeque < Txid > , 
@@ -78,7 +78,7 @@ impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> {
7878            unprocessed_leftover_txs :  VecDeque :: new ( ) , 
7979            canonical :  HashMap :: new ( ) , 
8080            not_canonical :  HashSet :: new ( ) , 
81-             canonical_ancestors :  HashMap :: new ( ) , 
81+             canonical_spends :  HashMap :: new ( ) , 
8282            canonical_roots :  VecDeque :: new ( ) , 
8383            queue :  VecDeque :: new ( ) , 
8484        } 
@@ -165,7 +165,7 @@ impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> {
165165
166166                // Any conflicts with a canonical tx can be added to `not_canonical`. Descendants 
167167                // of `not_canonical` txs can also be added to `not_canonical`. 
168-                 for  ( _,  conflict_txid)  in  self . tx_graph . direct_conflicts ( & tx. clone ( ) )  { 
168+                 for  ( _,  conflict_txid)  in  self . tx_graph . direct_conflicts ( & tx)  { 
169169                    TxDescendants :: new_include_root ( 
170170                        self . tx_graph , 
171171                        conflict_txid, 
@@ -187,16 +187,13 @@ impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> {
187187                    return  None ; 
188188                } 
189189
190-                 // Calculates all the existing ancestors for the given Txid 
191-                 self . canonical_ancestors . insert ( 
192-                     this_txid, 
193-                     tx. clone ( ) 
194-                         . input 
195-                         . iter ( ) 
196-                         . filter ( |txin| self . tx_graph . get_tx ( txin. previous_output . txid ) . is_some ( ) ) 
197-                         . map ( |txin| txin. previous_output . txid ) 
198-                         . collect ( ) , 
199-                 ) ; 
190+                 // Record each input's outpoint as being spent by this transaction 
191+                 for  input in  & tx. input  { 
192+                     if  self . tx_graph . get_tx ( input. previous_output . txid ) . is_some ( )  { 
193+                         self . canonical_spends 
194+                             . insert ( input. previous_output ,  this_txid) ; 
195+                     } 
196+                 } 
200197
201198                canonical_entry. insert ( ( tx,  this_reason) ) ; 
202199                Some ( this_txid) 
@@ -206,20 +203,23 @@ impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> {
206203
207204        if  detected_self_double_spend { 
208205            for  txid in  staged_queue { 
209-                 self . canonical . remove ( & txid) ; 
210-                 self . canonical_ancestors . remove ( & txid) ; 
206+                 if  let  Some ( ( tx,  _) )  = self . canonical . remove ( & txid)  { 
207+                     // Remove all the spends that were added for this transaction 
208+                     for  input in  & tx. input  { 
209+                         self . canonical_spends . remove ( & input. previous_output ) ; 
210+                     } 
211+                 } 
211212            } 
212213            for  txid in  undo_not_canonical { 
213214                self . not_canonical . remove ( & txid) ; 
214215            } 
215216        }  else  { 
216217            for  txid in  staged_queue { 
217218                let  tx = self . tx_graph . get_tx ( txid) . expect ( "tx must exist" ) ; 
218-                 let  has_no_ancestors = self 
219-                     . canonical_ancestors 
220-                     . get ( & txid) 
221-                     . expect ( "should exist" ) 
222-                     . is_empty ( ) ; 
219+                 let  has_no_ancestors = tx
220+                     . input 
221+                     . iter ( ) 
222+                     . all ( |input| self . tx_graph . get_tx ( input. previous_output . txid ) . is_none ( ) ) ; 
223223
224224                // check if it's a root: it's either a coinbase transaction or has no known 
225225                // ancestors in the tx_graph. 
@@ -269,7 +269,7 @@ impl<A: Anchor, C: ChainOracle> Iterator for CanonicalIter<'_, A, C> {
269269
270270        if  !self . canonical_roots . is_empty ( )  { 
271271            let  topological_iter = TopologicalIter :: new ( 
272-                 & self . canonical_ancestors , 
272+                 & self . canonical_spends , 
273273                self . canonical_roots . drain ( ..) . collect ( ) , 
274274                |txid| { 
275275                    let  tx_node = self . tx_graph . get_tx_node ( txid) . expect ( "tx should exist" ) ; 
@@ -405,15 +405,20 @@ impl<F> TopologicalIter<F>
405405where 
406406    F :  FnMut ( bitcoin:: Txid )  -> u32 , 
407407{ 
408-     fn  new ( ancestors :  & HashMap < Txid ,   Vec < Txid > > ,  roots :  Vec < Txid > ,  mut  sort_by :  F )  -> Self  { 
408+     fn  new ( canonical_spends :  & HashMap < OutPoint ,   Txid > ,  roots :  Vec < Txid > ,  mut  sort_by :  F )  -> Self  { 
409409        let  mut  inputs_count = HashMap :: new ( ) ; 
410410        let  mut  adj_list:  HashMap < Txid ,  Vec < Txid > >  = HashMap :: new ( ) ; 
411411
412-         for  ( txid,  ancestors)  in  ancestors { 
413-             for  ancestor in  ancestors { 
414-                 adj_list. entry ( * ancestor) . or_default ( ) . push ( * txid) ; 
415-                 * inputs_count. entry ( * txid) . or_insert ( 0 )  += 1 ; 
416-             } 
412+         // Build adjacency list from canonical_spends 
413+         // Each entry in canonical_spends tells us that outpoint is spent by txid 
414+         // So if outpoint's txid exists, we create an edge from that tx to the spending tx 
415+         for  ( outpoint,  spending_txid)  in  canonical_spends { 
416+             let  ancestor_txid = outpoint. txid ; 
417+             adj_list
418+                 . entry ( ancestor_txid) 
419+                 . or_default ( ) 
420+                 . push ( * spending_txid) ; 
421+             * inputs_count. entry ( * spending_txid) . or_insert ( 0 )  += 1 ; 
417422        } 
418423
419424        let  mut  current_level:  Vec < Txid >  = roots. to_vec ( ) ; 
0 commit comments