@@ -6,7 +6,7 @@ use alloc::collections::BTreeSet;
6
6
use alloc:: sync:: Arc ;
7
7
use alloc:: vec:: Vec ;
8
8
use bdk_core:: BlockId ;
9
- use bitcoin:: { Transaction , Txid } ;
9
+ use bitcoin:: { OutPoint , Transaction , Txid } ;
10
10
11
11
type CanonicalMap < A > = HashMap < Txid , ( Arc < Transaction > , CanonicalReason < A > ) > ;
12
12
type NotCanonicalSet = HashSet < Txid > ;
@@ -36,7 +36,7 @@ pub struct CanonicalIter<'g, A, C> {
36
36
canonical : CanonicalMap < A > ,
37
37
not_canonical : NotCanonicalSet ,
38
38
39
- canonical_ancestors : HashMap < Txid , Vec < Txid > > ,
39
+ canonical_spends : HashMap < OutPoint , Txid > ,
40
40
canonical_roots : VecDeque < Txid > ,
41
41
42
42
queue : VecDeque < Txid > ,
@@ -78,7 +78,7 @@ impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> {
78
78
unprocessed_leftover_txs : VecDeque :: new ( ) ,
79
79
canonical : HashMap :: new ( ) ,
80
80
not_canonical : HashSet :: new ( ) ,
81
- canonical_ancestors : HashMap :: new ( ) ,
81
+ canonical_spends : HashMap :: new ( ) ,
82
82
canonical_roots : VecDeque :: new ( ) ,
83
83
queue : VecDeque :: new ( ) ,
84
84
}
@@ -187,16 +187,13 @@ impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> {
187
187
return None ;
188
188
}
189
189
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
+ }
200
197
201
198
canonical_entry. insert ( ( tx, this_reason) ) ;
202
199
Some ( this_txid)
@@ -206,20 +203,23 @@ impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> {
206
203
207
204
if detected_self_double_spend {
208
205
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
+ }
211
212
}
212
213
for txid in undo_not_canonical {
213
214
self . not_canonical . remove ( & txid) ;
214
215
}
215
216
} else {
216
217
for txid in staged_queue {
217
218
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 ( ) ) ;
223
223
224
224
// check if it's a root: it's either a coinbase transaction or has no known
225
225
// ancestors in the tx_graph.
@@ -269,7 +269,7 @@ impl<A: Anchor, C: ChainOracle> Iterator for CanonicalIter<'_, A, C> {
269
269
270
270
if !self . canonical_roots . is_empty ( ) {
271
271
let topological_iter = TopologicalIter :: new (
272
- & self . canonical_ancestors ,
272
+ & self . canonical_spends ,
273
273
self . canonical_roots . drain ( ..) . collect ( ) ,
274
274
|txid| {
275
275
let tx_node = self . tx_graph . get_tx_node ( txid) . expect ( "tx should exist" ) ;
@@ -405,15 +405,17 @@ impl<F> TopologicalIter<F>
405
405
where
406
406
F : FnMut ( bitcoin:: Txid ) -> u32 ,
407
407
{
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 {
409
409
let mut inputs_count = HashMap :: new ( ) ;
410
410
let mut adj_list: HashMap < Txid , Vec < Txid > > = HashMap :: new ( ) ;
411
411
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. entry ( ancestor_txid) . or_default ( ) . push ( * spending_txid) ;
418
+ * inputs_count. entry ( * spending_txid) . or_insert ( 0 ) += 1 ;
417
419
}
418
420
419
421
let mut current_level: Vec < Txid > = roots. to_vec ( ) ;
0 commit comments