From c0f0dd78a7356bb44fc90f2785ba42d33dd05e1f Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 24 Sep 2024 15:39:40 +0200 Subject: [PATCH] feat: add transact function to 4788 (#11157) --- crates/evm/src/system_calls/eip4788.rs | 134 ++++++++++++++++--------- 1 file changed, 85 insertions(+), 49 deletions(-) diff --git a/crates/evm/src/system_calls/eip4788.rs b/crates/evm/src/system_calls/eip4788.rs index 79beaca695..055bfb634c 100644 --- a/crates/evm/src/system_calls/eip4788.rs +++ b/crates/evm/src/system_calls/eip4788.rs @@ -7,7 +7,7 @@ use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_execution_errors::{BlockExecutionError, BlockValidationError}; use reth_primitives::Header; use revm::{interpreter::Host, Database, DatabaseCommit, Evm}; -use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, B256}; +use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState, B256}; /// Apply the [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788) pre block contract call. /// @@ -50,6 +50,81 @@ where ) } +/// Applies the pre-block call to the [EIP-4788] beacon block root contract, using the given block, +/// [`ChainSpec`], EVM. +/// +/// Note: this does not commit the state changes to the database, it only transact the call. +/// +/// Returns `None` if Cancun is not active or the block is the genesis block, otherwise returns the +/// result of the call. +/// +/// [EIP-4788]: https://eips.ethereum.org/EIPS/eip-4788 +#[inline] +pub fn transact_beacon_root_contract_call( + evm_config: &EvmConfig, + chain_spec: &Spec, + block_timestamp: u64, + block_number: u64, + parent_beacon_block_root: Option, + evm: &mut Evm<'_, EXT, DB>, +) -> Result, BlockExecutionError> +where + DB: Database + DatabaseCommit, + DB::Error: core::fmt::Display, + EvmConfig: ConfigureEvm
, + Spec: EthereumHardforks, +{ + if !chain_spec.is_cancun_active_at_timestamp(block_timestamp) { + return Ok(None) + } + + let parent_beacon_block_root = + parent_beacon_block_root.ok_or(BlockValidationError::MissingParentBeaconBlockRoot)?; + + // if the block number is zero (genesis block) then the parent beacon block root must + // be 0x0 and no system transaction may occur as per EIP-4788 + if block_number == 0 { + if !parent_beacon_block_root.is_zero() { + return Err(BlockValidationError::CancunGenesisParentBeaconBlockRootNotZero { + parent_beacon_block_root, + } + .into()) + } + 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, + 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(), + } + .into()) + } + }; + + 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)) +} + /// Applies the pre-block call to the [EIP-4788] beacon block root contract, using the given block, /// [`ChainSpec`], EVM. /// @@ -72,55 +147,16 @@ where EvmConfig: ConfigureEvm
, Spec: EthereumHardforks, { - if !chain_spec.is_cancun_active_at_timestamp(block_timestamp) { - return Ok(()) + if let Some(res) = transact_beacon_root_contract_call( + evm_config, + chain_spec, + block_timestamp, + block_number, + parent_beacon_block_root, + evm, + )? { + evm.context.evm.db.commit(res.state); } - let parent_beacon_block_root = - parent_beacon_block_root.ok_or(BlockValidationError::MissingParentBeaconBlockRoot)?; - - // if the block number is zero (genesis block) then the parent beacon block root must - // be 0x0 and no system transaction may occur as per EIP-4788 - if block_number == 0 { - if !parent_beacon_block_root.is_zero() { - return Err(BlockValidationError::CancunGenesisParentBeaconBlockRootNotZero { - parent_beacon_block_root, - } - .into()) - } - return Ok(()) - } - - // 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, - alloy_eips::eip4788::SYSTEM_ADDRESS, - BEACON_ROOTS_ADDRESS, - parent_beacon_block_root.0.into(), - ); - - let mut state = match evm.transact() { - Ok(res) => res.state, - 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(), - } - .into()) - } - }; - - state.remove(&alloy_eips::eip4788::SYSTEM_ADDRESS); - state.remove(&evm.block().coinbase); - - evm.context.evm.db.commit(state); - - // re-set the previous env - evm.context.evm.env = previous_env; - Ok(()) }