@@ -5,7 +5,7 @@ use crate::tree::{
55 error:: { InsertBlockError , InsertBlockErrorKind , InsertPayloadError } ,
66 executor:: WorkloadExecutor ,
77 instrumented_state:: InstrumentedStateProvider ,
8- payload_processor:: { multiproof :: MultiProofConfig , PayloadProcessor } ,
8+ payload_processor:: PayloadProcessor ,
99 precompile_cache:: { CachedPrecompile , CachedPrecompileMetrics , PrecompileCacheMap } ,
1010 sparse_trie:: StateRootComputeOutcome ,
1111 EngineApiMetrics , EngineApiTreeState , ExecutionEnv , PayloadHandle , StateProviderBuilder ,
@@ -38,7 +38,7 @@ use reth_provider::{
3838 StateRootProvider , TrieReader ,
3939} ;
4040use reth_revm:: db:: State ;
41- use reth_trie:: { updates:: TrieUpdates , HashedPostState , TrieInput } ;
41+ use reth_trie:: { updates:: TrieUpdates , HashedPostState , TrieInputSorted } ;
4242use reth_trie_parallel:: root:: { ParallelStateRoot , ParallelStateRootError } ;
4343use std:: { collections:: HashMap , sync:: Arc , time:: Instant } ;
4444use tracing:: { debug, debug_span, error, info, instrument, trace, warn} ;
@@ -121,8 +121,6 @@ where
121121 metrics : EngineApiMetrics ,
122122 /// Validator for the payload.
123123 validator : V ,
124- /// A cleared trie input, kept around to be reused so allocations can be minimized.
125- trie_input : Option < TrieInput > ,
126124}
127125
128126impl < N , P , Evm , V > BasicEngineValidator < P , Evm , V >
@@ -166,7 +164,6 @@ where
166164 invalid_block_hook,
167165 metrics : EngineApiMetrics :: default ( ) ,
168166 validator,
169- trie_input : Default :: default ( ) ,
170167 }
171168 }
172169
@@ -530,8 +527,8 @@ where
530527 Ok ( ExecutedBlock {
531528 recovered_block : Arc :: new ( block) ,
532529 execution_output : Arc :: new ( ExecutionOutcome :: from ( ( output, block_num_hash. number ) ) ) ,
533- hashed_state : Arc :: new ( hashed_state) ,
534- trie_updates : Arc :: new ( trie_output) ,
530+ hashed_state : Arc :: new ( hashed_state. into_sorted ( ) ) ,
531+ trie_updates : Arc :: new ( trie_output. into_sorted ( ) ) ,
535532 } )
536533 }
537534
@@ -641,26 +638,24 @@ where
641638 hashed_state : & HashedPostState ,
642639 state : & EngineApiTreeState < N > ,
643640 ) -> Result < ( B256 , TrieUpdates ) , ParallelStateRootError > {
644- let ( mut input, block_hash) = self . compute_trie_input ( parent_hash, state, None ) ?;
641+ let ( mut input, block_hash) = self . compute_trie_input ( parent_hash, state) ?;
645642
646- // Extend with block we are validating root for.
647- input. append_ref ( hashed_state) ;
643+ // Extend state overlay with current block's sorted state.
644+ input. prefix_sets . extend ( hashed_state. construct_prefix_sets ( ) ) ;
645+ let sorted_hashed_state = hashed_state. clone ( ) . into_sorted ( ) ;
646+ Arc :: make_mut ( & mut input. state ) . extend_ref ( & sorted_hashed_state) ;
648647
649- // Convert the TrieInput into a MultProofConfig, since everything uses the sorted
650- // forms of the state/trie fields.
651- let ( _, multiproof_config) = MultiProofConfig :: from_input ( input) ;
648+ let TrieInputSorted { nodes, state, prefix_sets : prefix_sets_mut } = input;
652649
653650 let factory = OverlayStateProviderFactory :: new ( self . provider . clone ( ) )
654651 . with_block_hash ( Some ( block_hash) )
655- . with_trie_overlay ( Some ( multiproof_config . nodes_sorted ) )
656- . with_hashed_state_overlay ( Some ( multiproof_config . state_sorted ) ) ;
652+ . with_trie_overlay ( Some ( nodes ) )
653+ . with_hashed_state_overlay ( Some ( state ) ) ;
657654
658655 // The `hashed_state` argument is already taken into account as part of the overlay, but we
659656 // need to use the prefix sets which were generated from it to indicate to the
660657 // ParallelStateRoot which parts of the trie need to be recomputed.
661- let prefix_sets = Arc :: into_inner ( multiproof_config. prefix_sets )
662- . expect ( "MultiProofConfig was never cloned" )
663- . freeze ( ) ;
658+ let prefix_sets = prefix_sets_mut. freeze ( ) ;
664659
665660 ParallelStateRoot :: new ( factory, prefix_sets) . incremental_root_with_updates ( )
666661 }
@@ -756,26 +751,23 @@ where
756751 > {
757752 match strategy {
758753 StateRootStrategy :: StateRootTask => {
759- // get allocated trie input if it exists
760- let allocated_trie_input = self . trie_input . take ( ) ;
761-
762754 // Compute trie input
763755 let trie_input_start = Instant :: now ( ) ;
764- let ( trie_input, block_hash) =
765- self . compute_trie_input ( parent_hash, state, allocated_trie_input) ?;
756+ let ( trie_input, block_hash) = self . compute_trie_input ( parent_hash, state) ?;
757+
758+ self . metrics
759+ . block_validation
760+ . trie_input_duration
761+ . record ( trie_input_start. elapsed ( ) . as_secs_f64 ( ) ) ;
766762
767- // Convert the TrieInput into a MultProofConfig, since everything uses the sorted
768- // forms of the state/trie fields.
769- let ( trie_input, multiproof_config) = MultiProofConfig :: from_input ( trie_input) ;
770- self . trie_input . replace ( trie_input) ;
763+ // Create OverlayStateProviderFactory with sorted trie data for multiproofs
764+ let TrieInputSorted { nodes, state, .. } = trie_input;
771765
772- // Create OverlayStateProviderFactory with the multiproof config, for use with
773- // multiproofs.
774766 let multiproof_provider_factory =
775767 OverlayStateProviderFactory :: new ( self . provider . clone ( ) )
776768 . with_block_hash ( Some ( block_hash) )
777- . with_trie_overlay ( Some ( multiproof_config . nodes_sorted ) )
778- . with_hashed_state_overlay ( Some ( multiproof_config . state_sorted ) ) ;
769+ . with_trie_overlay ( Some ( nodes ) )
770+ . with_hashed_state_overlay ( Some ( state ) ) ;
779771
780772 // Use state root task only if prefix sets are empty, otherwise proof generation is
781773 // too expensive because it requires walking all paths in every proof.
@@ -887,14 +879,14 @@ where
887879 /// Computes the trie input at the provided parent hash, as well as the block number of the
888880 /// highest persisted ancestor.
889881 ///
890- /// The goal of this function is to take in-memory blocks and generate a [`TrieInput`] that
891- /// serves as an overlay to the database blocks.
882+ /// The goal of this function is to take in-memory blocks and generate a [`TrieInputSorted`]
883+ /// that serves as an overlay to the database blocks.
892884 ///
893885 /// It works as follows:
894886 /// 1. Collect in-memory blocks that are descendants of the provided parent hash using
895887 /// [`crate::tree::TreeState::blocks_by_hash`]. This returns the highest persisted ancestor
896888 /// hash (`block_hash`) and the list of in-memory descendant blocks.
897- /// 2. Extend the `TrieInput ` with the contents of these in-memory blocks (from oldest to
889+ /// 2. Extend the `TrieInputSorted ` with the contents of these in-memory blocks (from oldest to
898890 /// newest) to build the overlay state and trie updates that sit on top of the database view
899891 /// anchored at `block_hash`.
900892 #[ instrument(
@@ -907,11 +899,7 @@ where
907899 & self ,
908900 parent_hash : B256 ,
909901 state : & EngineApiTreeState < N > ,
910- allocated_trie_input : Option < TrieInput > ,
911- ) -> ProviderResult < ( TrieInput , B256 ) > {
912- // get allocated trie input or use a default trie input
913- let mut input = allocated_trie_input. unwrap_or_default ( ) ;
914-
902+ ) -> ProviderResult < ( TrieInputSorted , B256 ) > {
915903 let ( block_hash, blocks) =
916904 state. tree_state . blocks_by_hash ( parent_hash) . unwrap_or_else ( || ( parent_hash, vec ! [ ] ) ) ;
917905
@@ -921,10 +909,24 @@ where
921909 debug ! ( target: "engine::tree::payload_validator" , historical = ?block_hash, blocks = blocks. len( ) , "Parent found in memory" ) ;
922910 }
923911
924- // Extend with contents of parent in-memory blocks.
925- input. extend_with_blocks (
926- blocks. iter ( ) . rev ( ) . map ( |block| ( block. hashed_state ( ) , block. trie_updates ( ) ) ) ,
927- ) ;
912+ // Extend with contents of parent in-memory blocks directly in sorted form.
913+ let mut input = TrieInputSorted :: default ( ) ;
914+ let mut blocks_iter = blocks. iter ( ) . rev ( ) . peekable ( ) ;
915+
916+ if let Some ( first) = blocks_iter. next ( ) {
917+ input. state = Arc :: clone ( & first. hashed_state ) ;
918+ input. nodes = Arc :: clone ( & first. trie_updates ) ;
919+
920+ // Only clone and mutate if there are more in-memory blocks.
921+ if blocks_iter. peek ( ) . is_some ( ) {
922+ let state_mut = Arc :: make_mut ( & mut input. state ) ;
923+ let nodes_mut = Arc :: make_mut ( & mut input. nodes ) ;
924+ for block in blocks_iter {
925+ state_mut. extend_ref ( block. hashed_state ( ) ) ;
926+ nodes_mut. extend_ref ( block. trie_updates ( ) ) ;
927+ }
928+ }
929+ }
928930
929931 Ok ( ( input, block_hash) )
930932 }
0 commit comments