@@ -66,7 +66,7 @@ async fn test_l1_sync_batch_commit() -> eyre::Result<()> {
6666 let initial_safe = initial_status. l2 . fcs . safe_block_info ( ) . number ;
6767
6868 // Send BatchCommit transactions
69- for i in 0 ..=2 {
69+ for i in 0 ..=6 {
7070 let commit_batch_tx = read_test_transaction ( "commitBatch" , & i. to_string ( ) ) ?;
7171 fixture. anvil_send_raw_transaction ( commit_batch_tx) . await ?;
7272 }
@@ -187,3 +187,265 @@ async fn test_l1_sync_batch_finalized() -> eyre::Result<()> {
187187 Ok ( ( ) )
188188}
189189
190+ #[ tokio:: test]
191+ async fn test_l1_sync_batch_revert ( ) -> eyre:: Result < ( ) > {
192+ reth_tracing:: init_test_tracing ( ) ;
193+
194+ let mut fixture = TestFixture :: builder ( )
195+ . followers ( 1 )
196+ . with_chain_spec ( SCROLL_DEV . clone ( ) )
197+ . skip_l1_synced_notifications ( )
198+ . with_anvil_default_state ( )
199+ . with_anvil_chain_id ( 22222222 )
200+ . build ( )
201+ . await ?;
202+
203+ // Get initial status
204+ let initial_status = fixture. get_sequencer_status ( ) . await ?;
205+ let initial_safe = initial_status. l2 . fcs . safe_block_info ( ) . number ;
206+
207+ // Send BatchCommit transactions
208+ for i in 0 ..=6 {
209+ let commit_batch_tx = read_test_transaction ( "commitBatch" , & i. to_string ( ) ) ?;
210+ fixture. anvil_send_raw_transaction ( commit_batch_tx) . await ?;
211+ }
212+
213+ fixture. l1 ( ) . sync ( ) . await ?;
214+ fixture. expect_event ( ) . l1_synced ( ) . await ?;
215+ fixture. expect_event ( ) . batch_consolidated ( ) . await ?;
216+ fixture. anvil_mine_blocks ( 64 ) . await ?;
217+
218+ // Wait for l1 blocks to be processed
219+ tokio:: time:: sleep ( tokio:: time:: Duration :: from_secs ( 3 ) ) . await ;
220+
221+ // Check that safe head was updated
222+ let new_status = fixture. get_sequencer_status ( ) . await ?;
223+ assert ! (
224+ new_status. l2. fcs. safe_block_info( ) . number > initial_safe,
225+ "Safe head should advance after BatchCommit when synced and L1Synced"
226+ ) ;
227+
228+ // Send BatchRevert transactions
229+ let revert_batch_tx = read_test_transaction ( "revertBatch" , "0" ) ?;
230+ fixture. anvil_send_raw_transaction ( revert_batch_tx) . await ?;
231+ fixture. anvil_mine_blocks ( 64 ) . await ?;
232+
233+ // Wait for l1 blocks to be processed
234+ tokio:: time:: sleep ( tokio:: time:: Duration :: from_secs ( 3 ) ) . await ;
235+
236+ // Check that safe head was updated
237+ let revert_status = fixture. get_sequencer_status ( ) . await ?;
238+ assert ! (
239+ revert_status. l2. fcs. safe_block_info( ) . number < new_status. l2. fcs. safe_block_info( ) . number,
240+ "Safe head should advance after BatchCommit when synced and L1Synced"
241+ ) ;
242+
243+ Ok ( ( ) )
244+ }
245+
246+ // =============================================================================
247+ // Test Suite 2: L1 Reorg handling for different batch events
248+ // =============================================================================
249+
250+ /// Test: L1 reorg of BatchCommit after L1Synced.
251+ ///
252+ /// Expected: When a BatchCommit is reorged after the node has synced (L1Synced),
253+ /// the safe head should revert to the last block of the previous BatchCommit.
254+ #[ tokio:: test]
255+ async fn test_l1_reorg_batch_commit ( ) -> eyre:: Result < ( ) > {
256+ reth_tracing:: init_test_tracing ( ) ;
257+
258+ let mut fixture = TestFixture :: builder ( )
259+ . followers ( 1 )
260+ . with_chain_spec ( SCROLL_DEV . clone ( ) )
261+ . skip_l1_synced_notifications ( )
262+ . with_anvil_default_state ( )
263+ . with_anvil_chain_id ( 22222222 )
264+ . build ( )
265+ . await ?;
266+
267+ // Send BatchCommit transactions 0-2
268+ for i in 0 ..=2 {
269+ let commit_batch_tx = read_test_transaction ( "commitBatch" , & i. to_string ( ) ) ?;
270+ fixture. anvil_send_raw_transaction ( commit_batch_tx) . await ?;
271+ }
272+
273+ // Trigger L1 sync
274+ fixture. l1 ( ) . sync ( ) . await ?;
275+ fixture. expect_event ( ) . l1_synced ( ) . await ?;
276+ fixture. expect_event ( ) . batch_consolidated ( ) . await ?;
277+
278+ // Check that safe head was updated to batch 2
279+ let status_after_sync = fixture. get_sequencer_status ( ) . await ?;
280+ let safe_after_batch_2 = status_after_sync. l2 . fcs . safe_block_info ( ) . number ;
281+ tracing:: info!( "Safe head after batch 2: {}" , safe_after_batch_2) ;
282+
283+ // Send BatchCommit transaction 3
284+ let commit_batch_3_tx = read_test_transaction ( "commitBatch" , "3" ) ?;
285+ fixture. anvil_send_raw_transaction ( commit_batch_3_tx) . await ?;
286+
287+ // Wait for processing
288+ tokio:: time:: sleep ( tokio:: time:: Duration :: from_secs ( 3 ) ) . await ;
289+
290+ // Check that safe head advanced to batch 3
291+ let status_after_batch_3 = fixture. get_sequencer_status ( ) . await ?;
292+ let safe_after_batch_3 = status_after_batch_3. l2 . fcs . safe_block_info ( ) . number ;
293+ tracing:: info!( "Safe head after batch 3: {}" , safe_after_batch_3) ;
294+ assert ! (
295+ safe_after_batch_3 > safe_after_batch_2,
296+ "Safe head should advance after BatchCommit when L1Synced"
297+ ) ;
298+
299+ // Reorg to remove batch 3 (reorg depth 1)
300+ fixture. anvil_reorg ( 1 ) . await ?;
301+ fixture. anvil_mine_blocks ( 1 ) . await ?;
302+
303+ // Wait for reorg to be detected and processed
304+ tokio:: time:: sleep ( tokio:: time:: Duration :: from_secs ( 3 ) ) . await ;
305+
306+ // Check that safe head reverted to batch 2
307+ let status_after_reorg = fixture. get_sequencer_status ( ) . await ?;
308+ let safe_after_reorg = status_after_reorg. l2 . fcs . safe_block_info ( ) . number ;
309+ tracing:: info!( "Safe head after reorg: {}" , safe_after_reorg) ;
310+ assert_eq ! (
311+ safe_after_reorg, safe_after_batch_2,
312+ "Safe head should revert to previous BatchCommit after reorg"
313+ ) ;
314+
315+ Ok ( ( ) )
316+ }
317+
318+ /// Test: L1 reorg of BatchFinalized event.
319+ ///
320+ /// Expected: Reorging BatchFinalized should have no effect because we only update
321+ /// the finalized head after the BatchFinalized event is itself finalized on L1,
322+ /// meaning it can never be reorged in practice.
323+ #[ tokio:: test]
324+ async fn test_l1_reorg_batch_finalized ( ) -> eyre:: Result < ( ) > {
325+ reth_tracing:: init_test_tracing ( ) ;
326+
327+ let mut fixture = TestFixture :: builder ( )
328+ . followers ( 1 )
329+ . with_chain_spec ( SCROLL_DEV . clone ( ) )
330+ . skip_l1_synced_notifications ( )
331+ . with_anvil_default_state ( )
332+ . with_anvil_chain_id ( 22222222 )
333+ . build ( )
334+ . await ?;
335+
336+ // Send BatchCommit transactions
337+ for i in 0 ..=6 {
338+ let commit_batch_tx = read_test_transaction ( "commitBatch" , & i. to_string ( ) ) ?;
339+ fixture. anvil_send_raw_transaction ( commit_batch_tx) . await ?;
340+ }
341+
342+ // Send BatchFinalized transactions
343+ for i in 1 ..=2 {
344+ let finalize_batch_tx = read_test_transaction ( "finalizeBatch" , & i. to_string ( ) ) ?;
345+ fixture. anvil_send_raw_transaction ( finalize_batch_tx) . await ?;
346+ }
347+
348+ // Trigger L1 sync
349+ fixture. l1 ( ) . sync ( ) . await ?;
350+ fixture. expect_event ( ) . l1_synced ( ) . await ?;
351+
352+ // Wait for consolidate and finalization
353+ fixture. expect_event ( ) . batch_consolidated ( ) . await ?;
354+ tokio:: time:: sleep ( tokio:: time:: Duration :: from_secs ( 3 ) ) . await ;
355+
356+ // Get finalized head after batch finalization
357+ let status_after_finalize = fixture. get_sequencer_status ( ) . await ?;
358+ let finalized_after = status_after_finalize. l2 . fcs . finalized_block_info ( ) . number ;
359+ tracing:: info!( "Finalized head after batch finalized: {}" , finalized_after) ;
360+
361+ // Reorg to remove the BatchFinalized events
362+ fixture. anvil_reorg ( 2 ) . await ?;
363+ fixture. anvil_mine_blocks ( 1 ) . await ?;
364+
365+ // Wait for reorg detection
366+ tokio:: time:: sleep ( tokio:: time:: Duration :: from_secs ( 3 ) ) . await ;
367+
368+ // Check that finalized head hasn't changed
369+ let status_after_reorg = fixture. get_sequencer_status ( ) . await ?;
370+ let finalized_after_reorg = status_after_reorg. l2 . fcs . finalized_block_info ( ) . number ;
371+ tracing:: info!( "Finalized head after reorg: {}" , finalized_after_reorg) ;
372+ assert_eq ! (
373+ finalized_after_reorg, finalized_after,
374+ "Finalized head should not change after reorg of BatchFinalized"
375+ ) ;
376+
377+ Ok ( ( ) )
378+ }
379+
380+ /// Test: L1 reorg of BatchRevert event.
381+ ///
382+ /// Expected: When a BatchRevert is reorged, the safe head should be restored to
383+ /// the state before the revert was applied. If the reverted batches are re-committed
384+ /// after the reorg, the safe head should advance again.
385+ #[ tokio:: test]
386+ async fn test_l1_reorg_batch_revert ( ) -> eyre:: Result < ( ) > {
387+ reth_tracing:: init_test_tracing ( ) ;
388+
389+ let mut fixture = TestFixture :: builder ( )
390+ . followers ( 1 )
391+ . with_chain_spec ( SCROLL_DEV . clone ( ) )
392+ . skip_l1_synced_notifications ( )
393+ . with_anvil_default_state ( )
394+ . with_anvil_chain_id ( 22222222 )
395+ . build ( )
396+ . await ?;
397+
398+ // Trigger L1 sync
399+ fixture. l1 ( ) . sync ( ) . await ?;
400+ fixture. expect_event ( ) . l1_synced ( ) . await ?;
401+
402+ // Send BatchCommit transactions
403+ for i in 0 ..=6 {
404+ let commit_batch_tx = read_test_transaction ( "commitBatch" , & i. to_string ( ) ) ?;
405+ fixture. anvil_send_raw_transaction ( commit_batch_tx) . await ?;
406+ // if i!=0 { fixture.expect_event().batch_consolidated().await?; }
407+ }
408+
409+ // Wait for reorg to be detected and processed
410+ tokio:: time:: sleep ( tokio:: time:: Duration :: from_secs ( 3 ) ) . await ;
411+
412+ // Get safe head after all commits
413+ let status_after_commits = fixture. get_sequencer_status ( ) . await ?;
414+ let safe_after_commits = status_after_commits. l2 . fcs . safe_block_info ( ) . number ;
415+ tracing:: info!( "Safe head after all commits: {}" , safe_after_commits) ;
416+
417+ // Send BatchRevert transaction
418+ let revert_batch_tx = read_test_transaction ( "revertBatch" , "0" ) ?;
419+ fixture. anvil_send_raw_transaction ( revert_batch_tx) . await ?;
420+ fixture. anvil_mine_blocks ( 1 ) . await ?;
421+
422+ // Wait for revert to be processed
423+ tokio:: time:: sleep ( tokio:: time:: Duration :: from_secs ( 3 ) ) . await ;
424+
425+ // Check that safe head was reverted
426+ let status_after_revert = fixture. get_sequencer_status ( ) . await ?;
427+ let safe_after_revert = status_after_revert. l2 . fcs . safe_block_info ( ) . number ;
428+ tracing:: info!( "Safe head after revert: {}" , safe_after_revert) ;
429+ assert ! (
430+ safe_after_revert < safe_after_commits,
431+ "Safe head should decrease after BatchRevert"
432+ ) ;
433+
434+ // Reorg to remove the BatchRevert event (reorg depth 1)
435+ fixture. anvil_reorg ( 2 ) . await ?;
436+ fixture. anvil_mine_blocks ( 3 ) . await ?;
437+
438+ // Wait for reorg to be detected and processed
439+ tokio:: time:: sleep ( tokio:: time:: Duration :: from_secs ( 3 ) ) . await ;
440+
441+ // Check that safe head was restored to pre-revert state
442+ let status_after_reorg = fixture. get_sequencer_status ( ) . await ?;
443+ let safe_after_reorg = status_after_reorg. l2 . fcs . safe_block_info ( ) . number ;
444+ tracing:: info!( "Safe head after reorg: {}" , safe_after_reorg) ;
445+ assert_eq ! (
446+ safe_after_reorg, safe_after_commits,
447+ "Safe head should be restored after reorg of BatchRevert"
448+ ) ;
449+
450+ Ok ( ( ) )
451+ }
0 commit comments