@@ -366,12 +366,7 @@ where
366366 ) ;
367367 } ;
368368
369- let ( payload, fb_payload) = build_block (
370- & mut state,
371- & ctx,
372- & mut info,
373- !disable_state_root || ctx. attributes ( ) . no_tx_pool , // need to calculate state root for CL sync
374- ) ?;
369+ let ( payload, fb_payload) = build_block ( & mut state, & ctx, & mut info, true ) ?;
375370
376371 self . payload_tx
377372 . send ( payload. clone ( ) )
@@ -581,6 +576,7 @@ where
581576 ctx = ctx. with_cancel( fb_cancel) . with_extra_ctx( next_flashblocks_ctx) ;
582577 } ,
583578 _ = block_cancel. cancelled( ) => {
579+ self . resolve_best_payload( & mut state, & ctx, & mut info, & best_payload) . await ;
584580 self . record_flashblocks_metrics(
585581 & ctx,
586582 & info,
@@ -701,6 +697,8 @@ where
701697 // We got block cancelled, we won't need anything from the block at this point
702698 // Caution: this assume that block cancel token only cancelled when new FCU is received
703699 if block_cancel. is_cancelled ( ) {
700+ self . resolve_best_payload ( state, ctx, info, best_payload)
701+ . await ;
704702 self . record_flashblocks_metrics (
705703 ctx,
706704 info,
@@ -824,6 +822,52 @@ where
824822 }
825823 }
826824
825+ async fn resolve_best_payload <
826+ DB : Database < Error = ProviderError > + std:: fmt:: Debug + AsRef < P > ,
827+ P : StateRootProvider + HashedPostStateProvider + StorageRootProvider ,
828+ > (
829+ & self ,
830+ state : & mut State < DB > ,
831+ ctx : & OpPayloadBuilderCtx < FlashblocksExtraCtx > ,
832+ info : & mut ExecutionInfo < FlashblocksExecutionInfo > ,
833+ best_payload : & BlockCell < OpBuiltPayload > ,
834+ ) {
835+ if let Some ( payload) = best_payload. get ( )
836+ && payload. block ( ) . header ( ) . state_root == B256 :: ZERO
837+ {
838+ // Calculate state root for best payload on resolve payload to prevent
839+ // cache misses for locally built payloads.
840+ if let Ok ( state_root) = calculate_state_root_only ( state, ctx, info) {
841+ use reth_payload_primitives:: BuiltPayload as _;
842+ let payload_id = payload. id ( ) ;
843+ let fees = payload. fees ( ) ;
844+ let executed_block = payload. executed_block ( ) ;
845+
846+ // Get the current sealed block and extract its components
847+ let block = payload. into_sealed_block ( ) . into_block ( ) ;
848+ let ( mut header, body) = block. split ( ) ;
849+ header. state_root = state_root;
850+
851+ // Create a new sealed block with the updated header
852+ let updated_block =
853+ alloy_consensus:: Block :: < OpTransactionSigned > :: new ( header, body) ;
854+ let sealed_block = Arc :: new ( updated_block. seal_slow ( ) ) ;
855+
856+ // Update the best payload with the calculated staet root
857+ let updated_payload =
858+ OpBuiltPayload :: new ( payload_id, sealed_block, fees, executed_block) ;
859+ self . payload_tx . send ( updated_payload. clone ( ) ) . await . ok ( ) ; // ignore error here
860+ best_payload. set ( updated_payload) ;
861+
862+ debug ! (
863+ target: "payload_builder" ,
864+ state_root = %state_root,
865+ "Updated payload with calculated state root"
866+ ) ;
867+ }
868+ }
869+ }
870+
827871 /// Do some logging and metric recording when we stop build flashblocks
828872 fn record_flashblocks_metrics (
829873 & self ,
@@ -1203,3 +1247,47 @@ where
12031247 fb_payload,
12041248 ) )
12051249}
1250+
1251+ /// Calculates only the state root for an existing payload
1252+ fn calculate_state_root_only < DB , P , ExtraCtx > (
1253+ state : & mut State < DB > ,
1254+ ctx : & OpPayloadBuilderCtx < ExtraCtx > ,
1255+ info : & ExecutionInfo < FlashblocksExecutionInfo > ,
1256+ ) -> Result < B256 , PayloadBuilderError >
1257+ where
1258+ DB : Database < Error = ProviderError > + AsRef < P > ,
1259+ P : StateRootProvider + HashedPostStateProvider + StorageRootProvider ,
1260+ ExtraCtx : std:: fmt:: Debug + Default ,
1261+ {
1262+ let state_root_start_time = Instant :: now ( ) ;
1263+ state. merge_transitions ( BundleRetention :: Reverts ) ;
1264+ let execution_outcome = ExecutionOutcome :: new (
1265+ state. bundle_state . clone ( ) ,
1266+ vec ! [ info. receipts. clone( ) ] ,
1267+ ctx. block_number ( ) ,
1268+ vec ! [ ] ,
1269+ ) ;
1270+
1271+ let state_provider = state. database . as_ref ( ) ;
1272+ let hashed_state = state_provider. hashed_post_state ( execution_outcome. state ( ) ) ;
1273+ let ( state_root, _trie_output) = state
1274+ . database
1275+ . as_ref ( )
1276+ . state_root_with_updates ( hashed_state)
1277+ . inspect_err ( |err| {
1278+ warn ! ( target: "payload_builder" ,
1279+ parent_header=%ctx. parent( ) . hash( ) ,
1280+ %err,
1281+ "failed to calculate state root for payload"
1282+ ) ;
1283+ } ) ?;
1284+ let state_root_calculation_time = state_root_start_time. elapsed ( ) ;
1285+ ctx. metrics
1286+ . state_root_calculation_duration
1287+ . record ( state_root_calculation_time) ;
1288+ ctx. metrics
1289+ . state_root_calculation_gauge
1290+ . set ( state_root_calculation_time) ;
1291+
1292+ Ok ( state_root)
1293+ }
0 commit comments