@@ -4,7 +4,7 @@ use bdk_chain::{
44 collections:: * ,
55 local_chain:: LocalChain ,
66 tx_graph:: { Additions , TxGraph } ,
7- Append , BlockId , ChainPosition , ConfirmationHeightAnchor ,
7+ Anchor , Append , BlockId , ChainPosition , ConfirmationHeightAnchor ,
88} ;
99use bitcoin:: {
1010 hashes:: Hash , BlockHash , OutPoint , PackedLockTime , Script , Transaction , TxIn , TxOut , Txid ,
@@ -822,3 +822,136 @@ fn test_additions_last_seen_append() {
822822 ) ;
823823 }
824824}
825+
826+ #[ test]
827+ fn test_missing_blocks ( ) {
828+ /// An anchor implementation for testing, made up of `(the_anchor_block, random_data)`.
829+ #[ derive( Debug , Clone , Eq , PartialEq , PartialOrd , Ord , core:: hash:: Hash ) ]
830+ struct TestAnchor ( BlockId ) ;
831+
832+ impl Anchor for TestAnchor {
833+ fn anchor_block ( & self ) -> BlockId {
834+ self . 0
835+ }
836+ }
837+
838+ struct Scenario < ' a > {
839+ name : & ' a str ,
840+ graph : TxGraph < TestAnchor > ,
841+ chain : LocalChain ,
842+ exp_heights : & ' a [ u32 ] ,
843+ }
844+
845+ const fn new_anchor ( height : u32 , hash : BlockHash ) -> TestAnchor {
846+ TestAnchor ( BlockId { height, hash } )
847+ }
848+
849+ fn new_scenario < ' a > (
850+ name : & ' a str ,
851+ graph_anchors : & ' a [ ( Txid , TestAnchor ) ] ,
852+ chain : & ' a [ ( u32 , BlockHash ) ] ,
853+ exp_heights : & ' a [ u32 ] ,
854+ ) -> Scenario < ' a > {
855+ Scenario {
856+ name,
857+ graph : {
858+ let mut g = TxGraph :: default ( ) ;
859+ for ( txid, anchor) in graph_anchors {
860+ let _ = g. insert_anchor ( * txid, anchor. clone ( ) ) ;
861+ }
862+ g
863+ } ,
864+ chain : {
865+ let mut c = LocalChain :: default ( ) ;
866+ for ( height, hash) in chain {
867+ let _ = c. insert_block ( BlockId {
868+ height : * height,
869+ hash : * hash,
870+ } ) ;
871+ }
872+ c
873+ } ,
874+ exp_heights,
875+ }
876+ }
877+
878+ fn run ( scenarios : & [ Scenario ] ) {
879+ for scenario in scenarios {
880+ let Scenario {
881+ name,
882+ graph,
883+ chain,
884+ exp_heights,
885+ } = scenario;
886+
887+ let heights = graph. missing_heights ( chain) . collect :: < Vec < _ > > ( ) ;
888+ assert_eq ! ( & heights, exp_heights, "scenario: {}" , name) ;
889+ }
890+ }
891+
892+ run ( & [
893+ new_scenario (
894+ "2 txs with the same anchor (2:B) which is missing from chain" ,
895+ & [
896+ ( h ! ( "tx_1" ) , new_anchor ( 2 , h ! ( "B" ) ) ) ,
897+ ( h ! ( "tx_2" ) , new_anchor ( 2 , h ! ( "B" ) ) ) ,
898+ ] ,
899+ & [ ( 1 , h ! ( "A" ) ) , ( 3 , h ! ( "C" ) ) ] ,
900+ & [ 2 ] ,
901+ ) ,
902+ new_scenario (
903+ "2 txs with different anchors at the same height, one of the anchors is missing" ,
904+ & [
905+ ( h ! ( "tx_1" ) , new_anchor ( 2 , h ! ( "B1" ) ) ) ,
906+ ( h ! ( "tx_2" ) , new_anchor ( 2 , h ! ( "B2" ) ) ) ,
907+ ] ,
908+ & [ ( 1 , h ! ( "A" ) ) , ( 2 , h ! ( "B1" ) ) ] ,
909+ & [ ] ,
910+ ) ,
911+ new_scenario (
912+ "tx with 2 anchors of same height which are missing from the chain" ,
913+ & [
914+ ( h ! ( "tx" ) , new_anchor ( 3 , h ! ( "C1" ) ) ) ,
915+ ( h ! ( "tx" ) , new_anchor ( 3 , h ! ( "C2" ) ) ) ,
916+ ] ,
917+ & [ ( 1 , h ! ( "A" ) ) , ( 4 , h ! ( "D" ) ) ] ,
918+ & [ 3 ] ,
919+ ) ,
920+ new_scenario (
921+ "tx with 2 anchors at the same height, chain has this height but does not match either anchor" ,
922+ & [
923+ ( h ! ( "tx" ) , new_anchor ( 4 , h ! ( "D1" ) ) ) ,
924+ ( h ! ( "tx" ) , new_anchor ( 4 , h ! ( "D2" ) ) ) ,
925+ ] ,
926+ & [ ( 4 , h ! ( "D3" ) ) , ( 5 , h ! ( "E" ) ) ] ,
927+ & [ ] ,
928+ ) ,
929+ new_scenario (
930+ "tx with 2 anchors at different heights, one anchor exists in chain, should return nothing" ,
931+ & [
932+ ( h ! ( "tx" ) , new_anchor ( 3 , h ! ( "C" ) ) ) ,
933+ ( h ! ( "tx" ) , new_anchor ( 4 , h ! ( "D" ) ) ) ,
934+ ] ,
935+ & [ ( 4 , h ! ( "D" ) ) , ( 5 , h ! ( "E" ) ) ] ,
936+ & [ ] ,
937+ ) ,
938+ new_scenario (
939+ "tx with 2 anchors at different heights, first height is already in chain with different hash, iterator should only return 2nd height" ,
940+ & [
941+ ( h ! ( "tx" ) , new_anchor ( 5 , h ! ( "E1" ) ) ) ,
942+ ( h ! ( "tx" ) , new_anchor ( 6 , h ! ( "F1" ) ) ) ,
943+ ] ,
944+ & [ ( 4 , h ! ( "D" ) ) , ( 5 , h ! ( "E" ) ) , ( 7 , h ! ( "G" ) ) ] ,
945+ & [ 6 ] ,
946+ ) ,
947+ new_scenario (
948+ "tx with 2 anchors at different heights, neither height is in chain, both heights should be returned" ,
949+ & [
950+ ( h ! ( "tx" ) , new_anchor ( 3 , h ! ( "C" ) ) ) ,
951+ ( h ! ( "tx" ) , new_anchor ( 4 , h ! ( "D" ) ) ) ,
952+ ] ,
953+ & [ ( 1 , h ! ( "A" ) ) , ( 2 , h ! ( "B" ) ) ] ,
954+ & [ 3 , 4 ] ,
955+ ) ,
956+ ] ) ;
957+ }
0 commit comments