mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: alloy-evm and new revm integration (#14021)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de> Co-authored-by: rakita <rakita@users.noreply.github.com>
This commit is contained in:
@ -14,25 +14,22 @@ workspace = true
|
||||
# Reth
|
||||
reth-chainspec.workspace = true
|
||||
reth-ethereum-forks.workspace = true
|
||||
reth-revm.workspace = true
|
||||
reth-evm.workspace = true
|
||||
reth-primitives.workspace = true
|
||||
reth-ethereum-consensus.workspace = true
|
||||
reth-consensus.workspace = true
|
||||
revm.workspace = true
|
||||
|
||||
# Ethereum
|
||||
revm-primitives.workspace = true
|
||||
reth-primitives-traits.workspace = true
|
||||
|
||||
# Alloy
|
||||
alloy-primitives.workspace = true
|
||||
alloy-eips.workspace = true
|
||||
alloy-evm.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"] }
|
||||
@ -53,13 +50,11 @@ std = [
|
||||
"alloy-eips/std",
|
||||
"alloy-genesis/std",
|
||||
"alloy-primitives/std",
|
||||
"revm/std",
|
||||
"revm-primitives/std",
|
||||
"secp256k1/std",
|
||||
"reth-ethereum-forks/std",
|
||||
"serde_json/std",
|
||||
"reth-primitives-traits/std",
|
||||
"reth-chainspec/std",
|
||||
"derive_more/std",
|
||||
"alloy-evm/std",
|
||||
"reth-execution-types/std",
|
||||
]
|
||||
|
||||
@ -1,87 +1,86 @@
|
||||
use alloy_consensus::Header;
|
||||
use reth_chainspec::{ChainSpec, EthereumHardforks};
|
||||
use reth_ethereum_forks::EthereumHardfork;
|
||||
use reth_revm::specification::hardfork::SpecId;
|
||||
|
||||
/// Map the latest active hardfork at the given header to a revm
|
||||
/// [`SpecId`](revm_primitives::SpecId).
|
||||
pub fn revm_spec(chain_spec: &ChainSpec, header: &Header) -> revm_primitives::SpecId {
|
||||
/// Map the latest active hardfork at the given header to a revm [`SpecId`].
|
||||
pub fn revm_spec(chain_spec: &ChainSpec, header: &Header) -> SpecId {
|
||||
revm_spec_by_timestamp_and_block_number(chain_spec, header.timestamp, header.number)
|
||||
}
|
||||
|
||||
/// Map the latest active hardfork at the given timestamp or block number to a revm
|
||||
/// [`SpecId`](revm_primitives::SpecId).
|
||||
/// Map the latest active hardfork at the given timestamp or block number to a revm [`SpecId`].
|
||||
pub fn revm_spec_by_timestamp_and_block_number(
|
||||
chain_spec: &ChainSpec,
|
||||
timestamp: u64,
|
||||
block_number: u64,
|
||||
) -> revm_primitives::SpecId {
|
||||
) -> SpecId {
|
||||
if chain_spec
|
||||
.fork(EthereumHardfork::Osaka)
|
||||
.active_at_timestamp_or_number(timestamp, block_number)
|
||||
{
|
||||
revm_primitives::OSAKA
|
||||
SpecId::OSAKA
|
||||
} else if chain_spec
|
||||
.fork(EthereumHardfork::Prague)
|
||||
.active_at_timestamp_or_number(timestamp, block_number)
|
||||
{
|
||||
revm_primitives::PRAGUE
|
||||
SpecId::PRAGUE
|
||||
} else if chain_spec
|
||||
.fork(EthereumHardfork::Cancun)
|
||||
.active_at_timestamp_or_number(timestamp, block_number)
|
||||
{
|
||||
revm_primitives::CANCUN
|
||||
SpecId::CANCUN
|
||||
} else if chain_spec
|
||||
.fork(EthereumHardfork::Shanghai)
|
||||
.active_at_timestamp_or_number(timestamp, block_number)
|
||||
{
|
||||
revm_primitives::SHANGHAI
|
||||
SpecId::SHANGHAI
|
||||
} else if chain_spec.is_paris_active_at_block(block_number).is_some_and(|active| active) {
|
||||
revm_primitives::MERGE
|
||||
SpecId::MERGE
|
||||
} else if chain_spec
|
||||
.fork(EthereumHardfork::London)
|
||||
.active_at_timestamp_or_number(timestamp, block_number)
|
||||
{
|
||||
revm_primitives::LONDON
|
||||
SpecId::LONDON
|
||||
} else if chain_spec
|
||||
.fork(EthereumHardfork::Berlin)
|
||||
.active_at_timestamp_or_number(timestamp, block_number)
|
||||
{
|
||||
revm_primitives::BERLIN
|
||||
SpecId::BERLIN
|
||||
} else if chain_spec
|
||||
.fork(EthereumHardfork::Istanbul)
|
||||
.active_at_timestamp_or_number(timestamp, block_number)
|
||||
{
|
||||
revm_primitives::ISTANBUL
|
||||
SpecId::ISTANBUL
|
||||
} else if chain_spec
|
||||
.fork(EthereumHardfork::Petersburg)
|
||||
.active_at_timestamp_or_number(timestamp, block_number)
|
||||
{
|
||||
revm_primitives::PETERSBURG
|
||||
SpecId::PETERSBURG
|
||||
} else if chain_spec
|
||||
.fork(EthereumHardfork::Byzantium)
|
||||
.active_at_timestamp_or_number(timestamp, block_number)
|
||||
{
|
||||
revm_primitives::BYZANTIUM
|
||||
SpecId::BYZANTIUM
|
||||
} else if chain_spec
|
||||
.fork(EthereumHardfork::SpuriousDragon)
|
||||
.active_at_timestamp_or_number(timestamp, block_number)
|
||||
{
|
||||
revm_primitives::SPURIOUS_DRAGON
|
||||
SpecId::SPURIOUS_DRAGON
|
||||
} else if chain_spec
|
||||
.fork(EthereumHardfork::Tangerine)
|
||||
.active_at_timestamp_or_number(timestamp, block_number)
|
||||
{
|
||||
revm_primitives::TANGERINE
|
||||
SpecId::TANGERINE
|
||||
} else if chain_spec
|
||||
.fork(EthereumHardfork::Homestead)
|
||||
.active_at_timestamp_or_number(timestamp, block_number)
|
||||
{
|
||||
revm_primitives::HOMESTEAD
|
||||
SpecId::HOMESTEAD
|
||||
} else if chain_spec
|
||||
.fork(EthereumHardfork::Frontier)
|
||||
.active_at_timestamp_or_number(timestamp, block_number)
|
||||
{
|
||||
revm_primitives::FRONTIER
|
||||
SpecId::FRONTIER
|
||||
} else {
|
||||
panic!(
|
||||
"invalid hardfork chainspec: expected at least one hardfork, got {:?}",
|
||||
@ -104,7 +103,7 @@ mod tests {
|
||||
0,
|
||||
0
|
||||
),
|
||||
revm_primitives::CANCUN
|
||||
SpecId::CANCUN
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec_by_timestamp_and_block_number(
|
||||
@ -112,12 +111,12 @@ mod tests {
|
||||
0,
|
||||
0
|
||||
),
|
||||
revm_primitives::SHANGHAI
|
||||
SpecId::SHANGHAI
|
||||
);
|
||||
let mainnet = ChainSpecBuilder::mainnet().build();
|
||||
assert_eq!(
|
||||
revm_spec_by_timestamp_and_block_number(&mainnet, 0, mainnet.paris_block().unwrap()),
|
||||
revm_primitives::MERGE
|
||||
SpecId::MERGE
|
||||
);
|
||||
}
|
||||
|
||||
@ -125,75 +124,75 @@ mod tests {
|
||||
fn test_to_revm_spec() {
|
||||
assert_eq!(
|
||||
revm_spec(&ChainSpecBuilder::mainnet().cancun_activated().build(), &Default::default()),
|
||||
revm_primitives::CANCUN
|
||||
SpecId::CANCUN
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(
|
||||
&ChainSpecBuilder::mainnet().shanghai_activated().build(),
|
||||
&Default::default()
|
||||
),
|
||||
revm_primitives::SHANGHAI
|
||||
SpecId::SHANGHAI
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&ChainSpecBuilder::mainnet().paris_activated().build(), &Default::default()),
|
||||
revm_primitives::MERGE
|
||||
SpecId::MERGE
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&ChainSpecBuilder::mainnet().london_activated().build(), &Default::default()),
|
||||
revm_primitives::LONDON
|
||||
SpecId::LONDON
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&ChainSpecBuilder::mainnet().berlin_activated().build(), &Default::default()),
|
||||
revm_primitives::BERLIN
|
||||
SpecId::BERLIN
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(
|
||||
&ChainSpecBuilder::mainnet().istanbul_activated().build(),
|
||||
&Default::default()
|
||||
),
|
||||
revm_primitives::ISTANBUL
|
||||
SpecId::ISTANBUL
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(
|
||||
&ChainSpecBuilder::mainnet().petersburg_activated().build(),
|
||||
&Default::default()
|
||||
),
|
||||
revm_primitives::PETERSBURG
|
||||
SpecId::PETERSBURG
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(
|
||||
&ChainSpecBuilder::mainnet().byzantium_activated().build(),
|
||||
&Default::default()
|
||||
),
|
||||
revm_primitives::BYZANTIUM
|
||||
SpecId::BYZANTIUM
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(
|
||||
&ChainSpecBuilder::mainnet().spurious_dragon_activated().build(),
|
||||
&Default::default()
|
||||
),
|
||||
revm_primitives::SPURIOUS_DRAGON
|
||||
SpecId::SPURIOUS_DRAGON
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(
|
||||
&ChainSpecBuilder::mainnet().tangerine_whistle_activated().build(),
|
||||
&Default::default()
|
||||
),
|
||||
revm_primitives::TANGERINE
|
||||
SpecId::TANGERINE
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(
|
||||
&ChainSpecBuilder::mainnet().homestead_activated().build(),
|
||||
&Default::default()
|
||||
),
|
||||
revm_primitives::HOMESTEAD
|
||||
SpecId::HOMESTEAD
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(
|
||||
&ChainSpecBuilder::mainnet().frontier_activated().build(),
|
||||
&Default::default()
|
||||
),
|
||||
revm_primitives::FRONTIER
|
||||
SpecId::FRONTIER
|
||||
);
|
||||
}
|
||||
|
||||
@ -201,11 +200,11 @@ mod tests {
|
||||
fn test_eth_spec() {
|
||||
assert_eq!(
|
||||
revm_spec(&MAINNET, &Header { timestamp: 1710338135, ..Default::default() }),
|
||||
revm_primitives::CANCUN
|
||||
SpecId::CANCUN
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&MAINNET, &Header { timestamp: 1681338455, ..Default::default() }),
|
||||
revm_primitives::SHANGHAI
|
||||
SpecId::SHANGHAI
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@ -213,43 +212,43 @@ mod tests {
|
||||
&MAINNET,
|
||||
&Header { difficulty: U256::from(10_u128), number: 15537394, ..Default::default() }
|
||||
),
|
||||
revm_primitives::MERGE
|
||||
SpecId::MERGE
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&MAINNET, &Header { number: 15537394 - 10, ..Default::default() }),
|
||||
revm_primitives::LONDON
|
||||
SpecId::LONDON
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&MAINNET, &Header { number: 12244000 + 10, ..Default::default() }),
|
||||
revm_primitives::BERLIN
|
||||
SpecId::BERLIN
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&MAINNET, &Header { number: 12244000 - 10, ..Default::default() }),
|
||||
revm_primitives::ISTANBUL
|
||||
SpecId::ISTANBUL
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&MAINNET, &Header { number: 7280000 + 10, ..Default::default() }),
|
||||
revm_primitives::PETERSBURG
|
||||
SpecId::PETERSBURG
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&MAINNET, &Header { number: 7280000 - 10, ..Default::default() }),
|
||||
revm_primitives::BYZANTIUM
|
||||
SpecId::BYZANTIUM
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&MAINNET, &Header { number: 2675000 + 10, ..Default::default() }),
|
||||
revm_primitives::SPURIOUS_DRAGON
|
||||
SpecId::SPURIOUS_DRAGON
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&MAINNET, &Header { number: 2675000 - 10, ..Default::default() }),
|
||||
revm_primitives::TANGERINE
|
||||
SpecId::TANGERINE
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&MAINNET, &Header { number: 1150000 + 10, ..Default::default() }),
|
||||
revm_primitives::HOMESTEAD
|
||||
SpecId::HOMESTEAD
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&MAINNET, &Header { number: 1150000 - 10, ..Default::default() }),
|
||||
revm_primitives::FRONTIER
|
||||
SpecId::FRONTIER
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,8 +21,7 @@ use reth_evm::{
|
||||
};
|
||||
use reth_primitives::{EthPrimitives, Receipt, RecoveredBlock};
|
||||
use reth_primitives_traits::{BlockBody, SignedTransaction};
|
||||
use revm::db::State;
|
||||
use revm_primitives::{db::DatabaseCommit, ResultAndState};
|
||||
use reth_revm::{context_interface::result::ResultAndState, db::State, DatabaseCommit};
|
||||
|
||||
/// Factory for [`EthExecutionStrategy`].
|
||||
#[derive(Debug, Clone)]
|
||||
@ -300,10 +299,14 @@ mod tests {
|
||||
use reth_primitives::{Account, Block, BlockBody, Transaction};
|
||||
use reth_primitives_traits::{crypto::secp256k1::public_key_to_address, Block as _};
|
||||
use reth_revm::{
|
||||
database::StateProviderDatabase, test_utils::StateProviderTest, Database, TransitionState,
|
||||
database::StateProviderDatabase,
|
||||
db::TransitionState,
|
||||
primitives::{address, BLOCKHASH_SERVE_WINDOW},
|
||||
state::EvmState,
|
||||
test_utils::StateProviderTest,
|
||||
Database,
|
||||
};
|
||||
use reth_testing_utils::generators::{self, sign_tx_with_key_pair};
|
||||
use revm_primitives::{address, EvmState, BLOCKHASH_SERVE_WINDOW};
|
||||
use secp256k1::{Keypair, Secp256k1};
|
||||
use std::{collections::HashMap, sync::mpsc};
|
||||
|
||||
|
||||
@ -17,18 +17,20 @@
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use alloc::sync::Arc;
|
||||
use alloy_consensus::{BlockHeader, Header};
|
||||
pub use alloy_evm::EthEvm;
|
||||
use alloy_evm::EthEvmFactory;
|
||||
use alloy_primitives::{Address, U256};
|
||||
use core::{convert::Infallible, fmt::Debug};
|
||||
use reth_chainspec::{ChainSpec, EthChainSpec, MAINNET};
|
||||
use reth_evm::{env::EvmEnv, ConfigureEvm, ConfigureEvmEnv, Database, Evm, NextBlockEnvAttributes};
|
||||
use reth_evm::{ConfigureEvm, ConfigureEvmEnv, EvmEnv, NextBlockEnvAttributes};
|
||||
use reth_primitives::TransactionSigned;
|
||||
use reth_primitives_traits::transaction::execute::FillTxEnv;
|
||||
use revm::{inspector_handle_register, EvmBuilder};
|
||||
use revm_primitives::{
|
||||
AnalysisKind, BlobExcessGasAndPrice, BlockEnv, Bytes, CfgEnv, CfgEnvWithHandlerCfg, EVMError,
|
||||
HaltReason, HandlerCfg, ResultAndState, SpecId, TxEnv, TxKind,
|
||||
use reth_revm::{
|
||||
context::{BlockEnv, CfgEnv, TxEnv},
|
||||
context_interface::block::BlobExcessGasAndPrice,
|
||||
specification::hardfork::SpecId,
|
||||
};
|
||||
|
||||
mod config;
|
||||
@ -44,90 +46,17 @@ 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>(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>;
|
||||
type HaltReason = HaltReason;
|
||||
|
||||
fn block(&self) -> &BlockEnv {
|
||||
self.0.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 {
|
||||
chain_spec: Arc<ChainSpec>,
|
||||
evm_factory: EthEvmFactory,
|
||||
}
|
||||
|
||||
impl EthEvmConfig {
|
||||
/// Creates a new Ethereum EVM configuration with the given chain spec.
|
||||
pub const fn new(chain_spec: Arc<ChainSpec>) -> Self {
|
||||
Self { chain_spec }
|
||||
pub fn new(chain_spec: Arc<ChainSpec>) -> Self {
|
||||
Self { chain_spec, evm_factory: Default::default() }
|
||||
}
|
||||
|
||||
/// Creates a new Ethereum EVM configuration for the ethereum mainnet.
|
||||
@ -146,7 +75,7 @@ impl ConfigureEvmEnv for EthEvmConfig {
|
||||
type Transaction = TransactionSigned;
|
||||
type Error = Infallible;
|
||||
type TxEnv = TxEnv;
|
||||
type Spec = revm_primitives::SpecId;
|
||||
type Spec = SpecId;
|
||||
|
||||
fn tx_env(&self, transaction: &TransactionSigned, sender: Address) -> Self::TxEnv {
|
||||
let mut tx_env = TxEnv::default();
|
||||
@ -157,25 +86,24 @@ impl ConfigureEvmEnv for EthEvmConfig {
|
||||
fn evm_env(&self, header: &Self::Header) -> EvmEnv {
|
||||
let spec = config::revm_spec(self.chain_spec(), header);
|
||||
|
||||
let mut cfg_env = CfgEnv::default();
|
||||
cfg_env.chain_id = self.chain_spec.chain().id();
|
||||
cfg_env.perf_analyse_created_bytecodes = AnalysisKind::default();
|
||||
// configure evm env based on parent block
|
||||
let cfg_env = CfgEnv::new().with_chain_id(self.chain_spec.chain().id()).with_spec(spec);
|
||||
|
||||
let block_env = BlockEnv {
|
||||
number: U256::from(header.number()),
|
||||
coinbase: header.beneficiary(),
|
||||
timestamp: U256::from(header.timestamp()),
|
||||
number: header.number(),
|
||||
beneficiary: header.beneficiary(),
|
||||
timestamp: header.timestamp(),
|
||||
difficulty: if spec >= SpecId::MERGE { U256::ZERO } else { header.difficulty() },
|
||||
prevrandao: if spec >= SpecId::MERGE { header.mix_hash() } else { None },
|
||||
gas_limit: U256::from(header.gas_limit()),
|
||||
basefee: U256::from(header.base_fee_per_gas().unwrap_or_default()),
|
||||
gas_limit: header.gas_limit(),
|
||||
basefee: header.base_fee_per_gas().unwrap_or_default(),
|
||||
// EIP-4844 excess blob gas of this block, introduced in Cancun
|
||||
blob_excess_gas_and_price: header.excess_blob_gas.map(|excess_blob_gas| {
|
||||
BlobExcessGasAndPrice::new(excess_blob_gas, spec >= SpecId::PRAGUE)
|
||||
}),
|
||||
};
|
||||
|
||||
EvmEnv { cfg_env, spec, block_env }
|
||||
EvmEnv { cfg_env, block_env }
|
||||
}
|
||||
|
||||
fn next_evm_env(
|
||||
@ -183,9 +111,6 @@ impl ConfigureEvmEnv for EthEvmConfig {
|
||||
parent: &Self::Header,
|
||||
attributes: NextBlockEnvAttributes,
|
||||
) -> Result<EvmEnv, Self::Error> {
|
||||
// configure evm env based on parent block
|
||||
let cfg = CfgEnv::default().with_chain_id(self.chain_spec.chain().id());
|
||||
|
||||
// ensure we're not missing any timestamp based hardforks
|
||||
let spec_id = revm_spec_by_timestamp_and_block_number(
|
||||
&self.chain_spec,
|
||||
@ -193,6 +118,9 @@ impl ConfigureEvmEnv for EthEvmConfig {
|
||||
parent.number() + 1,
|
||||
);
|
||||
|
||||
// configure evm env based on parent block
|
||||
let cfg = CfgEnv::new().with_chain_id(self.chain_spec.chain().id()).with_spec(spec_id);
|
||||
|
||||
// if the parent block did not have excess blob gas (i.e. it was pre-cancun), but it is
|
||||
// cancun now, we need to set the excess blob gas to the default value(0)
|
||||
let blob_excess_gas_and_price = parent
|
||||
@ -206,7 +134,7 @@ impl ConfigureEvmEnv for EthEvmConfig {
|
||||
self.chain_spec.base_fee_params_at_timestamp(attributes.timestamp),
|
||||
);
|
||||
|
||||
let mut gas_limit = U256::from(attributes.gas_limit);
|
||||
let mut gas_limit = attributes.gas_limit;
|
||||
|
||||
// If we are on the London fork boundary, we need to multiply the parent's gas limit by the
|
||||
// elasticity multiplier to get the new gas limit.
|
||||
@ -217,71 +145,34 @@ impl ConfigureEvmEnv for EthEvmConfig {
|
||||
.elasticity_multiplier;
|
||||
|
||||
// multiply the gas limit by the elasticity multiplier
|
||||
gas_limit *= U256::from(elasticity_multiplier);
|
||||
gas_limit *= elasticity_multiplier as u64;
|
||||
|
||||
// set the base fee to the initial base fee from the EIP-1559 spec
|
||||
basefee = Some(INITIAL_BASE_FEE)
|
||||
}
|
||||
|
||||
let block_env = BlockEnv {
|
||||
number: U256::from(parent.number + 1),
|
||||
coinbase: attributes.suggested_fee_recipient,
|
||||
timestamp: U256::from(attributes.timestamp),
|
||||
number: parent.number + 1,
|
||||
beneficiary: attributes.suggested_fee_recipient,
|
||||
timestamp: attributes.timestamp,
|
||||
difficulty: U256::ZERO,
|
||||
prevrandao: Some(attributes.prev_randao),
|
||||
gas_limit,
|
||||
// calculate basefee based on parent block's gas usage
|
||||
basefee: basefee.map(U256::from).unwrap_or_default(),
|
||||
basefee: basefee.unwrap_or_default(),
|
||||
// calculate excess gas based on parent block's blob gas usage
|
||||
blob_excess_gas_and_price,
|
||||
};
|
||||
|
||||
Ok((CfgEnvWithHandlerCfg::new_with_spec_id(cfg, spec_id), block_env).into())
|
||||
Ok((cfg, block_env).into())
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigureEvm for EthEvmConfig {
|
||||
type Evm<'a, DB: Database + 'a, I: 'a> = EthEvm<'a, I, DB>;
|
||||
type EvmError<DBError: core::error::Error + Send + Sync + 'static> = EVMError<DBError>;
|
||||
type HaltReason = HaltReason;
|
||||
type EvmFactory = EthEvmFactory;
|
||||
|
||||
fn evm_with_env<DB: Database>(&self, db: DB, evm_env: EvmEnv) -> Self::Evm<'_, DB, ()> {
|
||||
let cfg_env_with_handler_cfg = CfgEnvWithHandlerCfg {
|
||||
cfg_env: evm_env.cfg_env,
|
||||
handler_cfg: HandlerCfg::new(evm_env.spec),
|
||||
};
|
||||
EthEvm(
|
||||
EvmBuilder::default()
|
||||
.with_db(db)
|
||||
.with_cfg_env_with_handler_cfg(cfg_env_with_handler_cfg)
|
||||
.with_block_env(evm_env.block_env)
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
|
||||
fn evm_with_env_and_inspector<DB, I>(
|
||||
&self,
|
||||
db: DB,
|
||||
evm_env: EvmEnv,
|
||||
inspector: I,
|
||||
) -> Self::Evm<'_, DB, I>
|
||||
where
|
||||
DB: Database,
|
||||
I: revm::GetInspector<DB>,
|
||||
{
|
||||
let cfg_env_with_handler_cfg = CfgEnvWithHandlerCfg {
|
||||
cfg_env: evm_env.cfg_env,
|
||||
handler_cfg: HandlerCfg::new(evm_env.spec),
|
||||
};
|
||||
EthEvm(
|
||||
EvmBuilder::default()
|
||||
.with_db(db)
|
||||
.with_external_context(inspector)
|
||||
.with_cfg_env_with_handler_cfg(cfg_env_with_handler_cfg)
|
||||
.with_block_env(evm_env.block_env)
|
||||
.append_handler_register(inspector_handle_register)
|
||||
.build(),
|
||||
)
|
||||
fn evm_factory(&self) -> &Self::EvmFactory {
|
||||
&self.evm_factory
|
||||
}
|
||||
}
|
||||
|
||||
@ -290,15 +181,14 @@ mod tests {
|
||||
use super::*;
|
||||
use alloy_consensus::Header;
|
||||
use alloy_genesis::Genesis;
|
||||
use alloy_primitives::U256;
|
||||
use reth_chainspec::{Chain, ChainSpec, MAINNET};
|
||||
use reth_evm::{env::EvmEnv, execute::ProviderError};
|
||||
use revm::{
|
||||
db::{CacheDB, EmptyDBTyped},
|
||||
inspectors::NoOpInspector,
|
||||
primitives::{BlockEnv, CfgEnv, SpecId},
|
||||
use reth_evm::{execute::ProviderError, EvmEnv};
|
||||
use reth_revm::{
|
||||
context::{BlockEnv, CfgEnv},
|
||||
database_interface::EmptyDBTyped,
|
||||
db::CacheDB,
|
||||
inspector::NoOpInspector,
|
||||
};
|
||||
use revm_primitives::HandlerCfg;
|
||||
|
||||
#[test]
|
||||
fn test_fill_cfg_and_block_env() {
|
||||
@ -337,14 +227,8 @@ mod tests {
|
||||
let evm = evm_config.evm_with_env(db, evm_env.clone());
|
||||
|
||||
// Check that the EVM environment
|
||||
assert_eq!(evm.context.evm.env.block, evm_env.block_env);
|
||||
assert_eq!(evm.context.evm.env.cfg, evm_env.cfg_env);
|
||||
|
||||
// Default spec ID
|
||||
assert_eq!(evm.handler.spec_id(), SpecId::LATEST);
|
||||
|
||||
// No Optimism
|
||||
assert_eq!(evm.handler.cfg, HandlerCfg { spec_id: SpecId::LATEST, ..Default::default() });
|
||||
assert_eq!(evm.block, evm_env.block_env);
|
||||
assert_eq!(evm.cfg, evm_env.cfg_env);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -362,13 +246,7 @@ mod tests {
|
||||
let evm = evm_config.evm_with_env(db, evm_env);
|
||||
|
||||
// Check that the EVM environment is initialized with the custom environment
|
||||
assert_eq!(evm.context.evm.inner.env.cfg, cfg);
|
||||
|
||||
// Default spec ID
|
||||
assert_eq!(evm.handler.spec_id(), SpecId::LATEST);
|
||||
|
||||
// No Optimism
|
||||
assert_eq!(evm.handler.cfg, HandlerCfg { spec_id: SpecId::LATEST, ..Default::default() });
|
||||
assert_eq!(evm.cfg, cfg);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -379,25 +257,18 @@ mod tests {
|
||||
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
|
||||
|
||||
// Create customs block and tx env
|
||||
let block = BlockEnv {
|
||||
basefee: U256::from(1000),
|
||||
gas_limit: U256::from(10_000_000),
|
||||
number: U256::from(42),
|
||||
..Default::default()
|
||||
};
|
||||
let block =
|
||||
BlockEnv { basefee: 1000, gas_limit: 10_000_000, number: 42, ..Default::default() };
|
||||
|
||||
let evm_env = EvmEnv { block_env: block, ..Default::default() };
|
||||
|
||||
let evm = evm_config.evm_with_env(db, evm_env.clone());
|
||||
|
||||
// Verify that the block and transaction environments are set correctly
|
||||
assert_eq!(evm.context.evm.env.block, evm_env.block_env);
|
||||
assert_eq!(evm.block, evm_env.block_env);
|
||||
|
||||
// Default spec ID
|
||||
assert_eq!(evm.handler.spec_id(), SpecId::LATEST);
|
||||
|
||||
// No Optimism
|
||||
assert_eq!(evm.handler.cfg, HandlerCfg { spec_id: SpecId::LATEST, ..Default::default() });
|
||||
assert_eq!(evm.cfg.spec, SpecId::LATEST);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -407,18 +278,15 @@ mod tests {
|
||||
|
||||
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
|
||||
|
||||
let evm_env = EvmEnv { spec: SpecId::CONSTANTINOPLE, ..Default::default() };
|
||||
let evm_env = EvmEnv {
|
||||
cfg_env: CfgEnv::new().with_spec(SpecId::CONSTANTINOPLE),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let evm = evm_config.evm_with_env(db, evm_env);
|
||||
|
||||
// Check that the spec ID is setup properly
|
||||
assert_eq!(evm.handler.spec_id(), SpecId::PETERSBURG);
|
||||
|
||||
// No Optimism
|
||||
assert_eq!(
|
||||
evm.handler.cfg,
|
||||
HandlerCfg { spec_id: SpecId::PETERSBURG, ..Default::default() }
|
||||
);
|
||||
assert_eq!(evm.cfg.spec, SpecId::CONSTANTINOPLE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -429,16 +297,11 @@ mod tests {
|
||||
|
||||
let evm_env = EvmEnv::default();
|
||||
|
||||
let evm = evm_config.evm_with_env_and_inspector(db, evm_env.clone(), NoOpInspector);
|
||||
let evm = evm_config.evm_with_env_and_inspector(db, evm_env.clone(), NoOpInspector {});
|
||||
|
||||
// Check that the EVM environment is set to default values
|
||||
assert_eq!(evm.context.evm.env.block, evm_env.block_env);
|
||||
assert_eq!(evm.context.evm.env.cfg, evm_env.cfg_env);
|
||||
assert_eq!(evm.context.external, NoOpInspector);
|
||||
assert_eq!(evm.handler.spec_id(), SpecId::LATEST);
|
||||
|
||||
// No Optimism
|
||||
assert_eq!(evm.handler.cfg, HandlerCfg { spec_id: SpecId::LATEST, ..Default::default() });
|
||||
assert_eq!(evm.block, evm_env.block_env);
|
||||
assert_eq!(evm.cfg, evm_env.cfg_env);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -449,18 +312,13 @@ mod tests {
|
||||
|
||||
let cfg_env = CfgEnv::default().with_chain_id(111);
|
||||
let block = BlockEnv::default();
|
||||
let evm_env =
|
||||
EvmEnv { cfg_env: cfg_env.clone(), block_env: block, spec: Default::default() };
|
||||
let evm_env = EvmEnv { cfg_env: cfg_env.clone(), block_env: block };
|
||||
|
||||
let evm = evm_config.evm_with_env_and_inspector(db, evm_env, NoOpInspector);
|
||||
let evm = evm_config.evm_with_env_and_inspector(db, evm_env, NoOpInspector {});
|
||||
|
||||
// Check that the EVM environment is set with custom configuration
|
||||
assert_eq!(evm.context.evm.env.cfg, cfg_env);
|
||||
assert_eq!(evm.context.external, NoOpInspector);
|
||||
assert_eq!(evm.handler.spec_id(), SpecId::LATEST);
|
||||
|
||||
// No Optimism
|
||||
assert_eq!(evm.handler.cfg, HandlerCfg { spec_id: SpecId::LATEST, ..Default::default() });
|
||||
assert_eq!(evm.cfg, cfg_env);
|
||||
assert_eq!(evm.cfg.spec, SpecId::LATEST);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -470,23 +328,15 @@ mod tests {
|
||||
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
|
||||
|
||||
// Create custom block and tx environment
|
||||
let block = BlockEnv {
|
||||
basefee: U256::from(1000),
|
||||
gas_limit: U256::from(10_000_000),
|
||||
number: U256::from(42),
|
||||
..Default::default()
|
||||
};
|
||||
let block =
|
||||
BlockEnv { basefee: 1000, gas_limit: 10_000_000, number: 42, ..Default::default() };
|
||||
let evm_env = EvmEnv { block_env: block, ..Default::default() };
|
||||
|
||||
let evm = evm_config.evm_with_env_and_inspector(db, evm_env.clone(), NoOpInspector);
|
||||
let evm = evm_config.evm_with_env_and_inspector(db, evm_env.clone(), NoOpInspector {});
|
||||
|
||||
// Verify that the block and transaction environments are set correctly
|
||||
assert_eq!(evm.context.evm.env.block, evm_env.block_env);
|
||||
assert_eq!(evm.context.external, NoOpInspector);
|
||||
assert_eq!(evm.handler.spec_id(), SpecId::LATEST);
|
||||
|
||||
// No Optimism
|
||||
assert_eq!(evm.handler.cfg, HandlerCfg { spec_id: SpecId::LATEST, ..Default::default() });
|
||||
assert_eq!(evm.block, evm_env.block_env);
|
||||
assert_eq!(evm.cfg.spec, SpecId::LATEST);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -495,21 +345,16 @@ mod tests {
|
||||
let evm_config = EthEvmConfig::new(MAINNET.clone());
|
||||
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
|
||||
|
||||
let evm_env = EvmEnv { spec: SpecId::CONSTANTINOPLE, ..Default::default() };
|
||||
let evm_env = EvmEnv {
|
||||
cfg_env: CfgEnv::new().with_spec(SpecId::CONSTANTINOPLE),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let evm = evm_config.evm_with_env_and_inspector(db, evm_env.clone(), NoOpInspector);
|
||||
let evm = evm_config.evm_with_env_and_inspector(db, evm_env.clone(), NoOpInspector {});
|
||||
|
||||
// Check that the spec ID is set properly
|
||||
assert_eq!(evm.handler.spec_id(), SpecId::PETERSBURG);
|
||||
assert_eq!(evm.context.evm.env.block, evm_env.block_env);
|
||||
assert_eq!(evm.context.evm.env.cfg, evm_env.cfg_env);
|
||||
assert_eq!(evm.context.evm.env.tx, Default::default());
|
||||
assert_eq!(evm.context.external, NoOpInspector);
|
||||
|
||||
// No Optimism
|
||||
assert_eq!(
|
||||
evm.handler.cfg,
|
||||
HandlerCfg { spec_id: SpecId::PETERSBURG, ..Default::default() }
|
||||
);
|
||||
assert_eq!(evm.block, evm_env.block_env);
|
||||
assert_eq!(evm.cfg, evm_env.cfg_env);
|
||||
assert_eq!(evm.tx, Default::default());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user