@@ -5,7 +5,7 @@ use bdk_chain::{
55 collections:: * ,
66 local_chain:: LocalChain ,
77 tx_graph:: { ChangeSet , TxGraph } ,
8- Anchor , Append , BlockId , ChainPosition , ConfirmationHeightAnchor ,
8+ Anchor , Append , BlockId , ChainOracle , ChainPosition , ConfirmationHeightAnchor ,
99} ;
1010use bitcoin:: {
1111 absolute, hashes:: Hash , BlockHash , OutPoint , ScriptBuf , Transaction , TxIn , TxOut , Txid ,
@@ -496,6 +496,208 @@ fn test_calculate_fee_on_coinbase() {
496496 assert_eq ! ( graph. calculate_fee( & tx) , Ok ( 0 ) ) ;
497497}
498498
499+ // `test_walk_ancestors` uses the following transaction structure:
500+ //
501+ // a0
502+ // / \
503+ // b0 b1 b2
504+ // / \ \ /
505+ // c0 c1 c2 c3
506+ // / \ /
507+ // d0 d1
508+ // \
509+ // e0
510+ //
511+ // where b0 and b1 spend a0, c0 and c1 spend b0, d0 spends c1, etc.
512+ #[ test]
513+ fn test_walk_ancestors ( ) {
514+ let local_chain: LocalChain = ( 0 ..=20 )
515+ . map ( |ht| ( ht, BlockHash :: hash ( format ! ( "Block Hash {}" , ht) . as_bytes ( ) ) ) )
516+ . collect :: < BTreeMap < u32 , BlockHash > > ( )
517+ . into ( ) ;
518+ let tip = local_chain. tip ( ) . expect ( "must have tip" ) ;
519+
520+ let tx_a0 = Transaction {
521+ input : vec ! [ TxIn {
522+ previous_output: OutPoint :: new( h!( "op0" ) , 0 ) ,
523+ ..TxIn :: default ( )
524+ } ] ,
525+ output : vec ! [ TxOut :: default ( ) , TxOut :: default ( ) ] ,
526+ ..common:: new_tx ( 0 )
527+ } ;
528+
529+ // tx_b0 spends tx_a0
530+ let tx_b0 = Transaction {
531+ input : vec ! [ TxIn {
532+ previous_output: OutPoint :: new( tx_a0. txid( ) , 0 ) ,
533+ ..TxIn :: default ( )
534+ } ] ,
535+ output : vec ! [ TxOut :: default ( ) , TxOut :: default ( ) ] ,
536+ ..common:: new_tx ( 0 )
537+ } ;
538+
539+ // tx_b1 spends tx_a0
540+ let tx_b1 = Transaction {
541+ input : vec ! [ TxIn {
542+ previous_output: OutPoint :: new( tx_a0. txid( ) , 1 ) ,
543+ ..TxIn :: default ( )
544+ } ] ,
545+ output : vec ! [ TxOut :: default ( ) ] ,
546+ ..common:: new_tx ( 0 )
547+ } ;
548+
549+ let tx_b2 = Transaction {
550+ input : vec ! [ TxIn {
551+ previous_output: OutPoint :: new( h!( "op1" ) , 0 ) ,
552+ ..TxIn :: default ( )
553+ } ] ,
554+ output : vec ! [ TxOut :: default ( ) ] ,
555+ ..common:: new_tx ( 0 )
556+ } ;
557+
558+ // tx_c0 spends tx_b0
559+ let tx_c0 = Transaction {
560+ input : vec ! [ TxIn {
561+ previous_output: OutPoint :: new( tx_b0. txid( ) , 0 ) ,
562+ ..TxIn :: default ( )
563+ } ] ,
564+ output : vec ! [ TxOut :: default ( ) ] ,
565+ ..common:: new_tx ( 0 )
566+ } ;
567+
568+ // tx_c1 spends tx_b0
569+ let tx_c1 = Transaction {
570+ input : vec ! [ TxIn {
571+ previous_output: OutPoint :: new( tx_b0. txid( ) , 1 ) ,
572+ ..TxIn :: default ( )
573+ } ] ,
574+ output : vec ! [ TxOut :: default ( ) ] ,
575+ ..common:: new_tx ( 0 )
576+ } ;
577+
578+ // tx_c2 spends tx_b1 and tx_b2
579+ let tx_c2 = Transaction {
580+ input : vec ! [
581+ TxIn {
582+ previous_output: OutPoint :: new( tx_b1. txid( ) , 0 ) ,
583+ ..TxIn :: default ( )
584+ } ,
585+ TxIn {
586+ previous_output: OutPoint :: new( tx_b2. txid( ) , 0 ) ,
587+ ..TxIn :: default ( )
588+ } ,
589+ ] ,
590+ output : vec ! [ TxOut :: default ( ) ] ,
591+ ..common:: new_tx ( 0 )
592+ } ;
593+
594+ let tx_c3 = Transaction {
595+ input : vec ! [ TxIn {
596+ previous_output: OutPoint :: new( h!( "op2" ) , 0 ) ,
597+ ..TxIn :: default ( )
598+ } ] ,
599+ output : vec ! [ TxOut :: default ( ) ] ,
600+ ..common:: new_tx ( 0 )
601+ } ;
602+
603+ // tx_d0 spends tx_c1
604+ let tx_d0 = Transaction {
605+ input : vec ! [ TxIn {
606+ previous_output: OutPoint :: new( tx_c1. txid( ) , 0 ) ,
607+ ..TxIn :: default ( )
608+ } ] ,
609+ output : vec ! [ TxOut :: default ( ) ] ,
610+ ..common:: new_tx ( 0 )
611+ } ;
612+
613+ // tx_d1 spends tx_c2 and tx_c3
614+ let tx_d1 = Transaction {
615+ input : vec ! [
616+ TxIn {
617+ previous_output: OutPoint :: new( tx_c2. txid( ) , 0 ) ,
618+ ..TxIn :: default ( )
619+ } ,
620+ TxIn {
621+ previous_output: OutPoint :: new( tx_c3. txid( ) , 0 ) ,
622+ ..TxIn :: default ( )
623+ } ,
624+ ] ,
625+ output : vec ! [ TxOut :: default ( ) ] ,
626+ ..common:: new_tx ( 0 )
627+ } ;
628+
629+ // tx_e0 spends tx_d1
630+ let tx_e0 = Transaction {
631+ input : vec ! [ TxIn {
632+ previous_output: OutPoint :: new( tx_d1. txid( ) , 0 ) ,
633+ ..TxIn :: default ( )
634+ } ] ,
635+ output : vec ! [ TxOut :: default ( ) ] ,
636+ ..common:: new_tx ( 0 )
637+ } ;
638+
639+ let mut graph = TxGraph :: < BlockId > :: new ( vec ! [
640+ tx_a0. clone( ) ,
641+ tx_b0. clone( ) ,
642+ tx_b1. clone( ) ,
643+ tx_b2. clone( ) ,
644+ tx_c0. clone( ) ,
645+ tx_c1. clone( ) ,
646+ tx_c2. clone( ) ,
647+ tx_c3. clone( ) ,
648+ tx_d0. clone( ) ,
649+ tx_d1. clone( ) ,
650+ tx_e0. clone( ) ,
651+ ] ) ;
652+
653+ [ & tx_a0, & tx_b1] . iter ( ) . for_each ( |& tx| {
654+ let _ = graph. insert_anchor ( tx. txid ( ) , tip. block_id ( ) ) ;
655+ } ) ;
656+
657+ let ancestors = [
658+ graph
659+ . walk_ancestors ( & tx_c0, |depth, tx| Some ( ( depth, tx) ) )
660+ . collect :: < Vec < _ > > ( ) ,
661+ graph
662+ . walk_ancestors ( & tx_d0, |depth, tx| Some ( ( depth, tx) ) )
663+ . collect :: < Vec < _ > > ( ) ,
664+ graph
665+ . walk_ancestors ( & tx_e0, |depth, tx| Some ( ( depth, tx) ) )
666+ . collect :: < Vec < _ > > ( ) ,
667+ // Only traverse unconfirmed ancestors of tx_e0 this time
668+ graph
669+ . walk_ancestors ( & tx_e0, |depth, tx| {
670+ let tx_node = graph. get_tx_node ( tx. txid ( ) ) ?;
671+ for block in tx_node. anchors {
672+ match local_chain. is_block_in_chain ( block. anchor_block ( ) , tip. block_id ( ) ) {
673+ Ok ( Some ( true ) ) => return None ,
674+ _ => continue ,
675+ }
676+ }
677+ Some ( ( depth, tx_node. tx ) )
678+ } )
679+ . collect :: < Vec < _ > > ( ) ,
680+ ] ;
681+
682+ let expected_ancestors = [
683+ vec ! [ ( 1 , & tx_b0) , ( 2 , & tx_a0) ] ,
684+ vec ! [ ( 1 , & tx_c1) , ( 2 , & tx_b0) , ( 3 , & tx_a0) ] ,
685+ vec ! [
686+ ( 1 , & tx_d1) ,
687+ ( 2 , & tx_c2) ,
688+ ( 2 , & tx_c3) ,
689+ ( 3 , & tx_b1) ,
690+ ( 3 , & tx_b2) ,
691+ ( 4 , & tx_a0) ,
692+ ] ,
693+ vec ! [ ( 1 , & tx_d1) , ( 2 , & tx_c2) , ( 2 , & tx_c3) , ( 3 , & tx_b2) ] ,
694+ ] ;
695+
696+ for ( txids, expected_txids) in ancestors. iter ( ) . zip ( expected_ancestors. iter ( ) ) {
697+ assert_eq ! ( txids, expected_txids) ;
698+ }
699+ }
700+
499701#[ test]
500702fn test_conflicting_descendants ( ) {
501703 let previous_output = OutPoint :: new ( h ! ( "op" ) , 2 ) ;
0 commit comments