@@ -5,7 +5,8 @@ use crate::{
55 EthEvmConfig ,
66} ;
77use alloc:: { boxed:: Box , sync:: Arc , vec, vec:: Vec } ;
8- use core:: fmt:: Display ;
8+ use core:: { fmt:: Display , num:: NonZeroUsize } ;
9+ use pevm:: { chain:: PevmEthereum , Pevm } ;
910use reth_chainspec:: { ChainSpec , EthereumHardforks , MAINNET } ;
1011use reth_ethereum_consensus:: validate_block_post_execution;
1112use reth_evm:: {
@@ -34,7 +35,7 @@ use reth_revm::{
3435 Evm ,
3536} ;
3637use revm_primitives:: {
37- db:: { Database , DatabaseCommit } ,
38+ db:: { DatabaseCommit , DatabaseRef } ,
3839 BlockEnv , CfgEnvWithHandlerCfg , EnvWithHandlerCfg , ResultAndState ,
3940} ;
4041use std:: collections:: hash_map:: Entry ;
@@ -71,12 +72,15 @@ where
7172{
7273 fn eth_executor < DB > ( & self , db : DB ) -> EthBlockExecutor < EvmConfig , DB >
7374 where
74- DB : Database < Error : Into < ProviderError > > ,
75+ DB : DatabaseRef < Error : Into < ProviderError > + Display > + Send + Sync ,
7576 {
7677 EthBlockExecutor :: new (
7778 self . chain_spec . clone ( ) ,
7879 self . evm_config . clone ( ) ,
7980 State :: builder ( ) . with_database ( db) . with_bundle_update ( ) . without_state_clear ( ) . build ( ) ,
81+ Pevm :: default ( ) ,
82+ PevmEthereum :: mainnet ( ) ,
83+ NonZeroUsize :: new ( 8 ) . unwrap ( ) ,
8084 )
8185 }
8286}
@@ -85,22 +89,22 @@ impl<EvmConfig> BlockExecutorProvider for EthExecutorProvider<EvmConfig>
8589where
8690 EvmConfig : ConfigureEvm < Header = Header > ,
8791{
88- type Executor < DB : Database < Error : Into < ProviderError > + Display > > =
92+ type Executor < DB : DatabaseRef < Error : Into < ProviderError > + Display > + Send + Sync > =
8993 EthBlockExecutor < EvmConfig , DB > ;
9094
91- type BatchExecutor < DB : Database < Error : Into < ProviderError > + Display > > =
95+ type BatchExecutor < DB : DatabaseRef < Error : Into < ProviderError > + Display > + Send + Sync > =
9296 EthBatchExecutor < EvmConfig , DB > ;
9397
9498 fn executor < DB > ( & self , db : DB ) -> Self :: Executor < DB >
9599 where
96- DB : Database < Error : Into < ProviderError > + Display > ,
100+ DB : DatabaseRef < Error : Into < ProviderError > + Display > + Send + Sync ,
97101 {
98102 self . eth_executor ( db)
99103 }
100104
101105 fn batch_executor < DB > ( & self , db : DB ) -> Self :: BatchExecutor < DB >
102106 where
103- DB : Database < Error : Into < ProviderError > + Display > ,
107+ DB : DatabaseRef < Error : Into < ProviderError > + Display > + Send + Sync ,
104108 {
105109 let executor = self . eth_executor ( db) ;
106110 EthBatchExecutor { executor, batch_record : BlockBatchRecord :: default ( ) }
@@ -138,14 +142,13 @@ where
138142 ///
139143 /// It does __not__ apply post-execution changes that do not require an [EVM](Evm), for that see
140144 /// [`EthBlockExecutor::post_execution`].
141- fn execute_state_transitions < Ext , DB > (
145+ fn _execute_state_transitions < Ext , DB > (
142146 & self ,
143147 block : & BlockWithSenders ,
144148 mut evm : Evm < ' _ , Ext , & mut State < DB > > ,
145- ) -> Result < EthExecuteOutput , BlockExecutionError >
149+ ) -> Result < ( EthExecuteOutput , Vec < ResultAndState > ) , BlockExecutionError >
146150 where
147- DB : Database ,
148- DB :: Error : Into < ProviderError > + Display ,
151+ DB : DatabaseRef < Error : Into < ProviderError > + Display > + Send + Sync ,
149152 {
150153 // apply pre execution changes
151154 apply_beacon_root_contract_call (
@@ -168,6 +171,7 @@ where
168171 // execute transactions
169172 let mut cumulative_gas_used = 0 ;
170173 let mut receipts = Vec :: with_capacity ( block. body . len ( ) ) ;
174+ let mut results = Vec :: with_capacity ( block. body . len ( ) ) ;
171175 for ( sender, transaction) in block. transactions_with_sender ( ) {
172176 // The sum of the transaction’s gas limit, Tg, and the gas utilized in this block prior,
173177 // must be no greater than the block’s gasLimit.
@@ -177,24 +181,25 @@ where
177181 transaction_gas_limit : transaction. gas_limit ( ) ,
178182 block_available_gas,
179183 }
180- . into ( ) )
184+ . into ( ) ) ;
181185 }
182186
183187 self . evm_config . fill_tx_env ( evm. tx_mut ( ) , transaction, * sender) ;
184188
185189 // Execute transaction.
186- let ResultAndState { result , state } = evm. transact ( ) . map_err ( move |err| {
190+ let result_and_state = evm. transact ( ) . map_err ( move |err| {
187191 let new_err = err. map_db_err ( |e| e. into ( ) ) ;
188192 // Ensure hash is calculated for error log, if not already done
189193 BlockValidationError :: EVM {
190194 hash : transaction. recalculate_hash ( ) ,
191195 error : Box :: new ( new_err) ,
192196 }
193197 } ) ?;
194- evm. db_mut ( ) . commit ( state) ;
198+ results. push ( result_and_state. clone ( ) ) ;
199+ evm. db_mut ( ) . commit ( result_and_state. state ) ;
195200
196201 // append gas used
197- cumulative_gas_used += result. gas_used ( ) ;
202+ cumulative_gas_used += result_and_state . result . gas_used ( ) ;
198203
199204 // Push transaction changeset and calculate header bloom filter for receipt.
200205 receipts. push (
@@ -203,10 +208,10 @@ where
203208 tx_type : transaction. tx_type ( ) ,
204209 // Success flag was added in `EIP-658: Embedding transaction status code in
205210 // receipts`.
206- success : result. is_success ( ) ,
211+ success : result_and_state . result . is_success ( ) ,
207212 cumulative_gas_used,
208213 // convert to reth log
209- logs : result. into_logs ( ) ,
214+ logs : result_and_state . result . into_logs ( ) ,
210215 ..Default :: default ( )
211216 } ,
212217 ) ;
@@ -230,7 +235,7 @@ where
230235 vec ! [ ]
231236 } ;
232237
233- Ok ( EthExecuteOutput { receipts, requests, gas_used : cumulative_gas_used } )
238+ Ok ( ( EthExecuteOutput { receipts, requests, gas_used : cumulative_gas_used } , results ) )
234239 }
235240}
236241
@@ -245,12 +250,29 @@ pub struct EthBlockExecutor<EvmConfig, DB> {
245250 executor : EthEvmExecutor < EvmConfig > ,
246251 /// The state to use for execution
247252 state : State < DB > ,
253+ /// Parallel executor
254+ pevm : Pevm ,
255+ chain : PevmEthereum ,
256+ concurrency_level : NonZeroUsize ,
248257}
249258
250259impl < EvmConfig , DB > EthBlockExecutor < EvmConfig , DB > {
251260 /// Creates a new Ethereum block executor.
252- pub const fn new ( chain_spec : Arc < ChainSpec > , evm_config : EvmConfig , state : State < DB > ) -> Self {
253- Self { executor : EthEvmExecutor { chain_spec, evm_config } , state }
261+ pub const fn new (
262+ chain_spec : Arc < ChainSpec > ,
263+ evm_config : EvmConfig ,
264+ state : State < DB > ,
265+ pevm : Pevm ,
266+ chain : PevmEthereum ,
267+ concurrency_level : NonZeroUsize ,
268+ ) -> Self {
269+ Self {
270+ executor : EthEvmExecutor { chain_spec, evm_config } ,
271+ state,
272+ pevm,
273+ chain,
274+ concurrency_level,
275+ }
254276 }
255277
256278 #[ inline]
@@ -268,14 +290,14 @@ impl<EvmConfig, DB> EthBlockExecutor<EvmConfig, DB> {
268290impl < EvmConfig , DB > EthBlockExecutor < EvmConfig , DB >
269291where
270292 EvmConfig : ConfigureEvm < Header = Header > ,
271- DB : Database < Error : Into < ProviderError > + Display > ,
293+ DB : DatabaseRef < Error : Into < ProviderError > + Display > + Send + Sync ,
272294{
273295 /// Configures a new evm configuration and block environment for the given block.
274296 ///
275297 /// # Caution
276298 ///
277299 /// This does not initialize the tx environment.
278- fn evm_env_for_block ( & self , header : & Header , total_difficulty : U256 ) -> EnvWithHandlerCfg {
300+ fn _evm_env_for_block ( & self , header : & Header , total_difficulty : U256 ) -> EnvWithHandlerCfg {
279301 let mut cfg = CfgEnvWithHandlerCfg :: new ( Default :: default ( ) , Default :: default ( ) ) ;
280302 let mut block_env = BlockEnv :: default ( ) ;
281303 self . executor . evm_config . fill_cfg_and_block_env (
@@ -303,16 +325,60 @@ where
303325 self . on_new_block ( & block. header ) ;
304326
305327 // 2. configure the evm and execute
306- let env = self . evm_env_for_block ( & block. header , total_difficulty) ;
307- let output = {
308- let evm = self . executor . evm_config . evm_with_env ( & mut self . state , env) ;
309- self . executor . execute_state_transitions ( block, evm)
310- } ?;
328+ let spec_id = crate :: config:: revm_spec (
329+ self . chain_spec ( ) ,
330+ & reth_chainspec:: Head {
331+ number : block. header . number ,
332+ timestamp : block. header . timestamp ,
333+ difficulty : block. header . difficulty ,
334+ total_difficulty,
335+ hash : Default :: default ( ) ,
336+ } ,
337+ ) ;
338+ let mut block_env = BlockEnv :: default ( ) ;
339+ self . executor . evm_config . fill_block_env (
340+ & mut block_env,
341+ & block. header ,
342+ spec_id >= revm_primitives:: SpecId :: MERGE ,
343+ ) ;
344+ let mut tx_envs = Vec :: with_capacity ( block. body . len ( ) ) ;
345+ for ( sender, transaction) in block. transactions_with_sender ( ) {
346+ let mut tx_env = revm_primitives:: TxEnv :: default ( ) ;
347+ self . executor . evm_config . fill_tx_env ( & mut tx_env, transaction, * sender) ;
348+ tx_envs. push ( tx_env) ;
349+ }
350+ let results =
351+ if tx_envs. len ( ) < self . concurrency_level . into ( ) || block. header . gas_used < 4_000_000 {
352+ pevm:: execute_revm_sequential ( & self . state , & self . chain , spec_id, block_env, tx_envs)
353+ } else {
354+ self . pevm . execute_revm_parallel (
355+ & self . state ,
356+ & self . chain ,
357+ spec_id,
358+ block_env,
359+ tx_envs,
360+ self . concurrency_level ,
361+ )
362+ }
363+ . unwrap_or_else ( |err| panic ! ( "{:?}" , err) ) ;
364+ let mut cumulative_gas_used = 0 ;
365+ let mut receipts = Vec :: with_capacity ( block. body . len ( ) ) ;
366+ for ( tx, ResultAndState { result, state } ) in block. transactions ( ) . zip ( results) {
367+ cumulative_gas_used += result. gas_used ( ) ;
368+ receipts. push ( Receipt {
369+ tx_type : tx. tx_type ( ) ,
370+ success : result. is_success ( ) ,
371+ cumulative_gas_used,
372+ logs : result. into_logs ( ) ,
373+ ..Default :: default ( )
374+ } ) ;
375+ self . state . commit ( state) ;
376+ }
311377
312378 // 3. apply post execution changes
313379 self . post_execution ( block, total_difficulty) ?;
314380
315- Ok ( output )
381+ Ok ( EthExecuteOutput { receipts , requests : Vec :: new ( ) , gas_used : cumulative_gas_used } )
316382 }
317383
318384 /// Apply settings before a new block is executed.
@@ -357,7 +423,7 @@ where
357423impl < EvmConfig , DB > Executor < DB > for EthBlockExecutor < EvmConfig , DB >
358424where
359425 EvmConfig : ConfigureEvm < Header = Header > ,
360- DB : Database < Error : Into < ProviderError > + Display > ,
426+ DB : DatabaseRef < Error : Into < ProviderError > + Display > + Send + Sync ,
361427{
362428 type Input < ' a > = BlockExecutionInput < ' a , BlockWithSenders > ;
363429 type Output = BlockExecutionOutput < Receipt > ;
@@ -392,7 +458,7 @@ pub struct BlockAccessListExecutor<EvmConfig, DB> {
392458impl < EvmConfig , DB > Executor < DB > for BlockAccessListExecutor < EvmConfig , DB >
393459where
394460 EvmConfig : ConfigureEvm < Header = Header > ,
395- DB : Database < Error : Into < ProviderError > + Display > ,
461+ DB : DatabaseRef < Error : Into < ProviderError > + Display > + Send + Sync ,
396462{
397463 type Input < ' a > = BlockExecutionInput < ' a , BlockWithSenders > ;
398464 type Output = BlockExecutionOutput < Receipt > ;
@@ -486,7 +552,7 @@ impl<EvmConfig, DB> EthBatchExecutor<EvmConfig, DB> {
486552impl < EvmConfig , DB > BatchExecutor < DB > for EthBatchExecutor < EvmConfig , DB >
487553where
488554 EvmConfig : ConfigureEvm < Header = Header > ,
489- DB : Database < Error : Into < ProviderError > + Display > ,
555+ DB : DatabaseRef < Error : Into < ProviderError > + Display > + Send + Sync ,
490556{
491557 type Input < ' a > = BlockExecutionInput < ' a , BlockWithSenders > ;
492558 type Output = ExecutionOutcome ;
0 commit comments