@@ -487,7 +487,7 @@ fn mempool_avoids_re_emission() -> anyhow::Result<()> {
487487/// If blockchain re-org includes the start height, emit new start height block
488488///
489489/// 1. mine 101 blocks
490- /// 2. emit blocks 99a, 100a
490+ /// 2. emit blocks 98a, 99a, 100a
491491/// 3. invalidate blocks 99a, 100a, 101a
492492/// 4. mine new blocks 99b, 100b, 101b
493493/// 5. emit block 99b
@@ -505,48 +505,45 @@ fn no_agreement_point() -> anyhow::Result<()> {
505505 let mut emitter = Emitter :: new (
506506 & client,
507507 CheckPoint :: new ( 0 , env. genesis_hash ( ) ?) ,
508- ( PREMINE_COUNT - 2 ) as u32 ,
508+ ( PREMINE_COUNT - 3 ) as u32 ,
509509 NO_EXPECTED_MEMPOOL_TXS ,
510510 ) ;
511511
512512 // mine 101 blocks
513513 env. mine_blocks ( PREMINE_COUNT , None ) ?;
514514
515- // emit block 99a
516- let block_header_99a = emitter
517- . next_block ( ) ?
518- . expect ( "block 99a header" )
519- . block
520- . header ;
521- let block_hash_99a = block_header_99a. block_hash ( ) ;
522- let block_hash_98a = block_header_99a. prev_blockhash ;
523-
524- // emit block 100a
525- let block_header_100a = emitter. next_block ( ) ?. expect ( "block 100a header" ) . block ;
526- let block_hash_100a = block_header_100a. block_hash ( ) ;
515+ // emit blocks: 98a, 99a, 100a
516+ let block_98a = emitter. next_block ( ) ?. expect ( "block 98a" ) ;
517+ let block_99a = emitter. next_block ( ) ?. expect ( "block 99a" ) ;
518+ let block_100a = emitter. next_block ( ) ?. expect ( "block 100a" ) ;
519+ assert_eq ! ( block_98a. block_height( ) , 98 ) ;
520+ assert_eq ! ( block_99a. block_height( ) , 99 ) ;
521+ assert_eq ! ( block_100a. block_height( ) , 100 ) ;
527522
528523 // get hash for block 101a
529- let block_hash_101a = env. rpc_client ( ) . get_block_hash ( 101 ) ?. block_hash ( ) ?;
524+ let blockhash_101a = env. rpc_client ( ) . get_block_hash ( 101 ) ?. block_hash ( ) ?;
530525
531526 // invalidate blocks 99a, 100a, 101a
532- env. rpc_client ( ) . invalidate_block ( block_hash_99a ) ?;
533- env. rpc_client ( ) . invalidate_block ( block_hash_100a ) ?;
534- env. rpc_client ( ) . invalidate_block ( block_hash_101a ) ?;
527+ env. rpc_client ( ) . invalidate_block ( blockhash_101a ) ?;
528+ env. rpc_client ( ) . invalidate_block ( block_100a . block_hash ( ) ) ?;
529+ env. rpc_client ( ) . invalidate_block ( block_99a . block_hash ( ) ) ?;
535530
536531 // mine new blocks 99b, 100b, 101b
537532 env. mine_blocks ( 3 , None ) ?;
538533
539534 // emit block header 99b
540- let block_header_99b = emitter
541- . next_block ( ) ?
542- . expect ( "block 99b header" )
543- . block
544- . header ;
545- let block_hash_99b = block_header_99b. block_hash ( ) ;
546- let block_hash_98b = block_header_99b. prev_blockhash ;
535+ let block_99b = emitter. next_block ( ) ?. expect ( "block 99b" ) ;
536+ assert_eq ! ( block_99b. block_height( ) , 99 ) ;
547537
548- assert_ne ! ( block_hash_99a, block_hash_99b) ;
549- assert_eq ! ( block_hash_98a, block_hash_98b) ;
538+ assert_ne ! ( block_99a. block_hash( ) , block_99b. block_hash( ) ) ;
539+ assert_eq ! (
540+ block_98a. block_hash( ) ,
541+ block_99a. block. header. prev_blockhash
542+ ) ;
543+ assert_eq ! (
544+ block_98a. block_hash( ) ,
545+ block_99b. block. header. prev_blockhash
546+ ) ;
550547
551548 Ok ( ( ) )
552549}
@@ -661,6 +658,47 @@ fn test_expect_tx_evicted() -> anyhow::Result<()> {
661658 Ok ( ( ) )
662659}
663660
661+ /// Creating a new [`Emitter`] after a reorg with `start_height` at the tip should still
662+ /// produce a connectable checkpoint. When blocks are invalidated, the emitted checkpoint must
663+ /// include the invalidation height so the update can connect with the original chain.
664+ #[ test]
665+ fn test_sync_with_new_emitter_after_reorg ( ) -> anyhow:: Result < ( ) > {
666+ let env = TestEnv :: new ( ) ?;
667+ let ( mut local_chain, _) = LocalChain :: from_genesis ( env. genesis_hash ( ) ?) ;
668+ let client = ClientExt :: get_rpc_client ( & env) ?;
669+
670+ env. mine_blocks ( 110 , None ) ?;
671+
672+ let mut emitter = Emitter :: new ( & client, local_chain. tip ( ) , 0 , NO_EXPECTED_MEMPOOL_TXS ) ;
673+ while let Some ( emission) = emitter. next_block ( ) ? {
674+ let _ = local_chain. apply_update ( emission. checkpoint ) ?;
675+ }
676+
677+ let pre_reorg_tip = local_chain. tip ( ) ;
678+ let tip_height = pre_reorg_tip. height ( ) ;
679+
680+ env. reorg ( 6 ) ?;
681+
682+ // New emitter with start_height = tip height (common caller pattern).
683+ let mut emitter = Emitter :: new (
684+ & client,
685+ local_chain. tip ( ) ,
686+ tip_height,
687+ NO_EXPECTED_MEMPOOL_TXS ,
688+ ) ;
689+
690+ while let Some ( emission) = emitter. next_block ( ) ? {
691+ let _ = local_chain
692+ . apply_update ( emission. checkpoint )
693+ . expect ( "emission checkpoint must connect with local chain" ) ;
694+ }
695+
696+ assert_eq ! ( local_chain. tip( ) . height( ) , tip_height) ;
697+ assert_ne ! ( local_chain. tip( ) . hash( ) , pre_reorg_tip. hash( ) ) ;
698+
699+ Ok ( ( ) )
700+ }
701+
664702#[ test]
665703fn detect_new_mempool_txs ( ) -> anyhow:: Result < ( ) > {
666704 let env = TestEnv :: new ( ) ?;
0 commit comments