mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
chore: move pre_block_beacon_root_contract_call to evm crates (#9244)
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -7197,6 +7197,7 @@ dependencies = [
|
||||
name = "reth-evm"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"alloy-eips",
|
||||
"auto_impl",
|
||||
"futures-util",
|
||||
"parking_lot 0.12.3",
|
||||
|
||||
@ -11,6 +11,7 @@ use reth_evm::{
|
||||
BatchExecutor, BlockExecutionError, BlockExecutionInput, BlockExecutionOutput,
|
||||
BlockExecutorProvider, BlockValidationError, Executor, ProviderError,
|
||||
},
|
||||
system_calls::apply_beacon_root_contract_call,
|
||||
ConfigureEvm,
|
||||
};
|
||||
use reth_execution_types::ExecutionOutcome;
|
||||
@ -22,8 +23,8 @@ use reth_revm::{
|
||||
batch::{BlockBatchRecord, BlockExecutorStats},
|
||||
db::states::bundle_state::BundleRetention,
|
||||
state_change::{
|
||||
apply_beacon_root_contract_call, apply_blockhashes_update,
|
||||
apply_withdrawal_requests_contract_call, post_block_balance_increments,
|
||||
apply_blockhashes_update, apply_withdrawal_requests_contract_call,
|
||||
post_block_balance_increments,
|
||||
},
|
||||
Evm, State,
|
||||
};
|
||||
@ -147,7 +148,7 @@ where
|
||||
DB::Error: Into<ProviderError> + std::fmt::Display,
|
||||
{
|
||||
// apply pre execution changes
|
||||
apply_beacon_root_contract_call(
|
||||
apply_beacon_root_contract_call::<EvmConfig, _, _>(
|
||||
&self.chain_spec,
|
||||
block.timestamp,
|
||||
block.number,
|
||||
|
||||
@ -16,7 +16,7 @@ use reth_chainspec::{ChainSpec, Head};
|
||||
use reth_evm::{ConfigureEvm, ConfigureEvmEnv};
|
||||
use reth_primitives::{transaction::FillTxEnv, Address, Header, TransactionSigned, U256};
|
||||
use reth_revm::{Database, EvmBuilder};
|
||||
use revm_primitives::{AnalysisKind, CfgEnvWithHandlerCfg, TxEnv};
|
||||
use revm_primitives::{AnalysisKind, Bytes, CfgEnvWithHandlerCfg, Env, TxEnv, TxKind};
|
||||
|
||||
mod config;
|
||||
pub use config::{revm_spec, revm_spec_by_timestamp_after_merge};
|
||||
@ -61,6 +61,45 @@ impl ConfigureEvmEnv for EthEvmConfig {
|
||||
fn fill_tx_env(&self, tx_env: &mut TxEnv, transaction: &TransactionSigned, sender: Address) {
|
||||
transaction.fill_tx_env(tx_env, sender);
|
||||
}
|
||||
|
||||
fn fill_tx_env_system_contract_call(
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigureEvm for EthEvmConfig {
|
||||
|
||||
@ -11,11 +11,10 @@
|
||||
|
||||
use reth_basic_payload_builder::{
|
||||
commit_withdrawals, is_better_payload, post_block_withdrawal_requests_contract_call,
|
||||
pre_block_beacon_root_contract_call, BuildArguments, BuildOutcome, PayloadBuilder,
|
||||
PayloadConfig, WithdrawalsOutcome,
|
||||
BuildArguments, BuildOutcome, PayloadBuilder, PayloadConfig, WithdrawalsOutcome,
|
||||
};
|
||||
use reth_errors::RethError;
|
||||
use reth_evm::ConfigureEvm;
|
||||
use reth_evm::{system_calls::pre_block_beacon_root_contract_call, ConfigureEvm};
|
||||
use reth_evm_ethereum::{eip6110::parse_deposits_from_receipts, EthEvmConfig};
|
||||
use reth_execution_types::ExecutionOutcome;
|
||||
use reth_payload_builder::{
|
||||
@ -114,11 +113,13 @@ where
|
||||
// apply eip-4788 pre block contract call
|
||||
pre_block_beacon_root_contract_call(
|
||||
&mut db,
|
||||
self.evm_config.clone(),
|
||||
&chain_spec,
|
||||
block_number,
|
||||
&initialized_cfg,
|
||||
&initialized_block_env,
|
||||
&attributes,
|
||||
block_number,
|
||||
attributes.timestamp,
|
||||
attributes.parent_beacon_block_root,
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!(target: "payload_builder",
|
||||
@ -126,7 +127,7 @@ where
|
||||
%err,
|
||||
"failed to apply beacon root contract call for empty payload"
|
||||
);
|
||||
err
|
||||
PayloadBuilderError::Internal(err.into())
|
||||
})?;
|
||||
|
||||
// apply eip-2935 blockhashes update
|
||||
@ -288,12 +289,22 @@ where
|
||||
// apply eip-4788 pre block contract call
|
||||
pre_block_beacon_root_contract_call(
|
||||
&mut db,
|
||||
evm_config.clone(),
|
||||
&chain_spec,
|
||||
block_number,
|
||||
&initialized_cfg,
|
||||
&initialized_block_env,
|
||||
&attributes,
|
||||
)?;
|
||||
block_number,
|
||||
attributes.timestamp,
|
||||
attributes.parent_beacon_block_root,
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!(target: "payload_builder",
|
||||
parent_hash=%parent_block.hash(),
|
||||
%err,
|
||||
"failed to apply beacon root contract call for empty payload"
|
||||
);
|
||||
PayloadBuilderError::Internal(err.into())
|
||||
})?;
|
||||
|
||||
// apply eip-2935 blockhashes update
|
||||
apply_blockhashes_update(
|
||||
|
||||
@ -21,7 +21,7 @@ reth-storage-errors.workspace = true
|
||||
reth-execution-types.workspace = true
|
||||
|
||||
revm.workspace = true
|
||||
|
||||
alloy-eips.workspace = true
|
||||
auto_impl.workspace = true
|
||||
futures-util.workspace = true
|
||||
parking_lot = { workspace = true, optional = true }
|
||||
|
||||
@ -19,12 +19,15 @@ use reth_primitives::{
|
||||
header::block_coinbase, Address, Header, TransactionSigned, TransactionSignedEcRecovered, U256,
|
||||
};
|
||||
use revm::{inspector_handle_register, Database, Evm, EvmBuilder, GetInspector};
|
||||
use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, SpecId, TxEnv};
|
||||
use revm_primitives::{
|
||||
BlockEnv, Bytes, CfgEnvWithHandlerCfg, Env, EnvWithHandlerCfg, SpecId, TxEnv,
|
||||
};
|
||||
|
||||
pub mod either;
|
||||
pub mod execute;
|
||||
pub mod noop;
|
||||
pub mod provider;
|
||||
pub mod system_calls;
|
||||
|
||||
#[cfg(any(test, feature = "test-utils"))]
|
||||
/// test helpers for mocking executor
|
||||
@ -117,6 +120,14 @@ pub trait ConfigureEvmEnv: Send + Sync + Unpin + Clone + 'static {
|
||||
/// Fill transaction environment from a [`TransactionSigned`] and the given sender address.
|
||||
fn fill_tx_env(&self, tx_env: &mut TxEnv, transaction: &TransactionSigned, sender: Address);
|
||||
|
||||
/// Fill transaction environment with a system contract call.
|
||||
fn fill_tx_env_system_contract_call(
|
||||
env: &mut Env,
|
||||
caller: Address,
|
||||
contract: Address,
|
||||
data: Bytes,
|
||||
);
|
||||
|
||||
/// Fill [`CfgEnvWithHandlerCfg`] fields according to the chain spec and given header
|
||||
fn fill_cfg_env(
|
||||
cfg_env: &mut CfgEnvWithHandlerCfg,
|
||||
|
||||
125
crates/evm/src/system_calls.rs
Normal file
125
crates/evm/src/system_calls.rs
Normal file
@ -0,0 +1,125 @@
|
||||
//! System contract call functions.
|
||||
|
||||
use alloy_eips::eip4788::BEACON_ROOTS_ADDRESS;
|
||||
use reth_chainspec::{ChainSpec, EthereumHardforks};
|
||||
use reth_execution_errors::{BlockExecutionError, BlockValidationError};
|
||||
use revm::{interpreter::Host, Database, DatabaseCommit, Evm};
|
||||
use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, B256};
|
||||
|
||||
use crate::ConfigureEvm;
|
||||
|
||||
/// Apply the [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788) pre block contract call.
|
||||
///
|
||||
/// This constructs a new [Evm] with the given DB, and environment
|
||||
/// ([`CfgEnvWithHandlerCfg`] and [`BlockEnv`]) to execute the pre block contract call.
|
||||
///
|
||||
/// This uses [`apply_beacon_root_contract_call`] to ultimately apply the beacon root contract state
|
||||
/// change.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn pre_block_beacon_root_contract_call<EvmConfig, DB>(
|
||||
db: &mut DB,
|
||||
_emv_config: EvmConfig,
|
||||
chain_spec: &ChainSpec,
|
||||
initialized_cfg: &CfgEnvWithHandlerCfg,
|
||||
initialized_block_env: &BlockEnv,
|
||||
block_number: u64,
|
||||
block_timestamp: u64,
|
||||
parent_beacon_block_root: Option<B256>,
|
||||
) -> Result<(), BlockExecutionError>
|
||||
where
|
||||
DB: Database + DatabaseCommit,
|
||||
DB::Error: std::fmt::Display,
|
||||
EvmConfig: ConfigureEvm,
|
||||
{
|
||||
// apply pre-block EIP-4788 contract call
|
||||
let mut evm_pre_block = 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();
|
||||
|
||||
// initialize a block from the env, because the pre block call needs the block itself
|
||||
apply_beacon_root_contract_call::<EvmConfig, _, _>(
|
||||
chain_spec,
|
||||
block_timestamp,
|
||||
block_number,
|
||||
parent_beacon_block_root,
|
||||
&mut evm_pre_block,
|
||||
)
|
||||
}
|
||||
|
||||
/// Applies the pre-block call to the [EIP-4788] beacon block root contract, using the given block,
|
||||
/// [`ChainSpec`], EVM.
|
||||
///
|
||||
/// If Cancun is not activated or the block is the genesis block, then this is a no-op, and no
|
||||
/// state changes are made.
|
||||
///
|
||||
/// [EIP-4788]: https://eips.ethereum.org/EIPS/eip-4788
|
||||
#[inline]
|
||||
pub fn apply_beacon_root_contract_call<EvmConfig, EXT, DB>(
|
||||
chain_spec: &ChainSpec,
|
||||
block_timestamp: u64,
|
||||
block_number: u64,
|
||||
parent_beacon_block_root: Option<B256>,
|
||||
evm: &mut Evm<'_, EXT, DB>,
|
||||
) -> Result<(), BlockExecutionError>
|
||||
where
|
||||
DB: Database + DatabaseCommit,
|
||||
DB::Error: core::fmt::Display,
|
||||
EvmConfig: ConfigureEvm,
|
||||
{
|
||||
if !chain_spec.is_cancun_active_at_timestamp(block_timestamp) {
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
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 != B256::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
|
||||
EvmConfig::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(())
|
||||
}
|
||||
@ -7,6 +7,7 @@ use reth_evm::{
|
||||
BatchExecutor, BlockExecutionError, BlockExecutionInput, BlockExecutionOutput,
|
||||
BlockExecutorProvider, BlockValidationError, Executor, ProviderError,
|
||||
},
|
||||
system_calls::apply_beacon_root_contract_call,
|
||||
ConfigureEvm,
|
||||
};
|
||||
use reth_execution_types::ExecutionOutcome;
|
||||
@ -16,7 +17,7 @@ use reth_prune_types::PruneModes;
|
||||
use reth_revm::{
|
||||
batch::{BlockBatchRecord, BlockExecutorStats},
|
||||
db::states::bundle_state::BundleRetention,
|
||||
state_change::{apply_beacon_root_contract_call, post_block_balance_increments},
|
||||
state_change::post_block_balance_increments,
|
||||
Evm, State,
|
||||
};
|
||||
use revm_primitives::{
|
||||
@ -121,7 +122,7 @@ where
|
||||
DB: Database<Error: Into<ProviderError> + std::fmt::Display>,
|
||||
{
|
||||
// apply pre execution changes
|
||||
apply_beacon_root_contract_call(
|
||||
apply_beacon_root_contract_call::<EvmConfig, _, _>(
|
||||
&self.chain_spec,
|
||||
block.timestamp,
|
||||
block.number,
|
||||
|
||||
@ -27,6 +27,7 @@ pub use l1::*;
|
||||
|
||||
mod error;
|
||||
pub use error::OptimismBlockExecutionError;
|
||||
use revm_primitives::{Bytes, Env, OptimismFields, TxKind};
|
||||
|
||||
/// Optimism-related EVM configuration.
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
@ -38,6 +39,49 @@ impl ConfigureEvmEnv for OptimismEvmConfig {
|
||||
transaction.fill_tx_env(tx_env, sender);
|
||||
}
|
||||
|
||||
fn fill_tx_env_system_contract_call(
|
||||
env: &mut Env,
|
||||
caller: Address,
|
||||
contract: Address,
|
||||
data: Bytes,
|
||||
) {
|
||||
env.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,
|
||||
optimism: OptimismFields {
|
||||
source_hash: None,
|
||||
mint: None,
|
||||
is_system_transaction: Some(false),
|
||||
// The L1 fee is not charged for the EIP-4788 transaction, submit zero bytes for the
|
||||
// enveloped tx size.
|
||||
enveloped_tx: Some(Bytes::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;
|
||||
}
|
||||
|
||||
fn fill_cfg_env(
|
||||
cfg_env: &mut CfgEnvWithHandlerCfg,
|
||||
chain_spec: &ChainSpec,
|
||||
|
||||
@ -6,7 +6,7 @@ use crate::{
|
||||
};
|
||||
use reth_basic_payload_builder::*;
|
||||
use reth_chainspec::{ChainSpec, EthereumHardforks, OptimismHardfork};
|
||||
use reth_evm::ConfigureEvm;
|
||||
use reth_evm::{system_calls::pre_block_beacon_root_contract_call, ConfigureEvm};
|
||||
use reth_execution_types::ExecutionOutcome;
|
||||
use reth_payload_builder::error::PayloadBuilderError;
|
||||
use reth_primitives::{
|
||||
@ -125,11 +125,13 @@ where
|
||||
// apply eip-4788 pre block contract call
|
||||
pre_block_beacon_root_contract_call(
|
||||
&mut db,
|
||||
self.evm_config.clone(),
|
||||
&chain_spec,
|
||||
block_number,
|
||||
&initialized_cfg,
|
||||
&initialized_block_env,
|
||||
&attributes,
|
||||
block_number,
|
||||
attributes.payload_attributes.timestamp,
|
||||
attributes.payload_attributes.parent_beacon_block_root,
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!(target: "payload_builder",
|
||||
@ -137,7 +139,7 @@ where
|
||||
%err,
|
||||
"failed to apply beacon root contract call for empty payload"
|
||||
);
|
||||
err
|
||||
PayloadBuilderError::Internal(err.into())
|
||||
})?;
|
||||
|
||||
let WithdrawalsOutcome { withdrawals_root, withdrawals } = commit_withdrawals(
|
||||
@ -286,12 +288,22 @@ where
|
||||
// apply eip-4788 pre block contract call
|
||||
pre_block_beacon_root_contract_call(
|
||||
&mut db,
|
||||
evm_config.clone(),
|
||||
&chain_spec,
|
||||
block_number,
|
||||
&initialized_cfg,
|
||||
&initialized_block_env,
|
||||
&attributes,
|
||||
)?;
|
||||
block_number,
|
||||
attributes.payload_attributes.timestamp,
|
||||
attributes.payload_attributes.parent_beacon_block_root,
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!(target: "payload_builder",
|
||||
parent_hash=%parent_block.hash(),
|
||||
%err,
|
||||
"failed to apply beacon root contract call for empty payload"
|
||||
);
|
||||
PayloadBuilderError::Internal(err.into())
|
||||
})?;
|
||||
|
||||
// Ensure that the create2deployer is force-deployed at the canyon transition. Optimism
|
||||
// blocks will always have at least a single transaction in them (the L1 info transaction),
|
||||
|
||||
@ -25,8 +25,7 @@ use reth_provider::{
|
||||
BlockReaderIdExt, BlockSource, CanonStateNotification, ProviderError, StateProviderFactory,
|
||||
};
|
||||
use reth_revm::state_change::{
|
||||
apply_beacon_root_contract_call, apply_withdrawal_requests_contract_call,
|
||||
post_block_withdrawals_balance_increments,
|
||||
apply_withdrawal_requests_contract_call, post_block_withdrawals_balance_increments,
|
||||
};
|
||||
use reth_tasks::TaskSpawner;
|
||||
use reth_transaction_pool::TransactionPool;
|
||||
@ -923,49 +922,6 @@ pub fn commit_withdrawals<DB: Database<Error = ProviderError>>(
|
||||
})
|
||||
}
|
||||
|
||||
/// Apply the [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788) pre block contract call.
|
||||
///
|
||||
/// This constructs a new [Evm] with the given DB, and environment
|
||||
/// ([`CfgEnvWithHandlerCfg`] and [`BlockEnv`]) to execute the pre block contract call.
|
||||
///
|
||||
/// The parent beacon block root used for the call is gathered from the given
|
||||
/// [`PayloadBuilderAttributes`].
|
||||
///
|
||||
/// This uses [`apply_beacon_root_contract_call`] to ultimately apply the beacon root contract state
|
||||
/// change.
|
||||
pub fn pre_block_beacon_root_contract_call<DB: Database + DatabaseCommit, Attributes>(
|
||||
db: &mut DB,
|
||||
chain_spec: &ChainSpec,
|
||||
block_number: u64,
|
||||
initialized_cfg: &CfgEnvWithHandlerCfg,
|
||||
initialized_block_env: &BlockEnv,
|
||||
attributes: &Attributes,
|
||||
) -> Result<(), PayloadBuilderError>
|
||||
where
|
||||
DB::Error: std::fmt::Display,
|
||||
Attributes: PayloadBuilderAttributes,
|
||||
{
|
||||
// apply pre-block EIP-4788 contract call
|
||||
let mut evm_pre_block = 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();
|
||||
|
||||
// initialize a block from the env, because the pre block call needs the block itself
|
||||
apply_beacon_root_contract_call(
|
||||
chain_spec,
|
||||
attributes.timestamp(),
|
||||
block_number,
|
||||
attributes.parent_beacon_block_root(),
|
||||
&mut evm_pre_block,
|
||||
)
|
||||
.map_err(|err| PayloadBuilderError::Internal(err.into()))
|
||||
}
|
||||
|
||||
/// Apply the [EIP-7002](https://eips.ethereum.org/EIPS/eip-7002) post block contract call.
|
||||
///
|
||||
/// This constructs a new [Evm] with the given DB, and environment
|
||||
|
||||
@ -1,34 +1,15 @@
|
||||
use crate::{
|
||||
revm_primitives::{Env, TxEnv},
|
||||
Address, Bytes, TxKind, B256, U256,
|
||||
Address, Bytes, TxKind, U256,
|
||||
};
|
||||
|
||||
use alloy_eips::{eip4788::BEACON_ROOTS_ADDRESS, eip7002::WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS};
|
||||
use alloy_eips::eip7002::WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS;
|
||||
#[cfg(feature = "optimism")]
|
||||
use revm_primitives::OptimismFields;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::vec::Vec;
|
||||
|
||||
/// Fill transaction environment with the EIP-4788 system contract message data.
|
||||
///
|
||||
/// This requirements for the beacon root contract call defined by
|
||||
/// [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788) are:
|
||||
///
|
||||
/// At the start of processing any execution block where `block.timestamp >= FORK_TIMESTAMP` (i.e.
|
||||
/// before processing any transactions), call [`BEACON_ROOTS_ADDRESS`] as
|
||||
/// [`SYSTEM_ADDRESS`](alloy_eips::eip4788::SYSTEM_ADDRESS) with the 32-byte input of
|
||||
/// `header.parent_beacon_block_root`. This will trigger the `set()` routine of the beacon roots
|
||||
/// contract.
|
||||
pub fn fill_tx_env_with_beacon_root_contract_call(env: &mut Env, parent_beacon_block_root: B256) {
|
||||
fill_tx_env_with_system_contract_call(
|
||||
env,
|
||||
alloy_eips::eip4788::SYSTEM_ADDRESS,
|
||||
BEACON_ROOTS_ADDRESS,
|
||||
parent_beacon_block_root.0.into(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Fill transaction environment with the EIP-7002 withdrawal requests contract message data.
|
||||
//
|
||||
/// This requirement for the withdrawal requests contract call defined by
|
||||
|
||||
@ -7,11 +7,8 @@ use reth_chainspec::{ChainSpec, EthereumHardforks};
|
||||
use reth_consensus_common::calc;
|
||||
use reth_execution_errors::{BlockExecutionError, BlockValidationError};
|
||||
use reth_primitives::{
|
||||
revm::env::{
|
||||
fill_tx_env_with_beacon_root_contract_call,
|
||||
fill_tx_env_with_withdrawal_requests_contract_call,
|
||||
},
|
||||
Address, Block, Request, Withdrawal, Withdrawals, B256, U256,
|
||||
revm::env::fill_tx_env_with_withdrawal_requests_contract_call, Address, Block, Request,
|
||||
Withdrawal, Withdrawals, B256, U256,
|
||||
};
|
||||
use reth_storage_errors::provider::ProviderError;
|
||||
use revm::{
|
||||
@ -139,72 +136,6 @@ fn eip2935_block_hash_slot<DB: Database<Error: Into<ProviderError>>>(
|
||||
Ok((slot, EvmStorageSlot::new_changed(current_hash, block_hash.into())))
|
||||
}
|
||||
|
||||
/// Applies the pre-block call to the [EIP-4788] beacon block root contract, using the given block,
|
||||
/// [`ChainSpec`], EVM.
|
||||
///
|
||||
/// If Cancun is not activated or the block is the genesis block, then this is a no-op, and no
|
||||
/// state changes are made.
|
||||
///
|
||||
/// [EIP-4788]: https://eips.ethereum.org/EIPS/eip-4788
|
||||
#[inline]
|
||||
pub fn apply_beacon_root_contract_call<EXT, DB: Database + DatabaseCommit>(
|
||||
chain_spec: &ChainSpec,
|
||||
block_timestamp: u64,
|
||||
block_number: u64,
|
||||
parent_beacon_block_root: Option<B256>,
|
||||
evm: &mut Evm<'_, EXT, DB>,
|
||||
) -> Result<(), BlockExecutionError>
|
||||
where
|
||||
DB::Error: core::fmt::Display,
|
||||
{
|
||||
if !chain_spec.is_cancun_active_at_timestamp(block_timestamp) {
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
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 != B256::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
|
||||
fill_tx_env_with_beacon_root_contract_call(&mut evm.context.evm.env, parent_beacon_block_root);
|
||||
|
||||
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(())
|
||||
}
|
||||
|
||||
/// Returns a map of addresses to their balance increments if the Shanghai hardfork is active at the
|
||||
/// given timestamp.
|
||||
///
|
||||
|
||||
@ -5,7 +5,7 @@ use std::time::{Duration, Instant};
|
||||
|
||||
use futures::Future;
|
||||
use reth_chainspec::EthereumHardforks;
|
||||
use reth_evm::{ConfigureEvm, ConfigureEvmEnv};
|
||||
use reth_evm::{system_calls::pre_block_beacon_root_contract_call, ConfigureEvm, ConfigureEvmEnv};
|
||||
use reth_execution_types::ExecutionOutcome;
|
||||
use reth_primitives::{
|
||||
constants::{eip4844::MAX_DATA_GAS_PER_BLOCK, BEACON_NONCE, EMPTY_ROOT_HASH},
|
||||
@ -25,8 +25,8 @@ use reth_revm::{
|
||||
database::StateProviderDatabase, state_change::post_block_withdrawals_balance_increments,
|
||||
};
|
||||
use reth_rpc_eth_types::{
|
||||
pending_block::{pre_block_beacon_root_contract_call, pre_block_blockhashes_update},
|
||||
EthApiError, EthResult, PendingBlock, PendingBlockEnv, PendingBlockEnvOrigin,
|
||||
pending_block::pre_block_blockhashes_update, EthApiError, EthResult, PendingBlock,
|
||||
PendingBlockEnv, PendingBlockEnvOrigin,
|
||||
};
|
||||
use reth_transaction_pool::{BestTransactionsAttributes, TransactionPool};
|
||||
use revm::{db::states::bundle_state::BundleRetention, DatabaseCommit, State};
|
||||
@ -235,12 +235,15 @@ pub trait LoadPendingBlock {
|
||||
// parent beacon block root
|
||||
pre_block_beacon_root_contract_call(
|
||||
&mut db,
|
||||
self.evm_config().clone(),
|
||||
chain_spec.as_ref(),
|
||||
block_number,
|
||||
&cfg,
|
||||
&block_env,
|
||||
block_number,
|
||||
block_env.timestamp.to::<u64>(),
|
||||
origin.header().parent_beacon_block_root,
|
||||
)?;
|
||||
)
|
||||
.map_err(|err| EthApiError::Internal(err.into()))?;
|
||||
origin.header().parent_beacon_block_root
|
||||
} else {
|
||||
None
|
||||
|
||||
@ -8,10 +8,10 @@ use derive_more::Constructor;
|
||||
use reth_chainspec::ChainSpec;
|
||||
use reth_primitives::{BlockId, BlockNumberOrTag, SealedBlockWithSenders, SealedHeader, B256};
|
||||
use reth_provider::ProviderError;
|
||||
use reth_revm::state_change::{apply_beacon_root_contract_call, apply_blockhashes_update};
|
||||
use reth_revm::state_change::apply_blockhashes_update;
|
||||
use revm_primitives::{
|
||||
db::{Database, DatabaseCommit},
|
||||
BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg,
|
||||
BlockEnv, CfgEnvWithHandlerCfg,
|
||||
};
|
||||
|
||||
use super::{EthApiError, EthResult};
|
||||
@ -27,45 +27,6 @@ pub struct PendingBlockEnv {
|
||||
pub origin: PendingBlockEnvOrigin,
|
||||
}
|
||||
|
||||
/// Apply the [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788) pre block contract call.
|
||||
///
|
||||
/// This constructs a new [Evm](revm::Evm) with the given DB, and environment
|
||||
/// [`CfgEnvWithHandlerCfg`] and [`BlockEnv`] to execute the pre block contract call.
|
||||
///
|
||||
/// This uses [`apply_beacon_root_contract_call`] to ultimately apply the beacon root contract state
|
||||
/// change.
|
||||
pub fn pre_block_beacon_root_contract_call<DB: Database + DatabaseCommit>(
|
||||
db: &mut DB,
|
||||
chain_spec: &ChainSpec,
|
||||
block_number: u64,
|
||||
initialized_cfg: &CfgEnvWithHandlerCfg,
|
||||
initialized_block_env: &BlockEnv,
|
||||
parent_beacon_block_root: Option<B256>,
|
||||
) -> EthResult<()>
|
||||
where
|
||||
DB::Error: fmt::Display,
|
||||
{
|
||||
// apply pre-block EIP-4788 contract call
|
||||
let mut evm_pre_block = revm::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();
|
||||
|
||||
// initialize a block from the env, because the pre block call needs the block itself
|
||||
apply_beacon_root_contract_call(
|
||||
chain_spec,
|
||||
initialized_block_env.timestamp.to::<u64>(),
|
||||
block_number,
|
||||
parent_beacon_block_root,
|
||||
&mut evm_pre_block,
|
||||
)
|
||||
.map_err(|err| EthApiError::Internal(err.into()))
|
||||
}
|
||||
|
||||
/// Apply the [EIP-2935](https://eips.ethereum.org/EIPS/eip-2935) pre block state transitions.
|
||||
///
|
||||
/// This constructs a new [Evm](revm::Evm) with the given DB, and environment
|
||||
|
||||
@ -93,6 +93,15 @@ impl ConfigureEvmEnv for MyEvmConfig {
|
||||
fn fill_tx_env(&self, tx_env: &mut TxEnv, transaction: &TransactionSigned, sender: Address) {
|
||||
EthEvmConfig::default().fill_tx_env(tx_env, transaction, sender)
|
||||
}
|
||||
|
||||
fn fill_tx_env_system_contract_call(
|
||||
env: &mut Env,
|
||||
caller: Address,
|
||||
contract: Address,
|
||||
data: Bytes,
|
||||
) {
|
||||
EthEvmConfig::fill_tx_env_system_contract_call(env, caller, contract, data)
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigureEvm for MyEvmConfig {
|
||||
|
||||
@ -145,6 +145,15 @@ impl ConfigureEvmEnv for MyEvmConfig {
|
||||
) {
|
||||
EthEvmConfig::fill_cfg_env(cfg_env, chain_spec, header, total_difficulty)
|
||||
}
|
||||
|
||||
fn fill_tx_env_system_contract_call(
|
||||
env: &mut Env,
|
||||
caller: Address,
|
||||
contract: Address,
|
||||
data: Bytes,
|
||||
) {
|
||||
EthEvmConfig::fill_tx_env_system_contract_call(env, caller, contract, data)
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigureEvm for MyEvmConfig {
|
||||
|
||||
Reference in New Issue
Block a user