@@ -20,7 +20,7 @@ use rollup_node_primitives::{
2020use rollup_node_providers:: L1MessageProvider ;
2121use rollup_node_sequencer:: { Sequencer , SequencerEvent } ;
2222use rollup_node_signer:: { SignatureAsBytes , SignerEvent , SignerHandle } ;
23- use rollup_node_watcher:: L1Notification ;
23+ use rollup_node_watcher:: { L1Notification , L1WatcherHandle , L1WatcherHandleTrait } ;
2424use scroll_alloy_consensus:: TxL1Message ;
2525use scroll_alloy_hardforks:: ScrollHardforks ;
2626use scroll_alloy_network:: Scroll ;
@@ -96,6 +96,7 @@ pub struct ChainOrchestrator<
9696 L1MP ,
9797 L2P ,
9898 EC ,
99+ H : L1WatcherHandleTrait = L1WatcherHandle ,
99100> {
100101 /// The configuration for the chain orchestrator.
101102 config : ChainOrchestratorConfig < ChainSpec > ,
@@ -112,7 +113,7 @@ pub struct ChainOrchestrator<
112113 /// A receiver for [`L1Notification`]s from the [`rollup_node_watcher::L1Watcher`].
113114 l1_notification_rx : Receiver < Arc < L1Notification > > ,
114115 /// Handle to send commands to the L1 watcher (e.g., for gap recovery).
115- l1_watcher_handle : Option < rollup_node_watcher :: L1WatcherHandle > ,
116+ l1_watcher_handle : Option < H > ,
116117 /// The network manager that manages the scroll p2p network.
117118 network : ScrollNetwork < N > ,
118119 /// The consensus algorithm used by the rollup node.
@@ -137,7 +138,8 @@ impl<
137138 L1MP : L1MessageProvider + Unpin + Clone + Send + Sync + ' static ,
138139 L2P : Provider < Scroll > + ' static ,
139140 EC : ScrollEngineApi + Sync + Send + ' static ,
140- > ChainOrchestrator < N , ChainSpec , L1MP , L2P , EC >
141+ H : L1WatcherHandleTrait ,
142+ > ChainOrchestrator < N , ChainSpec , L1MP , L2P , EC , H >
141143{
142144 /// Creates a new chain orchestrator.
143145 #[ allow( clippy:: too_many_arguments) ]
@@ -147,7 +149,7 @@ impl<
147149 block_client : Arc < FullBlockClient < <N as BlockDownloaderProvider >:: Client > > ,
148150 l2_provider : L2P ,
149151 l1_notification_rx : Receiver < Arc < L1Notification > > ,
150- l1_watcher_handle : Option < rollup_node_watcher :: L1WatcherHandle > ,
152+ l1_watcher_handle : Option < H > ,
151153 network : ScrollNetwork < N > ,
152154 consensus : Box < dyn Consensus + ' static > ,
153155 engine : Engine < EC > ,
@@ -2141,79 +2143,14 @@ mod tests {
21412143 use scroll_engine:: ForkchoiceState ;
21422144 use scroll_network:: ScrollNetworkHandle ;
21432145 use std:: collections:: HashMap ;
2144- use std:: sync:: { Arc , Mutex } ;
2146+ use std:: sync:: Arc ;
21452147 use tokio:: sync:: mpsc;
21462148
2147- /// Mock command handler for L1Watcher that tracks all reset_to_block calls.
2148- /// Returns a real L1WatcherHandle and a tracker for verifying calls.
2149- #[ derive( Clone ) ]
2150- struct MockL1WatcherCommandTracker {
2151- inner : Arc < Mutex < Vec < ( u64 , usize ) > > > , // (block_number, channel_capacity)
2152- }
2153-
2154- impl MockL1WatcherCommandTracker {
2155- fn new ( ) -> Self {
2156- Self { inner : Arc :: new ( Mutex :: new ( Vec :: new ( ) ) ) }
2157- }
2158-
2159- fn track_reset ( & self , block : u64 , capacity : usize ) {
2160- self . inner . lock ( ) . unwrap ( ) . push ( ( block, capacity) ) ;
2161- }
2162-
2163- fn get_reset_calls ( & self ) -> Vec < ( u64 , usize ) > {
2164- self . inner . lock ( ) . unwrap ( ) . clone ( )
2165- }
2166-
2167- fn assert_reset_called_with ( & self , block : u64 ) {
2168- let calls = self . get_reset_calls ( ) ;
2169- assert ! (
2170- calls. iter( ) . any( |( b, _) | * b == block) ,
2171- "Expected reset_to_block to be called with block {}, but got calls: {:?}" ,
2172- block,
2173- calls
2174- ) ;
2175- }
2176-
2177- fn assert_not_called ( & self ) {
2178- let calls = self . get_reset_calls ( ) ;
2179- assert ! ( calls. is_empty( ) , "Expected no reset_to_block calls, but got: {:?}" , calls) ;
2180- }
2181- }
2182-
2183- /// Creates a real L1WatcherHandle backed by a mock command handler.
2184- /// Returns the handle and a tracker for verifying calls.
2185- fn create_mock_l1_watcher_handle ( ) -> (
2186- rollup_node_watcher:: L1WatcherHandle ,
2187- MockL1WatcherCommandTracker ,
2188- tokio:: task:: JoinHandle < ( ) > ,
2189- ) {
2190- use rollup_node_watcher:: { L1WatcherCommand , L1WatcherHandle } ;
2191-
2192- let ( command_tx, mut command_rx) = mpsc:: unbounded_channel ( ) ;
2193- let handle = L1WatcherHandle :: new ( command_tx) ;
2194- let tracker = MockL1WatcherCommandTracker :: new ( ) ;
2195- let tracker_clone = tracker. clone ( ) ;
2196-
2197- // Spawn task to handle commands
2198- let join_handle = tokio:: spawn ( async move {
2199- while let Some ( command) = command_rx. recv ( ) . await {
2200- match command {
2201- L1WatcherCommand :: ResetToBlock { block, new_sender, response_sender } => {
2202- let capacity = new_sender. max_capacity ( ) ;
2203- tracker_clone. track_reset ( block, capacity) ;
2204- // Respond success
2205- let _ = response_sender. send ( ( ) ) ;
2206- }
2207- }
2208- }
2209- } ) ;
2210-
2211- ( handle, tracker, join_handle)
2212- }
2213-
22142149 #[ tokio:: test]
22152150 async fn test_gap_recovery ( )
22162151 {
2152+ use rollup_node_watcher:: MockL1WatcherHandle ;
2153+
22172154 // setup a test node
22182155 let ( mut nodes, _tasks, _wallet) = setup ( 1 , false ) . await . unwrap ( ) ;
22192156 let node = nodes. pop ( ) . unwrap ( ) ;
@@ -2260,17 +2197,20 @@ mod tests {
22602197 // prepare L1 notification channel
22612198 let ( l1_notification_tx, l1_notification_rx) = mpsc:: channel ( 100 ) ;
22622199
2200+ // create mock L1 watcher handle for testing gap recovery
2201+ let mock_l1_watcher_handle = MockL1WatcherHandle :: new ( ) ;
22632202
22642203 // initialize database state
22652204 db. set_latest_l1_block_number ( 0 ) . await . unwrap ( ) ;
22662205
2267- let chain_orchestrator = ChainOrchestrator :: new (
2206+ println ! ( "done" ) ;
2207+ let ( mut chain_orchestrator, handle) = ChainOrchestrator :: new (
22682208 db. clone ( ) ,
22692209 ChainOrchestratorConfig :: new ( node. inner . chain_spec ( ) . clone ( ) , 0 , 0 ) ,
22702210 Arc :: new ( block_client) ,
22712211 l2_provider,
22722212 l1_notification_rx,
2273- None , // TODO: set handle
2213+ Some ( mock_l1_watcher_handle . clone ( ) ) ,
22742214 network_handle. into_scroll_network ( ) . await ,
22752215 Box :: new ( NoopConsensus :: default ( ) ) ,
22762216 engine,
@@ -2292,6 +2232,13 @@ mod tests {
22922232 )
22932233 . await
22942234 . unwrap ( ) ;
2235+
2236+
2237+ // chain_orchestrator.run_until_shutdown(None)
2238+ // TODO: Implement test scenarios:
2239+ // 1. Insert batches with non-sequential indices to trigger gap detection
2240+ // 2. Feed L1 notifications that trigger gap detection
2241+ // 3. Use mock_l1_watcher_handle.assert_reset_to() to verify gap recovery was triggered
22952242 }
22962243
22972244 // Helper function to create a simple test batch commit
@@ -2312,7 +2259,4 @@ mod tests {
23122259 fn create_test_l1_message ( queue_index : u64 ) -> TxL1Message {
23132260 TxL1Message { queue_index, ..Default :: default ( ) }
23142261 }
2315-
2316- #[ tokio:: test]
2317- async fn test_batch_commit_gap_triggers_recovery ( ) { }
23182262}
0 commit comments