@@ -26,7 +26,10 @@ use scroll_alloy_consensus::{ScrollTxEnvelope, TxL1Message};
2626use scroll_alloy_hardforks:: ScrollHardforks ;
2727use scroll_alloy_network:: Scroll ;
2828use scroll_alloy_provider:: ScrollEngineApi ;
29- use scroll_db:: { Database , DatabaseError , DatabaseReadOperations , DatabaseWriteOperations , L1MessageKey , TXMut , UnwindResult } ;
29+ use scroll_db:: {
30+ Database , DatabaseError , DatabaseReadOperations , DatabaseWriteOperations , L1MessageKey , TXMut ,
31+ UnwindResult ,
32+ } ;
3033use scroll_derivation_pipeline:: { BatchDerivationResult , DerivationPipeline } ;
3134use scroll_engine:: Engine ;
3235use scroll_network:: {
@@ -61,7 +64,8 @@ pub use sync::{SyncMode, SyncState};
6164
6265mod status;
6366use crate :: ChainOrchestratorEvent :: {
64- BatchCommitDuplicate , BatchCommitGap , L1MessageDuplicate , L1MessageGap ,
67+ BatchCommitDuplicate , BatchCommitGap , BatchRevertDuplicate , BatchRevertGap , L1MessageDuplicate ,
68+ L1MessageGap ,
6569} ;
6670pub use status:: ChainOrchestratorStatus ;
6771
@@ -755,7 +759,14 @@ impl<
755759
756760 // Perform a consistency check to ensure the previous commit batch exists in the
757761 // database.
758- if tx. get_batch_by_index ( prev_batch_index) . await ?. is_none ( ) {
762+ if tx
763+ . get_batch_by_index ( prev_batch_index)
764+ . await ?
765+ . iter ( )
766+ . filter ( |x| x. reverted_block_number . is_none ( ) )
767+ . count ( ) ==
768+ 0
769+ {
759770 // Query database for the L1 block of the last known batch
760771 let reset_block = tx. get_last_batch_commit_l1_block ( ) . await ?. unwrap_or ( 0 ) ;
761772
@@ -766,16 +777,20 @@ impl<
766777 }
767778
768779 // Check if batch already exists in DB.
769- if let Some ( existing_batch) = tx. get_batch_by_index ( batch. index ) . await ? {
780+ for existing_batch in tx. get_batch_by_index ( batch. index ) . await ? {
770781 if existing_batch. hash == batch. hash {
771782 // This means we have already processed this batch commit, we will skip
772783 // it.
773784 return Ok ( Some ( BatchCommitDuplicate ( existing_batch. index ) ) ) ;
785+ } else if existing_batch. reverted_block_number . is_none ( ) {
786+ // This means we have received a different batch commit at the same
787+ // index which has not been reverted yet. ->
788+ // we missed a revert a event
789+ return Ok ( Some ( BatchRevertGap {
790+ missing_index : batch. index ,
791+ l1_block_number_reset : existing_batch. block_number ,
792+ } ) ) ;
774793 }
775- // TODO: once batch reverts are implemented, we need to handle this
776- // case.
777- // If we have a batch at the same index in the DB this means we have
778- // missed a batch revert event.
779794 }
780795
781796 let event = ChainOrchestratorEvent :: BatchCommitIndexed {
@@ -804,6 +819,16 @@ impl<
804819 ) ;
805820 self . l1_watcher_handle . trigger_gap_recovery ( l1_block_number_reset) . await ;
806821 }
822+ Some ( BatchRevertGap { missing_index, l1_block_number_reset } ) => {
823+ tracing:: warn!(
824+ target: "scroll::chain_orchestrator" ,
825+ "Batch revert gap detected at index {}, last known batch at L1 block {}" ,
826+ missing_index,
827+ l1_block_number_reset
828+ ) ;
829+ // TODO: getting channel closed here
830+ // self.l1_watcher_handle.trigger_gap_recovery(l1_block_number_reset).await;
831+ }
807832 Some ( BatchCommitDuplicate ( index) ) => {
808833 tracing:: info!(
809834 target: "scroll::chain_orchestrator" ,
@@ -867,6 +892,33 @@ impl<
867892 end_index : u64 ,
868893 l1_block_info : BlockInfo ,
869894 ) -> Result < Option < ChainOrchestratorEvent > , ChainOrchestratorError > {
895+ let event = self
896+ . database
897+ . tx ( move |tx| async move {
898+ // Check if we received this revert already.
899+ // If any of the batches with same index is reverted with the same L1 block then the
900+ // event is duplicate
901+ for existing_batch in tx. get_batch_by_index ( end_index) . await ? {
902+ if existing_batch. reverted_block_number == Some ( l1_block_info. number ) {
903+ return Ok :: < _ , ChainOrchestratorError > ( Some ( BatchRevertDuplicate (
904+ existing_batch. index ,
905+ ) ) ) ;
906+ }
907+ }
908+
909+ Ok ( None )
910+ } )
911+ . await ?;
912+
913+ if let Some ( BatchRevertDuplicate ( index) ) = event {
914+ tracing:: info!(
915+ target: "scroll::chain_orchestrator" ,
916+ "Duplicate batch revert detected at {:?}, skipping" ,
917+ index
918+ ) ;
919+ return Ok ( event) ;
920+ }
921+
870922 let ( safe_block_info, batch_info) = self
871923 . database
872924 . tx_mut ( move |tx| async move {
@@ -895,8 +947,7 @@ impl<
895947 l1_message : TxL1Message ,
896948 l1_block_info : BlockInfo ,
897949 ) -> Result < Option < ChainOrchestratorEvent > , ChainOrchestratorError > {
898- let l1_v2_message_queue_start_index =
899- self . config . l1_v2_message_queue_start_index ( ) ;
950+ let l1_v2_message_queue_start_index = self . config . l1_v2_message_queue_start_index ( ) ;
900951
901952 let event = self . database
902953 . tx_mut ( move |tx| {
0 commit comments