@@ -132,6 +132,44 @@ fn test_prefix_with_duplicate_block_error() {
132132 assert ! ( matches!( * error, CheckBlockError :: InvalidHeight { expected: 2 , actual: 3 } ) ) ;
133133}
134134
135+ /// Regression test for the bug where `check_block_subdag_atomicity` used the raw ledger
136+ /// tip round as `latest_round` instead of the last prefix block's round when a non-empty
137+ /// prefix was provided.
138+ #[ test]
139+ fn test_atomicity_check_uses_prefix_latest_block ( ) {
140+ let rng = & mut TestRng :: default ( ) ;
141+ let mut builder = TestChainBuilder :: new ( 4 , rng) ;
142+
143+ // External ledger starts at genesis and is never explicitly advanced in this test.
144+ let ledger = Ledger :: < CurrentNetwork , LedgerType < CurrentNetwork > > :: load (
145+ builder. genesis_block ( ) . clone ( ) ,
146+ StorageMode :: new_test ( None ) ,
147+ )
148+ . unwrap ( ) ;
149+
150+ // Identify the elected leader at round 2 and exclude them from block 1.
151+ // This guarantees their certificate at round 2 is absent from block 1's subdag,
152+ // making it a late-arriving *leader* certificate that will appear in block 2's subdag.
153+ let skip_idx = builder. get_leader_index ( 2 ) . expect ( "Leader not found for round 2" ) ;
154+ let block1 =
155+ builder. generate_block_with_opts ( & BlockOptions { skip_nodes : vec ! [ skip_idx] , ..Default :: default ( ) } , rng) ;
156+
157+ // Pre-process block 1 against the external ledger (still at genesis) so it can
158+ // be used as a prefix when validating block 2.
159+ let pending_block1 = ledger. check_block_subdag ( block1, & [ ] ) . unwrap ( ) ;
160+
161+ // Generate block 2 with all validators participating. The previously skipped
162+ // validator's certificates for rounds ≤ block1.anchor_round are now included in
163+ // block 2's subdag as late-arriving entries.
164+ let block2 = builder. generate_block ( rng) ;
165+
166+ // Block 2 must be accepted with block 1 as the prefix while the external ledger
167+ // is still at genesis. This would fail before the fix because the atomicity check
168+ // incorrectly used genesis's round (0) instead of block 1's anchor round, causing it
169+ // to flag the late-arriving leader cert at round 2 as a protocol violation.
170+ ledger. check_block_subdag ( block2, & [ pending_block1] ) . unwrap ( ) ;
171+ }
172+
135173#[ test]
136174fn test_check_block_content_invalid_height ( ) {
137175 let rng = & mut TestRng :: default ( ) ;
0 commit comments