@@ -18,6 +18,7 @@ use alloy_primitives::{map::foldhash::HashMap, Address, B256, U256};
1818use core:: time:: Duration ;
1919use reth:: payload:: PayloadBuilderAttributes ;
2020use reth_basic_payload_builder:: BuildOutcome ;
21+ use reth_chain_state:: { ExecutedBlock , ExecutedBlockWithTrieUpdates , ExecutedTrieUpdates } ;
2122use reth_evm:: { execute:: BlockBuilder , ConfigureEvm } ;
2223use reth_node_api:: { Block , NodePrimitives , PayloadBuilderError } ;
2324use reth_optimism_consensus:: { calculate_receipt_root_no_memo_optimism, isthmus} ;
@@ -26,14 +27,13 @@ use reth_optimism_forks::OpHardforks;
2627use reth_optimism_node:: { OpBuiltPayload , OpPayloadBuilderAttributes } ;
2728use reth_optimism_primitives:: { OpPrimitives , OpReceipt , OpTransactionSigned } ;
2829use reth_payload_util:: BestPayloadTransactions ;
30+ use reth_primitives_traits:: RecoveredBlock ;
2931use reth_provider:: {
3032 ExecutionOutcome , HashedPostStateProvider , ProviderError , StateRootProvider ,
3133 StorageRootProvider ,
3234} ;
3335use reth_revm:: {
34- database:: StateProviderDatabase ,
35- db:: { states:: bundle_state:: BundleRetention , BundleState } ,
36- State ,
36+ database:: StateProviderDatabase , db:: states:: bundle_state:: BundleRetention , State ,
3737} ;
3838use revm:: Database ;
3939use rollup_boost:: {
@@ -287,7 +287,7 @@ where
287287 ctx. add_builder_tx ( & mut info, & mut state, builder_tx_gas, message. clone ( ) ) ;
288288 }
289289
290- let ( payload, fb_payload, mut bundle_state ) = build_block ( state, & ctx, & mut info) ?;
290+ let ( payload, fb_payload) = build_block ( & mut state, & ctx, & mut info) ?;
291291
292292 best_payload. set ( payload. clone ( ) ) ;
293293 self . ws_pub
@@ -419,7 +419,6 @@ where
419419 "Building flashblock" ,
420420 ) ;
421421 let flashblock_build_start_time = Instant :: now ( ) ;
422- let db = StateProviderDatabase :: new ( & state_provider) ;
423422 // If it is the last flashblock, we need to account for the builder tx
424423 if ctx. is_last_flashblock ( ) {
425424 total_gas_per_batch = total_gas_per_batch. saturating_sub ( builder_tx_gas) ;
@@ -428,11 +427,6 @@ where
428427 * da_limit = da_limit. saturating_sub ( builder_tx_da_size) ;
429428 }
430429 }
431- let mut state = State :: builder ( )
432- . with_database ( db)
433- . with_bundle_update ( )
434- . with_bundle_prestate ( bundle_state)
435- . build ( ) ;
436430
437431 let best_txs_start_time = Instant :: now ( ) ;
438432 let best_txs = BestFlashblocksTxs :: new (
@@ -488,7 +482,7 @@ where
488482 } ;
489483
490484 let total_block_built_duration = Instant :: now ( ) ;
491- let build_result = build_block ( state, & ctx, & mut info) ;
485+ let build_result = build_block ( & mut state, & ctx, & mut info) ;
492486 let total_block_built_duration = total_block_built_duration. elapsed ( ) ;
493487 ctx. metrics
494488 . total_block_built_duration
@@ -506,7 +500,7 @@ where
506500 // Return the error
507501 return Err ( err) ;
508502 }
509- Ok ( ( new_payload, mut fb_payload, new_bundle_state ) ) => {
503+ Ok ( ( new_payload, mut fb_payload) ) => {
510504 fb_payload. index = ctx. increment_flashblock_index ( ) ; // fallback block is index 0, so we need to increment here
511505 fb_payload. base = None ;
512506
@@ -516,6 +510,21 @@ where
516510 tokio:: runtime:: Handle :: current ( )
517511 . block_on ( async { ctx. cancel . cancelled ( ) . await } ) ;
518512 } ) ;
513+
514+ // If main token got canceled in here that means we received get_payload and we should drop everything and now update best_payload
515+ // To ensure that we will return same blocks as rollup-boost (to leverage caches)
516+ if block_cancel. is_cancelled ( ) {
517+ ctx. metrics . block_built_success . increment ( 1 ) ;
518+ ctx. metrics
519+ . flashblock_count
520+ . record ( ctx. flashblock_index ( ) as f64 ) ;
521+ debug ! (
522+ target: "payload_builder" ,
523+ message = "Payload building complete, job cancelled during execution"
524+ ) ;
525+ span. record ( "flashblock_count" , ctx. flashblock_index ( ) ) ;
526+ return Ok ( ( ) ) ;
527+ }
519528 self . ws_pub
520529 . publish ( & fb_payload)
521530 . map_err ( PayloadBuilderError :: other) ?;
@@ -533,7 +542,6 @@ where
533542
534543 best_payload. set ( new_payload. clone ( ) ) ;
535544 // Update bundle_state for next iteration
536- bundle_state = new_bundle_state;
537545 total_gas_per_batch += gas_per_batch;
538546 if let Some ( da_limit) = da_per_batch {
539547 if let Some ( da) = total_da_per_batch. as_mut ( ) {
@@ -732,18 +740,17 @@ where
732740}
733741
734742fn build_block < DB , P , ExtraCtx > (
735- mut state : State < DB > ,
743+ state : & mut State < DB > ,
736744 ctx : & OpPayloadBuilderCtx < ExtraCtx > ,
737745 info : & mut ExecutionInfo < ExtraExecutionInfo > ,
738- ) -> Result < ( OpBuiltPayload , FlashblocksPayloadV1 , BundleState ) , PayloadBuilderError >
746+ ) -> Result < ( OpBuiltPayload , FlashblocksPayloadV1 ) , PayloadBuilderError >
739747where
740748 DB : Database < Error = ProviderError > + AsRef < P > ,
741749 P : StateRootProvider + HashedPostStateProvider + StorageRootProvider ,
742750 ExtraCtx : std:: fmt:: Debug + Default ,
743751{
744- // TODO: We must run this only once per block, but we are running it on every flashblock
745- // merge all transitions into bundle state, this would apply the withdrawal balance changes
746- // and 4788 contract call
752+ // We use it to preserve state, so we run merge_transitions on transition state at most once
753+ let untouched_transition_state = state. transition_state . clone ( ) ;
747754 let state_merge_start_time = Instant :: now ( ) ;
748755 state. merge_transitions ( BundleRetention :: Reverts ) ;
749756 let state_transition_merge_time = state_merge_start_time. elapsed ( ) ;
@@ -754,13 +761,11 @@ where
754761 . state_transition_merge_gauge
755762 . set ( state_transition_merge_time) ;
756763
757- let new_bundle = state. take_bundle ( ) ;
758-
759764 let block_number = ctx. block_number ( ) ;
760765 assert_eq ! ( block_number, ctx. parent( ) . number + 1 ) ;
761766
762767 let execution_outcome = ExecutionOutcome :: new (
763- new_bundle . clone ( ) ,
768+ state . bundle_state . clone ( ) ,
764769 vec ! [ info. receipts. clone( ) ] ,
765770 block_number,
766771 vec ! [ ] ,
@@ -779,11 +784,12 @@ where
779784 . block_logs_bloom ( block_number)
780785 . expect ( "Number is in range" ) ;
781786
787+ // TODO: maybe recreate state with bundle in here
782788 // // calculate the state root
783789 let state_root_start_time = Instant :: now ( ) ;
784790 let state_provider = state. database . as_ref ( ) ;
785791 let hashed_state = state_provider. hashed_post_state ( execution_outcome. state ( ) ) ;
786- let ( state_root, _trie_output ) = {
792+ let ( state_root, trie_output ) = {
787793 state
788794 . database
789795 . as_ref ( )
@@ -870,6 +876,19 @@ where
870876 } ,
871877 ) ;
872878
879+ let recovered_block =
880+ RecoveredBlock :: new_unhashed ( block. clone ( ) , info. executed_senders . clone ( ) ) ;
881+ // create the executed block data
882+ let executed: ExecutedBlockWithTrieUpdates < OpPrimitives > = ExecutedBlockWithTrieUpdates {
883+ block : ExecutedBlock {
884+ recovered_block : Arc :: new ( recovered_block) ,
885+ execution_output : Arc :: new ( execution_outcome) ,
886+ hashed_state : Arc :: new ( hashed_state) ,
887+ } ,
888+ trie : ExecutedTrieUpdates :: Present ( Arc :: new ( trie_output) ) ,
889+ } ;
890+ info ! ( target: "payload_builder" , message = "Executed block created" ) ;
891+
873892 let sealed_block = Arc :: new ( block. seal_slow ( ) ) ;
874893 debug ! ( target: "payload_builder" , ?sealed_block, "sealed built block" ) ;
875894
@@ -891,7 +910,8 @@ where
891910 . zip ( new_receipts. iter ( ) )
892911 . map ( |( tx, receipt) | ( tx. tx_hash ( ) , receipt. clone ( ) ) )
893912 . collect :: < HashMap < B256 , OpReceipt > > ( ) ;
894- let new_account_balances = new_bundle
913+ let new_account_balances = state
914+ . bundle_state
895915 . state
896916 . iter ( )
897917 . filter_map ( |( address, account) | account. info . as_ref ( ) . map ( |info| ( * address, info. balance ) ) )
@@ -935,18 +955,17 @@ where
935955 metadata : serde_json:: to_value ( & metadata) . unwrap_or_default ( ) ,
936956 } ;
937957
958+ // We clean bundle and place initial state transaction back
959+ state. take_bundle ( ) ;
960+ state. transition_state = untouched_transition_state;
961+
938962 Ok ( (
939963 OpBuiltPayload :: new (
940964 ctx. payload_id ( ) ,
941965 sealed_block,
942966 info. total_fees ,
943- // This must be set to NONE for now because we are doing merge transitions on every flashblock
944- // when it should only happen once per block, thus, it returns a confusing state back to op-reth.
945- // We can live without this for now because Op syncs up the executed block using new_payload
946- // calls, but eventually we would want to return the executed block here.
947- None ,
967+ Some ( executed) ,
948968 ) ,
949969 fb_payload,
950- new_bundle,
951970 ) )
952971}
0 commit comments