@@ -734,3 +734,67 @@ where
734734 Ok ( ( new_tip, changeset) )
735735 }
736736}
737+
738+ #[ cfg( test) ]
739+ mod test {
740+ use super :: * ;
741+
742+ use alloc:: vec:: Vec ;
743+ use bitcoin:: block:: Header ;
744+ use bitcoin:: consensus:: encode:: deserialize_hex;
745+ use bitcoin:: hashes:: Hash ;
746+
747+ // Test that `apply_update` can connect 1 header at a time
748+ // and fails if the hashes don't line up.
749+ #[ test]
750+ fn test_apply_update_single_header ( ) {
751+ let headers: Vec < Header > = [
752+ "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f2002000000" ,
753+ "0000002006226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f1c96cc459dbb0c7bbc722af14f913da868779290ad48ff87ee314ebb8ae08f384b166069ffff7f2001000000" ,
754+ "0000002078ce518c7dcfd99ad5859c35bd2be15794c0e5dc8e60c1fea3b0461c45da181ca80f828504f88c645ea46cfcf93156269807e3bd409e1317271a1546d238e9b24c166069ffff7f2001000000" ,
755+ "000000200dfd6c5af6ea3cb341a08db344f93743d94b630d122867faff855f6310e58864e6e0c859fda703d66d051b86f16f09b0cead182f3cbe13767cd91b6371ec252c4c166069ffff7f2000000000" ,
756+ ]
757+ . into_iter ( )
758+ . map ( |s| deserialize_hex :: < Header > ( s) . expect ( "failed to deserialize header" ) )
759+ . collect ( ) ;
760+
761+ let header_0 = headers[ 0 ] ;
762+ let header_1 = headers[ 1 ] ;
763+ let header_2 = headers[ 2 ] ;
764+ let header_3 = headers[ 3 ] ;
765+
766+ let ( mut chain, _) = LocalChain :: from_genesis ( header_0) ;
767+
768+ // Apply 1 `CheckPoint<Header>` at a time
769+ for ( height, header) in ( 1 ..) . zip ( [ header_1, header_2, header_3] ) {
770+ let changeset = chain. apply_update ( CheckPoint :: new ( height, header) ) . unwrap ( ) ;
771+ assert_eq ! (
772+ changeset,
773+ ChangeSet {
774+ blocks: [ ( height, Some ( headers[ height as usize ] ) ) ] . into( )
775+ } ,
776+ ) ;
777+ }
778+ assert_eq ! ( chain. tip. iter( ) . count( ) , 4 ) ;
779+ for height in 0 ..4 {
780+ assert ! ( chain
781+ . get( height)
782+ . is_some_and( |cp| cp. hash( ) == headers[ height as usize ] . block_hash( ) ) )
783+ }
784+
785+ // `apply_update` should error if the hashes don't line up
786+ chain = LocalChain :: from_blocks ( [ ( 0 , header_0) , ( 1 , header_1) ] . into ( ) ) . unwrap ( ) ;
787+ let mut header_2_alt = header_2;
788+ header_2_alt. prev_blockhash = BlockHash :: all_zeros ( ) ;
789+ let res = chain. apply_update ( CheckPoint :: new ( 2 , header_2_alt) ) ;
790+ assert ! (
791+ matches!(
792+ res,
793+ Err ( CannotConnectError {
794+ try_include_height: 1
795+ } )
796+ ) ,
797+ "`apply_update` failed to detect hash conflict"
798+ ) ;
799+ }
800+ }
0 commit comments