diff --git a/crates/ethereum-forks/src/forkcondition.rs b/crates/ethereum-forks/src/forkcondition.rs index e6be6a9c9a8f..e93f24ab2641 100644 --- a/crates/ethereum-forks/src/forkcondition.rs +++ b/crates/ethereum-forks/src/forkcondition.rs @@ -40,7 +40,9 @@ impl ForkCondition { /// Checks whether the fork condition is satisfied at the given block. /// - /// For TTD conditions, this will only return true if the activation block is already known. + /// This will return true if the block number is equal or greater than the activation block of: + /// - [`ForkCondition::Block`] + /// - [`ForkCondition::TTD`] /// /// For timestamp conditions, this will always return false. pub const fn active_at_block(&self, current_block: BlockNumber) -> bool { @@ -83,6 +85,11 @@ impl ForkCondition { matches!(self, Self::Timestamp(time) if timestamp >= *time && parent_timestamp < *time) } + /// Checks whether the fork condition is satisfied at the given timestamp or number. + pub const fn active_at_timestamp_or_number(&self, timestamp: u64, block_number: u64) -> bool { + self.active_at_timestamp(timestamp) || self.active_at_block(block_number) + } + /// Checks whether the fork condition is satisfied at the given head block. /// /// This will return true if: @@ -91,8 +98,7 @@ impl ForkCondition { /// - The condition is satisfied by the timestamp; /// - or the condition is satisfied by the total difficulty pub fn active_at_head(&self, head: &Head) -> bool { - self.active_at_block(head.number) || - self.active_at_timestamp(head.timestamp) || + self.active_at_timestamp_or_number(head.timestamp, head.number) || self.active_at_ttd(head.total_difficulty, head.difficulty) } diff --git a/crates/ethereum-forks/src/hardforks/ethereum.rs b/crates/ethereum-forks/src/hardforks/ethereum.rs index f43d37a7e1f1..c62c6a91a355 100644 --- a/crates/ethereum-forks/src/hardforks/ethereum.rs +++ b/crates/ethereum-forks/src/hardforks/ethereum.rs @@ -49,10 +49,10 @@ pub trait EthereumHardforks: Hardforks { /// (merge) block. fn is_paris_active_at_block(&self, block_number: u64) -> Option { match self.fork(EthereumHardfork::Paris) { - ForkCondition::Block(paris_block) => Some(block_number >= paris_block), ForkCondition::TTD { activation_block_number, .. } => { Some(block_number >= activation_block_number) } + ForkCondition::Block(paris_block) => Some(block_number >= paris_block), _ => None, } } diff --git a/crates/ethereum/evm/src/config.rs b/crates/ethereum/evm/src/config.rs index 40e024715f1f..de43400626fa 100644 --- a/crates/ethereum/evm/src/config.rs +++ b/crates/ethereum/evm/src/config.rs @@ -1,56 +1,86 @@ +use alloy_consensus::Header; use reth_chainspec::{ChainSpec, EthereumHardforks}; -use reth_ethereum_forks::{EthereumHardfork, Head}; +use reth_ethereum_forks::EthereumHardfork; -/// Returns the revm [`SpecId`](revm_primitives::SpecId) at the given timestamp. -/// -/// # Note -/// -/// This is only intended to be used after the merge, when hardforks are activated by -/// timestamp. -pub fn revm_spec_by_timestamp_after_merge( +/// 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 { + 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). +pub fn revm_spec_by_timestamp_and_block_number( chain_spec: &ChainSpec, timestamp: u64, + block_number: u64, ) -> revm_primitives::SpecId { - if chain_spec.is_osaka_active_at_timestamp(timestamp) { + if chain_spec + .fork(EthereumHardfork::Osaka) + .active_at_timestamp_or_number(timestamp, block_number) + { revm_primitives::OSAKA - } else if chain_spec.is_prague_active_at_timestamp(timestamp) { + } else if chain_spec + .fork(EthereumHardfork::Prague) + .active_at_timestamp_or_number(timestamp, block_number) + { revm_primitives::PRAGUE - } else if chain_spec.is_cancun_active_at_timestamp(timestamp) { + } else if chain_spec + .fork(EthereumHardfork::Cancun) + .active_at_timestamp_or_number(timestamp, block_number) + { revm_primitives::CANCUN - } else if chain_spec.is_shanghai_active_at_timestamp(timestamp) { + } else if chain_spec + .fork(EthereumHardfork::Shanghai) + .active_at_timestamp_or_number(timestamp, block_number) + { revm_primitives::SHANGHAI - } else { + } else if chain_spec.is_paris_active_at_block(block_number).is_some_and(|active| active) { revm_primitives::MERGE - } -} - -/// Map the latest active hardfork at the given block to a revm [`SpecId`](revm_primitives::SpecId). -pub fn revm_spec(chain_spec: &ChainSpec, block: &Head) -> revm_primitives::SpecId { - if chain_spec.fork(EthereumHardfork::Prague).active_at_head(block) { - revm_primitives::PRAGUE - } else if chain_spec.fork(EthereumHardfork::Cancun).active_at_head(block) { - revm_primitives::CANCUN - } else if chain_spec.fork(EthereumHardfork::Shanghai).active_at_head(block) { - revm_primitives::SHANGHAI - } else if chain_spec.is_paris_active_at_block(block.number).is_some_and(|active| active) { - revm_primitives::MERGE - } else if chain_spec.fork(EthereumHardfork::London).active_at_head(block) { + } else if chain_spec + .fork(EthereumHardfork::London) + .active_at_timestamp_or_number(timestamp, block_number) + { revm_primitives::LONDON - } else if chain_spec.fork(EthereumHardfork::Berlin).active_at_head(block) { + } else if chain_spec + .fork(EthereumHardfork::Berlin) + .active_at_timestamp_or_number(timestamp, block_number) + { revm_primitives::BERLIN - } else if chain_spec.fork(EthereumHardfork::Istanbul).active_at_head(block) { + } else if chain_spec + .fork(EthereumHardfork::Istanbul) + .active_at_timestamp_or_number(timestamp, block_number) + { revm_primitives::ISTANBUL - } else if chain_spec.fork(EthereumHardfork::Petersburg).active_at_head(block) { + } else if chain_spec + .fork(EthereumHardfork::Petersburg) + .active_at_timestamp_or_number(timestamp, block_number) + { revm_primitives::PETERSBURG - } else if chain_spec.fork(EthereumHardfork::Byzantium).active_at_head(block) { + } else if chain_spec + .fork(EthereumHardfork::Byzantium) + .active_at_timestamp_or_number(timestamp, block_number) + { revm_primitives::BYZANTIUM - } else if chain_spec.fork(EthereumHardfork::SpuriousDragon).active_at_head(block) { + } else if chain_spec + .fork(EthereumHardfork::SpuriousDragon) + .active_at_timestamp_or_number(timestamp, block_number) + { revm_primitives::SPURIOUS_DRAGON - } else if chain_spec.fork(EthereumHardfork::Tangerine).active_at_head(block) { + } else if chain_spec + .fork(EthereumHardfork::Tangerine) + .active_at_timestamp_or_number(timestamp, block_number) + { revm_primitives::TANGERINE - } else if chain_spec.fork(EthereumHardfork::Homestead).active_at_head(block) { + } else if chain_spec + .fork(EthereumHardfork::Homestead) + .active_at_timestamp_or_number(timestamp, block_number) + { revm_primitives::HOMESTEAD - } else if chain_spec.fork(EthereumHardfork::Frontier).active_at_head(block) { + } else if chain_spec + .fork(EthereumHardfork::Frontier) + .active_at_timestamp_or_number(timestamp, block_number) + { revm_primitives::FRONTIER } else { panic!( @@ -67,23 +97,26 @@ mod tests { use reth_chainspec::{ChainSpecBuilder, MAINNET}; #[test] - fn test_revm_spec_by_timestamp_after_merge() { + fn test_revm_spec_by_timestamp() { assert_eq!( - revm_spec_by_timestamp_after_merge( + revm_spec_by_timestamp_and_block_number( &ChainSpecBuilder::mainnet().cancun_activated().build(), + 0, 0 ), revm_primitives::CANCUN ); assert_eq!( - revm_spec_by_timestamp_after_merge( + revm_spec_by_timestamp_and_block_number( &ChainSpecBuilder::mainnet().shanghai_activated().build(), + 0, 0 ), revm_primitives::SHANGHAI ); + let mainnet = ChainSpecBuilder::mainnet().build(); assert_eq!( - revm_spec_by_timestamp_after_merge(&ChainSpecBuilder::mainnet().build(), 0), + revm_spec_by_timestamp_and_block_number(&mainnet, 0, mainnet.paris_block().unwrap()), revm_primitives::MERGE ); } @@ -91,60 +124,75 @@ mod tests { #[test] fn test_to_revm_spec() { assert_eq!( - revm_spec(&ChainSpecBuilder::mainnet().cancun_activated().build(), &Head::default()), + revm_spec(&ChainSpecBuilder::mainnet().cancun_activated().build(), &Default::default()), revm_primitives::CANCUN ); assert_eq!( - revm_spec(&ChainSpecBuilder::mainnet().shanghai_activated().build(), &Head::default()), + revm_spec( + &ChainSpecBuilder::mainnet().shanghai_activated().build(), + &Default::default() + ), revm_primitives::SHANGHAI ); assert_eq!( - revm_spec(&ChainSpecBuilder::mainnet().paris_activated().build(), &Head::default()), + revm_spec(&ChainSpecBuilder::mainnet().paris_activated().build(), &Default::default()), revm_primitives::MERGE ); assert_eq!( - revm_spec(&ChainSpecBuilder::mainnet().london_activated().build(), &Head::default()), + revm_spec(&ChainSpecBuilder::mainnet().london_activated().build(), &Default::default()), revm_primitives::LONDON ); assert_eq!( - revm_spec(&ChainSpecBuilder::mainnet().berlin_activated().build(), &Head::default()), + revm_spec(&ChainSpecBuilder::mainnet().berlin_activated().build(), &Default::default()), revm_primitives::BERLIN ); assert_eq!( - revm_spec(&ChainSpecBuilder::mainnet().istanbul_activated().build(), &Head::default()), + revm_spec( + &ChainSpecBuilder::mainnet().istanbul_activated().build(), + &Default::default() + ), revm_primitives::ISTANBUL ); assert_eq!( revm_spec( &ChainSpecBuilder::mainnet().petersburg_activated().build(), - &Head::default() + &Default::default() ), revm_primitives::PETERSBURG ); assert_eq!( - revm_spec(&ChainSpecBuilder::mainnet().byzantium_activated().build(), &Head::default()), + revm_spec( + &ChainSpecBuilder::mainnet().byzantium_activated().build(), + &Default::default() + ), revm_primitives::BYZANTIUM ); assert_eq!( revm_spec( &ChainSpecBuilder::mainnet().spurious_dragon_activated().build(), - &Head::default() + &Default::default() ), revm_primitives::SPURIOUS_DRAGON ); assert_eq!( revm_spec( &ChainSpecBuilder::mainnet().tangerine_whistle_activated().build(), - &Head::default() + &Default::default() ), revm_primitives::TANGERINE ); assert_eq!( - revm_spec(&ChainSpecBuilder::mainnet().homestead_activated().build(), &Head::default()), + revm_spec( + &ChainSpecBuilder::mainnet().homestead_activated().build(), + &Default::default() + ), revm_primitives::HOMESTEAD ); assert_eq!( - revm_spec(&ChainSpecBuilder::mainnet().frontier_activated().build(), &Head::default()), + revm_spec( + &ChainSpecBuilder::mainnet().frontier_activated().build(), + &Default::default() + ), revm_primitives::FRONTIER ); } @@ -152,60 +200,55 @@ mod tests { #[test] fn test_eth_spec() { assert_eq!( - revm_spec(&MAINNET, &Head { timestamp: 1710338135, ..Default::default() }), + revm_spec(&MAINNET, &Header { timestamp: 1710338135, ..Default::default() }), revm_primitives::CANCUN ); assert_eq!( - revm_spec(&MAINNET, &Head { timestamp: 1681338455, ..Default::default() }), + revm_spec(&MAINNET, &Header { timestamp: 1681338455, ..Default::default() }), revm_primitives::SHANGHAI ); assert_eq!( revm_spec( &MAINNET, - &Head { - total_difficulty: U256::from(58_750_000_000_000_000_000_010_u128), - difficulty: U256::from(10_u128), - number: 15537394, - ..Default::default() - } + &Header { difficulty: U256::from(10_u128), number: 15537394, ..Default::default() } ), revm_primitives::MERGE ); assert_eq!( - revm_spec(&MAINNET, &Head { number: 15537394 - 10, ..Default::default() }), + revm_spec(&MAINNET, &Header { number: 15537394 - 10, ..Default::default() }), revm_primitives::LONDON ); assert_eq!( - revm_spec(&MAINNET, &Head { number: 12244000 + 10, ..Default::default() }), + revm_spec(&MAINNET, &Header { number: 12244000 + 10, ..Default::default() }), revm_primitives::BERLIN ); assert_eq!( - revm_spec(&MAINNET, &Head { number: 12244000 - 10, ..Default::default() }), + revm_spec(&MAINNET, &Header { number: 12244000 - 10, ..Default::default() }), revm_primitives::ISTANBUL ); assert_eq!( - revm_spec(&MAINNET, &Head { number: 7280000 + 10, ..Default::default() }), + revm_spec(&MAINNET, &Header { number: 7280000 + 10, ..Default::default() }), revm_primitives::PETERSBURG ); assert_eq!( - revm_spec(&MAINNET, &Head { number: 7280000 - 10, ..Default::default() }), + revm_spec(&MAINNET, &Header { number: 7280000 - 10, ..Default::default() }), revm_primitives::BYZANTIUM ); assert_eq!( - revm_spec(&MAINNET, &Head { number: 2675000 + 10, ..Default::default() }), + revm_spec(&MAINNET, &Header { number: 2675000 + 10, ..Default::default() }), revm_primitives::SPURIOUS_DRAGON ); assert_eq!( - revm_spec(&MAINNET, &Head { number: 2675000 - 10, ..Default::default() }), + revm_spec(&MAINNET, &Header { number: 2675000 - 10, ..Default::default() }), revm_primitives::TANGERINE ); assert_eq!( - revm_spec(&MAINNET, &Head { number: 1150000 + 10, ..Default::default() }), + revm_spec(&MAINNET, &Header { number: 1150000 + 10, ..Default::default() }), revm_primitives::HOMESTEAD ); assert_eq!( - revm_spec(&MAINNET, &Head { number: 1150000 - 10, ..Default::default() }), + revm_spec(&MAINNET, &Header { number: 1150000 - 10, ..Default::default() }), revm_primitives::FRONTIER ); } diff --git a/crates/ethereum/evm/src/lib.rs b/crates/ethereum/evm/src/lib.rs index 502bb89524e3..5af8f8c024a8 100644 --- a/crates/ethereum/evm/src/lib.rs +++ b/crates/ethereum/evm/src/lib.rs @@ -20,9 +20,9 @@ extern crate alloc; use core::convert::Infallible; use alloc::{sync::Arc, vec::Vec}; -use alloy_consensus::Header; +use alloy_consensus::{BlockHeader, Header}; use alloy_primitives::{Address, Bytes, TxKind, U256}; -use reth_chainspec::{ChainSpec, Head}; +use reth_chainspec::ChainSpec; use reth_evm::{env::EvmEnv, ConfigureEvm, ConfigureEvmEnv, NextBlockEnvAttributes}; use reth_primitives::{transaction::FillTxEnv, TransactionSigned}; use revm_primitives::{ @@ -31,7 +31,7 @@ use revm_primitives::{ mod config; use alloy_eips::eip1559::INITIAL_BASE_FEE; -pub use config::{revm_spec, revm_spec_by_timestamp_after_merge}; +pub use config::{revm_spec, revm_spec_by_timestamp_and_block_number}; use reth_ethereum_forks::EthereumHardfork; pub mod execute; @@ -110,17 +110,7 @@ impl ConfigureEvmEnv for EthEvmConfig { } fn fill_cfg_env(&self, cfg_env: &mut CfgEnvWithHandlerCfg, header: &Header) { - let spec_id = config::revm_spec( - self.chain_spec(), - &Head { - number: header.number, - timestamp: header.timestamp, - difficulty: header.difficulty, - // NOTE: this does nothing within revm_spec - total_difficulty: U256::MIN, - hash: Default::default(), - }, - ); + let spec_id = config::revm_spec(self.chain_spec(), header); cfg_env.chain_id = self.chain_spec.chain().id(); cfg_env.perf_analyse_created_bytecodes = AnalysisKind::Analyse; @@ -137,7 +127,11 @@ impl ConfigureEvmEnv for EthEvmConfig { 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_after_merge(&self.chain_spec, attributes.timestamp); + let spec_id = revm_spec_by_timestamp_and_block_number( + &self.chain_spec, + attributes.timestamp, + parent.number() + 1, + ); // 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) diff --git a/crates/optimism/evm/src/config.rs b/crates/optimism/evm/src/config.rs index b32b0929424d..84775901c46d 100644 --- a/crates/optimism/evm/src/config.rs +++ b/crates/optimism/evm/src/config.rs @@ -1,7 +1,13 @@ -use reth_ethereum_forks::{EthereumHardfork, Head}; +use alloy_consensus::Header; use reth_optimism_chainspec::OpChainSpec; use reth_optimism_forks::OpHardfork; +/// Map the latest active hardfork at the given header to a revm +/// [`SpecId`](revm_primitives::SpecId). +pub fn revm_spec(chain_spec: &OpChainSpec, header: &Header) -> revm_primitives::SpecId { + revm_spec_by_timestamp_after_bedrock(chain_spec, header.timestamp) +} + /// Returns the revm [`SpecId`](revm_primitives::SpecId) at the given timestamp. /// /// # Note @@ -31,58 +37,6 @@ pub fn revm_spec_by_timestamp_after_bedrock( } } -/// Map the latest active hardfork at the given block to a revm [`SpecId`](revm_primitives::SpecId). -pub fn revm_spec(chain_spec: &OpChainSpec, block: &Head) -> revm_primitives::SpecId { - if chain_spec.fork(OpHardfork::Isthmus).active_at_head(block) { - todo!() - } else if chain_spec.fork(OpHardfork::Holocene).active_at_head(block) { - revm_primitives::HOLOCENE - } else if chain_spec.fork(OpHardfork::Granite).active_at_head(block) { - revm_primitives::GRANITE - } else if chain_spec.fork(OpHardfork::Fjord).active_at_head(block) { - revm_primitives::FJORD - } else if chain_spec.fork(OpHardfork::Ecotone).active_at_head(block) { - revm_primitives::ECOTONE - } else if chain_spec.fork(OpHardfork::Canyon).active_at_head(block) { - revm_primitives::CANYON - } else if chain_spec.fork(OpHardfork::Regolith).active_at_head(block) { - revm_primitives::REGOLITH - } else if chain_spec.fork(OpHardfork::Bedrock).active_at_head(block) { - revm_primitives::BEDROCK - } else if chain_spec.fork(EthereumHardfork::Prague).active_at_head(block) { - revm_primitives::PRAGUE - } else if chain_spec.fork(EthereumHardfork::Cancun).active_at_head(block) { - revm_primitives::CANCUN - } else if chain_spec.fork(EthereumHardfork::Shanghai).active_at_head(block) { - revm_primitives::SHANGHAI - } else if chain_spec.fork(EthereumHardfork::Paris).active_at_head(block) { - revm_primitives::MERGE - } else if chain_spec.fork(EthereumHardfork::London).active_at_head(block) { - revm_primitives::LONDON - } else if chain_spec.fork(EthereumHardfork::Berlin).active_at_head(block) { - revm_primitives::BERLIN - } else if chain_spec.fork(EthereumHardfork::Istanbul).active_at_head(block) { - revm_primitives::ISTANBUL - } else if chain_spec.fork(EthereumHardfork::Petersburg).active_at_head(block) { - revm_primitives::PETERSBURG - } else if chain_spec.fork(EthereumHardfork::Byzantium).active_at_head(block) { - revm_primitives::BYZANTIUM - } else if chain_spec.fork(EthereumHardfork::SpuriousDragon).active_at_head(block) { - revm_primitives::SPURIOUS_DRAGON - } else if chain_spec.fork(EthereumHardfork::Tangerine).active_at_head(block) { - revm_primitives::TANGERINE - } else if chain_spec.fork(EthereumHardfork::Homestead).active_at_head(block) { - revm_primitives::HOMESTEAD - } else if chain_spec.fork(EthereumHardfork::Frontier).active_at_head(block) { - revm_primitives::FRONTIER - } else { - panic!( - "invalid hardfork chainspec: expected at least one hardfork, got {:?}", - chain_spec.hardforks - ) - } -} - #[cfg(test)] mod tests { use super::*; @@ -134,31 +88,31 @@ mod tests { f(cs).build() } assert_eq!( - revm_spec(&op_cs(|cs| cs.holocene_activated()), &Head::default()), + revm_spec(&op_cs(|cs| cs.holocene_activated()), &Default::default()), revm_primitives::HOLOCENE ); assert_eq!( - revm_spec(&op_cs(|cs| cs.granite_activated()), &Head::default()), + revm_spec(&op_cs(|cs| cs.granite_activated()), &Default::default()), revm_primitives::GRANITE ); assert_eq!( - revm_spec(&op_cs(|cs| cs.fjord_activated()), &Head::default()), + revm_spec(&op_cs(|cs| cs.fjord_activated()), &Default::default()), revm_primitives::FJORD ); assert_eq!( - revm_spec(&op_cs(|cs| cs.ecotone_activated()), &Head::default()), + revm_spec(&op_cs(|cs| cs.ecotone_activated()), &Default::default()), revm_primitives::ECOTONE ); assert_eq!( - revm_spec(&op_cs(|cs| cs.canyon_activated()), &Head::default()), + revm_spec(&op_cs(|cs| cs.canyon_activated()), &Default::default()), revm_primitives::CANYON ); assert_eq!( - revm_spec(&op_cs(|cs| cs.bedrock_activated()), &Head::default()), + revm_spec(&op_cs(|cs| cs.bedrock_activated()), &Default::default()), revm_primitives::BEDROCK ); assert_eq!( - revm_spec(&op_cs(|cs| cs.regolith_activated()), &Head::default()), + revm_spec(&op_cs(|cs| cs.regolith_activated()), &Default::default()), revm_primitives::REGOLITH ); } diff --git a/crates/optimism/evm/src/lib.rs b/crates/optimism/evm/src/lib.rs index 9bfa5fd8634f..6b367b8f3e7f 100644 --- a/crates/optimism/evm/src/lib.rs +++ b/crates/optimism/evm/src/lib.rs @@ -18,7 +18,7 @@ use alloy_primitives::{Address, U256}; use op_alloy_consensus::EIP1559ParamError; use reth_evm::{env::EvmEnv, ConfigureEvm, ConfigureEvmEnv, NextBlockEnvAttributes}; use reth_optimism_chainspec::OpChainSpec; -use reth_primitives::{transaction::FillTxEnv, Head, TransactionSigned}; +use reth_primitives::{transaction::FillTxEnv, TransactionSigned}; use reth_revm::{ inspector_handle_register, primitives::{AnalysisKind, CfgEnvWithHandlerCfg, TxEnv}, @@ -111,18 +111,7 @@ impl ConfigureEvmEnv for OpEvmConfig { } fn fill_cfg_env(&self, cfg_env: &mut CfgEnvWithHandlerCfg, header: &Self::Header) { - let spec_id = revm_spec( - self.chain_spec(), - &Head { - number: header.number, - timestamp: header.timestamp, - difficulty: header.difficulty, - // NOTE: this does not matter within revm_spec as it uses paris hardfork block - // activation - total_difficulty: U256::MIN, - hash: Default::default(), - }, - ); + let spec_id = revm_spec(self.chain_spec(), header); cfg_env.chain_id = self.chain_spec.chain().id(); cfg_env.perf_analyse_created_bytecodes = AnalysisKind::Analyse;