mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: add Evm trait (#13823)
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -7514,6 +7514,7 @@ dependencies = [
|
||||
"alloy-genesis",
|
||||
"alloy-primitives",
|
||||
"alloy-sol-types",
|
||||
"derive_more",
|
||||
"reth-chainspec",
|
||||
"reth-consensus",
|
||||
"reth-ethereum-consensus",
|
||||
|
||||
@ -6,14 +6,13 @@ use pretty_assertions::Comparison;
|
||||
use reth_chainspec::{EthChainSpec, EthereumHardforks};
|
||||
use reth_engine_primitives::InvalidBlockHook;
|
||||
use reth_evm::{
|
||||
state_change::post_block_balance_increments, system_calls::SystemCaller, ConfigureEvm,
|
||||
state_change::post_block_balance_increments, system_calls::SystemCaller, ConfigureEvm, Evm,
|
||||
};
|
||||
use reth_primitives::{NodePrimitives, RecoveredBlock, SealedHeader};
|
||||
use reth_primitives_traits::{BlockBody, SignedTransaction};
|
||||
use reth_provider::{BlockExecutionOutput, ChainSpecProvider, StateProviderFactory};
|
||||
use reth_revm::{
|
||||
database::StateProviderDatabase, db::states::bundle_state::BundleRetention, DatabaseCommit,
|
||||
StateBuilder,
|
||||
database::StateProviderDatabase, db::states::bundle_state::BundleRetention, StateBuilder,
|
||||
};
|
||||
use reth_rpc_api::DebugApiClient;
|
||||
use reth_tracing::tracing::warn;
|
||||
@ -88,13 +87,8 @@ where
|
||||
// Re-execute all of the transactions in the block to load all touched accounts into
|
||||
// the cache DB.
|
||||
for tx in block.body().transactions() {
|
||||
self.evm_config.fill_tx_env(
|
||||
evm.tx_mut(),
|
||||
tx,
|
||||
tx.recover_signer().ok_or_eyre("failed to recover sender")?,
|
||||
);
|
||||
let result = evm.transact()?;
|
||||
evm.db_mut().commit(result.state);
|
||||
let signer = tx.recover_signer().ok_or_eyre("failed to recover sender")?;
|
||||
evm.transact_commit(self.evm_config.tx_env(tx, signer))?;
|
||||
}
|
||||
|
||||
drop(evm);
|
||||
|
||||
@ -15,7 +15,7 @@ use reth_errors::{BlockExecutionError, BlockValidationError, RethError, RethResu
|
||||
use reth_ethereum_forks::EthereumHardforks;
|
||||
use reth_evm::{
|
||||
state_change::post_block_withdrawals_balance_increments, system_calls::SystemCaller,
|
||||
ConfigureEvm,
|
||||
ConfigureEvm, Evm,
|
||||
};
|
||||
use reth_payload_validator::ExecutionPayloadValidator;
|
||||
use reth_primitives::{
|
||||
@ -325,8 +325,8 @@ where
|
||||
let tx_recovered = tx.clone().try_into_ecrecovered().map_err(|_| {
|
||||
BlockExecutionError::Validation(BlockValidationError::SenderRecoveryError)
|
||||
})?;
|
||||
evm_config.fill_tx_env(evm.tx_mut(), &tx_recovered, tx_recovered.signer());
|
||||
let exec_result = match evm.transact() {
|
||||
let tx_env = evm_config.tx_env(&tx_recovered, tx_recovered.signer());
|
||||
let exec_result = match evm.transact(tx_env) {
|
||||
Ok(result) => result,
|
||||
error @ Err(EVMError::Transaction(_) | EVMError::Header(_)) => {
|
||||
trace!(target: "engine::stream::reorg", hash = %tx.tx_hash(), ?error, "Error executing transaction from next block");
|
||||
|
||||
@ -30,6 +30,9 @@ alloy-eips.workspace = true
|
||||
alloy-sol-types.workspace = true
|
||||
alloy-consensus.workspace = true
|
||||
|
||||
# Misc
|
||||
derive_more.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
reth-testing-utils.workspace = true
|
||||
reth-evm = { workspace = true, features = ["test-utils"] }
|
||||
@ -55,5 +58,6 @@ std = [
|
||||
"reth-ethereum-forks/std",
|
||||
"serde_json/std",
|
||||
"reth-primitives-traits/std",
|
||||
"reth-chainspec/std"
|
||||
"reth-chainspec/std",
|
||||
"derive_more/std"
|
||||
]
|
||||
|
||||
@ -19,7 +19,7 @@ use reth_evm::{
|
||||
},
|
||||
state_change::post_block_balance_increments,
|
||||
system_calls::{OnStateHook, SystemCaller},
|
||||
ConfigureEvm, TxEnvOverrides,
|
||||
ConfigureEvm, Evm, TxEnvOverrides,
|
||||
};
|
||||
use reth_primitives::{EthPrimitives, Receipt, RecoveredBlock};
|
||||
use reth_primitives_traits::{BlockBody, SignedTransaction};
|
||||
@ -166,14 +166,14 @@ where
|
||||
.into())
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
@ -17,18 +17,18 @@
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use core::convert::Infallible;
|
||||
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use alloy_consensus::{BlockHeader, Header};
|
||||
use alloy_primitives::{Address, Bytes, TxKind, U256};
|
||||
use alloy_primitives::{Address, U256};
|
||||
use core::{convert::Infallible, fmt::Debug};
|
||||
use reth_chainspec::ChainSpec;
|
||||
use reth_evm::{env::EvmEnv, ConfigureEvm, ConfigureEvmEnv, NextBlockEnvAttributes};
|
||||
use reth_evm::{env::EvmEnv, ConfigureEvm, ConfigureEvmEnv, Evm, NextBlockEnvAttributes};
|
||||
use reth_primitives::TransactionSigned;
|
||||
use reth_primitives_traits::transaction::execute::FillTxEnv;
|
||||
use reth_revm::{inspector_handle_register, EvmBuilder};
|
||||
use reth_revm::{inspector_handle_register, Database, EvmBuilder};
|
||||
use revm_primitives::{
|
||||
AnalysisKind, BlobExcessGasAndPrice, BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, Env, SpecId, TxEnv,
|
||||
AnalysisKind, BlobExcessGasAndPrice, BlockEnv, Bytes, CfgEnv, CfgEnvWithHandlerCfg, EVMError,
|
||||
Env, ResultAndState, SpecId, TxEnv, TxKind,
|
||||
};
|
||||
|
||||
mod config;
|
||||
@ -44,6 +44,90 @@ pub mod dao_fork;
|
||||
/// [EIP-6110](https://eips.ethereum.org/EIPS/eip-6110) handling.
|
||||
pub mod eip6110;
|
||||
|
||||
/// Ethereum EVM implementation.
|
||||
#[derive(derive_more::Debug, derive_more::Deref, derive_more::DerefMut, derive_more::From)]
|
||||
#[debug(bound(DB::Error: Debug))]
|
||||
pub struct EthEvm<'a, EXT, DB: Database>(reth_revm::Evm<'a, EXT, DB>);
|
||||
|
||||
impl<EXT, DB: Database> Evm for EthEvm<'_, EXT, DB> {
|
||||
type DB = DB;
|
||||
type Tx = TxEnv;
|
||||
type Error = EVMError<DB::Error>;
|
||||
|
||||
fn block(&self) -> &BlockEnv {
|
||||
self.0.block()
|
||||
}
|
||||
|
||||
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 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,
|
||||
) -> 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
|
||||
nonce: None,
|
||||
gas_limit: 30_000_000,
|
||||
value: U256::ZERO,
|
||||
data,
|
||||
// Setting the gas price to zero enforces that no value is transferred as part of the
|
||||
// call, and that the call will not count against the block's gas limit
|
||||
gas_price: U256::ZERO,
|
||||
// The chain ID check is not relevant here and is disabled if set to None
|
||||
chain_id: None,
|
||||
// Setting the gas priority fee to None ensures the effective gas price is derived from
|
||||
// the `gas_price` field, which we need to be zero
|
||||
gas_priority_fee: None,
|
||||
access_list: Vec::new(),
|
||||
// blob fields can be None for this tx
|
||||
blob_hashes: Vec::new(),
|
||||
max_fee_per_blob_gas: None,
|
||||
// TODO remove this once this crate is no longer built with optimism
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
*self.tx_mut() = tx_env;
|
||||
|
||||
let prev_block_env = self.block().clone();
|
||||
|
||||
// ensure the block gas limit is >= the tx
|
||||
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
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/// Ethereum-related EVM configuration.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EthEvmConfig {
|
||||
@ -71,46 +155,6 @@ impl ConfigureEvmEnv for EthEvmConfig {
|
||||
transaction.fill_tx_env(tx_env, sender);
|
||||
}
|
||||
|
||||
fn fill_tx_env_system_contract_call(
|
||||
&self,
|
||||
env: &mut Env,
|
||||
caller: Address,
|
||||
contract: Address,
|
||||
data: Bytes,
|
||||
) {
|
||||
#[allow(clippy::needless_update)] // side-effect of optimism fields
|
||||
let tx = TxEnv {
|
||||
caller,
|
||||
transact_to: TxKind::Call(contract),
|
||||
// Explicitly set nonce to None so revm does not do any nonce checks
|
||||
nonce: None,
|
||||
gas_limit: 30_000_000,
|
||||
value: U256::ZERO,
|
||||
data,
|
||||
// Setting the gas price to zero enforces that no value is transferred as part of the
|
||||
// call, and that the call will not count against the block's gas limit
|
||||
gas_price: U256::ZERO,
|
||||
// The chain ID check is not relevant here and is disabled if set to None
|
||||
chain_id: None,
|
||||
// Setting the gas priority fee to None ensures the effective gas price is derived from
|
||||
// the `gas_price` field, which we need to be zero
|
||||
gas_priority_fee: None,
|
||||
access_list: Vec::new(),
|
||||
// blob fields can be None for this tx
|
||||
blob_hashes: Vec::new(),
|
||||
max_fee_per_blob_gas: None,
|
||||
// TODO remove this once this crate is no longer built with optimism
|
||||
..Default::default()
|
||||
};
|
||||
env.tx = tx;
|
||||
|
||||
// ensure the block gas limit is >= the tx
|
||||
env.block.gas_limit = U256::from(env.tx.gas_limit);
|
||||
|
||||
// disable the base fee check for this call by setting the base fee to zero
|
||||
env.block.basefee = U256::ZERO;
|
||||
}
|
||||
|
||||
fn fill_cfg_env(&self, cfg_env: &mut CfgEnvWithHandlerCfg, header: &Header) {
|
||||
let spec_id = config::revm_spec(self.chain_spec(), header);
|
||||
|
||||
@ -184,18 +228,22 @@ impl ConfigureEvmEnv for EthEvmConfig {
|
||||
}
|
||||
|
||||
impl ConfigureEvm for EthEvmConfig {
|
||||
fn evm_with_env<DB: reth_revm::Database>(
|
||||
type Evm<'a, DB: Database + 'a, I: 'a> = EthEvm<'a, I, DB>;
|
||||
|
||||
fn evm_with_env<DB: Database>(
|
||||
&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()
|
||||
) -> Self::Evm<'_, DB, ()> {
|
||||
EthEvm(
|
||||
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<DB, I>(
|
||||
@ -204,19 +252,21 @@ impl ConfigureEvm for EthEvmConfig {
|
||||
evm_env: EvmEnv,
|
||||
tx: TxEnv,
|
||||
inspector: I,
|
||||
) -> reth_revm::Evm<'_, I, DB>
|
||||
) -> Self::Evm<'_, DB, I>
|
||||
where
|
||||
DB: reth_revm::Database,
|
||||
DB: Database,
|
||||
I: reth_revm::GetInspector<DB>,
|
||||
{
|
||||
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()
|
||||
EthEvm(
|
||||
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(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5,4 +5,4 @@ pub use reth_evm::execute::BasicBlockExecutorProvider;
|
||||
#[doc(inline)]
|
||||
pub use reth_evm_ethereum::execute::{EthExecutionStrategyFactory, EthExecutorProvider};
|
||||
#[doc(inline)]
|
||||
pub use reth_evm_ethereum::EthEvmConfig;
|
||||
pub use reth_evm_ethereum::{EthEvm, EthEvmConfig};
|
||||
|
||||
@ -22,7 +22,9 @@ use reth_basic_payload_builder::{
|
||||
use reth_chain_state::ExecutedBlock;
|
||||
use reth_chainspec::{ChainSpec, ChainSpecProvider};
|
||||
use reth_errors::RethError;
|
||||
use reth_evm::{env::EvmEnv, system_calls::SystemCaller, ConfigureEvm, NextBlockEnvAttributes};
|
||||
use reth_evm::{
|
||||
env::EvmEnv, system_calls::SystemCaller, ConfigureEvm, Evm, NextBlockEnvAttributes,
|
||||
};
|
||||
use reth_evm_ethereum::{eip6110::parse_deposits_from_receipts, EthEvmConfig};
|
||||
use reth_execution_types::ExecutionOutcome;
|
||||
use reth_payload_builder::{EthBuiltPayload, EthPayloadBuilderAttributes};
|
||||
@ -270,9 +272,9 @@ where
|
||||
}
|
||||
|
||||
// Configure the environment for the tx.
|
||||
*evm.tx_mut() = evm_config.tx_env(tx.tx(), tx.signer());
|
||||
let tx_env = 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 {
|
||||
|
||||
@ -20,8 +20,8 @@ extern crate alloc;
|
||||
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};
|
||||
use revm::{Database, DatabaseCommit, GetInspector};
|
||||
use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, EVMError, ResultAndState, SpecId, TxEnv};
|
||||
|
||||
pub mod either;
|
||||
/// EVM environment configuration.
|
||||
@ -38,13 +38,64 @@ pub mod system_calls;
|
||||
/// test helpers for mocking executor
|
||||
pub mod test_utils;
|
||||
|
||||
/// An abstraction over EVM.
|
||||
///
|
||||
/// At this point, assumed to be implemented on wrappers around [`revm::Evm`].
|
||||
pub trait Evm {
|
||||
/// Database type held by the EVM.
|
||||
type DB;
|
||||
/// Transaction environment
|
||||
type Tx;
|
||||
/// Error type.
|
||||
type Error;
|
||||
|
||||
/// Reference to [`BlockEnv`].
|
||||
fn block(&self) -> &BlockEnv;
|
||||
|
||||
/// Consumes the type and returns the underlying [`EvmEnv`].
|
||||
fn into_env(self) -> EvmEnv;
|
||||
|
||||
/// Executes the given transaction.
|
||||
fn transact(&mut self, tx: Self::Tx) -> Result<ResultAndState, Self::Error>;
|
||||
|
||||
/// Executes a system call.
|
||||
fn transact_system_call(
|
||||
&mut self,
|
||||
caller: Address,
|
||||
contract: Address,
|
||||
data: Bytes,
|
||||
) -> Result<ResultAndState, Self::Error>;
|
||||
|
||||
/// Returns a mutable reference to the underlying database.
|
||||
fn db_mut(&mut self) -> &mut Self::DB;
|
||||
|
||||
/// Executes a transaction and commits the state changes to the underlying database.
|
||||
fn transact_commit(&mut self, tx_env: Self::Tx) -> Result<ResultAndState, Self::Error>
|
||||
where
|
||||
Self::DB: DatabaseCommit,
|
||||
{
|
||||
let result = self.transact(tx_env)?;
|
||||
self.db_mut().commit(result.state.clone());
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for configuring the EVM for executing full blocks.
|
||||
pub trait ConfigureEvm: ConfigureEvmEnv {
|
||||
/// The EVM implementation.
|
||||
type Evm<'a, DB: Database + 'a, I: 'a>: Evm<Tx = TxEnv, DB = DB, Error = EVMError<DB::Error>>;
|
||||
|
||||
/// 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<DB: Database>(&self, db: DB, evm_env: EvmEnv, tx: TxEnv) -> Evm<'_, (), DB>;
|
||||
fn evm_with_env<DB: Database>(
|
||||
&self,
|
||||
db: DB,
|
||||
evm_env: EvmEnv,
|
||||
tx: TxEnv,
|
||||
) -> Self::Evm<'_, DB, ()>;
|
||||
|
||||
/// Returns a new EVM with the given database configured with `cfg` and `block_env`
|
||||
/// configuration derived from the given header. Relies on
|
||||
@ -53,7 +104,7 @@ pub trait ConfigureEvm: ConfigureEvmEnv {
|
||||
/// # Caution
|
||||
///
|
||||
/// This does not initialize the tx environment.
|
||||
fn evm_for_block<DB: Database>(&self, db: DB, header: &Self::Header) -> Evm<'_, (), DB> {
|
||||
fn evm_for_block<DB: Database>(&self, db: DB, header: &Self::Header) -> Self::Evm<'_, DB, ()> {
|
||||
let evm_env = self.cfg_and_block_env(header);
|
||||
self.evm_with_env(db, evm_env, Default::default())
|
||||
}
|
||||
@ -70,7 +121,7 @@ pub trait ConfigureEvm: ConfigureEvmEnv {
|
||||
evm_env: EvmEnv,
|
||||
tx: TxEnv,
|
||||
inspector: I,
|
||||
) -> Evm<'_, I, DB>
|
||||
) -> Self::Evm<'_, DB, I>
|
||||
where
|
||||
DB: Database,
|
||||
I: GetInspector<DB>;
|
||||
@ -81,11 +132,18 @@ where
|
||||
T: ConfigureEvm,
|
||||
&'b T: ConfigureEvmEnv<Header = T::Header>,
|
||||
{
|
||||
fn evm_for_block<DB: Database>(&self, db: DB, header: &Self::Header) -> Evm<'_, (), DB> {
|
||||
type Evm<'a, DB: Database + 'a, I: 'a> = T::Evm<'a, DB, I>;
|
||||
|
||||
fn evm_for_block<DB: Database>(&self, db: DB, header: &Self::Header) -> Self::Evm<'_, DB, ()> {
|
||||
(*self).evm_for_block(db, header)
|
||||
}
|
||||
|
||||
fn evm_with_env<DB: Database>(&self, db: DB, evm_env: EvmEnv, tx: TxEnv) -> Evm<'_, (), DB> {
|
||||
fn evm_with_env<DB: Database>(
|
||||
&self,
|
||||
db: DB,
|
||||
evm_env: EvmEnv,
|
||||
tx: TxEnv,
|
||||
) -> Self::Evm<'_, DB, ()> {
|
||||
(*self).evm_with_env(db, evm_env, tx)
|
||||
}
|
||||
|
||||
@ -95,7 +153,7 @@ where
|
||||
evm_env: EvmEnv,
|
||||
tx_env: TxEnv,
|
||||
inspector: I,
|
||||
) -> Evm<'_, I, DB>
|
||||
) -> Self::Evm<'_, DB, I>
|
||||
where
|
||||
DB: Database,
|
||||
I: GetInspector<DB>,
|
||||
@ -129,15 +187,6 @@ pub trait ConfigureEvmEnv: Send + Sync + Unpin + Clone + 'static {
|
||||
/// Fill transaction environment from a transaction and the given sender address.
|
||||
fn fill_tx_env(&self, tx_env: &mut TxEnv, transaction: &Self::Transaction, sender: Address);
|
||||
|
||||
/// Fill transaction environment with a system contract call.
|
||||
fn fill_tx_env_system_contract_call(
|
||||
&self,
|
||||
env: &mut Env,
|
||||
caller: Address,
|
||||
contract: Address,
|
||||
data: Bytes,
|
||||
);
|
||||
|
||||
/// Returns a [`CfgEnvWithHandlerCfg`] for the given header.
|
||||
fn cfg_env(&self, header: &Self::Header) -> CfgEnvWithHandlerCfg {
|
||||
let mut cfg = CfgEnvWithHandlerCfg::new(Default::default(), Default::default());
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
//! [EIP-2935](https://eips.ethereum.org/EIPS/eip-2935) system call implementation.
|
||||
|
||||
use alloc::{boxed::Box, string::ToString};
|
||||
use core::fmt::Display;
|
||||
|
||||
use alloc::string::ToString;
|
||||
use alloy_eips::eip2935::HISTORY_STORAGE_ADDRESS;
|
||||
|
||||
use crate::ConfigureEvm;
|
||||
use crate::Evm;
|
||||
use alloy_primitives::B256;
|
||||
use reth_chainspec::EthereumHardforks;
|
||||
use reth_execution_errors::{BlockExecutionError, BlockValidationError};
|
||||
use revm::{interpreter::Host, Database, Evm};
|
||||
use revm_primitives::ResultAndState;
|
||||
|
||||
/// Applies the pre-block call to the [EIP-2935] blockhashes contract, using the given block,
|
||||
@ -23,19 +24,13 @@ use revm_primitives::ResultAndState;
|
||||
///
|
||||
/// [EIP-2935]: https://eips.ethereum.org/EIPS/eip-2935
|
||||
#[inline]
|
||||
pub(crate) fn transact_blockhashes_contract_call<EvmConfig, EXT, DB>(
|
||||
evm_config: &EvmConfig,
|
||||
pub(crate) fn transact_blockhashes_contract_call(
|
||||
chain_spec: impl EthereumHardforks,
|
||||
block_timestamp: u64,
|
||||
block_number: u64,
|
||||
parent_block_hash: B256,
|
||||
evm: &mut Evm<'_, EXT, DB>,
|
||||
) -> Result<Option<ResultAndState>, BlockExecutionError>
|
||||
where
|
||||
DB: Database,
|
||||
DB::Error: core::fmt::Display,
|
||||
EvmConfig: ConfigureEvm,
|
||||
{
|
||||
evm: &mut impl Evm<Error: Display>,
|
||||
) -> Result<Option<ResultAndState>, BlockExecutionError> {
|
||||
if !chain_spec.is_prague_active_at_timestamp(block_timestamp) {
|
||||
return Ok(None)
|
||||
}
|
||||
@ -46,21 +41,13 @@ where
|
||||
return Ok(None)
|
||||
}
|
||||
|
||||
// get previous env
|
||||
let previous_env = Box::new(evm.context.env().clone());
|
||||
|
||||
// modify env for pre block call
|
||||
evm_config.fill_tx_env_system_contract_call(
|
||||
&mut evm.context.evm.env,
|
||||
let mut res = match evm.transact_system_call(
|
||||
alloy_eips::eip4788::SYSTEM_ADDRESS,
|
||||
HISTORY_STORAGE_ADDRESS,
|
||||
parent_block_hash.0.into(),
|
||||
);
|
||||
|
||||
let mut res = match evm.transact() {
|
||||
) {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
evm.context.evm.env = previous_env;
|
||||
return Err(BlockValidationError::BlockHashContractCall { message: e.to_string() }.into())
|
||||
}
|
||||
};
|
||||
@ -73,8 +60,5 @@ where
|
||||
res.state.remove(&alloy_eips::eip4788::SYSTEM_ADDRESS);
|
||||
res.state.remove(&evm.block().coinbase);
|
||||
|
||||
// re-set the previous env
|
||||
evm.context.evm.env = previous_env;
|
||||
|
||||
Ok(Some(res))
|
||||
}
|
||||
|
||||
@ -1,12 +1,11 @@
|
||||
//! [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788) system call implementation.
|
||||
use crate::Evm;
|
||||
use alloc::{boxed::Box, string::ToString};
|
||||
|
||||
use crate::ConfigureEvm;
|
||||
use alloy_eips::eip4788::BEACON_ROOTS_ADDRESS;
|
||||
use alloy_primitives::B256;
|
||||
use core::fmt::Display;
|
||||
use reth_chainspec::EthereumHardforks;
|
||||
use reth_execution_errors::{BlockExecutionError, BlockValidationError};
|
||||
use revm::{interpreter::Host, Database, Evm};
|
||||
use revm_primitives::ResultAndState;
|
||||
|
||||
/// Applies the pre-block call to the [EIP-4788] beacon block root contract, using the given block,
|
||||
@ -19,20 +18,13 @@ use revm_primitives::ResultAndState;
|
||||
///
|
||||
/// [EIP-4788]: https://eips.ethereum.org/EIPS/eip-4788
|
||||
#[inline]
|
||||
pub(crate) fn transact_beacon_root_contract_call<EvmConfig, EXT, DB, Spec>(
|
||||
evm_config: &EvmConfig,
|
||||
chain_spec: &Spec,
|
||||
pub(crate) fn transact_beacon_root_contract_call(
|
||||
chain_spec: impl EthereumHardforks,
|
||||
block_timestamp: u64,
|
||||
block_number: u64,
|
||||
parent_beacon_block_root: Option<B256>,
|
||||
evm: &mut Evm<'_, EXT, DB>,
|
||||
) -> Result<Option<ResultAndState>, BlockExecutionError>
|
||||
where
|
||||
DB: Database,
|
||||
DB::Error: core::fmt::Display,
|
||||
EvmConfig: ConfigureEvm,
|
||||
Spec: EthereumHardforks,
|
||||
{
|
||||
evm: &mut impl Evm<Error: Display>,
|
||||
) -> Result<Option<ResultAndState>, BlockExecutionError> {
|
||||
if !chain_spec.is_cancun_active_at_timestamp(block_timestamp) {
|
||||
return Ok(None)
|
||||
}
|
||||
@ -52,21 +44,13 @@ where
|
||||
return Ok(None)
|
||||
}
|
||||
|
||||
// get previous env
|
||||
let previous_env = Box::new(evm.context.env().clone());
|
||||
|
||||
// modify env for pre block call
|
||||
evm_config.fill_tx_env_system_contract_call(
|
||||
&mut evm.context.evm.env,
|
||||
let mut res = match evm.transact_system_call(
|
||||
alloy_eips::eip4788::SYSTEM_ADDRESS,
|
||||
BEACON_ROOTS_ADDRESS,
|
||||
parent_beacon_block_root.0.into(),
|
||||
);
|
||||
|
||||
let mut res = match evm.transact() {
|
||||
) {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
evm.context.evm.env = previous_env;
|
||||
return Err(BlockValidationError::BeaconRootContractCall {
|
||||
parent_beacon_block_root: Box::new(parent_beacon_block_root),
|
||||
message: e.to_string(),
|
||||
@ -83,8 +67,5 @@ where
|
||||
res.state.remove(&alloy_eips::eip4788::SYSTEM_ADDRESS);
|
||||
res.state.remove(&evm.block().coinbase);
|
||||
|
||||
// re-set the previous env
|
||||
evm.context.evm.env = previous_env;
|
||||
|
||||
Ok(Some(res))
|
||||
}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
//! [EIP-7002](https://eips.ethereum.org/EIPS/eip-7002) system call implementation.
|
||||
use crate::ConfigureEvm;
|
||||
use alloc::{boxed::Box, format};
|
||||
use crate::Evm;
|
||||
use alloc::format;
|
||||
use alloy_eips::eip7002::WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS;
|
||||
use alloy_primitives::Bytes;
|
||||
use core::fmt::Display;
|
||||
use reth_execution_errors::{BlockExecutionError, BlockValidationError};
|
||||
use revm::{interpreter::Host, Database, Evm};
|
||||
use revm_primitives::{ExecutionResult, ResultAndState};
|
||||
|
||||
/// Applies the post-block call to the EIP-7002 withdrawal requests contract.
|
||||
@ -13,19 +13,10 @@ use revm_primitives::{ExecutionResult, ResultAndState};
|
||||
///
|
||||
/// Note: this does not commit the state changes to the database, it only transact the call.
|
||||
#[inline]
|
||||
pub(crate) fn transact_withdrawal_requests_contract_call<EvmConfig, EXT, DB>(
|
||||
evm_config: &EvmConfig,
|
||||
evm: &mut Evm<'_, EXT, DB>,
|
||||
) -> Result<ResultAndState, BlockExecutionError>
|
||||
where
|
||||
DB: Database,
|
||||
DB::Error: core::fmt::Display,
|
||||
EvmConfig: ConfigureEvm,
|
||||
{
|
||||
// get previous env
|
||||
let previous_env = Box::new(evm.context.env().clone());
|
||||
|
||||
// Fill transaction environment with the EIP-7002 withdrawal requests contract message data.
|
||||
pub(crate) fn transact_withdrawal_requests_contract_call(
|
||||
evm: &mut impl Evm<Error: Display>,
|
||||
) -> Result<ResultAndState, BlockExecutionError> {
|
||||
// Execute EIP-7002 withdrawal requests contract message data.
|
||||
//
|
||||
// This requirement for the withdrawal requests contract call defined by
|
||||
// [EIP-7002](https://eips.ethereum.org/EIPS/eip-7002) is:
|
||||
@ -33,17 +24,13 @@ where
|
||||
// At the end of processing any execution block where `block.timestamp >= FORK_TIMESTAMP` (i.e.
|
||||
// after processing all transactions and after performing the block body withdrawal requests
|
||||
// validations), call the contract as `SYSTEM_ADDRESS`.
|
||||
evm_config.fill_tx_env_system_contract_call(
|
||||
&mut evm.context.evm.env,
|
||||
let mut res = match evm.transact_system_call(
|
||||
alloy_eips::eip7002::SYSTEM_ADDRESS,
|
||||
WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS,
|
||||
Bytes::new(),
|
||||
);
|
||||
|
||||
let mut res = match evm.transact() {
|
||||
) {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
evm.context.evm.env = previous_env;
|
||||
return Err(BlockValidationError::WithdrawalRequestsContractCall {
|
||||
message: format!("execution failed: {e}"),
|
||||
}
|
||||
@ -59,9 +46,6 @@ where
|
||||
res.state.remove(&alloy_eips::eip7002::SYSTEM_ADDRESS);
|
||||
res.state.remove(&evm.block().coinbase);
|
||||
|
||||
// re-set the previous env
|
||||
evm.context.evm.env = previous_env;
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
//! [EIP-7251](https://eips.ethereum.org/EIPS/eip-7251) system call implementation.
|
||||
use crate::ConfigureEvm;
|
||||
use alloc::{boxed::Box, format};
|
||||
use crate::Evm;
|
||||
use alloc::format;
|
||||
use alloy_eips::eip7251::CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS;
|
||||
use alloy_primitives::Bytes;
|
||||
use core::fmt::Display;
|
||||
use reth_execution_errors::{BlockExecutionError, BlockValidationError};
|
||||
use revm::{interpreter::Host, Database, Evm};
|
||||
use revm_primitives::{ExecutionResult, ResultAndState};
|
||||
|
||||
/// Applies the post-block call to the EIP-7251 consolidation requests contract.
|
||||
@ -14,19 +14,10 @@ use revm_primitives::{ExecutionResult, ResultAndState};
|
||||
///
|
||||
/// Note: this does not commit the state changes to the database, it only transact the call.
|
||||
#[inline]
|
||||
pub(crate) fn transact_consolidation_requests_contract_call<EvmConfig, EXT, DB>(
|
||||
evm_config: &EvmConfig,
|
||||
evm: &mut Evm<'_, EXT, DB>,
|
||||
) -> Result<ResultAndState, BlockExecutionError>
|
||||
where
|
||||
DB: Database,
|
||||
DB::Error: core::fmt::Display,
|
||||
EvmConfig: ConfigureEvm,
|
||||
{
|
||||
// get previous env
|
||||
let previous_env = Box::new(evm.context.env().clone());
|
||||
|
||||
// Fill transaction environment with the EIP-7251 consolidation requests contract message data.
|
||||
pub(crate) fn transact_consolidation_requests_contract_call(
|
||||
evm: &mut impl Evm<Error: Display>,
|
||||
) -> Result<ResultAndState, BlockExecutionError> {
|
||||
// Execute EIP-7251 consolidation requests contract message data.
|
||||
//
|
||||
// This requirement for the consolidation requests contract call defined by
|
||||
// [EIP-7251](https://eips.ethereum.org/EIPS/eip-7251) is:
|
||||
@ -35,17 +26,13 @@ where
|
||||
// after processing all transactions and after performing the block body requests validations)
|
||||
// clienst software MUST [..] call the contract as `SYSTEM_ADDRESS` and empty input data to
|
||||
// trigger the system subroutine execute.
|
||||
evm_config.fill_tx_env_system_contract_call(
|
||||
&mut evm.context.evm.env,
|
||||
let mut res = match evm.transact_system_call(
|
||||
alloy_eips::eip7002::SYSTEM_ADDRESS,
|
||||
CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS,
|
||||
Bytes::new(),
|
||||
);
|
||||
|
||||
let mut res = match evm.transact() {
|
||||
) {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
evm.context.evm.env = previous_env;
|
||||
return Err(BlockValidationError::ConsolidationRequestsContractCall {
|
||||
message: format!("execution failed: {e}"),
|
||||
}
|
||||
@ -61,9 +48,6 @@ where
|
||||
res.state.remove(&alloy_eips::eip7002::SYSTEM_ADDRESS);
|
||||
res.state.remove(&evm.block().coinbase);
|
||||
|
||||
// re-set the previous env
|
||||
evm.context.evm.env = previous_env;
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
//! System contract call functions.
|
||||
|
||||
use crate::{ConfigureEvm, EvmEnv};
|
||||
use crate::{ConfigureEvm, Evm, EvmEnv};
|
||||
use alloc::{boxed::Box, sync::Arc};
|
||||
use alloy_consensus::BlockHeader;
|
||||
use alloy_eips::{
|
||||
@ -10,7 +10,7 @@ use alloy_primitives::Bytes;
|
||||
use core::fmt::Display;
|
||||
use reth_chainspec::EthereumHardforks;
|
||||
use reth_execution_errors::BlockExecutionError;
|
||||
use revm::{Database, DatabaseCommit, Evm};
|
||||
use revm::{Database, DatabaseCommit};
|
||||
use revm_primitives::{EvmState, B256};
|
||||
|
||||
mod eip2935;
|
||||
@ -76,15 +76,11 @@ where
|
||||
Chainspec: EthereumHardforks,
|
||||
{
|
||||
/// Apply pre execution changes.
|
||||
pub fn apply_pre_execution_changes<DB, Ext>(
|
||||
pub fn apply_pre_execution_changes(
|
||||
&mut self,
|
||||
header: &EvmConfig::Header,
|
||||
evm: &mut Evm<'_, Ext, DB>,
|
||||
) -> Result<(), BlockExecutionError>
|
||||
where
|
||||
DB: Database + DatabaseCommit,
|
||||
DB::Error: Display,
|
||||
{
|
||||
evm: &mut impl Evm<DB: DatabaseCommit, Error: Display>,
|
||||
) -> Result<(), BlockExecutionError> {
|
||||
self.apply_blockhashes_contract_call(
|
||||
header.timestamp(),
|
||||
header.number(),
|
||||
@ -102,14 +98,10 @@ where
|
||||
}
|
||||
|
||||
/// Apply post execution changes.
|
||||
pub fn apply_post_execution_changes<DB, Ext>(
|
||||
pub fn apply_post_execution_changes(
|
||||
&mut self,
|
||||
evm: &mut Evm<'_, Ext, DB>,
|
||||
) -> Result<Requests, BlockExecutionError>
|
||||
where
|
||||
DB: Database + DatabaseCommit,
|
||||
DB::Error: Display,
|
||||
{
|
||||
evm: &mut impl Evm<DB: DatabaseCommit, Error: Display>,
|
||||
) -> Result<Requests, BlockExecutionError> {
|
||||
let mut requests = Requests::default();
|
||||
|
||||
// Collect all EIP-7685 requests
|
||||
@ -152,19 +144,14 @@ where
|
||||
}
|
||||
|
||||
/// Applies the pre-block call to the EIP-2935 blockhashes contract.
|
||||
pub fn apply_blockhashes_contract_call<DB, Ext>(
|
||||
pub fn apply_blockhashes_contract_call(
|
||||
&mut self,
|
||||
timestamp: u64,
|
||||
block_number: u64,
|
||||
parent_block_hash: B256,
|
||||
evm: &mut Evm<'_, Ext, DB>,
|
||||
) -> Result<(), BlockExecutionError>
|
||||
where
|
||||
DB: Database + DatabaseCommit,
|
||||
DB::Error: Display,
|
||||
{
|
||||
evm: &mut impl Evm<DB: DatabaseCommit, Error: Display>,
|
||||
) -> Result<(), BlockExecutionError> {
|
||||
let result_and_state = eip2935::transact_blockhashes_contract_call(
|
||||
&self.evm_config,
|
||||
&self.chain_spec,
|
||||
timestamp,
|
||||
block_number,
|
||||
@ -176,7 +163,7 @@ where
|
||||
if let Some(ref mut hook) = self.hook {
|
||||
hook.on_state(&res.state);
|
||||
}
|
||||
evm.context.evm.db.commit(res.state);
|
||||
evm.db_mut().commit(res.state);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -207,19 +194,14 @@ where
|
||||
}
|
||||
|
||||
/// Applies the pre-block call to the EIP-4788 beacon root contract.
|
||||
pub fn apply_beacon_root_contract_call<DB, Ext>(
|
||||
pub fn apply_beacon_root_contract_call(
|
||||
&mut self,
|
||||
timestamp: u64,
|
||||
block_number: u64,
|
||||
parent_block_hash: Option<B256>,
|
||||
evm: &mut Evm<'_, Ext, DB>,
|
||||
) -> Result<(), BlockExecutionError>
|
||||
where
|
||||
DB: Database + DatabaseCommit,
|
||||
DB::Error: Display,
|
||||
{
|
||||
evm: &mut impl Evm<DB: DatabaseCommit, Error: Display>,
|
||||
) -> Result<(), BlockExecutionError> {
|
||||
let result_and_state = eip4788::transact_beacon_root_contract_call(
|
||||
&self.evm_config,
|
||||
&self.chain_spec,
|
||||
timestamp,
|
||||
block_number,
|
||||
@ -231,7 +213,7 @@ where
|
||||
if let Some(ref mut hook) = self.hook {
|
||||
hook.on_state(&res.state);
|
||||
}
|
||||
evm.context.evm.db.commit(res.state);
|
||||
evm.db_mut().commit(res.state);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -256,21 +238,16 @@ where
|
||||
}
|
||||
|
||||
/// Applies the post-block call to the EIP-7002 withdrawal request contract.
|
||||
pub fn apply_withdrawal_requests_contract_call<DB, Ext>(
|
||||
pub fn apply_withdrawal_requests_contract_call(
|
||||
&mut self,
|
||||
evm: &mut Evm<'_, Ext, DB>,
|
||||
) -> Result<Bytes, BlockExecutionError>
|
||||
where
|
||||
DB: Database + DatabaseCommit,
|
||||
DB::Error: Display,
|
||||
{
|
||||
let result_and_state =
|
||||
eip7002::transact_withdrawal_requests_contract_call(&self.evm_config.clone(), evm)?;
|
||||
evm: &mut impl Evm<DB: DatabaseCommit, Error: Display>,
|
||||
) -> Result<Bytes, BlockExecutionError> {
|
||||
let result_and_state = eip7002::transact_withdrawal_requests_contract_call(evm)?;
|
||||
|
||||
if let Some(ref mut hook) = self.hook {
|
||||
hook.on_state(&result_and_state.state);
|
||||
}
|
||||
evm.context.evm.db.commit(result_and_state.state);
|
||||
evm.db_mut().commit(result_and_state.state);
|
||||
|
||||
eip7002::post_commit(result_and_state.result)
|
||||
}
|
||||
@ -294,21 +271,16 @@ where
|
||||
}
|
||||
|
||||
/// Applies the post-block call to the EIP-7251 consolidation requests contract.
|
||||
pub fn apply_consolidation_requests_contract_call<DB, Ext>(
|
||||
pub fn apply_consolidation_requests_contract_call(
|
||||
&mut self,
|
||||
evm: &mut Evm<'_, Ext, DB>,
|
||||
) -> Result<Bytes, BlockExecutionError>
|
||||
where
|
||||
DB: Database + DatabaseCommit,
|
||||
DB::Error: Display,
|
||||
{
|
||||
let result_and_state =
|
||||
eip7251::transact_consolidation_requests_contract_call(&self.evm_config.clone(), evm)?;
|
||||
evm: &mut impl Evm<DB: DatabaseCommit, Error: Display>,
|
||||
) -> Result<Bytes, BlockExecutionError> {
|
||||
let result_and_state = eip7251::transact_consolidation_requests_contract_call(evm)?;
|
||||
|
||||
if let Some(ref mut hook) = self.hook {
|
||||
hook.on_state(&result_and_state.state);
|
||||
}
|
||||
evm.context.evm.db.commit(result_and_state.state);
|
||||
evm.db_mut().commit(result_and_state.state);
|
||||
|
||||
eip7251::post_commit(result_and_state.result)
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -17,16 +17,14 @@ use alloy_rpc_types_eth::{
|
||||
};
|
||||
use futures::Future;
|
||||
use reth_chainspec::EthChainSpec;
|
||||
use reth_evm::{env::EvmEnv, ConfigureEvm, ConfigureEvmEnv};
|
||||
use reth_evm::{env::EvmEnv, ConfigureEvm, ConfigureEvmEnv, Evm};
|
||||
use reth_node_api::BlockBody;
|
||||
use reth_primitives_traits::SignedTransaction;
|
||||
use reth_provider::{BlockIdReader, ChainSpecProvider, ProviderHeader};
|
||||
use reth_revm::{
|
||||
database::StateProviderDatabase,
|
||||
db::CacheDB,
|
||||
primitives::{
|
||||
BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ExecutionResult, ResultAndState, TxEnv,
|
||||
},
|
||||
primitives::{BlockEnv, ExecutionResult, ResultAndState, TxEnv},
|
||||
DatabaseRef,
|
||||
};
|
||||
use reth_rpc_eth_types::{
|
||||
@ -41,7 +39,6 @@ use reth_rpc_eth_types::{
|
||||
};
|
||||
use revm::{Database, DatabaseCommit, GetInspector};
|
||||
use revm_inspectors::{access_list::AccessListInspector, transfer::TransferInspector};
|
||||
use revm_primitives::Env;
|
||||
use tracing::trace;
|
||||
|
||||
/// Result type for `eth_simulateV1` RPC method.
|
||||
@ -493,7 +490,7 @@ pub trait Call:
|
||||
f(StateProviderTraitObjWrapper(&state))
|
||||
}
|
||||
|
||||
/// Executes the [`EnvWithHandlerCfg`] against the given [Database] without committing state
|
||||
/// Executes the [`TxEnv`] against the given [Database] without committing state
|
||||
/// changes.
|
||||
fn transact<DB>(
|
||||
&self,
|
||||
@ -505,21 +502,14 @@ pub trait Call:
|
||||
DB: Database,
|
||||
EthApiError: From<DB::Error>,
|
||||
{
|
||||
let mut evm = self.evm_config().evm_with_env(db, evm_env, tx_env);
|
||||
let res = evm.transact().map_err(Self::Error::from_evm_err)?;
|
||||
let (_, env) = evm.into_db_and_env_with_handler_cfg();
|
||||
let mut evm = self.evm_config().evm_with_env(db, evm_env, Default::default());
|
||||
let res = evm.transact(tx_env.clone()).map_err(Self::Error::from_evm_err)?;
|
||||
let evm_env = evm.into_env();
|
||||
|
||||
let EnvWithHandlerCfg { env, handler_cfg } = env;
|
||||
let Env { cfg, block, tx } = *env;
|
||||
let evm_env = EvmEnv {
|
||||
cfg_env_with_handler_cfg: CfgEnvWithHandlerCfg { cfg_env: cfg, handler_cfg },
|
||||
block_env: block,
|
||||
};
|
||||
|
||||
Ok((res, (evm_env, tx)))
|
||||
Ok((res, (evm_env, tx_env)))
|
||||
}
|
||||
|
||||
/// Executes the [`EnvWithHandlerCfg`] against the given [Database] without committing state
|
||||
/// Executes the [`EvmEnv`] against the given [Database] without committing state
|
||||
/// changes.
|
||||
fn transact_with_inspector<DB>(
|
||||
&self,
|
||||
@ -532,18 +522,16 @@ pub trait Call:
|
||||
DB: Database,
|
||||
EthApiError: From<DB::Error>,
|
||||
{
|
||||
let mut evm = self.evm_config().evm_with_env_and_inspector(db, evm_env, tx_env, inspector);
|
||||
let res = evm.transact().map_err(Self::Error::from_evm_err)?;
|
||||
let (_, env) = evm.into_db_and_env_with_handler_cfg();
|
||||
let mut evm = self.evm_config().evm_with_env_and_inspector(
|
||||
db,
|
||||
evm_env,
|
||||
Default::default(),
|
||||
inspector,
|
||||
);
|
||||
let res = evm.transact(tx_env.clone()).map_err(Self::Error::from_evm_err)?;
|
||||
let evm_env = evm.into_env();
|
||||
|
||||
let EnvWithHandlerCfg { env, handler_cfg } = env;
|
||||
let Env { cfg, block, tx } = *env;
|
||||
let evm_env = EvmEnv {
|
||||
cfg_env_with_handler_cfg: CfgEnvWithHandlerCfg { cfg_env: cfg, handler_cfg },
|
||||
block_env: block,
|
||||
};
|
||||
|
||||
Ok((res, (evm_env, tx)))
|
||||
Ok((res, (evm_env, tx_env)))
|
||||
}
|
||||
|
||||
/// Executes the call request at the given [`BlockId`].
|
||||
@ -581,7 +569,7 @@ pub trait Call:
|
||||
/// Prepares the state and env for the given [`TransactionRequest`] at the given [`BlockId`] and
|
||||
/// executes the closure on a new task returning the result of the closure.
|
||||
///
|
||||
/// This returns the configured [`EnvWithHandlerCfg`] for the given [`TransactionRequest`] at
|
||||
/// This returns the configured [`EvmEnv`] for the given [`TransactionRequest`] at
|
||||
/// the given [`BlockId`] and with configured call settings: `prepare_call_env`.
|
||||
///
|
||||
/// This is primarily used by `eth_call`.
|
||||
@ -704,8 +692,8 @@ pub trait Call:
|
||||
break
|
||||
}
|
||||
|
||||
self.evm_config().fill_tx_env(evm.tx_mut(), tx, *sender);
|
||||
evm.transact_commit().map_err(Self::Error::from_evm_err)?;
|
||||
let tx_env = self.evm_config().tx_env(tx, *sender);
|
||||
evm.transact_commit(tx_env).map_err(Self::Error::from_evm_err)?;
|
||||
index += 1;
|
||||
}
|
||||
Ok(index)
|
||||
@ -790,7 +778,7 @@ pub trait Call:
|
||||
Ok(env)
|
||||
}
|
||||
|
||||
/// Prepares the [`EnvWithHandlerCfg`] for execution of calls.
|
||||
/// Prepares the [`EvmEnv`] for execution of calls.
|
||||
///
|
||||
/// Does not commit any changes to the underlying database.
|
||||
///
|
||||
|
||||
@ -13,7 +13,7 @@ use reth_chainspec::{EthChainSpec, EthereumHardforks};
|
||||
use reth_errors::RethError;
|
||||
use reth_evm::{
|
||||
env::EvmEnv, state_change::post_block_withdrawals_balance_increments,
|
||||
system_calls::SystemCaller, ConfigureEvm, ConfigureEvmEnv, NextBlockEnvAttributes,
|
||||
system_calls::SystemCaller, ConfigureEvm, ConfigureEvmEnv, Evm, NextBlockEnvAttributes,
|
||||
};
|
||||
use reth_primitives::{InvalidTransactionError, RecoveredBlock};
|
||||
use reth_primitives_traits::Receipt;
|
||||
@ -325,9 +325,10 @@ pub trait LoadPendingBlock:
|
||||
}
|
||||
|
||||
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 mut evm =
|
||||
self.evm_config().evm_with_env(&mut db, evm_env.clone(), Default::default());
|
||||
|
||||
let ResultAndState { result, state } = match evm.transact() {
|
||||
let ResultAndState { result, state } = match evm.transact(tx_env) {
|
||||
Ok(res) => res,
|
||||
Err(err) => {
|
||||
match err {
|
||||
|
||||
@ -7,7 +7,7 @@ use alloy_primitives::B256;
|
||||
use alloy_rpc_types_eth::{BlockId, TransactionInfo};
|
||||
use futures::Future;
|
||||
use reth_chainspec::ChainSpecProvider;
|
||||
use reth_evm::{env::EvmEnv, system_calls::SystemCaller, ConfigureEvm, ConfigureEvmEnv};
|
||||
use reth_evm::{env::EvmEnv, system_calls::SystemCaller, ConfigureEvm, ConfigureEvmEnv, Evm};
|
||||
use reth_primitives::RecoveredBlock;
|
||||
use reth_primitives_traits::{BlockBody, SignedTransaction};
|
||||
use reth_provider::{BlockReader, ProviderBlock, ProviderHeader, ProviderTx};
|
||||
@ -18,9 +18,7 @@ use reth_rpc_eth_types::{
|
||||
};
|
||||
use revm::{db::CacheDB, Database, DatabaseCommit, GetInspector, Inspector};
|
||||
use revm_inspectors::tracing::{TracingInspector, TracingInspectorConfig};
|
||||
use revm_primitives::{
|
||||
CfgEnvWithHandlerCfg, Env, EnvWithHandlerCfg, EvmState, ExecutionResult, ResultAndState, TxEnv,
|
||||
};
|
||||
use revm_primitives::{EvmState, ExecutionResult, ResultAndState, TxEnv};
|
||||
use std::{fmt::Display, sync::Arc};
|
||||
|
||||
/// Executes CPU heavy tasks.
|
||||
@ -33,7 +31,7 @@ pub trait Trace:
|
||||
>,
|
||||
>
|
||||
{
|
||||
/// Executes the [`EnvWithHandlerCfg`] against the given [Database] without committing state
|
||||
/// Executes the [`EvmEnv`] against the given [Database] without committing state
|
||||
/// changes.
|
||||
fn inspect<DB, I>(
|
||||
&self,
|
||||
@ -47,23 +45,22 @@ pub trait Trace:
|
||||
EthApiError: From<DB::Error>,
|
||||
I: GetInspector<DB>,
|
||||
{
|
||||
let mut evm = self.evm_config().evm_with_env_and_inspector(db, evm_env, tx_env, inspector);
|
||||
let res = evm.transact().map_err(Self::Error::from_evm_err)?;
|
||||
let (_, env) = evm.into_db_and_env_with_handler_cfg();
|
||||
let EnvWithHandlerCfg { env, handler_cfg } = env;
|
||||
let Env { cfg, block, tx } = *env;
|
||||
let evm_env = EvmEnv {
|
||||
cfg_env_with_handler_cfg: CfgEnvWithHandlerCfg { cfg_env: cfg, handler_cfg },
|
||||
block_env: block,
|
||||
};
|
||||
Ok((res, (evm_env, tx)))
|
||||
let mut evm = self.evm_config().evm_with_env_and_inspector(
|
||||
db,
|
||||
evm_env,
|
||||
Default::default(),
|
||||
inspector,
|
||||
);
|
||||
let res = evm.transact(tx_env.clone()).map_err(Self::Error::from_evm_err)?;
|
||||
let evm_env = evm.into_env();
|
||||
Ok((res, (evm_env, tx_env)))
|
||||
}
|
||||
|
||||
/// Executes the transaction on top of the given [`BlockId`] with a tracer configured by the
|
||||
/// config.
|
||||
///
|
||||
/// The callback is then called with the [`TracingInspector`] and the [`ResultAndState`] after
|
||||
/// the configured [`EnvWithHandlerCfg`] was inspected.
|
||||
/// the configured [`EvmEnv`] was inspected.
|
||||
///
|
||||
/// Caution: this is blocking
|
||||
fn trace_at<F, R>(
|
||||
@ -92,7 +89,7 @@ pub trait Trace:
|
||||
/// config.
|
||||
///
|
||||
/// The callback is then called with the [`TracingInspector`] and the [`ResultAndState`] after
|
||||
/// the configured [`EnvWithHandlerCfg`] was inspected.
|
||||
/// the configured [`EvmEnv`] was inspected.
|
||||
fn spawn_trace_at_with_state<F, R>(
|
||||
&self,
|
||||
evm_env: EvmEnv,
|
||||
|
||||
@ -6,7 +6,7 @@ use alloy_primitives::{Keccak256, U256};
|
||||
use alloy_rpc_types_mev::{EthCallBundle, EthCallBundleResponse, EthCallBundleTransactionResult};
|
||||
use jsonrpsee::core::RpcResult;
|
||||
use reth_chainspec::EthChainSpec;
|
||||
use reth_evm::{ConfigureEvm, ConfigureEvmEnv};
|
||||
use reth_evm::{ConfigureEvm, ConfigureEvmEnv, Evm};
|
||||
use reth_primitives_traits::SignedTransaction;
|
||||
use reth_provider::{ChainSpecProvider, HeaderProvider};
|
||||
use reth_revm::database::StateProviderDatabase;
|
||||
@ -197,9 +197,9 @@ where
|
||||
|
||||
hasher.update(*tx.tx_hash());
|
||||
let gas_price = tx.effective_gas_price(basefee);
|
||||
eth_api.evm_config().fill_tx_env(evm.tx_mut(), &tx, signer);
|
||||
let ResultAndState { result, state } =
|
||||
evm.transact().map_err(Eth::Error::from_evm_err)?;
|
||||
let ResultAndState { result, state } = evm
|
||||
.transact(eth_api.evm_config().tx_env(&tx, signer))
|
||||
.map_err(Eth::Error::from_evm_err)?;
|
||||
|
||||
let gas_used = result.gas_used();
|
||||
total_gas_used += gas_used;
|
||||
@ -245,7 +245,7 @@ where
|
||||
if transactions.peek().is_some() {
|
||||
// need to apply the state changes of this call before executing
|
||||
// the next call
|
||||
evm.context.evm.db.commit(state)
|
||||
evm.db_mut().commit(state)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ use alloy_rpc_types_mev::{
|
||||
};
|
||||
use jsonrpsee::core::RpcResult;
|
||||
use reth_chainspec::EthChainSpec;
|
||||
use reth_evm::{ConfigureEvm, ConfigureEvmEnv};
|
||||
use reth_evm::{ConfigureEvm, ConfigureEvmEnv, Evm};
|
||||
use reth_provider::{ChainSpecProvider, HeaderProvider, ProviderTx};
|
||||
use reth_revm::database::StateProviderDatabase;
|
||||
use reth_rpc_api::MevSimApiServer;
|
||||
@ -324,10 +324,10 @@ where
|
||||
)
|
||||
.into());
|
||||
}
|
||||
eth_api.evm_config().fill_tx_env(evm.tx_mut(), &item.tx, item.signer);
|
||||
|
||||
let ResultAndState { result, state } =
|
||||
evm.transact().map_err(EthApiError::from_eth_err)?;
|
||||
let ResultAndState { result, state } = evm
|
||||
.transact(eth_api.evm_config().tx_env(&item.tx, item.signer))
|
||||
.map_err(EthApiError::from_eth_err)?;
|
||||
|
||||
if !result.is_success() && !item.can_revert {
|
||||
return Err(EthApiError::InvalidParams(
|
||||
@ -366,7 +366,7 @@ where
|
||||
}
|
||||
|
||||
// Apply state changes
|
||||
evm.context.evm.db.commit(state);
|
||||
evm.db_mut().commit(state);
|
||||
}
|
||||
|
||||
// After processing all transactions, process refunds
|
||||
|
||||
@ -7,23 +7,23 @@ use alloy_consensus::BlockHeader;
|
||||
use alloy_eips::{eip4895::Withdrawal, eip7685::Requests};
|
||||
use alloy_sol_macro::sol;
|
||||
use alloy_sol_types::SolCall;
|
||||
#[cfg(feature = "optimism")]
|
||||
use reth::revm::primitives::OptimismFields;
|
||||
use reth::{
|
||||
api::{ConfigureEvm, NodeTypesWithEngine},
|
||||
builder::{components::ExecutorBuilder, BuilderContext, FullNodeTypes},
|
||||
cli::Cli,
|
||||
providers::ProviderError,
|
||||
revm::{
|
||||
interpreter::Host,
|
||||
primitives::{address, Address, Bytes, Env, TransactTo, TxEnv, U256},
|
||||
Database, DatabaseCommit, Evm, State,
|
||||
primitives::{address, Address},
|
||||
Database, DatabaseCommit, State,
|
||||
},
|
||||
};
|
||||
use reth_chainspec::{ChainSpec, EthereumHardforks};
|
||||
use reth_evm::execute::{
|
||||
BlockExecutionError, BlockExecutionStrategy, BlockExecutionStrategyFactory, ExecuteOutput,
|
||||
InternalBlockExecutionError,
|
||||
use reth_evm::{
|
||||
execute::{
|
||||
BlockExecutionError, BlockExecutionStrategy, BlockExecutionStrategyFactory, ExecuteOutput,
|
||||
InternalBlockExecutionError,
|
||||
},
|
||||
Evm,
|
||||
};
|
||||
use reth_evm_ethereum::EthEvmConfig;
|
||||
use reth_node_ethereum::{node::EthereumAddOns, BasicBlockExecutorProvider, EthereumNode};
|
||||
@ -177,19 +177,11 @@ sol!(
|
||||
|
||||
/// Applies the post-block call to the withdrawal / deposit contract, using the given block,
|
||||
/// [`ChainSpec`], EVM.
|
||||
pub fn apply_withdrawals_contract_call<EXT, DB: Database + DatabaseCommit>(
|
||||
pub fn apply_withdrawals_contract_call(
|
||||
withdrawals: &[Withdrawal],
|
||||
evm: &mut Evm<'_, EXT, DB>,
|
||||
) -> Result<(), BlockExecutionError>
|
||||
where
|
||||
DB::Error: std::fmt::Display,
|
||||
{
|
||||
// get previous env
|
||||
let previous_env = Box::new(evm.context.env().clone());
|
||||
|
||||
// modify env for pre block call
|
||||
fill_tx_env_with_system_contract_call(
|
||||
&mut evm.context.evm.env,
|
||||
evm: &mut impl Evm<Error: Display, DB: DatabaseCommit>,
|
||||
) -> Result<(), BlockExecutionError> {
|
||||
let mut state = match evm.transact_system_call(
|
||||
SYSTEM_ADDRESS,
|
||||
WITHDRAWALS_ADDRESS,
|
||||
withdrawalsCall {
|
||||
@ -198,12 +190,9 @@ where
|
||||
}
|
||||
.abi_encode()
|
||||
.into(),
|
||||
);
|
||||
|
||||
let mut state = match evm.transact() {
|
||||
) {
|
||||
Ok(res) => res.state,
|
||||
Err(e) => {
|
||||
evm.context.evm.env = previous_env;
|
||||
return Err(BlockExecutionError::Internal(InternalBlockExecutionError::Other(
|
||||
format!("withdrawal contract system call revert: {}", e).into(),
|
||||
)))
|
||||
@ -213,47 +202,8 @@ where
|
||||
// Clean-up post system tx context
|
||||
state.remove(&SYSTEM_ADDRESS);
|
||||
state.remove(&evm.block().coinbase);
|
||||
evm.context.evm.db.commit(state);
|
||||
// re-set the previous env
|
||||
evm.context.evm.env = previous_env;
|
||||
|
||||
evm.db_mut().commit(state);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fill_tx_env_with_system_contract_call(
|
||||
env: &mut Env,
|
||||
caller: Address,
|
||||
contract: Address,
|
||||
data: Bytes,
|
||||
) {
|
||||
env.tx = TxEnv {
|
||||
caller,
|
||||
transact_to: TransactTo::Call(contract),
|
||||
// Explicitly set nonce to None so revm does not do any nonce checks
|
||||
nonce: None,
|
||||
gas_limit: 30_000_000,
|
||||
value: U256::ZERO,
|
||||
data,
|
||||
// Setting the gas price to zero enforces that no value is transferred as part of the call,
|
||||
// and that the call will not count against the block's gas limit
|
||||
gas_price: U256::ZERO,
|
||||
// The chain ID check is not relevant here and is disabled if set to None
|
||||
chain_id: None,
|
||||
// Setting the gas priority fee to None ensures the effective gas price is derived from the
|
||||
// `gas_price` field, which we need to be zero
|
||||
gas_priority_fee: None,
|
||||
access_list: Vec::new(),
|
||||
// blob fields can be None for this tx
|
||||
blob_hashes: Vec::new(),
|
||||
max_fee_per_blob_gas: None,
|
||||
authorization_list: None,
|
||||
#[cfg(feature = "optimism")]
|
||||
optimism: OptimismFields::default(),
|
||||
};
|
||||
|
||||
// ensure the block gas limit is >= the tx
|
||||
env.block.gas_limit = U256::from(env.tx.gas_limit);
|
||||
|
||||
// disable the base fee check for this call by setting the base fee to zero
|
||||
env.block.basefee = U256::ZERO;
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ use reth::{
|
||||
inspector_handle_register,
|
||||
precompile::{Precompile, PrecompileOutput, PrecompileSpecId},
|
||||
primitives::{CfgEnvWithHandlerCfg, Env, PrecompileResult, TxEnv},
|
||||
ContextPrecompiles, Database, Evm, EvmBuilder, GetInspector,
|
||||
ContextPrecompiles, Database, EvmBuilder, GetInspector,
|
||||
},
|
||||
rpc::types::engine::PayloadAttributes,
|
||||
tasks::TaskManager,
|
||||
@ -24,7 +24,7 @@ use reth::{
|
||||
};
|
||||
use reth_chainspec::{Chain, ChainSpec};
|
||||
use reth_evm::env::EvmEnv;
|
||||
use reth_evm_ethereum::EthEvmConfig;
|
||||
use reth_evm_ethereum::{EthEvm, EthEvmConfig};
|
||||
use reth_node_api::{
|
||||
ConfigureEvm, ConfigureEvmEnv, FullNodeTypes, NextBlockEnvAttributes, NodeTypes,
|
||||
NodeTypesWithEngine, PayloadTypes,
|
||||
@ -93,16 +93,6 @@ impl ConfigureEvmEnv for MyEvmConfig {
|
||||
self.inner.fill_tx_env(tx_env, transaction, sender);
|
||||
}
|
||||
|
||||
fn fill_tx_env_system_contract_call(
|
||||
&self,
|
||||
env: &mut Env,
|
||||
caller: Address,
|
||||
contract: Address,
|
||||
data: Bytes,
|
||||
) {
|
||||
self.inner.fill_tx_env_system_contract_call(env, caller, contract, data);
|
||||
}
|
||||
|
||||
fn fill_cfg_env(&self, cfg_env: &mut CfgEnvWithHandlerCfg, header: &Self::Header) {
|
||||
self.inner.fill_cfg_env(cfg_env, header);
|
||||
}
|
||||
@ -117,7 +107,14 @@ impl ConfigureEvmEnv for MyEvmConfig {
|
||||
}
|
||||
|
||||
impl ConfigureEvm for MyEvmConfig {
|
||||
fn evm_with_env<DB: Database>(&self, db: DB, evm_env: EvmEnv, tx: TxEnv) -> Evm<'_, (), DB> {
|
||||
type Evm<'a, DB: Database + 'a, I: 'a> = EthEvm<'a, I, DB>;
|
||||
|
||||
fn evm_with_env<DB: Database>(
|
||||
&self,
|
||||
db: DB,
|
||||
evm_env: EvmEnv,
|
||||
tx: TxEnv,
|
||||
) -> Self::Evm<'_, DB, ()> {
|
||||
EvmBuilder::default()
|
||||
.with_db(db)
|
||||
.with_cfg_env_with_handler_cfg(evm_env.cfg_env_with_handler_cfg)
|
||||
@ -126,6 +123,7 @@ impl ConfigureEvm for MyEvmConfig {
|
||||
// add additional precompiles
|
||||
.append_handler_register(MyEvmConfig::set_precompiles)
|
||||
.build()
|
||||
.into()
|
||||
}
|
||||
|
||||
fn evm_with_env_and_inspector<DB, I>(
|
||||
@ -134,7 +132,7 @@ impl ConfigureEvm for MyEvmConfig {
|
||||
evm_env: EvmEnv,
|
||||
tx: TxEnv,
|
||||
inspector: I,
|
||||
) -> Evm<'_, I, DB>
|
||||
) -> Self::Evm<'_, DB, I>
|
||||
where
|
||||
DB: Database,
|
||||
I: GetInspector<DB>,
|
||||
@ -149,6 +147,7 @@ impl ConfigureEvm for MyEvmConfig {
|
||||
.append_handler_register(MyEvmConfig::set_precompiles)
|
||||
.append_handler_register(inspector_handle_register)
|
||||
.build()
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ use reth::{
|
||||
primitives::{
|
||||
CfgEnvWithHandlerCfg, Env, PrecompileResult, SpecId, StatefulPrecompileMut, TxEnv,
|
||||
},
|
||||
ContextPrecompile, ContextPrecompiles, Database, Evm, EvmBuilder, GetInspector,
|
||||
ContextPrecompile, ContextPrecompiles, Database, EvmBuilder, GetInspector,
|
||||
},
|
||||
tasks::TaskManager,
|
||||
};
|
||||
@ -25,8 +25,8 @@ use reth_evm::env::EvmEnv;
|
||||
use reth_node_api::{ConfigureEvm, ConfigureEvmEnv, FullNodeTypes, NodeTypes};
|
||||
use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig};
|
||||
use reth_node_ethereum::{
|
||||
node::EthereumAddOns, BasicBlockExecutorProvider, EthEvmConfig, EthExecutionStrategyFactory,
|
||||
EthereumNode,
|
||||
evm::EthEvm, node::EthereumAddOns, BasicBlockExecutorProvider, EthEvmConfig,
|
||||
EthExecutionStrategyFactory, EthereumNode,
|
||||
};
|
||||
use reth_primitives::{EthPrimitives, TransactionSigned};
|
||||
use reth_tracing::{RethTracer, Tracer};
|
||||
@ -155,16 +155,6 @@ impl ConfigureEvmEnv for MyEvmConfig {
|
||||
self.inner.fill_tx_env(tx_env, transaction, sender)
|
||||
}
|
||||
|
||||
fn fill_tx_env_system_contract_call(
|
||||
&self,
|
||||
env: &mut Env,
|
||||
caller: Address,
|
||||
contract: Address,
|
||||
data: Bytes,
|
||||
) {
|
||||
self.inner.fill_tx_env_system_contract_call(env, caller, contract, data)
|
||||
}
|
||||
|
||||
fn fill_cfg_env(&self, cfg_env: &mut CfgEnvWithHandlerCfg, header: &Self::Header) {
|
||||
self.inner.fill_cfg_env(cfg_env, header)
|
||||
}
|
||||
@ -179,7 +169,14 @@ impl ConfigureEvmEnv for MyEvmConfig {
|
||||
}
|
||||
|
||||
impl ConfigureEvm for MyEvmConfig {
|
||||
fn evm_with_env<DB: Database>(&self, db: DB, evm_env: EvmEnv, tx: TxEnv) -> Evm<'_, (), DB> {
|
||||
type Evm<'a, DB: Database + 'a, I: 'a> = EthEvm<'a, I, DB>;
|
||||
|
||||
fn evm_with_env<DB: Database>(
|
||||
&self,
|
||||
db: DB,
|
||||
evm_env: EvmEnv,
|
||||
tx: TxEnv,
|
||||
) -> Self::Evm<'_, DB, ()> {
|
||||
let new_cache = self.precompile_cache.clone();
|
||||
EvmBuilder::default()
|
||||
.with_db(db)
|
||||
@ -191,6 +188,7 @@ impl ConfigureEvm for MyEvmConfig {
|
||||
MyEvmConfig::set_precompiles(handler, new_cache.clone())
|
||||
}))
|
||||
.build()
|
||||
.into()
|
||||
}
|
||||
|
||||
fn evm_with_env_and_inspector<DB, I>(
|
||||
@ -199,7 +197,7 @@ impl ConfigureEvm for MyEvmConfig {
|
||||
evm_env: EvmEnv,
|
||||
tx: TxEnv,
|
||||
inspector: I,
|
||||
) -> Evm<'_, I, DB>
|
||||
) -> Self::Evm<'_, DB, I>
|
||||
where
|
||||
DB: Database,
|
||||
I: GetInspector<DB>,
|
||||
@ -217,6 +215,7 @@ impl ConfigureEvm for MyEvmConfig {
|
||||
}))
|
||||
.append_handler_register(inspector_handle_register)
|
||||
.build()
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user