feat: add Evm trait (#13823)

This commit is contained in:
Arsenii Kulikov
2025-01-18 19:42:39 +04:00
committed by GitHub
parent cef0c927c9
commit c46f23f8de
25 changed files with 453 additions and 460 deletions

View File

@ -19,7 +19,7 @@ use reth_evm::{
},
state_change::post_block_balance_increments,
system_calls::{OnStateHook, SystemCaller},
ConfigureEvm, TxEnvOverrides,
ConfigureEvm, Evm, TxEnvOverrides,
};
use reth_optimism_chainspec::OpChainSpec;
use reth_optimism_consensus::validate_block_post_execution;
@ -226,14 +226,14 @@ where
.transpose()
.map_err(|_| OpBlockExecutionError::AccountLoadFailed(*sender))?;
self.evm_config.fill_tx_env(evm.tx_mut(), transaction, *sender);
let mut tx_env = self.evm_config.tx_env(transaction, *sender);
if let Some(tx_env_overrides) = &mut self.tx_env_overrides {
tx_env_overrides.apply(evm.tx_mut());
tx_env_overrides.apply(&mut tx_env);
}
// Execute transaction.
let result_and_state = evm.transact().map_err(move |err| {
let result_and_state = evm.transact(tx_env).map_err(move |err| {
let new_err = err.map_db_err(|e| e.into());
// Ensure hash is calculated for error log, if not already done
BlockValidationError::EVM {

View File

@ -12,19 +12,20 @@
extern crate alloc;
use alloc::{sync::Arc, vec::Vec};
use alloc::sync::Arc;
use alloy_consensus::Header;
use alloy_eips::eip7840::BlobParams;
use alloy_primitives::{Address, U256};
use core::fmt::Debug;
use op_alloy_consensus::EIP1559ParamError;
use reth_evm::{env::EvmEnv, ConfigureEvm, ConfigureEvmEnv, NextBlockEnvAttributes};
use reth_evm::{env::EvmEnv, ConfigureEvm, ConfigureEvmEnv, Evm, NextBlockEnvAttributes};
use reth_optimism_chainspec::OpChainSpec;
use reth_optimism_primitives::OpTransactionSigned;
use reth_primitives_traits::FillTxEnv;
use reth_revm::{
inspector_handle_register,
primitives::{AnalysisKind, CfgEnvWithHandlerCfg, TxEnv},
Database, Evm, EvmBuilder, GetInspector,
Database, EvmBuilder, GetInspector,
};
mod config;
@ -39,44 +40,48 @@ pub use receipts::*;
mod error;
pub use error::OpBlockExecutionError;
use revm_primitives::{
BlobExcessGasAndPrice, BlockEnv, Bytes, CfgEnv, Env, HandlerCfg, OptimismFields, SpecId, TxKind,
BlobExcessGasAndPrice, BlockEnv, Bytes, CfgEnv, EVMError, Env, HandlerCfg, OptimismFields,
ResultAndState, SpecId, TxKind,
};
/// Optimism-related EVM configuration.
#[derive(Debug, Clone)]
pub struct OpEvmConfig {
chain_spec: Arc<OpChainSpec>,
}
/// OP EVM implementation.
#[derive(derive_more::Debug, derive_more::Deref, derive_more::DerefMut, derive_more::From)]
#[debug(bound(DB::Error: Debug))]
pub struct OpEvm<'a, EXT, DB: Database>(reth_revm::Evm<'a, EXT, DB>);
impl OpEvmConfig {
/// Creates a new [`OpEvmConfig`] with the given chain spec.
pub const fn new(chain_spec: Arc<OpChainSpec>) -> Self {
Self { chain_spec }
impl<EXT, DB: Database> Evm for OpEvm<'_, EXT, DB> {
type DB = DB;
type Tx = TxEnv;
type Error = EVMError<DB::Error>;
fn block(&self) -> &BlockEnv {
self.0.block()
}
/// Returns the chain spec associated with this configuration.
pub const fn chain_spec(&self) -> &Arc<OpChainSpec> {
&self.chain_spec
}
}
impl ConfigureEvmEnv for OpEvmConfig {
type Header = Header;
type Transaction = OpTransactionSigned;
type Error = EIP1559ParamError;
fn fill_tx_env(&self, tx_env: &mut TxEnv, transaction: &OpTransactionSigned, sender: Address) {
transaction.fill_tx_env(tx_env, sender);
fn into_env(self) -> EvmEnv {
let Env { cfg, block, tx: _ } = *self.0.context.evm.inner.env;
EvmEnv {
cfg_env_with_handler_cfg: CfgEnvWithHandlerCfg {
cfg_env: cfg,
handler_cfg: self.0.handler.cfg,
},
block_env: block,
}
}
fn fill_tx_env_system_contract_call(
&self,
env: &mut Env,
fn transact(&mut self, tx: Self::Tx) -> Result<ResultAndState, Self::Error> {
*self.tx_mut() = tx;
self.0.transact()
}
fn transact_system_call(
&mut self,
caller: Address,
contract: Address,
data: Bytes,
) {
env.tx = TxEnv {
) -> Result<ResultAndState, Self::Error> {
#[allow(clippy::needless_update)] // side-effect of optimism fields
let tx_env = TxEnv {
caller,
transact_to: TxKind::Call(contract),
// Explicitly set nonce to None so revm does not do any nonce checks
@ -107,11 +112,54 @@ impl ConfigureEvmEnv for OpEvmConfig {
},
};
*self.tx_mut() = tx_env;
let prev_block_env = self.block().clone();
// ensure the block gas limit is >= the tx
env.block.gas_limit = U256::from(env.tx.gas_limit);
self.block_mut().gas_limit = U256::from(self.tx().gas_limit);
// disable the base fee check for this call by setting the base fee to zero
env.block.basefee = U256::ZERO;
self.block_mut().basefee = U256::ZERO;
let res = self.0.transact();
// re-set the block env
*self.block_mut() = prev_block_env;
res
}
fn db_mut(&mut self) -> &mut Self::DB {
&mut self.context.evm.db
}
}
/// Optimism-related EVM configuration.
#[derive(Debug, Clone)]
pub struct OpEvmConfig {
chain_spec: Arc<OpChainSpec>,
}
impl OpEvmConfig {
/// Creates a new [`OpEvmConfig`] with the given chain spec.
pub const fn new(chain_spec: Arc<OpChainSpec>) -> Self {
Self { chain_spec }
}
/// Returns the chain spec associated with this configuration.
pub const fn chain_spec(&self) -> &Arc<OpChainSpec> {
&self.chain_spec
}
}
impl ConfigureEvmEnv for OpEvmConfig {
type Header = Header;
type Transaction = OpTransactionSigned;
type Error = EIP1559ParamError;
fn fill_tx_env(&self, tx_env: &mut TxEnv, transaction: &OpTransactionSigned, sender: Address) {
transaction.fill_tx_env(tx_env, sender);
}
fn fill_cfg_env(&self, cfg_env: &mut CfgEnvWithHandlerCfg, header: &Self::Header) {
@ -168,12 +216,14 @@ impl ConfigureEvmEnv for OpEvmConfig {
}
impl ConfigureEvm for OpEvmConfig {
type Evm<'a, DB: Database + 'a, I: 'a> = OpEvm<'a, I, DB>;
fn evm_with_env<DB: Database>(
&self,
db: DB,
mut evm_env: EvmEnv,
tx: TxEnv,
) -> Evm<'_, (), DB> {
) -> Self::Evm<'_, DB, ()> {
evm_env.cfg_env_with_handler_cfg.handler_cfg.is_optimism = true;
EvmBuilder::default()
@ -182,6 +232,7 @@ impl ConfigureEvm for OpEvmConfig {
.with_block_env(evm_env.block_env)
.with_tx_env(tx)
.build()
.into()
}
fn evm_with_env_and_inspector<DB, I>(
@ -190,7 +241,7 @@ impl ConfigureEvm for OpEvmConfig {
mut evm_env: EvmEnv,
tx: TxEnv,
inspector: I,
) -> Evm<'_, I, DB>
) -> Self::Evm<'_, DB, I>
where
DB: Database,
I: GetInspector<DB>,
@ -205,6 +256,7 @@ impl ConfigureEvm for OpEvmConfig {
.with_tx_env(tx)
.append_handler_register(inspector_handle_register)
.build()
.into()
}
}

View File

@ -15,7 +15,9 @@ use op_alloy_rpc_types_engine::OpPayloadAttributes;
use reth_basic_payload_builder::*;
use reth_chain_state::ExecutedBlock;
use reth_chainspec::{ChainSpecProvider, EthereumHardforks};
use reth_evm::{env::EvmEnv, system_calls::SystemCaller, ConfigureEvm, NextBlockEnvAttributes};
use reth_evm::{
env::EvmEnv, system_calls::SystemCaller, ConfigureEvm, Evm, NextBlockEnvAttributes,
};
use reth_execution_types::ExecutionOutcome;
use reth_optimism_chainspec::OpChainSpec;
use reth_optimism_consensus::calculate_receipt_root_no_memo_optimism;
@ -777,9 +779,9 @@ where
))
})?;
*evm.tx_mut() = self.evm_config.tx_env(sequencer_tx.tx(), sequencer_tx.signer());
let tx_env = self.evm_config.tx_env(sequencer_tx.tx(), sequencer_tx.signer());
let ResultAndState { result, state } = match evm.transact() {
let ResultAndState { result, state } = match evm.transact(tx_env) {
Ok(res) => res,
Err(err) => {
match err {
@ -874,9 +876,9 @@ where
}
// Configure the environment for the tx.
*evm.tx_mut() = self.evm_config.tx_env(tx.tx(), tx.signer());
let tx_env = self.evm_config.tx_env(tx.tx(), tx.signer());
let ResultAndState { result, state } = match evm.transact() {
let ResultAndState { result, state } = match evm.transact(tx_env) {
Ok(res) => res,
Err(err) => {
match err {