diff --git a/Cargo.lock b/Cargo.lock index 69b5d07900b5..09258315cf79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9004,6 +9004,7 @@ dependencies = [ "reth-chain-state", "reth-chainspec", "reth-errors", + "reth-evm", "reth-execution-types", "reth-metrics", "reth-primitives", diff --git a/crates/ethereum/evm/src/lib.rs b/crates/ethereum/evm/src/lib.rs index 2aaa063d745b..50907223a1a2 100644 --- a/crates/ethereum/evm/src/lib.rs +++ b/crates/ethereum/evm/src/lib.rs @@ -26,6 +26,7 @@ use reth_chainspec::ChainSpec; use reth_evm::{env::EvmEnv, ConfigureEvm, ConfigureEvmEnv, NextBlockEnvAttributes}; use reth_primitives::TransactionSigned; use reth_primitives_traits::transaction::execute::FillTxEnv; +use reth_revm::{inspector_handle_register, EvmBuilder}; use revm_primitives::{ AnalysisKind, BlobExcessGasAndPrice, BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, Env, SpecId, TxEnv, }; @@ -182,24 +183,57 @@ impl ConfigureEvmEnv for EthEvmConfig { } } -impl ConfigureEvm for EthEvmConfig {} +impl ConfigureEvm for EthEvmConfig { + fn evm_with_env( + &self, + db: DB, + evm_env: EvmEnv, + tx: TxEnv, + ) -> reth_revm::Evm<'_, (), DB> { + EvmBuilder::default() + .with_db(db) + .with_cfg_env_with_handler_cfg(evm_env.cfg_env_with_handler_cfg) + .with_block_env(evm_env.block_env) + .with_tx_env(tx) + .build() + } + + fn evm_with_env_and_inspector( + &self, + db: DB, + evm_env: EvmEnv, + tx: TxEnv, + inspector: I, + ) -> reth_revm::Evm<'_, I, DB> + where + DB: reth_revm::Database, + I: reth_revm::GetInspector, + { + EvmBuilder::default() + .with_db(db) + .with_external_context(inspector) + .with_cfg_env_with_handler_cfg(evm_env.cfg_env_with_handler_cfg) + .with_block_env(evm_env.block_env) + .with_tx_env(tx) + .append_handler_register(inspector_handle_register) + .build() + } +} #[cfg(test)] mod tests { use super::*; - use alloy_consensus::{constants::KECCAK_EMPTY, Header}; + use alloy_consensus::Header; use alloy_genesis::Genesis; - use alloy_primitives::{B256, U256}; + use alloy_primitives::U256; use reth_chainspec::{Chain, ChainSpec, MAINNET}; use reth_evm::{env::EvmEnv, execute::ProviderError}; use reth_revm::{ db::{CacheDB, EmptyDBTyped}, inspectors::NoOpInspector, primitives::{BlockEnv, CfgEnv, SpecId}, - JournaledState, }; use revm_primitives::HandlerCfg; - use std::collections::HashSet; #[test] fn test_fill_cfg_and_block_env() { @@ -226,45 +260,6 @@ mod tests { assert_eq!(cfg_env_with_handler_cfg.chain_id, chain_spec.chain().id()); } - #[test] - #[allow(clippy::needless_update)] - fn test_evm_configure() { - // Create a default `EthEvmConfig` - let evm_config = EthEvmConfig::new(MAINNET.clone()); - - // Initialize an empty database wrapped in CacheDB - let db = CacheDB::>::default(); - - // Create an EVM instance using the configuration and the database - let evm = evm_config.evm(db); - - // Check that the EVM environment is initialized with default values - assert_eq!(evm.context.evm.inner.env, Box::default()); - - // Latest spec ID and no warm preloaded addresses - assert_eq!( - evm.context.evm.inner.journaled_state, - JournaledState::new(SpecId::LATEST, HashSet::default()) - ); - - // Ensure that the accounts database is empty - assert!(evm.context.evm.inner.db.accounts.is_empty()); - - // Ensure that the block hashes database is empty - assert!(evm.context.evm.inner.db.block_hashes.is_empty()); - - // Verify that there are two default contracts in the contracts database - assert_eq!(evm.context.evm.inner.db.contracts.len(), 2); - assert!(evm.context.evm.inner.db.contracts.contains_key(&KECCAK_EMPTY)); - assert!(evm.context.evm.inner.db.contracts.contains_key(&B256::ZERO)); - - // Ensure that the logs database is empty - assert!(evm.context.evm.inner.db.logs.is_empty()); - - // No Optimism - assert_eq!(evm.handler.cfg, HandlerCfg { spec_id: SpecId::LATEST, ..Default::default() }); - } - #[test] #[allow(clippy::needless_update)] fn test_evm_with_env_default_spec() { @@ -374,57 +369,15 @@ mod tests { let evm = evm_config.evm_with_env(db, evm_env, Default::default()); // Check that the spec ID is setup properly - assert_eq!(evm.handler.spec_id(), SpecId::CONSTANTINOPLE); + assert_eq!(evm.handler.spec_id(), SpecId::PETERSBURG); // No Optimism assert_eq!( evm.handler.cfg, - HandlerCfg { spec_id: SpecId::CONSTANTINOPLE, ..Default::default() } + HandlerCfg { spec_id: SpecId::PETERSBURG, ..Default::default() } ); } - #[test] - #[allow(clippy::needless_update)] - fn test_evm_with_inspector() { - let evm_config = EthEvmConfig::new(MAINNET.clone()); - - let db = CacheDB::>::default(); - - // No operation inspector - let noop = NoOpInspector; - - let evm = evm_config.evm_with_inspector(db, noop); - - // Check that the inspector is set correctly - assert_eq!(evm.context.external, noop); - - // Check that the EVM environment is initialized with default values - assert_eq!(evm.context.evm.inner.env, Box::default()); - - // Latest spec ID and no warm preloaded addresses - assert_eq!( - evm.context.evm.inner.journaled_state, - JournaledState::new(SpecId::LATEST, HashSet::default()) - ); - - // Ensure that the accounts database is empty - assert!(evm.context.evm.inner.db.accounts.is_empty()); - - // Ensure that the block hashes database is empty - assert!(evm.context.evm.inner.db.block_hashes.is_empty()); - - // Verify that there are two default contracts in the contracts database - assert_eq!(evm.context.evm.inner.db.contracts.len(), 2); - assert!(evm.context.evm.inner.db.contracts.contains_key(&KECCAK_EMPTY)); - assert!(evm.context.evm.inner.db.contracts.contains_key(&B256::ZERO)); - - // Ensure that the logs database is empty - assert!(evm.context.evm.inner.db.logs.is_empty()); - - // No Optimism - assert_eq!(evm.handler.cfg, HandlerCfg { spec_id: SpecId::LATEST, ..Default::default() }); - } - #[test] #[allow(clippy::needless_update)] fn test_evm_with_env_and_default_inspector() { @@ -530,7 +483,7 @@ mod tests { ); // Check that the spec ID is set properly - assert_eq!(evm.handler.spec_id(), SpecId::CONSTANTINOPLE); + assert_eq!(evm.handler.spec_id(), SpecId::PETERSBURG); assert_eq!(evm.context.evm.env.block, evm_env.block_env); assert_eq!(evm.context.evm.env.cfg, evm_env.cfg_env_with_handler_cfg.cfg_env); assert_eq!(evm.context.evm.env.tx, Default::default()); @@ -539,7 +492,7 @@ mod tests { // No Optimism assert_eq!( evm.handler.cfg, - HandlerCfg { spec_id: SpecId::CONSTANTINOPLE, ..Default::default() } + HandlerCfg { spec_id: SpecId::PETERSBURG, ..Default::default() } ); } } diff --git a/crates/ethereum/payload/src/lib.rs b/crates/ethereum/payload/src/lib.rs index 7d49570ff8d4..ca1156fbb400 100644 --- a/crates/ethereum/payload/src/lib.rs +++ b/crates/ethereum/payload/src/lib.rs @@ -202,12 +202,7 @@ where // apply eip-4788 pre block contract call system_caller - .pre_block_beacon_root_contract_call( - &mut db, - evm_env.cfg_env_with_handler_cfg(), - evm_env.block_env(), - attributes.parent_beacon_block_root, - ) + .pre_block_beacon_root_contract_call(&mut db, &evm_env, attributes.parent_beacon_block_root) .map_err(|err| { warn!(target: "payload_builder", parent_hash=%parent_header.hash(), @@ -220,8 +215,7 @@ where // apply eip-2935 blockhashes update system_caller.pre_block_blockhashes_contract_call( &mut db, - evm_env.cfg_env_with_handler_cfg(), - evm_env.block_env(), + &evm_env, parent_header.hash(), ) .map_err(|err| { diff --git a/crates/evm/src/builder.rs b/crates/evm/src/builder.rs deleted file mode 100644 index 94531dd0ff01..000000000000 --- a/crates/evm/src/builder.rs +++ /dev/null @@ -1,141 +0,0 @@ -//! Builder for creating an EVM with a database and environment. - -use alloc::boxed::Box; -use revm::{inspector_handle_register, Database, Evm, EvmBuilder, GetInspector}; -use revm_primitives::EnvWithHandlerCfg; - -/// Builder for creating an EVM with a database and environment. -/// -/// Wrapper around [`EvmBuilder`] that allows for setting the database and environment for the EVM. -/// -/// This is useful for creating an EVM with a custom database and environment without having to -/// necessarily rely on Revm inspector. -#[derive(Debug)] -pub struct RethEvmBuilder { - /// The database to use for the EVM. - db: DB, - /// The environment to use for the EVM. - env: Option>, - /// The external context for the EVM. - external_context: EXT, -} - -impl RethEvmBuilder { - /// Create a new EVM builder with the given database. - pub const fn new(db: DB) -> Self { - Self { db, env: None, external_context: () } - } -} - -impl RethEvmBuilder -where - DB: Database, -{ - /// Set the environment for the EVM. - pub fn with_env(mut self, env: Box) -> Self { - self.env = Some(env); - self - } - - /// Set the external context for the EVM. - pub fn with_external_context(self, external_context: EXT1) -> RethEvmBuilder { - RethEvmBuilder { db: self.db, env: self.env, external_context } - } - - /// Build the EVM with the given database and environment. - pub fn build<'a>(self) -> Evm<'a, EXT, DB> { - let mut builder = - EvmBuilder::default().with_db(self.db).with_external_context(self.external_context); - if let Some(env) = self.env { - builder = builder.with_spec_id(env.spec_id()); - builder = builder.with_env(env.env); - } - - builder.build() - } - - /// Build the EVM with the given database and environment, using the given inspector. - pub fn build_with_inspector<'a, I>(self, inspector: I) -> Evm<'a, I, DB> - where - I: GetInspector, - EXT: 'a, - { - let mut builder = - EvmBuilder::default().with_db(self.db).with_external_context(self.external_context); - if let Some(env) = self.env { - builder = builder.with_spec_id(env.spec_id()); - builder = builder.with_env(env.env); - } - builder - .with_external_context(inspector) - .append_handler_register(inspector_handle_register) - .build() - } -} - -/// Trait for configuring an EVM builder. -pub trait ConfigureEvmBuilder { - /// The type of EVM builder that this trait can configure. - type Builder<'a, DB: Database>: EvmFactory; -} - -/// Trait for configuring the EVM for executing full blocks. -pub trait EvmFactory { - /// Returns new EVM with the given database - /// - /// This does not automatically configure the EVM with [`crate::ConfigureEvmEnv`] methods. It is - /// up to the caller to call an appropriate method to fill the transaction and block - /// environment before executing any transactions using the provided EVM. - fn evm(self, db: DB) -> Evm<'static, (), DB> - where - Self: Sized, - { - RethEvmBuilder::new(db).build() - } - - /// Returns a new EVM with the given database configured with the given environment settings, - /// including the spec id. - /// - /// This will preserve any handler modifications - fn evm_with_env<'a, DB: Database + 'a>( - &self, - db: DB, - env: EnvWithHandlerCfg, - ) -> Evm<'a, (), DB> { - RethEvmBuilder::new(db).with_env(env.into()).build() - } - - /// Returns a new EVM with the given database configured with the given environment settings, - /// including the spec id. - /// - /// This will use the given external inspector as the EVM external context. - /// - /// This will preserve any handler modifications - fn evm_with_env_and_inspector( - &self, - db: DB, - env: EnvWithHandlerCfg, - inspector: I, - ) -> Evm<'_, I, DB> - where - DB: Database, - I: GetInspector, - { - RethEvmBuilder::new(db).with_env(env.into()).build_with_inspector(inspector) - } - - /// Returns a new EVM with the given inspector. - /// - /// Caution: This does not automatically configure the EVM with [`crate::ConfigureEvmEnv`] - /// methods. It is up to the caller to call an appropriate method to fill the transaction - /// and block environment before executing any transactions using the provided EVM. - fn evm_with_inspector(&self, db: DB, inspector: I) -> Evm<'_, I, DB> - where - DB: Database, - I: GetInspector, - { - RethEvmBuilder::new(db).build_with_inspector(inspector) - } -} - -impl EvmFactory for RethEvmBuilder {} diff --git a/crates/evm/src/lib.rs b/crates/evm/src/lib.rs index 2b5c98adcbb3..1271bb14b77b 100644 --- a/crates/evm/src/lib.rs +++ b/crates/evm/src/lib.rs @@ -17,14 +17,12 @@ extern crate alloc; -use crate::builder::RethEvmBuilder; use alloy_consensus::BlockHeader as _; use alloy_primitives::{Address, Bytes, B256, U256}; use reth_primitives_traits::{BlockHeader, SignedTransaction}; use revm::{Database, Evm, GetInspector}; use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, Env, SpecId, TxEnv}; -pub mod builder; pub mod either; /// EVM environment configuration. pub mod env; @@ -42,26 +40,11 @@ pub mod test_utils; /// Trait for configuring the EVM for executing full blocks. pub trait ConfigureEvm: ConfigureEvmEnv { - /// Returns new EVM with the given database - /// - /// This does not automatically configure the EVM with [`ConfigureEvmEnv`] methods. It is up to - /// the caller to call an appropriate method to fill the transaction and block environment - /// before executing any transactions using the provided EVM. - fn evm(&self, db: DB) -> Evm<'_, (), DB> { - RethEvmBuilder::new(db).build() - } - /// Returns a new EVM with the given database configured with the given environment settings, /// including the spec id and transaction environment. /// /// This will preserve any handler modifications - fn evm_with_env(&self, db: DB, evm_env: EvmEnv, tx: TxEnv) -> Evm<'_, (), DB> { - let mut evm = self.evm(db); - evm.modify_spec_id(evm_env.cfg_env_with_handler_cfg.handler_cfg.spec_id); - evm.context.evm.env = - Env::boxed(evm_env.cfg_env_with_handler_cfg.cfg_env, evm_env.block_env, tx); - evm - } + fn evm_with_env(&self, db: DB, evm_env: EvmEnv, tx: TxEnv) -> Evm<'_, (), DB>; /// Returns a new EVM with the given database configured with `cfg` and `block_env` /// configuration derived from the given header. Relies on @@ -90,27 +73,7 @@ pub trait ConfigureEvm: ConfigureEvmEnv { ) -> Evm<'_, I, DB> where DB: Database, - I: GetInspector, - { - let mut evm = self.evm_with_inspector(db, inspector); - evm.modify_spec_id(evm_env.cfg_env_with_handler_cfg.handler_cfg.spec_id); - evm.context.evm.env = - Env::boxed(evm_env.cfg_env_with_handler_cfg.cfg_env, evm_env.block_env, tx); - evm - } - - /// Returns a new EVM with the given inspector. - /// - /// Caution: This does not automatically configure the EVM with [`ConfigureEvmEnv`] methods. It - /// is up to the caller to call an appropriate method to fill the transaction and block - /// environment before executing any transactions using the provided EVM. - fn evm_with_inspector(&self, db: DB, inspector: I) -> Evm<'_, I, DB> - where - DB: Database, - I: GetInspector, - { - RethEvmBuilder::new(db).build_with_inspector(inspector) - } + I: GetInspector; } impl<'b, T> ConfigureEvm for &'b T @@ -118,10 +81,6 @@ where T: ConfigureEvm, &'b T: ConfigureEvmEnv
, { - fn evm(&self, db: DB) -> Evm<'_, (), DB> { - (*self).evm(db) - } - fn evm_for_block(&self, db: DB, header: &Self::Header) -> Evm<'_, (), DB> { (*self).evm_for_block(db, header) } @@ -143,14 +102,6 @@ where { (*self).evm_with_env_and_inspector(db, evm_env, tx_env, inspector) } - - fn evm_with_inspector(&self, db: DB, inspector: I) -> Evm<'_, I, DB> - where - DB: Database, - I: GetInspector, - { - (*self).evm_with_inspector(db, inspector) - } } /// This represents the set of methods used to configure the EVM's environment before block diff --git a/crates/evm/src/system_calls/mod.rs b/crates/evm/src/system_calls/mod.rs index 4d0fc8041d45..63527b29b219 100644 --- a/crates/evm/src/system_calls/mod.rs +++ b/crates/evm/src/system_calls/mod.rs @@ -1,6 +1,6 @@ //! System contract call functions. -use crate::ConfigureEvm; +use crate::{ConfigureEvm, EvmEnv}; use alloc::{boxed::Box, sync::Arc}; use alloy_consensus::BlockHeader; use alloy_eips::{ @@ -11,7 +11,7 @@ use core::fmt::Display; use reth_chainspec::EthereumHardforks; use reth_execution_errors::BlockExecutionError; use revm::{Database, DatabaseCommit, Evm}; -use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, EvmState, B256}; +use revm_primitives::{EvmState, B256}; mod eip2935; mod eip4788; @@ -70,24 +70,6 @@ impl SystemCaller { pub fn finish(self) {} } -fn initialize_evm<'a, DB>( - db: &'a mut DB, - initialized_cfg: &'a CfgEnvWithHandlerCfg, - initialized_block_env: &'a BlockEnv, -) -> Evm<'a, (), &'a mut DB> -where - DB: Database, -{ - Evm::builder() - .with_db(db) - .with_env_with_handler_cfg(EnvWithHandlerCfg::new_with_cfg_env( - initialized_cfg.clone(), - initialized_block_env.clone(), - Default::default(), - )) - .build() -} - impl SystemCaller where EvmConfig: ConfigureEvm, @@ -149,18 +131,19 @@ where pub fn pre_block_blockhashes_contract_call( &mut self, db: &mut DB, - initialized_cfg: &CfgEnvWithHandlerCfg, - initialized_block_env: &BlockEnv, + evm_env: &EvmEnv, parent_block_hash: B256, ) -> Result<(), BlockExecutionError> where DB: Database + DatabaseCommit, DB::Error: Display, { - let mut evm = initialize_evm(db, initialized_cfg, initialized_block_env); + let evm_config = self.evm_config.clone(); + let mut evm = evm_config.evm_with_env(db, evm_env.clone(), Default::default()); + self.apply_blockhashes_contract_call( - initialized_block_env.timestamp.to(), - initialized_block_env.number.to(), + evm_env.block_env.timestamp.to(), + evm_env.block_env.number.to(), parent_block_hash, &mut evm, )?; @@ -203,19 +186,19 @@ where pub fn pre_block_beacon_root_contract_call( &mut self, db: &mut DB, - initialized_cfg: &CfgEnvWithHandlerCfg, - initialized_block_env: &BlockEnv, + evm_env: &EvmEnv, parent_beacon_block_root: Option, ) -> Result<(), BlockExecutionError> where DB: Database + DatabaseCommit, DB::Error: Display, { - let mut evm = initialize_evm(db, initialized_cfg, initialized_block_env); + let evm_config = self.evm_config.clone(); + let mut evm = evm_config.evm_with_env(db, evm_env.clone(), Default::default()); self.apply_beacon_root_contract_call( - initialized_block_env.timestamp.to(), - initialized_block_env.number.to(), + evm_env.block_env.timestamp.to(), + evm_env.block_env.number.to(), parent_beacon_block_root, &mut evm, )?; @@ -258,14 +241,14 @@ where pub fn post_block_withdrawal_requests_contract_call( &mut self, db: &mut DB, - initialized_cfg: &CfgEnvWithHandlerCfg, - initialized_block_env: &BlockEnv, + evm_env: &EvmEnv, ) -> Result where DB: Database + DatabaseCommit, DB::Error: Display, { - let mut evm = initialize_evm(db, initialized_cfg, initialized_block_env); + let evm_config = self.evm_config.clone(); + let mut evm = evm_config.evm_with_env(db, evm_env.clone(), Default::default()); let result = self.apply_withdrawal_requests_contract_call(&mut evm)?; @@ -296,14 +279,14 @@ where pub fn post_block_consolidation_requests_contract_call( &mut self, db: &mut DB, - initialized_cfg: &CfgEnvWithHandlerCfg, - initialized_block_env: &BlockEnv, + evm_env: &EvmEnv, ) -> Result where DB: Database + DatabaseCommit, DB::Error: Display, { - let mut evm = initialize_evm(db, initialized_cfg, initialized_block_env); + let evm_config = self.evm_config.clone(); + let mut evm = evm_config.evm_with_env(db, evm_env.clone(), Default::default()); let res = self.apply_consolidation_requests_contract_call(&mut evm)?; diff --git a/crates/optimism/evm/src/lib.rs b/crates/optimism/evm/src/lib.rs index dbadd23b0317..ad172c764411 100644 --- a/crates/optimism/evm/src/lib.rs +++ b/crates/optimism/evm/src/lib.rs @@ -168,19 +168,41 @@ impl ConfigureEvmEnv for OpEvmConfig { } impl ConfigureEvm for OpEvmConfig { - fn evm(&self, db: DB) -> Evm<'_, (), DB> { - EvmBuilder::default().with_db(db).optimism().build() + fn evm_with_env( + &self, + db: DB, + mut evm_env: EvmEnv, + tx: TxEnv, + ) -> Evm<'_, (), DB> { + evm_env.cfg_env_with_handler_cfg.handler_cfg.is_optimism = true; + + EvmBuilder::default() + .with_db(db) + .with_cfg_env_with_handler_cfg(evm_env.cfg_env_with_handler_cfg) + .with_block_env(evm_env.block_env) + .with_tx_env(tx) + .build() } - fn evm_with_inspector(&self, db: DB, inspector: I) -> Evm<'_, I, DB> + fn evm_with_env_and_inspector( + &self, + db: DB, + mut evm_env: EvmEnv, + tx: TxEnv, + inspector: I, + ) -> Evm<'_, I, DB> where DB: Database, I: GetInspector, { + evm_env.cfg_env_with_handler_cfg.handler_cfg.is_optimism = true; + EvmBuilder::default() .with_db(db) .with_external_context(inspector) - .optimism() + .with_cfg_env_with_handler_cfg(evm_env.cfg_env_with_handler_cfg) + .with_block_env(evm_env.block_env) + .with_tx_env(tx) .append_handler_register(inspector_handle_register) .build() } @@ -189,14 +211,10 @@ impl ConfigureEvm for OpEvmConfig { #[cfg(test)] mod tests { use super::*; - use alloy_consensus::{constants::KECCAK_EMPTY, Header, Receipt}; + use alloy_consensus::{Header, Receipt}; use alloy_eips::eip7685::Requests; use alloy_genesis::Genesis; - use alloy_primitives::{ - bytes, - map::{HashMap, HashSet}, - Address, LogData, B256, U256, - }; + use alloy_primitives::{bytes, map::HashMap, Address, LogData, B256, U256}; use reth_chainspec::ChainSpec; use reth_evm::execute::ProviderError; use reth_execution_types::{ @@ -209,7 +227,6 @@ mod tests { db::{BundleState, CacheDB, EmptyDBTyped}, inspectors::NoOpInspector, primitives::{AccountInfo, BlockEnv, CfgEnv, SpecId}, - JournaledState, }; use revm_primitives::HandlerCfg; use std::sync::Arc; @@ -244,47 +261,6 @@ mod tests { assert_eq!(cfg_env_with_handler_cfg.chain_id, chain_spec.chain().id()); } - #[test] - fn test_evm_configure() { - // Create a default `OpEvmConfig` - let evm_config = test_evm_config(); - - // Initialize an empty database wrapped in CacheDB - let db = CacheDB::>::default(); - - // Create an EVM instance using the configuration and the database - let evm = evm_config.evm(db); - - // Check that the EVM environment is initialized with default values - assert_eq!(evm.context.evm.inner.env, Box::default()); - - // Latest spec ID and no warm preloaded addresses - assert_eq!( - evm.context.evm.inner.journaled_state, - JournaledState::new(SpecId::LATEST, HashSet::default()) - ); - - // Ensure that the accounts database is empty - assert!(evm.context.evm.inner.db.accounts.is_empty()); - - // Ensure that the block hashes database is empty - assert!(evm.context.evm.inner.db.block_hashes.is_empty()); - - // Verify that there are two default contracts in the contracts database - assert_eq!(evm.context.evm.inner.db.contracts.len(), 2); - assert!(evm.context.evm.inner.db.contracts.contains_key(&KECCAK_EMPTY)); - assert!(evm.context.evm.inner.db.contracts.contains_key(&B256::ZERO)); - - // Ensure that the logs database is empty - assert!(evm.context.evm.inner.db.logs.is_empty()); - - // Optimism in handler - assert_eq!(evm.handler.cfg, HandlerCfg { spec_id: SpecId::LATEST, is_optimism: true }); - - // Default spec ID - assert_eq!(evm.handler.spec_id(), SpecId::LATEST); - } - #[test] fn test_evm_with_env_default_spec() { let evm_config = test_evm_config(); @@ -389,50 +365,6 @@ mod tests { assert_eq!(evm.handler.cfg, HandlerCfg { spec_id: SpecId::ECOTONE, is_optimism: true }); } - #[test] - fn test_evm_with_inspector() { - let evm_config = test_evm_config(); - - let db = CacheDB::>::default(); - - // No operation inspector - let noop = NoOpInspector; - - let evm = evm_config.evm_with_inspector(db, noop); - - // Check that the inspector is set correctly - assert_eq!(evm.context.external, noop); - - // Check that the EVM environment is initialized with default values - assert_eq!(evm.context.evm.inner.env, Box::default()); - - // Latest spec ID and no warm preloaded addresses - assert_eq!( - evm.context.evm.inner.journaled_state, - JournaledState::new(SpecId::LATEST, HashSet::default()) - ); - - // Ensure that the accounts database is empty - assert!(evm.context.evm.inner.db.accounts.is_empty()); - - // Ensure that the block hashes database is empty - assert!(evm.context.evm.inner.db.block_hashes.is_empty()); - - // Verify that there are two default contracts in the contracts database - assert_eq!(evm.context.evm.inner.db.contracts.len(), 2); - assert!(evm.context.evm.inner.db.contracts.contains_key(&KECCAK_EMPTY)); - assert!(evm.context.evm.inner.db.contracts.contains_key(&B256::ZERO)); - - // Ensure that the logs database is empty - assert!(evm.context.evm.inner.db.logs.is_empty()); - - // Default spec ID - assert_eq!(evm.handler.spec_id(), SpecId::LATEST); - - // Optimism in handler - assert_eq!(evm.handler.cfg, HandlerCfg { spec_id: SpecId::LATEST, is_optimism: true }); - } - #[test] fn test_evm_with_env_and_default_inspector() { let evm_config = test_evm_config(); diff --git a/crates/optimism/payload/src/builder.rs b/crates/optimism/payload/src/builder.rs index 12dbd0b5bca2..fd2bcffe596b 100644 --- a/crates/optimism/payload/src/builder.rs +++ b/crates/optimism/payload/src/builder.rs @@ -713,8 +713,7 @@ where SystemCaller::new(self.evm_config.clone(), self.chain_spec.clone()) .pre_block_beacon_root_contract_call( db, - &self.evm_env.cfg_env_with_handler_cfg, - &self.evm_env.block_env, + &self.evm_env, self.attributes().payload_attributes.parent_beacon_block_root, ) .map_err(|err| { diff --git a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs index e947a0d0a6d7..968ef379fced 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs @@ -23,10 +23,7 @@ use reth_provider::{ }; use reth_revm::{ database::StateProviderDatabase, - primitives::{ - BlockEnv, CfgEnvWithHandlerCfg, EVMError, Env, ExecutionResult, InvalidTransaction, - ResultAndState, - }, + primitives::{BlockEnv, EVMError, ExecutionResult, InvalidTransaction, ResultAndState}, }; use reth_rpc_eth_types::{EthApiError, PendingBlock, PendingBlockEnv, PendingBlockEnvOrigin}; use reth_transaction_pool::{ @@ -65,7 +62,7 @@ pub trait LoadPendingBlock: &self, ) -> &Mutex, ProviderReceipt>>>; - /// Configures the [`CfgEnvWithHandlerCfg`] and [`BlockEnv`] for the pending block + /// Configures the [`EvmEnv`] for the pending block /// /// If no pending block is available, this will derive it from the `latest` block #[expect(clippy::type_complexity)] @@ -86,12 +83,10 @@ pub trait LoadPendingBlock: // Note: for the PENDING block we assume it is past the known merge block and // thus this will not fail when looking up the total // difficulty value for the blockenv. - let EvmEnv { cfg_env_with_handler_cfg, block_env } = - self.evm_config().cfg_and_block_env(block.header()); + let evm_env = self.evm_config().cfg_and_block_env(block.header()); return Ok(PendingBlockEnv::new( - cfg_env_with_handler_cfg, - block_env, + evm_env, PendingBlockEnvOrigin::ActualPending(block, receipts), )); } @@ -105,7 +100,7 @@ pub trait LoadPendingBlock: .map_err(Self::Error::from_eth_err)? .ok_or(EthApiError::HeaderNotFound(BlockNumberOrTag::Latest.into()))?; - let EvmEnv { cfg_env_with_handler_cfg, block_env } = self + let evm_env = self .evm_config() .next_cfg_and_block_env( &latest, @@ -119,11 +114,7 @@ pub trait LoadPendingBlock: .map_err(RethError::other) .map_err(Self::Error::from_eth_err)?; - Ok(PendingBlockEnv::new( - cfg_env_with_handler_cfg, - block_env, - PendingBlockEnvOrigin::DerivedFromLatest(latest.hash()), - )) + Ok(PendingBlockEnv::new(evm_env, PendingBlockEnvOrigin::DerivedFromLatest(latest.hash()))) } /// Returns the locally built pending block @@ -159,7 +150,7 @@ pub trait LoadPendingBlock: // check if the block is still good if let Some(pending_block) = lock.as_ref() { // this is guaranteed to be the `latest` header - if pending.block_env.number.to::() == pending_block.block.number() && + if pending.evm_env.block_env.number.to::() == pending_block.block.number() && parent_hash == pending_block.block.parent_hash() && now <= pending_block.expires_at { @@ -171,7 +162,7 @@ pub trait LoadPendingBlock: let (sealed_block, receipts) = match self .spawn_blocking_io(move |this| { // we rebuild the block - this.build_block(pending.cfg, pending.block_env, parent_hash) + this.build_block(pending.evm_env, parent_hash) }) .await { @@ -243,8 +234,7 @@ pub trait LoadPendingBlock: #[expect(clippy::type_complexity)] fn build_block( &self, - cfg: CfgEnvWithHandlerCfg, - block_env: BlockEnv, + evm_env: EvmEnv, parent_hash: B256, ) -> Result< (RecoveredBlock>, Vec>), @@ -262,15 +252,15 @@ pub trait LoadPendingBlock: let mut cumulative_gas_used = 0; let mut sum_blob_gas_used = 0; - let block_gas_limit: u64 = block_env.gas_limit.to::(); - let base_fee = block_env.basefee.to::(); + let block_gas_limit: u64 = evm_env.block_env.gas_limit.to::(); + let base_fee = evm_env.block_env.basefee.to::(); let mut executed_txs = Vec::new(); let mut senders = Vec::new(); let mut best_txs = self.pool().best_transactions_with_attributes(BestTransactionsAttributes::new( base_fee, - block_env.get_blob_gasprice().map(|gasprice| gasprice as u64), + evm_env.block_env.get_blob_gasprice().map(|gasprice| gasprice as u64), )); let chain_spec = self.provider().chain_spec(); @@ -278,7 +268,7 @@ pub trait LoadPendingBlock: let mut system_caller = SystemCaller::new(self.evm_config().clone(), chain_spec.clone()); system_caller - .pre_block_blockhashes_contract_call(&mut db, &cfg, &block_env, parent_hash) + .pre_block_blockhashes_contract_call(&mut db, &evm_env, parent_hash) .map_err(|err| EthApiError::Internal(err.into()))?; let mut results = Vec::new(); @@ -334,14 +324,8 @@ pub trait LoadPendingBlock: } } - // Configure the environment for the block. - let env = Env::boxed( - cfg.cfg_env.clone(), - block_env.clone(), - Self::evm_config(self).tx_env(tx.tx(), tx.signer()), - ); - - let mut evm = revm::Evm::builder().with_env(env).with_db(&mut db).build(); + let tx_env = self.evm_config().tx_env(tx.tx(), tx.signer()); + let mut evm = self.evm_config().evm_with_env(&mut db, evm_env.clone(), tx_env); let ResultAndState { result, state } = match evm.transact() { Ok(res) => res, @@ -399,7 +383,7 @@ pub trait LoadPendingBlock: // executes the withdrawals and commits them to the Database and BundleState. let balance_increments = post_block_withdrawals_balance_increments( chain_spec.as_ref(), - block_env.timestamp.try_into().unwrap_or(u64::MAX), + evm_env.block_env.timestamp.try_into().unwrap_or(u64::MAX), &[], ); @@ -416,7 +400,7 @@ pub trait LoadPendingBlock: let state_root = db.database.state_root(hashed_state).map_err(Self::Error::from_eth_err)?; let (block, receipts) = self.assemble_block_and_receipts( - &block_env, + &evm_env.block_env, parent_hash, state_root, executed_txs, diff --git a/crates/rpc/rpc-eth-api/src/helpers/state.rs b/crates/rpc/rpc-eth-api/src/helpers/state.rs index fe068ec4d1e6..2f33ab1122a2 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/state.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/state.rs @@ -219,9 +219,8 @@ pub trait LoadState: { async move { if at.is_pending() { - let PendingBlockEnv { cfg, block_env, origin } = - self.pending_block_env_and_cfg()?; - Ok(((cfg, block_env).into(), origin.state_block_id())) + let PendingBlockEnv { evm_env, origin } = self.pending_block_env_and_cfg()?; + Ok((evm_env, origin.state_block_id())) } else { // Use cached values if there is no pending block let block_hash = RpcNodeCore::provider(self) diff --git a/crates/rpc/rpc-eth-api/src/helpers/trace.rs b/crates/rpc/rpc-eth-api/src/helpers/trace.rs index 810a49f07ac3..5e99ba134d29 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/trace.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/trace.rs @@ -457,21 +457,11 @@ pub trait Trace: SystemCaller::new(self.evm_config().clone(), self.provider().chain_spec()); // apply relevant system calls system_caller - .pre_block_beacon_root_contract_call( - db, - evm_env.cfg_env_with_handler_cfg(), - evm_env.block_env(), - block.parent_beacon_block_root(), - ) + .pre_block_beacon_root_contract_call(db, evm_env, block.parent_beacon_block_root()) .map_err(|_| EthApiError::EvmCustom("failed to apply 4788 system call".to_string()))?; system_caller - .pre_block_blockhashes_contract_call( - db, - evm_env.cfg_env_with_handler_cfg(), - evm_env.block_env(), - block.parent_hash(), - ) + .pre_block_blockhashes_contract_call(db, evm_env, block.parent_hash()) .map_err(|_| { EthApiError::EvmCustom("failed to apply blockhashes system call".to_string()) })?; diff --git a/crates/rpc/rpc-eth-types/Cargo.toml b/crates/rpc/rpc-eth-types/Cargo.toml index 72b153ab0845..11bf6c6231d2 100644 --- a/crates/rpc/rpc-eth-types/Cargo.toml +++ b/crates/rpc/rpc-eth-types/Cargo.toml @@ -15,6 +15,7 @@ workspace = true reth-chainspec.workspace = true reth-chain-state.workspace = true reth-errors.workspace = true +reth-evm.workspace = true reth-execution-types.workspace = true reth-metrics.workspace = true reth-primitives = { workspace = true, features = ["secp256k1"] } diff --git a/crates/rpc/rpc-eth-types/src/pending_block.rs b/crates/rpc/rpc-eth-types/src/pending_block.rs index 62d5954cd9a5..bfd6da992729 100644 --- a/crates/rpc/rpc-eth-types/src/pending_block.rs +++ b/crates/rpc/rpc-eth-types/src/pending_block.rs @@ -8,17 +8,15 @@ use alloy_consensus::BlockHeader; use alloy_eips::{BlockId, BlockNumberOrTag}; use alloy_primitives::B256; use derive_more::Constructor; +use reth_evm::EvmEnv; use reth_primitives::{Receipt, RecoveredBlock}; use reth_primitives_traits::Block; -use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg}; -/// Configured [`BlockEnv`] and [`CfgEnvWithHandlerCfg`] for a pending block. +/// Configured [`EvmEnv`] for a pending block. #[derive(Debug, Clone, Constructor)] pub struct PendingBlockEnv { - /// Configured [`CfgEnvWithHandlerCfg`] for the pending block. - pub cfg: CfgEnvWithHandlerCfg, - /// Configured [`BlockEnv`] for the pending block. - pub block_env: BlockEnv, + /// Configured [`EvmEnv`] for the pending block. + pub evm_env: EvmEnv, /// Origin block for the config pub origin: PendingBlockEnvOrigin, } diff --git a/examples/custom-evm/src/main.rs b/examples/custom-evm/src/main.rs index 3490914b67bc..ac534d43c677 100644 --- a/examples/custom-evm/src/main.rs +++ b/examples/custom-evm/src/main.rs @@ -55,8 +55,8 @@ impl MyEvmConfig { impl MyEvmConfig { /// Sets the precompiles to the EVM handler /// - /// This will be invoked when the EVM is created via [ConfigureEvm::evm] or - /// [ConfigureEvm::evm_with_inspector] + /// This will be invoked when the EVM is created via [ConfigureEvm::evm_with_env] or + /// [ConfigureEvm::evm_with_env_and_inspector] /// /// This will use the default mainnet precompiles and add additional precompiles. pub fn set_precompiles(handler: &mut EvmHandler) @@ -117,15 +117,24 @@ impl ConfigureEvmEnv for MyEvmConfig { } impl ConfigureEvm for MyEvmConfig { - fn evm(&self, db: DB) -> Evm<'_, (), DB> { + fn evm_with_env(&self, db: DB, evm_env: EvmEnv, tx: TxEnv) -> Evm<'_, (), DB> { EvmBuilder::default() .with_db(db) + .with_cfg_env_with_handler_cfg(evm_env.cfg_env_with_handler_cfg) + .with_block_env(evm_env.block_env) + .with_tx_env(tx) // add additional precompiles .append_handler_register(MyEvmConfig::set_precompiles) .build() } - fn evm_with_inspector(&self, db: DB, inspector: I) -> Evm<'_, I, DB> + fn evm_with_env_and_inspector( + &self, + db: DB, + evm_env: EvmEnv, + tx: TxEnv, + inspector: I, + ) -> Evm<'_, I, DB> where DB: Database, I: GetInspector, @@ -133,6 +142,9 @@ impl ConfigureEvm for MyEvmConfig { EvmBuilder::default() .with_db(db) .with_external_context(inspector) + .with_cfg_env_with_handler_cfg(evm_env.cfg_env_with_handler_cfg) + .with_block_env(evm_env.block_env) + .with_tx_env(tx) // add additional precompiles .append_handler_register(MyEvmConfig::set_precompiles) .append_handler_register(inspector_handle_register) diff --git a/examples/stateful-precompile/src/main.rs b/examples/stateful-precompile/src/main.rs index 1fb4dbefb3a9..2cdebfe5602c 100644 --- a/examples/stateful-precompile/src/main.rs +++ b/examples/stateful-precompile/src/main.rs @@ -68,8 +68,8 @@ impl MyEvmConfig { /// Sets the precompiles to the EVM handler /// - /// This will be invoked when the EVM is created via [ConfigureEvm::evm] or - /// [ConfigureEvm::evm_with_inspector] + /// This will be invoked when the EVM is created via [ConfigureEvm::evm_with_env] or + /// [ConfigureEvm::evm_with_env_and_inspector] /// /// This will use the default mainnet precompiles and wrap them with a cache. pub fn set_precompiles( @@ -179,10 +179,13 @@ impl ConfigureEvmEnv for MyEvmConfig { } impl ConfigureEvm for MyEvmConfig { - fn evm(&self, db: DB) -> Evm<'_, (), DB> { + fn evm_with_env(&self, db: DB, evm_env: EvmEnv, tx: TxEnv) -> Evm<'_, (), DB> { let new_cache = self.precompile_cache.clone(); EvmBuilder::default() .with_db(db) + .with_cfg_env_with_handler_cfg(evm_env.cfg_env_with_handler_cfg) + .with_block_env(evm_env.block_env) + .with_tx_env(tx) // add additional precompiles .append_handler_register_box(Box::new(move |handler| { MyEvmConfig::set_precompiles(handler, new_cache.clone()) @@ -190,7 +193,13 @@ impl ConfigureEvm for MyEvmConfig { .build() } - fn evm_with_inspector(&self, db: DB, inspector: I) -> Evm<'_, I, DB> + fn evm_with_env_and_inspector( + &self, + db: DB, + evm_env: EvmEnv, + tx: TxEnv, + inspector: I, + ) -> Evm<'_, I, DB> where DB: Database, I: GetInspector, @@ -199,6 +208,9 @@ impl ConfigureEvm for MyEvmConfig { EvmBuilder::default() .with_db(db) .with_external_context(inspector) + .with_cfg_env_with_handler_cfg(evm_env.cfg_env_with_handler_cfg) + .with_block_env(evm_env.block_env) + .with_tx_env(tx) // add additional precompiles .append_handler_register_box(Box::new(move |handler| { MyEvmConfig::set_precompiles(handler, new_cache.clone())