@@ -39,6 +39,7 @@ use revm::state::EvmState;
3939use state:: TreeState ;
4040use std:: {
4141 fmt:: Debug ,
42+ ops,
4243 sync:: {
4344 mpsc:: { Receiver , RecvError , RecvTimeoutError , Sender } ,
4445 Arc ,
@@ -426,9 +427,13 @@ where
426427 match self . try_recv_engine_message ( ) {
427428 Ok ( Some ( msg) ) => {
428429 debug ! ( target: "engine::tree" , %msg, "received new engine message" ) ;
429- if let Err ( fatal) = self . on_engine_message ( msg) {
430- error ! ( target: "engine::tree" , %fatal, "insert block fatal error" ) ;
431- return
430+ match self . on_engine_message ( msg) {
431+ Ok ( ops:: ControlFlow :: Break ( ( ) ) ) => return ,
432+ Ok ( ops:: ControlFlow :: Continue ( ( ) ) ) => { }
433+ Err ( fatal) => {
434+ error ! ( target: "engine::tree" , %fatal, "insert block fatal error" ) ;
435+ return
436+ }
432437 }
433438 }
434439 Ok ( None ) => {
@@ -1315,14 +1320,50 @@ where
13151320 if let Some ( new_tip_num) = self . find_disk_reorg ( ) ? {
13161321 self . remove_blocks ( new_tip_num)
13171322 } else if self . should_persist ( ) {
1318- let blocks_to_persist = self . get_canonical_blocks_to_persist ( ) ?;
1323+ let blocks_to_persist =
1324+ self . get_canonical_blocks_to_persist ( PersistTarget :: Threshold ) ?;
13191325 self . persist_blocks ( blocks_to_persist) ;
13201326 }
13211327 }
13221328
13231329 Ok ( ( ) )
13241330 }
13251331
1332+ /// Finishes termination by persisting all remaining blocks and signaling completion.
1333+ ///
1334+ /// This blocks until all persistence is complete. Always signals completion,
1335+ /// even if an error occurs.
1336+ fn finish_termination (
1337+ & mut self ,
1338+ pending_termination : oneshot:: Sender < ( ) > ,
1339+ ) -> Result < ( ) , AdvancePersistenceError > {
1340+ trace ! ( target: "engine::tree" , "finishing termination, persisting remaining blocks" ) ;
1341+ let result = self . persist_until_complete ( ) ;
1342+ let _ = pending_termination. send ( ( ) ) ;
1343+ result
1344+ }
1345+
1346+ /// Persists all remaining blocks until none are left.
1347+ fn persist_until_complete ( & mut self ) -> Result < ( ) , AdvancePersistenceError > {
1348+ loop {
1349+ // Wait for any in-progress persistence to complete (blocking)
1350+ if let Some ( ( rx, start_time, _action) ) = self . persistence_state . rx . take ( ) {
1351+ let result = rx. blocking_recv ( ) . map_err ( |_| TryRecvError :: Closed ) ?;
1352+ self . on_persistence_complete ( result, start_time) ?;
1353+ }
1354+
1355+ let blocks_to_persist = self . get_canonical_blocks_to_persist ( PersistTarget :: Head ) ?;
1356+
1357+ if blocks_to_persist. is_empty ( ) {
1358+ debug ! ( target: "engine::tree" , "persistence complete, signaling termination" ) ;
1359+ return Ok ( ( ) )
1360+ }
1361+
1362+ debug ! ( target: "engine::tree" , count = blocks_to_persist. len( ) , "persisting remaining blocks before shutdown" ) ;
1363+ self . persist_blocks ( blocks_to_persist) ;
1364+ }
1365+ }
1366+
13261367 /// Handles a completed persistence task.
13271368 fn on_persistence_complete (
13281369 & mut self ,
@@ -1348,10 +1389,12 @@ where
13481389 }
13491390
13501391 /// Handles a message from the engine.
1392+ ///
1393+ /// Returns `ControlFlow::Break(())` if the engine should terminate.
13511394 fn on_engine_message (
13521395 & mut self ,
13531396 msg : FromEngine < EngineApiRequest < T , N > , N :: Block > ,
1354- ) -> Result < ( ) , InsertBlockFatalError > {
1397+ ) -> Result < ops :: ControlFlow < ( ) > , InsertBlockFatalError > {
13551398 match msg {
13561399 FromEngine :: Event ( event) => match event {
13571400 FromOrchestrator :: BackfillSyncStarted => {
@@ -1361,14 +1404,21 @@ where
13611404 FromOrchestrator :: BackfillSyncFinished ( ctrl) => {
13621405 self . on_backfill_sync_finished ( ctrl) ?;
13631406 }
1407+ FromOrchestrator :: Terminate { tx } => {
1408+ debug ! ( target: "engine::tree" , "received terminate request" ) ;
1409+ if let Err ( err) = self . finish_termination ( tx) {
1410+ error ! ( target: "engine::tree" , %err, "Termination failed" ) ;
1411+ }
1412+ return Ok ( ops:: ControlFlow :: Break ( ( ) ) )
1413+ }
13641414 } ,
13651415 FromEngine :: Request ( request) => {
13661416 match request {
13671417 EngineApiRequest :: InsertExecutedBlock ( block) => {
13681418 let block_num_hash = block. recovered_block ( ) . num_hash ( ) ;
13691419 if block_num_hash. number <= self . state . tree_state . canonical_block_number ( ) {
13701420 // outdated block that can be skipped
1371- return Ok ( ( ) )
1421+ return Ok ( ops :: ControlFlow :: Continue ( ( ) ) )
13721422 }
13731423
13741424 debug ! ( target: "engine::tree" , block=?block_num_hash, "inserting already executed block" ) ;
@@ -1476,7 +1526,7 @@ where
14761526 }
14771527 }
14781528 }
1479- Ok ( ( ) )
1529+ Ok ( ops :: ControlFlow :: Continue ( ( ) ) )
14801530 }
14811531
14821532 /// Invoked if the backfill sync has finished to target.
@@ -1710,10 +1760,10 @@ where
17101760 }
17111761
17121762 /// Returns a batch of consecutive canonical blocks to persist in the range
1713- /// `(last_persisted_number .. canonical_head - threshold]`. The expected
1714- /// order is oldest -> newest.
1763+ /// `(last_persisted_number .. target]`. The expected order is oldest -> newest.
17151764 fn get_canonical_blocks_to_persist (
17161765 & self ,
1766+ target : PersistTarget ,
17171767 ) -> Result < Vec < ExecutedBlock < N > > , AdvancePersistenceError > {
17181768 // We will calculate the state root using the database, so we need to be sure there are no
17191769 // changes
@@ -1724,9 +1774,12 @@ where
17241774 let last_persisted_number = self . persistence_state . last_persisted_block . number ;
17251775 let canonical_head_number = self . state . tree_state . canonical_block_number ( ) ;
17261776
1727- // Persist only up to block buffer target
1728- let target_number =
1729- canonical_head_number. saturating_sub ( self . config . memory_block_buffer_target ( ) ) ;
1777+ let target_number = match target {
1778+ PersistTarget :: Head => canonical_head_number,
1779+ PersistTarget :: Threshold => {
1780+ canonical_head_number. saturating_sub ( self . config . memory_block_buffer_target ( ) )
1781+ }
1782+ } ;
17301783
17311784 debug ! (
17321785 target: "engine::tree" ,
@@ -2869,3 +2922,12 @@ pub enum InsertPayloadOk {
28692922 /// The payload was valid and inserted into the tree.
28702923 Inserted ( BlockStatus ) ,
28712924}
2925+
2926+ /// Target for block persistence.
2927+ #[ derive( Debug , Clone , Copy ) ]
2928+ enum PersistTarget {
2929+ /// Persist up to `canonical_head - memory_block_buffer_target`.
2930+ Threshold ,
2931+ /// Persist all blocks up to and including the canonical head.
2932+ Head ,
2933+ }
0 commit comments