@@ -15,8 +15,8 @@ use signet_block_processor::{AliasOracleFactory, SignetBlockProcessorV1};
1515use signet_evm:: EthereumHardfork ;
1616use signet_extract:: Extractor ;
1717use signet_node_config:: SignetNodeConfig ;
18- use signet_rpc:: { ChainNotifier , NewBlockNotification , RpcServerGuard } ;
19- use signet_storage:: { HistoryRead , HotKv , HotKvRead , UnifiedStorage } ;
18+ use signet_rpc:: { ChainNotifier , NewBlockNotification , ReorgNotification , RpcServerGuard } ;
19+ use signet_storage:: { DrainedBlock , HistoryRead , HotKv , HotKvRead , UnifiedStorage } ;
2020use signet_types:: { PairedHeights , constants:: SignetSystemConstants } ;
2121use std:: { fmt, sync:: Arc } ;
2222use tokio:: sync:: watch;
@@ -296,7 +296,8 @@ where
296296
297297 // NB: REVERTS MUST RUN FIRST
298298 if let Some ( chain) = notification. reverted_chain ( ) {
299- changed |= self . on_host_revert ( & chain) . wrap_err ( "error encountered during revert" ) ?;
299+ changed |=
300+ self . on_host_revert ( & chain) . await . wrap_err ( "error encountered during revert" ) ?;
300301 }
301302
302303 if let Some ( chain) = notification. committed_chain ( ) {
@@ -360,6 +361,20 @@ where
360361 let _ = self . chain . send_new_block ( notif) ;
361362 }
362363
364+ /// Send a reorg notification on the broadcast channel.
365+ fn notify_reorg ( & self , drained : Vec < DrainedBlock > , common_ancestor : u64 ) {
366+ let removed_hashes = drained. iter ( ) . map ( |d| d. header . hash ( ) ) . collect ( ) ;
367+ let removed_logs = drained
368+ . into_iter ( )
369+ . flat_map ( |d| d. receipts )
370+ . flat_map ( |r| r. receipt . logs )
371+ . map ( |l| l. inner )
372+ . collect ( ) ;
373+ let notif = ReorgNotification { common_ancestor, removed_hashes, removed_logs } ;
374+ // Ignore send errors — no subscribers is fine.
375+ let _ = self . chain . send_reorg ( notif) ;
376+ }
377+
363378 /// Update the status channel and block tags. This keeps the RPC node
364379 /// in sync with the latest block information.
365380 fn update_status ( & self ) -> eyre:: Result < ( ) > {
@@ -476,7 +491,7 @@ where
476491 ///
477492 /// Returns `true` if any rollup state was unwound.
478493 #[ instrument( skip_all, fields( first = chain. first( ) . number( ) , tip = chain. tip( ) . number( ) ) ) ]
479- pub fn on_host_revert ( & self , chain : & Arc < Chain < Host > > ) -> eyre:: Result < bool > {
494+ pub async fn on_host_revert ( & self , chain : & Arc < Chain < Host > > ) -> eyre:: Result < bool > {
480495 // If the end is before the RU genesis, nothing to do.
481496 if chain. tip ( ) . number ( ) <= self . constants . host_deploy_height ( ) {
482497 return Ok ( false ) ;
@@ -489,7 +504,15 @@ where
489504 . unwrap_or_default ( )
490505 . saturating_sub ( 1 ) ;
491506
492- self . storage . unwind_above ( target) ?;
507+ let drained = self . storage . drain_above ( target) . await ?;
508+
509+ // The early return above guards against no-op reverts, so drained
510+ // should always contain at least one block. Guard defensively.
511+ debug_assert ! ( !drained. is_empty( ) , "drain_above returned empty after host revert" ) ;
512+ if !drained. is_empty ( ) {
513+ self . notify_reorg ( drained, target) ;
514+ }
515+
493516 Ok ( true )
494517 }
495518}
0 commit comments