@@ -1121,4 +1121,45 @@ mod tests {
11211121
11221122 Ok ( ( ) )
11231123 }
1124+
1125+ #[ tokio:: test]
1126+ async fn test_handle_deadlock_prevention ( ) -> eyre:: Result < ( ) > {
1127+ let ( finalized, latest, chain) = chain ( 10 ) ;
1128+ let unfinalized_blocks = chain[ 1 ..5 ] . to_vec ( ) ;
1129+ let ( mut watcher, _rx, handle) =
1130+ l1_watcher ( unfinalized_blocks. clone ( ) , chain, vec ! [ ] , finalized, latest) ;
1131+
1132+ // When: Fill the channel to capacity LOG_QUERY_BLOCK_RANGE
1133+ for i in 0 ..LOG_QUERY_BLOCK_RANGE {
1134+ watcher. notify ( L1Notification :: NewBlock ( i) ) . await ?;
1135+ }
1136+
1137+ // Channel is now full. Spawn a task that will try to send another notification
1138+ // This blocks until we send the command to reset.
1139+ let watcher_handle_task = tokio:: spawn ( async move {
1140+ // This would normally block, but the reset command should interrupt it
1141+ let result = watcher. notify ( L1Notification :: NewBlock ( 1000 ) ) . await ;
1142+ // After reset is handled, the notify returns without sending
1143+ ( watcher, result)
1144+ } ) ;
1145+
1146+ // Give the notify a chance to start blocking
1147+ tokio:: time:: sleep ( Duration :: from_millis ( 50 ) ) . await ;
1148+
1149+ // Then: Send reset command - this should NOT deadlock
1150+ let ( new_tx, _new_rx) = mpsc:: channel ( 2 ) ;
1151+ let reset_result = tokio:: time:: timeout (
1152+ Duration :: from_secs ( 1 ) ,
1153+ handle. reset_to_block ( 100 , new_tx) ,
1154+ ) . await ;
1155+
1156+ assert ! ( reset_result?. is_ok( ) , "Reset should succeed" ) ;
1157+
1158+ // Verify the watcher processed the reset
1159+ let ( watcher, notify_result) = watcher_handle_task. await ?;
1160+ assert ! ( notify_result. is_ok( ) , "Notify should complete after handling reset" ) ;
1161+ assert_eq ! ( watcher. current_block_number, 100 , "Watcher should be reset to block 100" ) ;
1162+
1163+ Ok ( ( ) )
1164+ }
11241165}
0 commit comments