diff --git a/Cargo.lock b/Cargo.lock index b580a68e6..f4c97a3da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7083,9 +7083,13 @@ dependencies = [ "alloy-primitives", "alloy-rlp", "arbitrary", + "auto_impl", "crc", + "dyn-clone", + "once_cell", "proptest", "proptest-derive 0.5.0", + "rustc-hash 2.0.0", "serde", "thiserror-no-std", ] diff --git a/crates/blockchain-tree/src/blockchain_tree.rs b/crates/blockchain-tree/src/blockchain_tree.rs index 5d73a1a78..66ed04478 100644 --- a/crates/blockchain-tree/src/blockchain_tree.rs +++ b/crates/blockchain-tree/src/blockchain_tree.rs @@ -15,8 +15,8 @@ use reth_evm::execute::BlockExecutorProvider; use reth_execution_errors::{BlockExecutionError, BlockValidationError}; use reth_execution_types::{Chain, ExecutionOutcome}; use reth_primitives::{ - BlockHash, BlockNumHash, BlockNumber, ForkBlock, GotExpected, Hardfork, Receipt, SealedBlock, - SealedBlockWithSenders, SealedHeader, StaticFileSegment, B256, U256, + BlockHash, BlockNumHash, BlockNumber, EthereumHardfork, ForkBlock, GotExpected, Receipt, + SealedBlock, SealedBlockWithSenders, SealedHeader, StaticFileSegment, B256, U256, }; use reth_provider::{ BlockExecutionWriter, BlockNumReader, BlockWriter, CanonStateNotification, @@ -402,7 +402,7 @@ where .externals .provider_factory .chain_spec() - .fork(Hardfork::Paris) + .fork(EthereumHardfork::Paris) .active_at_ttd(parent_td, U256::ZERO) { return Err(BlockExecutionError::Validation(BlockValidationError::BlockPreMerge { @@ -1043,7 +1043,7 @@ where .externals .provider_factory .chain_spec() - .fork(Hardfork::Paris) + .fork(EthereumHardfork::Paris) .active_at_ttd(td, U256::ZERO) { return Err(CanonicalError::from(BlockValidationError::BlockPreMerge { diff --git a/crates/chainspec/src/spec.rs b/crates/chainspec/src/spec.rs index 4d53352dc..81e759772 100644 --- a/crates/chainspec/src/spec.rs +++ b/crates/chainspec/src/spec.rs @@ -14,8 +14,8 @@ use alloy_trie::EMPTY_ROOT_HASH; use derive_more::From; use once_cell::sync::Lazy; use reth_ethereum_forks::{ - chains::ethereum::{GOERLI_HARDFORKS, HOLESKY_HARDFORKS, MAINNET_HARDFORKS, SEPOLIA_HARDFORKS}, - DisplayHardforks, ForkCondition, ForkFilter, ForkFilterKey, ForkHash, ForkId, Hardfork, Head, + ChainHardforks, DisplayHardforks, EthereumHardfork, EthereumHardforks, ForkCondition, + ForkFilter, ForkFilterKey, ForkHash, ForkId, Hardfork, Head, DEV_HARDFORKS, }; use reth_network_peers::NodeRecord; use reth_primitives_traits::{ @@ -27,7 +27,7 @@ use reth_primitives_traits::{ }; use reth_trie_common::root::state_root_ref_unhashed; #[cfg(feature = "std")] -use std::{collections::BTreeMap, sync::Arc}; +use std::sync::Arc; #[cfg(feature = "optimism")] use crate::constants::optimism::{ @@ -36,7 +36,7 @@ use crate::constants::optimism::{ }; pub use alloy_eips::eip1559::BaseFeeParams; #[cfg(feature = "optimism")] -use reth_ethereum_forks::chains::optimism::*; +use reth_ethereum_forks::OptimismHardfork; #[cfg(feature = "optimism")] use crate::net::{base_nodes, base_testnet_nodes, op_nodes, op_testnet_nodes}; @@ -56,7 +56,7 @@ pub static MAINNET: Lazy> = Lazy::new(|| { 15537394, U256::from(58_750_003_716_598_352_816_469u128), )), - hardforks: MAINNET_HARDFORKS.into(), + hardforks: EthereumHardfork::mainnet().into(), // https://etherscan.io/tx/0xe75fb554e433e03763a1560646ee22dcb74e5274b34c5ad644e7c0f619a7e1d0 deposit_contract: Some(DepositContract::new( address!("00000000219ab540356cbb839cbe05303d7705fa"), @@ -80,7 +80,7 @@ pub static GOERLI: Lazy> = Lazy::new(|| { )), // paris_block_and_final_difficulty: Some((7382818, U256::from(10_790_000))), - hardforks: GOERLI_HARDFORKS.into(), + hardforks: EthereumHardfork::goerli().into(), // https://goerli.etherscan.io/tx/0xa3c07dc59bfdb1bfc2d50920fed2ef2c1c4e0a09fe2325dbc14e07702f965a78 deposit_contract: Some(DepositContract::new( address!("ff50ed3d0ec03ac01d4c79aad74928bff48a7b2b"), @@ -104,7 +104,7 @@ pub static SEPOLIA: Lazy> = Lazy::new(|| { )), // paris_block_and_final_difficulty: Some((1450409, U256::from(17_000_018_015_853_232u128))), - hardforks: SEPOLIA_HARDFORKS.into(), + hardforks: EthereumHardfork::sepolia().into(), // https://sepolia.etherscan.io/tx/0x025ecbf81a2f1220da6285d1701dc89fb5a956b62562ee922e1a9efd73eb4b14 deposit_contract: Some(DepositContract::new( address!("7f02c3e3c98b133055b8b348b2ac625669ed295d"), @@ -127,7 +127,7 @@ pub static HOLESKY: Lazy> = Lazy::new(|| { "b5f7f912443c940f21fd611f12828d75b534364ed9e95ca4e307729a4661bde4" )), paris_block_and_final_difficulty: Some((0, U256::from(1))), - hardforks: HOLESKY_HARDFORKS.into(), + hardforks: EthereumHardfork::holesky().into(), deposit_contract: Some(DepositContract::new( address!("4242424242424242424242424242424242424242"), 0, @@ -152,32 +152,7 @@ pub static DEV: Lazy> = Lazy::new(|| { "2f980576711e3617a5e4d83dd539548ec0f7792007d505a3d2e9674833af2d7c" )), paris_block_and_final_difficulty: Some((0, U256::from(0))), - hardforks: BTreeMap::from([ - (Hardfork::Frontier, ForkCondition::Block(0)), - (Hardfork::Homestead, ForkCondition::Block(0)), - (Hardfork::Dao, ForkCondition::Block(0)), - (Hardfork::Tangerine, ForkCondition::Block(0)), - (Hardfork::SpuriousDragon, ForkCondition::Block(0)), - (Hardfork::Byzantium, ForkCondition::Block(0)), - (Hardfork::Constantinople, ForkCondition::Block(0)), - (Hardfork::Petersburg, ForkCondition::Block(0)), - (Hardfork::Istanbul, ForkCondition::Block(0)), - (Hardfork::MuirGlacier, ForkCondition::Block(0)), - (Hardfork::Berlin, ForkCondition::Block(0)), - (Hardfork::London, ForkCondition::Block(0)), - ( - Hardfork::Paris, - ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::from(0) }, - ), - (Hardfork::Shanghai, ForkCondition::Timestamp(0)), - (Hardfork::Cancun, ForkCondition::Timestamp(0)), - #[cfg(feature = "optimism")] - (Hardfork::Regolith, ForkCondition::Timestamp(0)), - #[cfg(feature = "optimism")] - (Hardfork::Bedrock, ForkCondition::Block(0)), - #[cfg(feature = "optimism")] - (Hardfork::Ecotone, ForkCondition::Timestamp(0)), - ]), + hardforks: DEV_HARDFORKS.clone(), base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()), deposit_contract: None, // TODO: do we even have? ..Default::default() @@ -198,11 +173,11 @@ pub static OP_MAINNET: Lazy> = Lazy::new(|| { "7ca38a1916c42007829c55e69d3e9a73265554b586a499015373241b8a3fa48b" )), paris_block_and_final_difficulty: Some((0, U256::from(0))), - hardforks: OP_MAINNET_HARDFORKS.into(), + hardforks: OptimismHardfork::op_mainnet(), base_fee_params: BaseFeeParamsKind::Variable( vec![ - (Hardfork::London, OP_BASE_FEE_PARAMS), - (Hardfork::Canyon, OP_CANYON_BASE_FEE_PARAMS), + (EthereumHardfork::London.boxed(), OP_BASE_FEE_PARAMS), + (OptimismHardfork::Canyon.boxed(), OP_CANYON_BASE_FEE_PARAMS), ] .into(), ), @@ -223,11 +198,11 @@ pub static OP_SEPOLIA: Lazy> = Lazy::new(|| { "102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d" )), paris_block_and_final_difficulty: Some((0, U256::from(0))), - hardforks: OP_SEPOLIA_HARDFORKS.into(), + hardforks: OptimismHardfork::op_sepolia(), base_fee_params: BaseFeeParamsKind::Variable( vec![ - (Hardfork::London, OP_SEPOLIA_BASE_FEE_PARAMS), - (Hardfork::Canyon, OP_SEPOLIA_CANYON_BASE_FEE_PARAMS), + (EthereumHardfork::London.boxed(), OP_SEPOLIA_BASE_FEE_PARAMS), + (OptimismHardfork::Canyon.boxed(), OP_SEPOLIA_CANYON_BASE_FEE_PARAMS), ] .into(), ), @@ -248,11 +223,11 @@ pub static BASE_SEPOLIA: Lazy> = Lazy::new(|| { "0dcc9e089e30b90ddfc55be9a37dd15bc551aeee999d2e2b51414c54eaf934e4" )), paris_block_and_final_difficulty: Some((0, U256::from(0))), - hardforks: BASE_SEPOLIA_HARDFORKS.into(), + hardforks: OptimismHardfork::base_sepolia(), base_fee_params: BaseFeeParamsKind::Variable( vec![ - (Hardfork::London, BASE_SEPOLIA_BASE_FEE_PARAMS), - (Hardfork::Canyon, BASE_SEPOLIA_CANYON_BASE_FEE_PARAMS), + (EthereumHardfork::London.boxed(), BASE_SEPOLIA_BASE_FEE_PARAMS), + (OptimismHardfork::Canyon.boxed(), BASE_SEPOLIA_CANYON_BASE_FEE_PARAMS), ] .into(), ), @@ -273,11 +248,11 @@ pub static BASE_MAINNET: Lazy> = Lazy::new(|| { "f712aa9241cc24369b143cf6dce85f0902a9731e70d66818a3a5845b296c73dd" )), paris_block_and_final_difficulty: Some((0, U256::from(0))), - hardforks: BASE_MAINNET_HARDFORKS.into(), + hardforks: OptimismHardfork::base_mainnet(), base_fee_params: BaseFeeParamsKind::Variable( vec![ - (Hardfork::London, OP_BASE_FEE_PARAMS), - (Hardfork::Canyon, OP_CANYON_BASE_FEE_PARAMS), + (EthereumHardfork::London.boxed(), OP_BASE_FEE_PARAMS), + (OptimismHardfork::Canyon.boxed(), OP_CANYON_BASE_FEE_PARAMS), ] .into(), ), @@ -319,7 +294,15 @@ impl From for BaseFeeParamsKind { /// A type alias to a vector of tuples of [Hardfork] and [`BaseFeeParams`], sorted by [Hardfork] /// activation order. This is used to specify dynamic EIP-1559 parameters for chains like Optimism. #[derive(Clone, Debug, PartialEq, Eq, From)] -pub struct ForkBaseFeeParams(Vec<(Hardfork, BaseFeeParams)>); +pub struct ForkBaseFeeParams(Vec<(Box, BaseFeeParams)>); + +impl std::ops::Deref for ChainSpec { + type Target = ChainHardforks; + + fn deref(&self) -> &Self::Target { + &self.hardforks + } +} /// An Ethereum chain specification. /// @@ -342,12 +325,12 @@ pub struct ChainSpec { /// The genesis block pub genesis: Genesis, - /// The block at which [`Hardfork::Paris`] was activated and the final difficulty at this - /// block. + /// The block at which [`EthereumHardfork::Paris`] was activated and the final difficulty at + /// this block. pub paris_block_and_final_difficulty: Option<(u64, U256)>, /// The active hard forks and their activation conditions - pub hardforks: BTreeMap, + pub hardforks: ChainHardforks, /// The deposit contract deployed for `PoS` pub deposit_contract: Option, @@ -404,7 +387,7 @@ impl ChainSpec { #[inline] #[cfg(feature = "optimism")] pub fn is_optimism(&self) -> bool { - self.chain.is_optimism() || self.hardforks.contains_key(&Hardfork::Bedrock) + self.chain.is_optimism() || self.hardforks.get(OptimismHardfork::Bedrock).is_some() } /// Returns `true` if this chain contains Optimism configuration. @@ -435,7 +418,7 @@ impl ChainSpec { // If shanghai is activated, initialize the header with an empty withdrawals hash, and // empty withdrawals list. let withdrawals_root = self - .fork(Hardfork::Shanghai) + .fork(EthereumHardfork::Shanghai) .active_at_timestamp(self.genesis.timestamp) .then_some(EMPTY_WITHDRAWALS); @@ -496,7 +479,7 @@ impl ChainSpec { self.genesis.base_fee_per_gas.map(|fee| fee as u64).unwrap_or(EIP1559_INITIAL_BASE_FEE); // If London is activated at genesis, we set the initial base fee as per EIP-1559. - self.fork(Hardfork::London).active_at_block(0).then_some(genesis_base_fee) + self.hardforks.fork(EthereumHardfork::London).active_at_block(0).then_some(genesis_base_fee) } /// Get the [`BaseFeeParams`] for the chain at the given timestamp. @@ -508,7 +491,7 @@ impl ChainSpec { // first one that corresponds to a hardfork that is active at the // given timestamp. for (fork, params) in bf_params.iter().rev() { - if self.is_fork_active_at_timestamp(*fork, timestamp) { + if self.hardforks.is_fork_active_at_timestamp(fork.clone(), timestamp) { return *params } } @@ -527,7 +510,7 @@ impl ChainSpec { // first one that corresponds to a hardfork that is active at the // given timestamp. for (fork, params) in bf_params.iter().rev() { - if self.is_fork_active_at_block(*fork, block_number) { + if self.hardforks.is_fork_active_at_block(fork.clone(), block_number) { return *params } } @@ -564,130 +547,55 @@ impl ChainSpec { } /// Get the fork filter for the given hardfork - pub fn hardfork_fork_filter(&self, fork: Hardfork) -> Option { - match self.fork(fork) { + pub fn hardfork_fork_filter(&self, fork: H) -> Option { + match self.hardforks.fork(fork.clone()) { ForkCondition::Never => None, - _ => Some(self.fork_filter(self.satisfy(self.fork(fork)))), + _ => Some(self.fork_filter(self.satisfy(self.hardforks.fork(fork)))), } } - /// Returns the forks in this specification and their activation conditions. - pub const fn hardforks(&self) -> &BTreeMap { - &self.hardforks - } - /// Returns the hardfork display helper. pub fn display_hardforks(&self) -> DisplayHardforks { DisplayHardforks::new( - self.hardforks(), + &self.hardforks, self.paris_block_and_final_difficulty.map(|(block, _)| block), ) } /// Get the fork id for the given hardfork. #[inline] - pub fn hardfork_fork_id(&self, fork: Hardfork) -> Option { - match self.fork(fork) { + pub fn hardfork_fork_id(&self, fork: H) -> Option { + let condition = self.hardforks.fork(fork); + match condition { ForkCondition::Never => None, - _ => Some(self.fork_id(&self.satisfy(self.fork(fork)))), + _ => Some(self.fork_id(&self.satisfy(condition))), } } - /// Convenience method to get the fork id for [`Hardfork::Shanghai`] from a given chainspec. + /// Convenience method to get the fork id for [`EthereumHardfork::Shanghai`] from a given + /// chainspec. #[inline] pub fn shanghai_fork_id(&self) -> Option { - self.hardfork_fork_id(Hardfork::Shanghai) + self.hardfork_fork_id(EthereumHardfork::Shanghai) } - /// Convenience method to get the fork id for [`Hardfork::Cancun`] from a given chainspec. + /// Convenience method to get the fork id for [`EthereumHardfork::Cancun`] from a given + /// chainspec. #[inline] pub fn cancun_fork_id(&self) -> Option { - self.hardfork_fork_id(Hardfork::Cancun) + self.hardfork_fork_id(EthereumHardfork::Cancun) } /// Convenience method to get the latest fork id from the chainspec. Panics if chainspec has no /// hardforks. #[inline] pub fn latest_fork_id(&self) -> ForkId { - self.hardfork_fork_id(*self.hardforks().last_key_value().unwrap().0).unwrap() - } - - /// Get the fork condition for the given fork. - pub fn fork(&self, fork: Hardfork) -> ForkCondition { - self.hardforks.get(&fork).copied().unwrap_or(ForkCondition::Never) - } - - /// Get an iterator of all hardforks with their respective activation conditions. - pub fn forks_iter(&self) -> impl Iterator + '_ { - self.hardforks.iter().map(|(f, b)| (*f, *b)) - } - - /// Convenience method to check if a fork is active at a given timestamp. - #[inline] - pub fn is_fork_active_at_timestamp(&self, fork: Hardfork, timestamp: u64) -> bool { - self.fork(fork).active_at_timestamp(timestamp) - } - - /// Convenience method to check if a fork is active at a given block number - #[inline] - pub fn is_fork_active_at_block(&self, fork: Hardfork, block_number: u64) -> bool { - self.fork(fork).active_at_block(block_number) - } - - /// Convenience method to check if [`Hardfork::Shanghai`] is active at a given timestamp. - #[inline] - pub fn is_shanghai_active_at_timestamp(&self, timestamp: u64) -> bool { - self.is_fork_active_at_timestamp(Hardfork::Shanghai, timestamp) - } - - /// Convenience method to check if [`Hardfork::Cancun`] is active at a given timestamp. - #[inline] - pub fn is_cancun_active_at_timestamp(&self, timestamp: u64) -> bool { - self.is_fork_active_at_timestamp(Hardfork::Cancun, timestamp) - } - - /// Convenience method to check if [`Hardfork::Prague`] is active at a given timestamp. - #[inline] - pub fn is_prague_active_at_timestamp(&self, timestamp: u64) -> bool { - self.is_fork_active_at_timestamp(Hardfork::Prague, timestamp) - } - - /// Convenience method to check if [`Hardfork::Byzantium`] is active at a given block number. - #[inline] - pub fn is_byzantium_active_at_block(&self, block_number: u64) -> bool { - self.fork(Hardfork::Byzantium).active_at_block(block_number) - } - - /// Convenience method to check if [`Hardfork::SpuriousDragon`] is active at a given block - /// number. - #[inline] - pub fn is_spurious_dragon_active_at_block(&self, block_number: u64) -> bool { - self.fork(Hardfork::SpuriousDragon).active_at_block(block_number) - } - - /// Convenience method to check if [`Hardfork::Homestead`] is active at a given block number. - #[inline] - pub fn is_homestead_active_at_block(&self, block_number: u64) -> bool { - self.fork(Hardfork::Homestead).active_at_block(block_number) - } - - /// The Paris hardfork (merge) is activated via block number. If we have knowledge of the block, - /// this function will return true if the block number is greater than or equal to the Paris - /// (merge) block. - pub fn is_paris_active_at_block(&self, block_number: u64) -> Option { - self.paris_block_and_final_difficulty.map(|(paris_block, _)| block_number >= paris_block) - } - - /// Convenience method to check if [`Hardfork::Bedrock`] is active at a given block number. - #[cfg(feature = "optimism")] - #[inline] - pub fn is_bedrock_active_at_block(&self, block_number: u64) -> bool { - self.fork(Hardfork::Bedrock).active_at_block(block_number) + self.hardfork_fork_id(self.hardforks.last().unwrap().0).unwrap() } /// Creates a [`ForkFilter`] for the block described by [Head]. pub fn fork_filter(&self, head: Head) -> ForkFilter { - let forks = self.forks_iter().filter_map(|(_, condition)| { + let forks = self.hardforks.forks_iter().filter_map(|(_, condition)| { // We filter out TTD-based forks w/o a pre-known block since those do not show up in the // fork filter. Some(match condition { @@ -707,7 +615,7 @@ impl ChainSpec { let mut current_applied = 0; // handle all block forks before handling timestamp based forks. see: https://eips.ethereum.org/EIPS/eip-6122 - for (_, cond) in self.forks_iter() { + for (_, cond) in self.hardforks.forks_iter() { // handle block based forks and the sepolia merge netsplit block edge case (TTD // ForkCondition with Some(block)) if let ForkCondition::Block(block) | @@ -729,7 +637,7 @@ impl ChainSpec { // timestamp are ALWAYS applied after the merge. // // this filter ensures that no block-based forks are returned - for timestamp in self.forks_iter().filter_map(|(_, cond)| { + for timestamp in self.hardforks.forks_iter().filter_map(|(_, cond)| { cond.as_timestamp().filter(|time| time > &self.genesis.timestamp) }) { let cond = ForkCondition::Timestamp(timestamp); @@ -773,7 +681,7 @@ impl ChainSpec { /// /// Note: this returns None if the `ChainSpec` is not configured with a TTD/Timestamp fork. pub(crate) fn last_block_fork_before_merge_or_timestamp(&self) -> Option { - let mut hardforks_iter = self.forks_iter().peekable(); + let mut hardforks_iter = self.hardforks.forks_iter().peekable(); while let Some((_, curr_cond)) = hardforks_iter.next() { if let Some((_, next_cond)) = hardforks_iter.peek() { // peek and find the first occurrence of ForkCondition::TTD (merge) , or in @@ -839,37 +747,37 @@ impl From for ChainSpec { // Block-based hardforks let hardfork_opts = [ - (Hardfork::Homestead, genesis.config.homestead_block), - (Hardfork::Dao, genesis.config.dao_fork_block), - (Hardfork::Tangerine, genesis.config.eip150_block), - (Hardfork::SpuriousDragon, genesis.config.eip155_block), - (Hardfork::Byzantium, genesis.config.byzantium_block), - (Hardfork::Constantinople, genesis.config.constantinople_block), - (Hardfork::Petersburg, genesis.config.petersburg_block), - (Hardfork::Istanbul, genesis.config.istanbul_block), - (Hardfork::MuirGlacier, genesis.config.muir_glacier_block), - (Hardfork::Berlin, genesis.config.berlin_block), - (Hardfork::London, genesis.config.london_block), - (Hardfork::ArrowGlacier, genesis.config.arrow_glacier_block), - (Hardfork::GrayGlacier, genesis.config.gray_glacier_block), + (EthereumHardfork::Homestead.boxed(), genesis.config.homestead_block), + (EthereumHardfork::Dao.boxed(), genesis.config.dao_fork_block), + (EthereumHardfork::Tangerine.boxed(), genesis.config.eip150_block), + (EthereumHardfork::SpuriousDragon.boxed(), genesis.config.eip155_block), + (EthereumHardfork::Byzantium.boxed(), genesis.config.byzantium_block), + (EthereumHardfork::Constantinople.boxed(), genesis.config.constantinople_block), + (EthereumHardfork::Petersburg.boxed(), genesis.config.petersburg_block), + (EthereumHardfork::Istanbul.boxed(), genesis.config.istanbul_block), + (EthereumHardfork::MuirGlacier.boxed(), genesis.config.muir_glacier_block), + (EthereumHardfork::Berlin.boxed(), genesis.config.berlin_block), + (EthereumHardfork::London.boxed(), genesis.config.london_block), + (EthereumHardfork::ArrowGlacier.boxed(), genesis.config.arrow_glacier_block), + (EthereumHardfork::GrayGlacier.boxed(), genesis.config.gray_glacier_block), #[cfg(feature = "optimism")] - (Hardfork::Bedrock, optimism_genesis_info.bedrock_block), + (OptimismHardfork::Bedrock.boxed(), optimism_genesis_info.bedrock_block), ]; let mut hardforks = hardfork_opts - .iter() - .filter_map(|(hardfork, opt)| opt.map(|block| (*hardfork, ForkCondition::Block(block)))) - .collect::>(); + .into_iter() + .filter_map(|(hardfork, opt)| opt.map(|block| (hardfork, ForkCondition::Block(block)))) + .collect::>(); // Paris let paris_block_and_final_difficulty = if let Some(ttd) = genesis.config.terminal_total_difficulty { - hardforks.insert( - Hardfork::Paris, + hardforks.push(( + EthereumHardfork::Paris.boxed(), ForkCondition::TTD { total_difficulty: ttd, fork_block: genesis.config.merge_netsplit_block, }, - ); + )); genesis.config.merge_netsplit_block.map(|block| (block, ttd)) } else { @@ -878,28 +786,45 @@ impl From for ChainSpec { // Time-based hardforks let time_hardfork_opts = [ - (Hardfork::Shanghai, genesis.config.shanghai_time), - (Hardfork::Cancun, genesis.config.cancun_time), - (Hardfork::Prague, genesis.config.prague_time), + (EthereumHardfork::Shanghai.boxed(), genesis.config.shanghai_time), + (EthereumHardfork::Cancun.boxed(), genesis.config.cancun_time), + (EthereumHardfork::Prague.boxed(), genesis.config.prague_time), #[cfg(feature = "optimism")] - (Hardfork::Regolith, optimism_genesis_info.regolith_time), + (OptimismHardfork::Regolith.boxed(), optimism_genesis_info.regolith_time), #[cfg(feature = "optimism")] - (Hardfork::Canyon, optimism_genesis_info.canyon_time), + (OptimismHardfork::Canyon.boxed(), optimism_genesis_info.canyon_time), #[cfg(feature = "optimism")] - (Hardfork::Ecotone, optimism_genesis_info.ecotone_time), + (OptimismHardfork::Ecotone.boxed(), optimism_genesis_info.ecotone_time), #[cfg(feature = "optimism")] - (Hardfork::Fjord, optimism_genesis_info.fjord_time), + (OptimismHardfork::Fjord.boxed(), optimism_genesis_info.fjord_time), ]; let time_hardforks = time_hardfork_opts - .iter() + .into_iter() .filter_map(|(hardfork, opt)| { - opt.map(|time| (*hardfork, ForkCondition::Timestamp(time))) + opt.map(|time| (hardfork, ForkCondition::Timestamp(time))) }) - .collect::>(); + .collect::>(); hardforks.extend(time_hardforks); + // Uses ethereum or optimism main chains to find proper order + #[cfg(not(feature = "optimism"))] + let mainnet_hardforks: ChainHardforks = EthereumHardfork::mainnet().into(); + #[cfg(not(feature = "optimism"))] + let mainnet_order = mainnet_hardforks.forks_iter(); + #[cfg(feature = "optimism")] + let mainnet_hardforks = OptimismHardfork::op_mainnet(); + #[cfg(feature = "optimism")] + let mainnet_order = mainnet_hardforks.forks_iter(); + + let mut ordered_hardforks = Vec::with_capacity(hardforks.len()); + for (hardfork, _) in mainnet_order { + if let Some(pos) = hardforks.iter().position(|(e, _)| **e == *hardfork) { + ordered_hardforks.push(hardforks[pos].clone()); + } + } + // NOTE: in full node, we prune all receipts except the deposit contract's. We do not // have the deployment block in the genesis file, so we use block zero. We use the same // deposit topic as the mainnet contract if we have the deposit contract address in the @@ -912,7 +837,7 @@ impl From for ChainSpec { chain: genesis.config.chain_id.into(), genesis, genesis_hash: None, - hardforks, + hardforks: ChainHardforks::new(hardforks), paris_block_and_final_difficulty, deposit_contract, #[cfg(feature = "optimism")] @@ -927,7 +852,7 @@ impl From for ChainSpec { pub struct ChainSpecBuilder { chain: Option, genesis: Option, - hardforks: BTreeMap, + hardforks: ChainHardforks, } impl ChainSpecBuilder { @@ -939,7 +864,9 @@ impl ChainSpecBuilder { hardforks: MAINNET.hardforks.clone(), } } +} +impl ChainSpecBuilder { /// Set the chain ID pub const fn chain(mut self, chain: Chain) -> Self { self.chain = Some(chain); @@ -953,14 +880,14 @@ impl ChainSpecBuilder { } /// Add the given fork with the given activation condition to the spec. - pub fn with_fork(mut self, fork: Hardfork, condition: ForkCondition) -> Self { + pub fn with_fork(mut self, fork: EthereumHardfork, condition: ForkCondition) -> Self { self.hardforks.insert(fork, condition); self } /// Remove the given fork from the spec. - pub fn without_fork(mut self, fork: Hardfork) -> Self { - self.hardforks.remove(&fork); + pub fn without_fork(mut self, fork: EthereumHardfork) -> Self { + self.hardforks.remove(fork); self } @@ -969,77 +896,77 @@ impl ChainSpecBuilder { /// Does not set the merge netsplit block. pub fn paris_at_ttd(self, ttd: U256) -> Self { self.with_fork( - Hardfork::Paris, + EthereumHardfork::Paris, ForkCondition::TTD { total_difficulty: ttd, fork_block: None }, ) } /// Enable Frontier at genesis. pub fn frontier_activated(mut self) -> Self { - self.hardforks.insert(Hardfork::Frontier, ForkCondition::Block(0)); + self.hardforks.insert(EthereumHardfork::Frontier, ForkCondition::Block(0)); self } /// Enable Homestead at genesis. pub fn homestead_activated(mut self) -> Self { self = self.frontier_activated(); - self.hardforks.insert(Hardfork::Homestead, ForkCondition::Block(0)); + self.hardforks.insert(EthereumHardfork::Homestead, ForkCondition::Block(0)); self } /// Enable Tangerine at genesis. pub fn tangerine_whistle_activated(mut self) -> Self { self = self.homestead_activated(); - self.hardforks.insert(Hardfork::Tangerine, ForkCondition::Block(0)); + self.hardforks.insert(EthereumHardfork::Tangerine, ForkCondition::Block(0)); self } /// Enable Spurious Dragon at genesis. pub fn spurious_dragon_activated(mut self) -> Self { self = self.tangerine_whistle_activated(); - self.hardforks.insert(Hardfork::SpuriousDragon, ForkCondition::Block(0)); + self.hardforks.insert(EthereumHardfork::SpuriousDragon, ForkCondition::Block(0)); self } /// Enable Byzantium at genesis. pub fn byzantium_activated(mut self) -> Self { self = self.spurious_dragon_activated(); - self.hardforks.insert(Hardfork::Byzantium, ForkCondition::Block(0)); + self.hardforks.insert(EthereumHardfork::Byzantium, ForkCondition::Block(0)); self } /// Enable Constantinople at genesis. pub fn constantinople_activated(mut self) -> Self { self = self.byzantium_activated(); - self.hardforks.insert(Hardfork::Constantinople, ForkCondition::Block(0)); + self.hardforks.insert(EthereumHardfork::Constantinople, ForkCondition::Block(0)); self } /// Enable Petersburg at genesis. pub fn petersburg_activated(mut self) -> Self { self = self.constantinople_activated(); - self.hardforks.insert(Hardfork::Petersburg, ForkCondition::Block(0)); + self.hardforks.insert(EthereumHardfork::Petersburg, ForkCondition::Block(0)); self } /// Enable Istanbul at genesis. pub fn istanbul_activated(mut self) -> Self { self = self.petersburg_activated(); - self.hardforks.insert(Hardfork::Istanbul, ForkCondition::Block(0)); + self.hardforks.insert(EthereumHardfork::Istanbul, ForkCondition::Block(0)); self } /// Enable Berlin at genesis. pub fn berlin_activated(mut self) -> Self { self = self.istanbul_activated(); - self.hardforks.insert(Hardfork::Berlin, ForkCondition::Block(0)); + self.hardforks.insert(EthereumHardfork::Berlin, ForkCondition::Block(0)); self } /// Enable London at genesis. pub fn london_activated(mut self) -> Self { self = self.berlin_activated(); - self.hardforks.insert(Hardfork::London, ForkCondition::Block(0)); + self.hardforks.insert(EthereumHardfork::London, ForkCondition::Block(0)); self } @@ -1047,7 +974,7 @@ impl ChainSpecBuilder { pub fn paris_activated(mut self) -> Self { self = self.london_activated(); self.hardforks.insert( - Hardfork::Paris, + EthereumHardfork::Paris, ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO }, ); self @@ -1056,14 +983,14 @@ impl ChainSpecBuilder { /// Enable Shanghai at genesis. pub fn shanghai_activated(mut self) -> Self { self = self.paris_activated(); - self.hardforks.insert(Hardfork::Shanghai, ForkCondition::Timestamp(0)); + self.hardforks.insert(EthereumHardfork::Shanghai, ForkCondition::Timestamp(0)); self } /// Enable Cancun at genesis. pub fn cancun_activated(mut self) -> Self { self = self.shanghai_activated(); - self.hardforks.insert(Hardfork::Cancun, ForkCondition::Timestamp(0)); + self.hardforks.insert(EthereumHardfork::Cancun, ForkCondition::Timestamp(0)); self } @@ -1071,7 +998,7 @@ impl ChainSpecBuilder { #[cfg(feature = "optimism")] pub fn bedrock_activated(mut self) -> Self { self = self.paris_activated(); - self.hardforks.insert(Hardfork::Bedrock, ForkCondition::Block(0)); + self.hardforks.insert(OptimismHardfork::Bedrock, ForkCondition::Block(0)); self } @@ -1079,7 +1006,7 @@ impl ChainSpecBuilder { #[cfg(feature = "optimism")] pub fn regolith_activated(mut self) -> Self { self = self.bedrock_activated(); - self.hardforks.insert(Hardfork::Regolith, ForkCondition::Timestamp(0)); + self.hardforks.insert(OptimismHardfork::Regolith, ForkCondition::Timestamp(0)); self } @@ -1088,8 +1015,8 @@ impl ChainSpecBuilder { pub fn canyon_activated(mut self) -> Self { self = self.regolith_activated(); // Canyon also activates changes from L1's Shanghai hardfork - self.hardforks.insert(Hardfork::Shanghai, ForkCondition::Timestamp(0)); - self.hardforks.insert(Hardfork::Canyon, ForkCondition::Timestamp(0)); + self.hardforks.insert(EthereumHardfork::Shanghai, ForkCondition::Timestamp(0)); + self.hardforks.insert(OptimismHardfork::Canyon, ForkCondition::Timestamp(0)); self } @@ -1097,8 +1024,8 @@ impl ChainSpecBuilder { #[cfg(feature = "optimism")] pub fn ecotone_activated(mut self) -> Self { self = self.canyon_activated(); - self.hardforks.insert(Hardfork::Cancun, ForkCondition::Timestamp(0)); - self.hardforks.insert(Hardfork::Ecotone, ForkCondition::Timestamp(0)); + self.hardforks.insert(EthereumHardfork::Cancun, ForkCondition::Timestamp(0)); + self.hardforks.insert(OptimismHardfork::Ecotone, ForkCondition::Timestamp(0)); self } @@ -1106,7 +1033,7 @@ impl ChainSpecBuilder { #[cfg(feature = "optimism")] pub fn fjord_activated(mut self) -> Self { self = self.ecotone_activated(); - self.hardforks.insert(Hardfork::Fjord, ForkCondition::Timestamp(0)); + self.hardforks.insert(OptimismHardfork::Fjord, ForkCondition::Timestamp(0)); self } @@ -1118,9 +1045,9 @@ impl ChainSpecBuilder { /// [`Self::genesis`]) pub fn build(self) -> ChainSpec { let paris_block_and_final_difficulty = { - self.hardforks.get(&Hardfork::Paris).and_then(|cond| { + self.hardforks.get(EthereumHardfork::Paris).and_then(|cond| { if let ForkCondition::TTD { fork_block, total_difficulty } = cond { - fork_block.map(|fork_block| (fork_block, *total_difficulty)) + fork_block.map(|fork_block| (fork_block, total_difficulty)) } else { None } @@ -1208,11 +1135,11 @@ impl OptimismGenesisInfo { BaseFeeParamsKind::Variable( vec![ ( - Hardfork::London, + EthereumHardfork::London.boxed(), BaseFeeParams::new(denominator as u128, elasticity as u128), ), ( - Hardfork::Canyon, + OptimismHardfork::Canyon.boxed(), BaseFeeParams::new(canyon_denominator as u128, elasticity as u128), ), ] @@ -1236,10 +1163,14 @@ mod tests { use alloy_chains::Chain; use alloy_genesis::{ChainConfig, GenesisAccount}; use alloy_primitives::{b256, hex}; + use core::ops::Deref; use reth_ethereum_forks::{ForkCondition, ForkHash, ForkId, Head}; use reth_trie_common::TrieAccount; use std::{collections::HashMap, str::FromStr}; + #[cfg(feature = "optimism")] + use reth_ethereum_forks::OptimismHardforks; + fn test_fork_ids(spec: &ChainSpec, cases: &[(Head, ForkId)]) { for (block, expected_id) in cases { let computed_id = spec.fork_id(block); @@ -1251,14 +1182,14 @@ mod tests { } } - fn test_hardfork_fork_ids(spec: &ChainSpec, cases: &[(Hardfork, ForkId)]) { + fn test_hardfork_fork_ids(spec: &ChainSpec, cases: &[(EthereumHardfork, ForkId)]) { for (hardfork, expected_id) in cases { if let Some(computed_id) = spec.hardfork_fork_id(*hardfork) { assert_eq!( expected_id, &computed_id, "Expected fork ID {expected_id:?}, computed fork ID {computed_id:?} for hardfork {hardfork}" ); - if matches!(hardfork, Hardfork::Shanghai) { + if matches!(hardfork, EthereumHardfork::Shanghai) { if let Some(shangai_id) = spec.shanghai_fork_id() { assert_eq!( expected_id, &shangai_id, @@ -1304,8 +1235,8 @@ Post-merge hard forks (timestamp based): let spec = ChainSpec::builder() .chain(Chain::mainnet()) .genesis(Genesis::default()) - .with_fork(Hardfork::Frontier, ForkCondition::Block(0)) - .with_fork(Hardfork::Shanghai, ForkCondition::Never) + .with_fork(EthereumHardfork::Frontier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Shanghai, ForkCondition::Never) .build(); assert_eq!( spec.display_hardforks().to_string(), @@ -1320,21 +1251,21 @@ Post-merge hard forks (timestamp based): let spec = ChainSpec::builder() .chain(Chain::mainnet()) .genesis(Genesis::default()) - .with_fork(Hardfork::Frontier, ForkCondition::Block(0)) - .with_fork(Hardfork::Homestead, ForkCondition::Block(0)) - .with_fork(Hardfork::Tangerine, ForkCondition::Block(0)) - .with_fork(Hardfork::SpuriousDragon, ForkCondition::Block(0)) - .with_fork(Hardfork::Byzantium, ForkCondition::Block(0)) - .with_fork(Hardfork::Constantinople, ForkCondition::Block(0)) - .with_fork(Hardfork::Istanbul, ForkCondition::Block(0)) - .with_fork(Hardfork::MuirGlacier, ForkCondition::Block(0)) - .with_fork(Hardfork::Berlin, ForkCondition::Block(0)) - .with_fork(Hardfork::London, ForkCondition::Block(0)) - .with_fork(Hardfork::ArrowGlacier, ForkCondition::Block(0)) - .with_fork(Hardfork::GrayGlacier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Frontier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Homestead, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Tangerine, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::SpuriousDragon, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Byzantium, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Constantinople, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Istanbul, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::MuirGlacier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Berlin, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::London, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::ArrowGlacier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::GrayGlacier, ForkCondition::Block(0)) .build(); - assert_eq!(spec.hardforks().len(), 12, "12 forks should be active."); + assert_eq!(spec.deref().len(), 12, "12 forks should be active."); assert_eq!( spec.fork_id(&Head { number: 1, ..Default::default() }), ForkId { hash: ForkHash::from(spec.genesis_hash()), next: 0 }, @@ -1348,16 +1279,16 @@ Post-merge hard forks (timestamp based): let unique_spec = ChainSpec::builder() .chain(Chain::mainnet()) .genesis(empty_genesis.clone()) - .with_fork(Hardfork::Frontier, ForkCondition::Block(0)) - .with_fork(Hardfork::Homestead, ForkCondition::Block(1)) + .with_fork(EthereumHardfork::Frontier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Homestead, ForkCondition::Block(1)) .build(); let duplicate_spec = ChainSpec::builder() .chain(Chain::mainnet()) .genesis(empty_genesis) - .with_fork(Hardfork::Frontier, ForkCondition::Block(0)) - .with_fork(Hardfork::Homestead, ForkCondition::Block(1)) - .with_fork(Hardfork::Tangerine, ForkCondition::Block(1)) + .with_fork(EthereumHardfork::Frontier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Homestead, ForkCondition::Block(1)) + .with_fork(EthereumHardfork::Tangerine, ForkCondition::Block(1)) .build(); assert_eq!( @@ -1374,9 +1305,9 @@ Post-merge hard forks (timestamp based): let happy_path_case = ChainSpec::builder() .chain(Chain::mainnet()) .genesis(empty_genesis.clone()) - .with_fork(Hardfork::Frontier, ForkCondition::Block(0)) - .with_fork(Hardfork::Homestead, ForkCondition::Block(73)) - .with_fork(Hardfork::Shanghai, ForkCondition::Timestamp(11313123)) + .with_fork(EthereumHardfork::Frontier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Homestead, ForkCondition::Block(73)) + .with_fork(EthereumHardfork::Shanghai, ForkCondition::Timestamp(11313123)) .build(); let happy_path_head = happy_path_case.satisfy(ForkCondition::Timestamp(11313123)); let happy_path_expected = Head { number: 73, timestamp: 11313123, ..Default::default() }; @@ -1388,10 +1319,10 @@ Post-merge hard forks (timestamp based): let multiple_timestamp_fork_case = ChainSpec::builder() .chain(Chain::mainnet()) .genesis(empty_genesis.clone()) - .with_fork(Hardfork::Frontier, ForkCondition::Block(0)) - .with_fork(Hardfork::Homestead, ForkCondition::Block(73)) - .with_fork(Hardfork::Shanghai, ForkCondition::Timestamp(11313123)) - .with_fork(Hardfork::Cancun, ForkCondition::Timestamp(11313398)) + .with_fork(EthereumHardfork::Frontier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Homestead, ForkCondition::Block(73)) + .with_fork(EthereumHardfork::Shanghai, ForkCondition::Timestamp(11313123)) + .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(11313398)) .build(); let multi_timestamp_head = multiple_timestamp_fork_case.satisfy(ForkCondition::Timestamp(11313398)); @@ -1405,7 +1336,7 @@ Post-merge hard forks (timestamp based): let no_block_fork_case = ChainSpec::builder() .chain(Chain::mainnet()) .genesis(empty_genesis.clone()) - .with_fork(Hardfork::Shanghai, ForkCondition::Timestamp(11313123)) + .with_fork(EthereumHardfork::Shanghai, ForkCondition::Timestamp(11313123)) .build(); let no_block_fork_head = no_block_fork_case.satisfy(ForkCondition::Timestamp(11313123)); let no_block_fork_expected = Head { number: 0, timestamp: 11313123, ..Default::default() }; @@ -1417,16 +1348,16 @@ Post-merge hard forks (timestamp based): let fork_cond_ttd_blocknum_case = ChainSpec::builder() .chain(Chain::mainnet()) .genesis(empty_genesis.clone()) - .with_fork(Hardfork::Frontier, ForkCondition::Block(0)) - .with_fork(Hardfork::Homestead, ForkCondition::Block(73)) + .with_fork(EthereumHardfork::Frontier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Homestead, ForkCondition::Block(73)) .with_fork( - Hardfork::Paris, + EthereumHardfork::Paris, ForkCondition::TTD { fork_block: Some(101), total_difficulty: U256::from(10_790_000), }, ) - .with_fork(Hardfork::Shanghai, ForkCondition::Timestamp(11313123)) + .with_fork(EthereumHardfork::Shanghai, ForkCondition::Timestamp(11313123)) .build(); let fork_cond_ttd_blocknum_head = fork_cond_ttd_blocknum_case.satisfy(ForkCondition::Timestamp(11313123)); @@ -1443,8 +1374,8 @@ Post-merge hard forks (timestamp based): let fork_cond_block_only_case = ChainSpec::builder() .chain(Chain::mainnet()) .genesis(empty_genesis) - .with_fork(Hardfork::Frontier, ForkCondition::Block(0)) - .with_fork(Hardfork::Homestead, ForkCondition::Block(73)) + .with_fork(EthereumHardfork::Frontier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Homestead, ForkCondition::Block(73)) .build(); let fork_cond_block_only_head = fork_cond_block_only_case.satisfy(ForkCondition::Block(73)); let fork_cond_block_only_expected = Head { number: 73, ..Default::default() }; @@ -1472,63 +1403,69 @@ Post-merge hard forks (timestamp based): &MAINNET, &[ ( - Hardfork::Frontier, + EthereumHardfork::Frontier, ForkId { hash: ForkHash([0xfc, 0x64, 0xec, 0x04]), next: 1150000 }, ), ( - Hardfork::Homestead, + EthereumHardfork::Homestead, ForkId { hash: ForkHash([0x97, 0xc2, 0xc3, 0x4c]), next: 1920000 }, ), - (Hardfork::Dao, ForkId { hash: ForkHash([0x91, 0xd1, 0xf9, 0x48]), next: 2463000 }), ( - Hardfork::Tangerine, + EthereumHardfork::Dao, + ForkId { hash: ForkHash([0x91, 0xd1, 0xf9, 0x48]), next: 2463000 }, + ), + ( + EthereumHardfork::Tangerine, ForkId { hash: ForkHash([0x7a, 0x64, 0xda, 0x13]), next: 2675000 }, ), ( - Hardfork::SpuriousDragon, + EthereumHardfork::SpuriousDragon, ForkId { hash: ForkHash([0x3e, 0xdd, 0x5b, 0x10]), next: 4370000 }, ), ( - Hardfork::Byzantium, + EthereumHardfork::Byzantium, ForkId { hash: ForkHash([0xa0, 0x0b, 0xc3, 0x24]), next: 7280000 }, ), ( - Hardfork::Constantinople, + EthereumHardfork::Constantinople, ForkId { hash: ForkHash([0x66, 0x8d, 0xb0, 0xaf]), next: 9069000 }, ), ( - Hardfork::Petersburg, + EthereumHardfork::Petersburg, ForkId { hash: ForkHash([0x66, 0x8d, 0xb0, 0xaf]), next: 9069000 }, ), ( - Hardfork::Istanbul, + EthereumHardfork::Istanbul, ForkId { hash: ForkHash([0x87, 0x9d, 0x6e, 0x30]), next: 9200000 }, ), ( - Hardfork::MuirGlacier, + EthereumHardfork::MuirGlacier, ForkId { hash: ForkHash([0xe0, 0x29, 0xe9, 0x91]), next: 12244000 }, ), ( - Hardfork::Berlin, + EthereumHardfork::Berlin, ForkId { hash: ForkHash([0x0e, 0xb4, 0x40, 0xf6]), next: 12965000 }, ), ( - Hardfork::London, + EthereumHardfork::London, ForkId { hash: ForkHash([0xb7, 0x15, 0x07, 0x7d]), next: 13773000 }, ), ( - Hardfork::ArrowGlacier, + EthereumHardfork::ArrowGlacier, ForkId { hash: ForkHash([0x20, 0xc3, 0x27, 0xfc]), next: 15050000 }, ), ( - Hardfork::GrayGlacier, + EthereumHardfork::GrayGlacier, ForkId { hash: ForkHash([0xf0, 0xaf, 0xd0, 0xe3]), next: 1681338455 }, ), ( - Hardfork::Shanghai, + EthereumHardfork::Shanghai, ForkId { hash: ForkHash([0xdc, 0xe9, 0x6c, 0x2d]), next: 1710338135 }, ), - (Hardfork::Cancun, ForkId { hash: ForkHash([0x9f, 0x3d, 0x22, 0x54]), next: 0 }), + ( + EthereumHardfork::Cancun, + ForkId { hash: ForkHash([0x9f, 0x3d, 0x22, 0x54]), next: 0 }, + ), ], ); } @@ -1539,50 +1476,53 @@ Post-merge hard forks (timestamp based): &GOERLI, &[ ( - Hardfork::Frontier, + EthereumHardfork::Frontier, ForkId { hash: ForkHash([0xa3, 0xf5, 0xab, 0x08]), next: 1561651 }, ), ( - Hardfork::Homestead, + EthereumHardfork::Homestead, ForkId { hash: ForkHash([0xa3, 0xf5, 0xab, 0x08]), next: 1561651 }, ), ( - Hardfork::Tangerine, + EthereumHardfork::Tangerine, ForkId { hash: ForkHash([0xa3, 0xf5, 0xab, 0x08]), next: 1561651 }, ), ( - Hardfork::SpuriousDragon, + EthereumHardfork::SpuriousDragon, ForkId { hash: ForkHash([0xa3, 0xf5, 0xab, 0x08]), next: 1561651 }, ), ( - Hardfork::Byzantium, + EthereumHardfork::Byzantium, ForkId { hash: ForkHash([0xa3, 0xf5, 0xab, 0x08]), next: 1561651 }, ), ( - Hardfork::Constantinople, + EthereumHardfork::Constantinople, ForkId { hash: ForkHash([0xa3, 0xf5, 0xab, 0x08]), next: 1561651 }, ), ( - Hardfork::Petersburg, + EthereumHardfork::Petersburg, ForkId { hash: ForkHash([0xa3, 0xf5, 0xab, 0x08]), next: 1561651 }, ), ( - Hardfork::Istanbul, + EthereumHardfork::Istanbul, ForkId { hash: ForkHash([0xc2, 0x5e, 0xfa, 0x5c]), next: 4460644 }, ), ( - Hardfork::Berlin, + EthereumHardfork::Berlin, ForkId { hash: ForkHash([0x75, 0x7a, 0x1c, 0x47]), next: 5062605 }, ), ( - Hardfork::London, + EthereumHardfork::London, ForkId { hash: ForkHash([0xb8, 0xc6, 0x29, 0x9d]), next: 1678832736 }, ), ( - Hardfork::Shanghai, + EthereumHardfork::Shanghai, ForkId { hash: ForkHash([0xf9, 0x84, 0x3a, 0xbf]), next: 1705473120 }, ), - (Hardfork::Cancun, ForkId { hash: ForkHash([0x70, 0xcc, 0x14, 0xe2]), next: 0 }), + ( + EthereumHardfork::Cancun, + ForkId { hash: ForkHash([0x70, 0xcc, 0x14, 0xe2]), next: 0 }, + ), ], ); } @@ -1593,54 +1533,57 @@ Post-merge hard forks (timestamp based): &SEPOLIA, &[ ( - Hardfork::Frontier, + EthereumHardfork::Frontier, ForkId { hash: ForkHash([0xfe, 0x33, 0x66, 0xe7]), next: 1735371 }, ), ( - Hardfork::Homestead, + EthereumHardfork::Homestead, ForkId { hash: ForkHash([0xfe, 0x33, 0x66, 0xe7]), next: 1735371 }, ), ( - Hardfork::Tangerine, + EthereumHardfork::Tangerine, ForkId { hash: ForkHash([0xfe, 0x33, 0x66, 0xe7]), next: 1735371 }, ), ( - Hardfork::SpuriousDragon, + EthereumHardfork::SpuriousDragon, ForkId { hash: ForkHash([0xfe, 0x33, 0x66, 0xe7]), next: 1735371 }, ), ( - Hardfork::Byzantium, + EthereumHardfork::Byzantium, ForkId { hash: ForkHash([0xfe, 0x33, 0x66, 0xe7]), next: 1735371 }, ), ( - Hardfork::Constantinople, + EthereumHardfork::Constantinople, ForkId { hash: ForkHash([0xfe, 0x33, 0x66, 0xe7]), next: 1735371 }, ), ( - Hardfork::Petersburg, + EthereumHardfork::Petersburg, ForkId { hash: ForkHash([0xfe, 0x33, 0x66, 0xe7]), next: 1735371 }, ), ( - Hardfork::Istanbul, + EthereumHardfork::Istanbul, ForkId { hash: ForkHash([0xfe, 0x33, 0x66, 0xe7]), next: 1735371 }, ), ( - Hardfork::Berlin, + EthereumHardfork::Berlin, ForkId { hash: ForkHash([0xfe, 0x33, 0x66, 0xe7]), next: 1735371 }, ), ( - Hardfork::London, + EthereumHardfork::London, ForkId { hash: ForkHash([0xfe, 0x33, 0x66, 0xe7]), next: 1735371 }, ), ( - Hardfork::Paris, + EthereumHardfork::Paris, ForkId { hash: ForkHash([0xb9, 0x6c, 0xbd, 0x13]), next: 1677557088 }, ), ( - Hardfork::Shanghai, + EthereumHardfork::Shanghai, ForkId { hash: ForkHash([0xf7, 0xf9, 0xbc, 0x08]), next: 1706655072 }, ), - (Hardfork::Cancun, ForkId { hash: ForkHash([0x88, 0xcf, 0x81, 0xd9]), next: 0 }), + ( + EthereumHardfork::Cancun, + ForkId { hash: ForkHash([0x88, 0xcf, 0x81, 0xd9]), next: 0 }, + ), ], ); } @@ -2141,8 +2084,8 @@ Post-merge hard forks (timestamp based): cancun_time: u64, ) -> ChainSpec { builder - .with_fork(Hardfork::Shanghai, ForkCondition::Timestamp(shanghai_time)) - .with_fork(Hardfork::Cancun, ForkCondition::Timestamp(cancun_time)) + .with_fork(EthereumHardfork::Shanghai, ForkCondition::Timestamp(shanghai_time)) + .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(cancun_time)) .build() } @@ -2197,14 +2140,14 @@ Post-merge hard forks (timestamp based): let terminal_block_ttd = U256::from(58750003716598352816469_u128); let terminal_block_difficulty = U256::from(11055787484078698_u128); assert!(!chainspec - .fork(Hardfork::Paris) + .fork(EthereumHardfork::Paris) .active_at_ttd(terminal_block_ttd, terminal_block_difficulty)); // Check that Paris is active on first PoS block #15537394. let first_pos_block_ttd = U256::from(58750003716598352816469_u128); let first_pos_difficulty = U256::ZERO; assert!(chainspec - .fork(Hardfork::Paris) + .fork(EthereumHardfork::Paris) .active_at_ttd(first_pos_block_ttd, first_pos_difficulty)); } @@ -2280,55 +2223,64 @@ Post-merge hard forks (timestamp based): // assert a bunch of hardforks that should be set assert_eq!( - chainspec.hardforks.get(&Hardfork::Homestead).unwrap(), - &ForkCondition::Block(0) + chainspec.hardforks.get(EthereumHardfork::Homestead).unwrap(), + ForkCondition::Block(0) ); assert_eq!( - chainspec.hardforks.get(&Hardfork::Tangerine).unwrap(), - &ForkCondition::Block(0) + chainspec.hardforks.get(EthereumHardfork::Tangerine).unwrap(), + ForkCondition::Block(0) ); assert_eq!( - chainspec.hardforks.get(&Hardfork::SpuriousDragon).unwrap(), - &ForkCondition::Block(0) + chainspec.hardforks.get(EthereumHardfork::SpuriousDragon).unwrap(), + ForkCondition::Block(0) ); assert_eq!( - chainspec.hardforks.get(&Hardfork::Byzantium).unwrap(), - &ForkCondition::Block(0) + chainspec.hardforks.get(EthereumHardfork::Byzantium).unwrap(), + ForkCondition::Block(0) ); assert_eq!( - chainspec.hardforks.get(&Hardfork::Constantinople).unwrap(), - &ForkCondition::Block(0) + chainspec.hardforks.get(EthereumHardfork::Constantinople).unwrap(), + ForkCondition::Block(0) ); assert_eq!( - chainspec.hardforks.get(&Hardfork::Petersburg).unwrap(), - &ForkCondition::Block(0) - ); - assert_eq!(chainspec.hardforks.get(&Hardfork::Istanbul).unwrap(), &ForkCondition::Block(0)); - assert_eq!( - chainspec.hardforks.get(&Hardfork::MuirGlacier).unwrap(), - &ForkCondition::Block(0) - ); - assert_eq!(chainspec.hardforks.get(&Hardfork::Berlin).unwrap(), &ForkCondition::Block(0)); - assert_eq!(chainspec.hardforks.get(&Hardfork::London).unwrap(), &ForkCondition::Block(0)); - assert_eq!( - chainspec.hardforks.get(&Hardfork::ArrowGlacier).unwrap(), - &ForkCondition::Block(0) + chainspec.hardforks.get(EthereumHardfork::Petersburg).unwrap(), + ForkCondition::Block(0) ); assert_eq!( - chainspec.hardforks.get(&Hardfork::GrayGlacier).unwrap(), - &ForkCondition::Block(0) + chainspec.hardforks.get(EthereumHardfork::Istanbul).unwrap(), + ForkCondition::Block(0) + ); + assert_eq!( + chainspec.hardforks.get(EthereumHardfork::MuirGlacier).unwrap(), + ForkCondition::Block(0) + ); + assert_eq!( + chainspec.hardforks.get(EthereumHardfork::Berlin).unwrap(), + ForkCondition::Block(0) + ); + assert_eq!( + chainspec.hardforks.get(EthereumHardfork::London).unwrap(), + ForkCondition::Block(0) + ); + assert_eq!( + chainspec.hardforks.get(EthereumHardfork::ArrowGlacier).unwrap(), + ForkCondition::Block(0) + ); + assert_eq!( + chainspec.hardforks.get(EthereumHardfork::GrayGlacier).unwrap(), + ForkCondition::Block(0) ); // including time based hardforks assert_eq!( - chainspec.hardforks.get(&Hardfork::Shanghai).unwrap(), - &ForkCondition::Timestamp(0) + chainspec.hardforks.get(EthereumHardfork::Shanghai).unwrap(), + ForkCondition::Timestamp(0) ); // including time based hardforks assert_eq!( - chainspec.hardforks.get(&Hardfork::Cancun).unwrap(), - &ForkCondition::Timestamp(1) + chainspec.hardforks.get(EthereumHardfork::Cancun).unwrap(), + ForkCondition::Timestamp(1) ); // alloc key -> expected rlp mapping @@ -2424,14 +2376,14 @@ Post-merge hard forks (timestamp based): hex!("9a6049ac535e3dc7436c189eaa81c73f35abd7f282ab67c32944ff0301d63360").into(); assert_eq!(chainspec.genesis_header().state_root, expected_state_root); let hard_forks = vec![ - Hardfork::Byzantium, - Hardfork::Homestead, - Hardfork::Istanbul, - Hardfork::Petersburg, - Hardfork::Constantinople, + EthereumHardfork::Byzantium, + EthereumHardfork::Homestead, + EthereumHardfork::Istanbul, + EthereumHardfork::Petersburg, + EthereumHardfork::Constantinople, ]; - for ref fork in hard_forks { - assert_eq!(chainspec.hardforks.get(fork).unwrap(), &ForkCondition::Block(0)); + for fork in hard_forks { + assert_eq!(chainspec.hardforks.get(fork).unwrap(), ForkCondition::Block(0)); } let expected_hash: B256 = @@ -2680,7 +2632,7 @@ Post-merge hard forks (timestamp based): #[test] fn holesky_paris_activated_at_genesis() { assert!(HOLESKY - .fork(Hardfork::Paris) + .fork(EthereumHardfork::Paris) .active_at_ttd(HOLESKY.genesis.difficulty, HOLESKY.genesis.difficulty)); } @@ -2734,13 +2686,16 @@ Post-merge hard forks (timestamp based): chain: Chain::mainnet(), genesis: Genesis::default(), genesis_hash: None, - hardforks: BTreeMap::from([(Hardfork::Frontier, ForkCondition::Never)]), + hardforks: ChainHardforks::new(vec![( + EthereumHardfork::Frontier.boxed(), + ForkCondition::Never, + )]), paris_block_and_final_difficulty: None, deposit_contract: None, ..Default::default() }; - assert_eq!(spec.hardfork_fork_id(Hardfork::Frontier), None); + assert_eq!(spec.hardfork_fork_id(EthereumHardfork::Frontier), None); } #[test] @@ -2749,13 +2704,16 @@ Post-merge hard forks (timestamp based): chain: Chain::mainnet(), genesis: Genesis::default(), genesis_hash: None, - hardforks: BTreeMap::from([(Hardfork::Shanghai, ForkCondition::Never)]), + hardforks: ChainHardforks::new(vec![( + EthereumHardfork::Shanghai.boxed(), + ForkCondition::Never, + )]), paris_block_and_final_difficulty: None, deposit_contract: None, ..Default::default() }; - assert_eq!(spec.hardfork_fork_filter(Hardfork::Shanghai), None); + assert_eq!(spec.hardfork_fork_filter(EthereumHardfork::Shanghai), None); } #[test] @@ -2873,17 +2831,17 @@ Post-merge hard forks (timestamp based): BaseFeeParamsKind::Constant(BaseFeeParams::new(70, 60)) ); - assert!(!chain_spec.is_fork_active_at_block(Hardfork::Bedrock, 0)); - assert!(!chain_spec.is_fork_active_at_timestamp(Hardfork::Regolith, 0)); - assert!(!chain_spec.is_fork_active_at_timestamp(Hardfork::Canyon, 0)); - assert!(!chain_spec.is_fork_active_at_timestamp(Hardfork::Ecotone, 0)); - assert!(!chain_spec.is_fork_active_at_timestamp(Hardfork::Fjord, 0)); + assert!(!chain_spec.is_fork_active_at_block(OptimismHardfork::Bedrock, 0)); + assert!(!chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Regolith, 0)); + assert!(!chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Canyon, 0)); + assert!(!chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Ecotone, 0)); + assert!(!chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Fjord, 0)); - assert!(chain_spec.is_fork_active_at_block(Hardfork::Bedrock, 10)); - assert!(chain_spec.is_fork_active_at_timestamp(Hardfork::Regolith, 20)); - assert!(chain_spec.is_fork_active_at_timestamp(Hardfork::Canyon, 30)); - assert!(chain_spec.is_fork_active_at_timestamp(Hardfork::Ecotone, 40)); - assert!(chain_spec.is_fork_active_at_timestamp(Hardfork::Fjord, 50)); + assert!(chain_spec.is_fork_active_at_block(OptimismHardfork::Bedrock, 10)); + assert!(chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Regolith, 20)); + assert!(chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Canyon, 30)); + assert!(chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Ecotone, 40)); + assert!(chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Fjord, 50)); } #[cfg(feature = "optimism")] @@ -2934,24 +2892,24 @@ Post-merge hard forks (timestamp based): chain_spec.base_fee_params, BaseFeeParamsKind::Variable( vec![ - (Hardfork::London, BaseFeeParams::new(70, 60)), - (Hardfork::Canyon, BaseFeeParams::new(80, 60)), + (EthereumHardfork::London.boxed(), BaseFeeParams::new(70, 60)), + (OptimismHardfork::Canyon.boxed(), BaseFeeParams::new(80, 60)), ] .into() ) ); - assert!(!chain_spec.is_fork_active_at_block(Hardfork::Bedrock, 0)); - assert!(!chain_spec.is_fork_active_at_timestamp(Hardfork::Regolith, 0)); - assert!(!chain_spec.is_fork_active_at_timestamp(Hardfork::Canyon, 0)); - assert!(!chain_spec.is_fork_active_at_timestamp(Hardfork::Ecotone, 0)); - assert!(!chain_spec.is_fork_active_at_timestamp(Hardfork::Fjord, 0)); + assert!(!chain_spec.is_fork_active_at_block(OptimismHardfork::Bedrock, 0)); + assert!(!chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Regolith, 0)); + assert!(!chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Canyon, 0)); + assert!(!chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Ecotone, 0)); + assert!(!chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Fjord, 0)); - assert!(chain_spec.is_fork_active_at_block(Hardfork::Bedrock, 10)); - assert!(chain_spec.is_fork_active_at_timestamp(Hardfork::Regolith, 20)); - assert!(chain_spec.is_fork_active_at_timestamp(Hardfork::Canyon, 30)); - assert!(chain_spec.is_fork_active_at_timestamp(Hardfork::Ecotone, 40)); - assert!(chain_spec.is_fork_active_at_timestamp(Hardfork::Fjord, 50)); + assert!(chain_spec.is_fork_active_at_block(OptimismHardfork::Bedrock, 10)); + assert!(chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Regolith, 20)); + assert!(chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Canyon, 30)); + assert!(chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Ecotone, 40)); + assert!(chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Fjord, 50)); } #[cfg(feature = "optimism")] @@ -2992,7 +2950,10 @@ Post-merge hard forks (timestamp based): let actual_chain_id = genesis.config.chain_id; assert_eq!(actual_chain_id, 8453); - assert_eq!(chainspec.hardforks.get(&Hardfork::Istanbul), Some(&ForkCondition::Block(0))); + assert_eq!( + chainspec.hardforks.get(EthereumHardfork::Istanbul), + Some(ForkCondition::Block(0)) + ); let actual_bedrock_block = genesis.config.extra_fields.get("bedrockBlock"); assert_eq!(actual_bedrock_block, Some(serde_json::Value::from(0)).as_ref()); @@ -3021,8 +2982,8 @@ Post-merge hard forks (timestamp based): }) ); - assert!(chainspec.is_fork_active_at_block(Hardfork::Bedrock, 0)); + assert!(chainspec.is_fork_active_at_block(OptimismHardfork::Bedrock, 0)); - assert!(chainspec.is_fork_active_at_timestamp(Hardfork::Regolith, 20)); + assert!(chainspec.is_fork_active_at_timestamp(OptimismHardfork::Regolith, 20)); } } diff --git a/crates/consensus/auto-seal/src/lib.rs b/crates/consensus/auto-seal/src/lib.rs index ba6c67487..2fd93e7ca 100644 --- a/crates/consensus/auto-seal/src/lib.rs +++ b/crates/consensus/auto-seal/src/lib.rs @@ -16,7 +16,7 @@ #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] use reth_beacon_consensus::BeaconEngineMessage; -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_consensus::{Consensus, ConsensusError, PostExecutionInput}; use reth_engine_primitives::EngineTypes; use reth_execution_errors::{BlockExecutionError, BlockValidationError}; diff --git a/crates/consensus/beacon/src/engine/mod.rs b/crates/consensus/beacon/src/engine/mod.rs index 3391a1de9..d08dcc259 100644 --- a/crates/consensus/beacon/src/engine/mod.rs +++ b/crates/consensus/beacon/src/engine/mod.rs @@ -2492,7 +2492,7 @@ mod tests { use super::*; use alloy_genesis::Genesis; use reth_db::test_utils::create_test_static_files_dir; - use reth_primitives::{Hardfork, U256}; + use reth_primitives::{EthereumHardfork, U256}; use reth_provider::{ providers::StaticFileProvider, test_utils::blocks::BlockchainTestData, }; @@ -2721,9 +2721,9 @@ mod tests { async fn payload_pre_merge() { let data = BlockchainTestData::default(); let mut block1 = data.blocks[0].0.block.clone(); - block1 - .header - .set_difficulty(MAINNET.fork(Hardfork::Paris).ttd().unwrap() - U256::from(1)); + block1.header.set_difficulty( + MAINNET.fork(EthereumHardfork::Paris).ttd().unwrap() - U256::from(1), + ); block1 = block1.unseal().seal_slow(); let (block2, exec_result2) = data.blocks[1].clone(); let mut block2 = block2.unseal().block; diff --git a/crates/consensus/common/src/calc.rs b/crates/consensus/common/src/calc.rs index 27320700b..feb7bff0d 100644 --- a/crates/consensus/common/src/calc.rs +++ b/crates/consensus/common/src/calc.rs @@ -1,4 +1,4 @@ -use reth_chainspec::{Chain, ChainSpec, Hardfork}; +use reth_chainspec::{Chain, ChainSpec, EthereumHardfork}; use reth_primitives::{constants::ETH_TO_WEI, BlockNumber, U256}; /// Calculates the base block reward. @@ -26,7 +26,7 @@ pub fn base_block_reward( block_difficulty: U256, total_difficulty: U256, ) -> Option { - if chain_spec.fork(Hardfork::Paris).active_at_ttd(total_difficulty, block_difficulty) || + if chain_spec.fork(EthereumHardfork::Paris).active_at_ttd(total_difficulty, block_difficulty) || chain_spec.chain == Chain::goerli() { None @@ -39,9 +39,9 @@ pub fn base_block_reward( /// /// Caution: The caller must ensure that the block number is before the merge. pub fn base_block_reward_pre_merge(chain_spec: &ChainSpec, block_number: BlockNumber) -> u128 { - if chain_spec.fork(Hardfork::Constantinople).active_at_block(block_number) { + if chain_spec.fork(EthereumHardfork::Constantinople).active_at_block(block_number) { ETH_TO_WEI * 2 - } else if chain_spec.fork(Hardfork::Byzantium).active_at_block(block_number) { + } else if chain_spec.fork(EthereumHardfork::Byzantium).active_at_block(block_number) { ETH_TO_WEI * 3 } else { ETH_TO_WEI * 5 diff --git a/crates/consensus/common/src/validation.rs b/crates/consensus/common/src/validation.rs index 31bde166e..dc04d74dc 100644 --- a/crates/consensus/common/src/validation.rs +++ b/crates/consensus/common/src/validation.rs @@ -1,6 +1,6 @@ //! Collection of methods for block validation. -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_consensus::ConsensusError; use reth_primitives::{ constants::{ @@ -8,7 +8,7 @@ use reth_primitives::{ MAXIMUM_EXTRA_DATA_SIZE, }, eip4844::calculate_excess_blob_gas, - GotExpected, Hardfork, Header, SealedBlock, SealedHeader, + EthereumHardfork, GotExpected, Header, SealedBlock, SealedHeader, }; /// Gas used needs to be less than gas limit. Gas used is going to be checked after execution. @@ -29,7 +29,7 @@ pub fn validate_header_base_fee( header: &SealedHeader, chain_spec: &ChainSpec, ) -> Result<(), ConsensusError> { - if chain_spec.fork(Hardfork::London).active_at_block(header.number) && + if chain_spec.fork(EthereumHardfork::London).active_at_block(header.number) && header.base_fee_per_gas.is_none() { return Err(ConsensusError::BaseFeeMissing) @@ -192,11 +192,11 @@ pub fn validate_against_parent_eip1559_base_fee( parent: &SealedHeader, chain_spec: &ChainSpec, ) -> Result<(), ConsensusError> { - if chain_spec.fork(Hardfork::London).active_at_block(header.number) { + if chain_spec.fork(EthereumHardfork::London).active_at_block(header.number) { let base_fee = header.base_fee_per_gas.ok_or(ConsensusError::BaseFeeMissing)?; let expected_base_fee = - if chain_spec.fork(Hardfork::London).transitions_at_block(header.number) { + if chain_spec.fork(EthereumHardfork::London).transitions_at_block(header.number) { reth_primitives::constants::EIP1559_INITIAL_BASE_FEE } else { // This BaseFeeMissing will not happen as previous blocks are checked to have diff --git a/crates/ethereum-forks/Cargo.toml b/crates/ethereum-forks/Cargo.toml index bcdbc6551..9bdc0c98c 100644 --- a/crates/ethereum-forks/Cargo.toml +++ b/crates/ethereum-forks/Cargo.toml @@ -23,11 +23,15 @@ crc = "3" # misc serde = { workspace = true, features = ["derive"], optional = true } thiserror-no-std = { workspace = true, default-features = false } +once_cell.workspace = true +dyn-clone.workspace = true +rustc-hash.workspace = true # arbitrary utils arbitrary = { workspace = true, features = ["derive"], optional = true } proptest = { workspace = true, optional = true } proptest-derive = { workspace = true, optional = true } +auto_impl.workspace = true [dev-dependencies] arbitrary = { workspace = true, features = ["derive"] } diff --git a/crates/ethereum-forks/src/chains/dev.rs b/crates/ethereum-forks/src/chains/dev.rs deleted file mode 100644 index 866be0dd4..000000000 --- a/crates/ethereum-forks/src/chains/dev.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::{ForkCondition, Hardfork}; -use alloy_primitives::uint; - -/// Dev hardforks -pub const DEV_HARDFORKS: [(Hardfork, ForkCondition); 14] = [ - (Hardfork::Frontier, ForkCondition::Block(0)), - (Hardfork::Homestead, ForkCondition::Block(0)), - (Hardfork::Dao, ForkCondition::Block(0)), - (Hardfork::Tangerine, ForkCondition::Block(0)), - (Hardfork::SpuriousDragon, ForkCondition::Block(0)), - (Hardfork::Byzantium, ForkCondition::Block(0)), - (Hardfork::Constantinople, ForkCondition::Block(0)), - (Hardfork::Petersburg, ForkCondition::Block(0)), - (Hardfork::Istanbul, ForkCondition::Block(1561651)), - (Hardfork::Berlin, ForkCondition::Block(4460644)), - (Hardfork::London, ForkCondition::Block(5062605)), - ( - Hardfork::Paris, - ForkCondition::TTD { fork_block: None, total_difficulty: uint!(10_790_000_U256) }, - ), - (Hardfork::Shanghai, ForkCondition::Timestamp(1678832736)), - (Hardfork::Cancun, ForkCondition::Timestamp(1705473120)), -]; diff --git a/crates/ethereum-forks/src/chains/ethereum.rs b/crates/ethereum-forks/src/chains/ethereum.rs deleted file mode 100644 index 6db4d95fc..000000000 --- a/crates/ethereum-forks/src/chains/ethereum.rs +++ /dev/null @@ -1,94 +0,0 @@ -use crate::{ForkCondition, Hardfork}; -use alloy_primitives::{uint, U256}; - -/// Ethereum mainnet hardforks -pub const MAINNET_HARDFORKS: [(Hardfork, ForkCondition); 17] = [ - (Hardfork::Frontier, ForkCondition::Block(0)), - (Hardfork::Homestead, ForkCondition::Block(1150000)), - (Hardfork::Dao, ForkCondition::Block(1920000)), - (Hardfork::Tangerine, ForkCondition::Block(2463000)), - (Hardfork::SpuriousDragon, ForkCondition::Block(2675000)), - (Hardfork::Byzantium, ForkCondition::Block(4370000)), - (Hardfork::Constantinople, ForkCondition::Block(7280000)), - (Hardfork::Petersburg, ForkCondition::Block(7280000)), - (Hardfork::Istanbul, ForkCondition::Block(9069000)), - (Hardfork::MuirGlacier, ForkCondition::Block(9200000)), - (Hardfork::Berlin, ForkCondition::Block(12244000)), - (Hardfork::London, ForkCondition::Block(12965000)), - (Hardfork::ArrowGlacier, ForkCondition::Block(13773000)), - (Hardfork::GrayGlacier, ForkCondition::Block(15050000)), - ( - Hardfork::Paris, - ForkCondition::TTD { - fork_block: None, - total_difficulty: uint!(58_750_000_000_000_000_000_000_U256), - }, - ), - (Hardfork::Shanghai, ForkCondition::Timestamp(1681338455)), - (Hardfork::Cancun, ForkCondition::Timestamp(1710338135)), -]; - -/// Ethereum Goerli hardforks -pub const GOERLI_HARDFORKS: [(Hardfork, ForkCondition); 14] = [ - (Hardfork::Frontier, ForkCondition::Block(0)), - (Hardfork::Homestead, ForkCondition::Block(0)), - (Hardfork::Dao, ForkCondition::Block(0)), - (Hardfork::Tangerine, ForkCondition::Block(0)), - (Hardfork::SpuriousDragon, ForkCondition::Block(0)), - (Hardfork::Byzantium, ForkCondition::Block(0)), - (Hardfork::Constantinople, ForkCondition::Block(0)), - (Hardfork::Petersburg, ForkCondition::Block(0)), - (Hardfork::Istanbul, ForkCondition::Block(1561651)), - (Hardfork::Berlin, ForkCondition::Block(4460644)), - (Hardfork::London, ForkCondition::Block(5062605)), - ( - Hardfork::Paris, - ForkCondition::TTD { fork_block: None, total_difficulty: uint!(10_790_000_U256) }, - ), - (Hardfork::Shanghai, ForkCondition::Timestamp(1678832736)), - (Hardfork::Cancun, ForkCondition::Timestamp(1705473120)), -]; - -/// Ethereum Sepolia hardforks -pub const SEPOLIA_HARDFORKS: [(Hardfork, ForkCondition); 15] = [ - (Hardfork::Frontier, ForkCondition::Block(0)), - (Hardfork::Homestead, ForkCondition::Block(0)), - (Hardfork::Dao, ForkCondition::Block(0)), - (Hardfork::Tangerine, ForkCondition::Block(0)), - (Hardfork::SpuriousDragon, ForkCondition::Block(0)), - (Hardfork::Byzantium, ForkCondition::Block(0)), - (Hardfork::Constantinople, ForkCondition::Block(0)), - (Hardfork::Petersburg, ForkCondition::Block(0)), - (Hardfork::Istanbul, ForkCondition::Block(0)), - (Hardfork::MuirGlacier, ForkCondition::Block(0)), - (Hardfork::Berlin, ForkCondition::Block(0)), - (Hardfork::London, ForkCondition::Block(0)), - ( - Hardfork::Paris, - ForkCondition::TTD { - fork_block: Some(1735371), - total_difficulty: uint!(17_000_000_000_000_000_U256), - }, - ), - (Hardfork::Shanghai, ForkCondition::Timestamp(1677557088)), - (Hardfork::Cancun, ForkCondition::Timestamp(1706655072)), -]; - -/// Ethereum Holesky hardforks -pub const HOLESKY_HARDFORKS: [(Hardfork, ForkCondition); 15] = [ - (Hardfork::Frontier, ForkCondition::Block(0)), - (Hardfork::Homestead, ForkCondition::Block(0)), - (Hardfork::Dao, ForkCondition::Block(0)), - (Hardfork::Tangerine, ForkCondition::Block(0)), - (Hardfork::SpuriousDragon, ForkCondition::Block(0)), - (Hardfork::Byzantium, ForkCondition::Block(0)), - (Hardfork::Constantinople, ForkCondition::Block(0)), - (Hardfork::Petersburg, ForkCondition::Block(0)), - (Hardfork::Istanbul, ForkCondition::Block(0)), - (Hardfork::MuirGlacier, ForkCondition::Block(0)), - (Hardfork::Berlin, ForkCondition::Block(0)), - (Hardfork::London, ForkCondition::Block(0)), - (Hardfork::Paris, ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO }), - (Hardfork::Shanghai, ForkCondition::Timestamp(1696000704)), - (Hardfork::Cancun, ForkCondition::Timestamp(1707305664)), -]; diff --git a/crates/ethereum-forks/src/chains/mod.rs b/crates/ethereum-forks/src/chains/mod.rs deleted file mode 100644 index ef775777f..000000000 --- a/crates/ethereum-forks/src/chains/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -/// Ethereum chains -pub mod ethereum; - -/// Optimism chains -#[cfg(feature = "optimism")] -pub mod optimism; - -/// Dev chain -pub mod dev; diff --git a/crates/ethereum-forks/src/chains/optimism.rs b/crates/ethereum-forks/src/chains/optimism.rs deleted file mode 100644 index 37af4a19f..000000000 --- a/crates/ethereum-forks/src/chains/optimism.rs +++ /dev/null @@ -1,105 +0,0 @@ -use crate::{ForkCondition, Hardfork}; -use alloy_primitives::U256; - -/// Optimism mainnet hardforks -pub const OP_MAINNET_HARDFORKS: [(Hardfork, ForkCondition); 21] = [ - (Hardfork::Frontier, ForkCondition::Block(0)), - (Hardfork::Homestead, ForkCondition::Block(0)), - (Hardfork::Tangerine, ForkCondition::Block(0)), - (Hardfork::SpuriousDragon, ForkCondition::Block(0)), - (Hardfork::Byzantium, ForkCondition::Block(0)), - (Hardfork::Constantinople, ForkCondition::Block(0)), - (Hardfork::Petersburg, ForkCondition::Block(0)), - (Hardfork::Istanbul, ForkCondition::Block(0)), - (Hardfork::MuirGlacier, ForkCondition::Block(0)), - (Hardfork::Berlin, ForkCondition::Block(3950000)), - (Hardfork::London, ForkCondition::Block(105235063)), - (Hardfork::ArrowGlacier, ForkCondition::Block(105235063)), - (Hardfork::GrayGlacier, ForkCondition::Block(105235063)), - ( - Hardfork::Paris, - ForkCondition::TTD { fork_block: Some(105235063), total_difficulty: U256::ZERO }, - ), - (Hardfork::Bedrock, ForkCondition::Block(105235063)), - (Hardfork::Regolith, ForkCondition::Timestamp(0)), - (Hardfork::Shanghai, ForkCondition::Timestamp(1704992401)), - (Hardfork::Canyon, ForkCondition::Timestamp(1704992401)), - (Hardfork::Cancun, ForkCondition::Timestamp(1710374401)), - (Hardfork::Ecotone, ForkCondition::Timestamp(1710374401)), - (Hardfork::Fjord, ForkCondition::Timestamp(1720627201)), -]; - -/// Optimism Sepolia hardforks -pub const OP_SEPOLIA_HARDFORKS: [(Hardfork, ForkCondition); 21] = [ - (Hardfork::Frontier, ForkCondition::Block(0)), - (Hardfork::Homestead, ForkCondition::Block(0)), - (Hardfork::Tangerine, ForkCondition::Block(0)), - (Hardfork::SpuriousDragon, ForkCondition::Block(0)), - (Hardfork::Byzantium, ForkCondition::Block(0)), - (Hardfork::Constantinople, ForkCondition::Block(0)), - (Hardfork::Petersburg, ForkCondition::Block(0)), - (Hardfork::Istanbul, ForkCondition::Block(0)), - (Hardfork::MuirGlacier, ForkCondition::Block(0)), - (Hardfork::Berlin, ForkCondition::Block(0)), - (Hardfork::London, ForkCondition::Block(0)), - (Hardfork::ArrowGlacier, ForkCondition::Block(0)), - (Hardfork::GrayGlacier, ForkCondition::Block(0)), - (Hardfork::Paris, ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO }), - (Hardfork::Bedrock, ForkCondition::Block(0)), - (Hardfork::Regolith, ForkCondition::Timestamp(0)), - (Hardfork::Shanghai, ForkCondition::Timestamp(1699981200)), - (Hardfork::Canyon, ForkCondition::Timestamp(1699981200)), - (Hardfork::Cancun, ForkCondition::Timestamp(1708534800)), - (Hardfork::Ecotone, ForkCondition::Timestamp(1708534800)), - (Hardfork::Fjord, ForkCondition::Timestamp(1716998400)), -]; - -/// Base Sepolia hardforks -pub const BASE_SEPOLIA_HARDFORKS: [(Hardfork, ForkCondition); 21] = [ - (Hardfork::Frontier, ForkCondition::Block(0)), - (Hardfork::Homestead, ForkCondition::Block(0)), - (Hardfork::Tangerine, ForkCondition::Block(0)), - (Hardfork::SpuriousDragon, ForkCondition::Block(0)), - (Hardfork::Byzantium, ForkCondition::Block(0)), - (Hardfork::Constantinople, ForkCondition::Block(0)), - (Hardfork::Petersburg, ForkCondition::Block(0)), - (Hardfork::Istanbul, ForkCondition::Block(0)), - (Hardfork::MuirGlacier, ForkCondition::Block(0)), - (Hardfork::Berlin, ForkCondition::Block(0)), - (Hardfork::London, ForkCondition::Block(0)), - (Hardfork::ArrowGlacier, ForkCondition::Block(0)), - (Hardfork::GrayGlacier, ForkCondition::Block(0)), - (Hardfork::Paris, ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO }), - (Hardfork::Bedrock, ForkCondition::Block(0)), - (Hardfork::Regolith, ForkCondition::Timestamp(0)), - (Hardfork::Shanghai, ForkCondition::Timestamp(1699981200)), - (Hardfork::Canyon, ForkCondition::Timestamp(1699981200)), - (Hardfork::Cancun, ForkCondition::Timestamp(1708534800)), - (Hardfork::Ecotone, ForkCondition::Timestamp(1708534800)), - (Hardfork::Fjord, ForkCondition::Timestamp(1716998400)), -]; - -/// Base Mainnet hardforks -pub const BASE_MAINNET_HARDFORKS: [(Hardfork, ForkCondition); 21] = [ - (Hardfork::Frontier, ForkCondition::Block(0)), - (Hardfork::Homestead, ForkCondition::Block(0)), - (Hardfork::Tangerine, ForkCondition::Block(0)), - (Hardfork::SpuriousDragon, ForkCondition::Block(0)), - (Hardfork::Byzantium, ForkCondition::Block(0)), - (Hardfork::Constantinople, ForkCondition::Block(0)), - (Hardfork::Petersburg, ForkCondition::Block(0)), - (Hardfork::Istanbul, ForkCondition::Block(0)), - (Hardfork::MuirGlacier, ForkCondition::Block(0)), - (Hardfork::Berlin, ForkCondition::Block(0)), - (Hardfork::London, ForkCondition::Block(0)), - (Hardfork::ArrowGlacier, ForkCondition::Block(0)), - (Hardfork::GrayGlacier, ForkCondition::Block(0)), - (Hardfork::Paris, ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO }), - (Hardfork::Bedrock, ForkCondition::Block(0)), - (Hardfork::Regolith, ForkCondition::Timestamp(0)), - (Hardfork::Shanghai, ForkCondition::Timestamp(1704992401)), - (Hardfork::Canyon, ForkCondition::Timestamp(1704992401)), - (Hardfork::Cancun, ForkCondition::Timestamp(1710374401)), - (Hardfork::Ecotone, ForkCondition::Timestamp(1710374401)), - (Hardfork::Fjord, ForkCondition::Timestamp(1720627201)), -]; diff --git a/crates/ethereum-forks/src/display.rs b/crates/ethereum-forks/src/display.rs index 3c1424083..d8a2007e4 100644 --- a/crates/ethereum-forks/src/display.rs +++ b/crates/ethereum-forks/src/display.rs @@ -6,9 +6,7 @@ use alloc::{ vec::Vec, }; -use crate::{ForkCondition, Hardfork}; -#[cfg(feature = "std")] -use std::collections::BTreeMap; +use crate::{hardforks::Hardforks, ForkCondition}; /// A container to pretty-print a hardfork. /// @@ -146,27 +144,22 @@ impl core::fmt::Display for DisplayHardforks { impl DisplayHardforks { /// Creates a new [`DisplayHardforks`] from an iterator of hardforks. - pub fn new( - hardforks: &BTreeMap, - known_paris_block: Option, - ) -> Self { + pub fn new(hardforks: &H, known_paris_block: Option) -> Self { let mut pre_merge = Vec::new(); let mut with_merge = Vec::new(); let mut post_merge = Vec::new(); - for (fork, condition) in hardforks { + for (fork, condition) in hardforks.forks_iter() { let mut display_fork = - DisplayFork { name: fork.to_string(), activated_at: *condition, eip: None }; + DisplayFork { name: fork.name().to_string(), activated_at: condition, eip: None }; match condition { ForkCondition::Block(_) => { pre_merge.push(display_fork); } ForkCondition::TTD { total_difficulty, .. } => { - display_fork.activated_at = ForkCondition::TTD { - fork_block: known_paris_block, - total_difficulty: *total_difficulty, - }; + display_fork.activated_at = + ForkCondition::TTD { fork_block: known_paris_block, total_difficulty }; with_merge.push(display_fork); } ForkCondition::Timestamp(_) => { diff --git a/crates/ethereum-forks/src/hardfork.rs b/crates/ethereum-forks/src/hardfork.rs deleted file mode 100644 index fa095dea5..000000000 --- a/crates/ethereum-forks/src/hardfork.rs +++ /dev/null @@ -1,702 +0,0 @@ -use alloy_chains::Chain; -use core::{ - fmt, - fmt::{Display, Formatter}, - str::FromStr, -}; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -#[cfg(not(feature = "std"))] -use alloc::{format, string::String}; - -/// Represents the consensus type of a blockchain fork. -/// -/// This enum defines two variants: `ProofOfWork` for hardforks that use a proof-of-work consensus -/// mechanism, and `ProofOfStake` for hardforks that use a proof-of-stake consensus mechanism. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum ConsensusType { - /// Indicates a proof-of-work consensus mechanism. - ProofOfWork, - /// Indicates a proof-of-stake consensus mechanism. - ProofOfStake, -} - -/// The name of an Ethereum hardfork. -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] -#[non_exhaustive] -pub enum Hardfork { - /// Frontier: . - Frontier, - /// Homestead: . - Homestead, - /// The DAO fork: . - Dao, - /// Tangerine: . - Tangerine, - /// Spurious Dragon: . - SpuriousDragon, - /// Byzantium: . - Byzantium, - /// Constantinople: . - Constantinople, - /// Petersburg: . - Petersburg, - /// Istanbul: . - Istanbul, - /// Muir Glacier: . - MuirGlacier, - /// Berlin: . - Berlin, - /// London: . - London, - /// Arrow Glacier: . - ArrowGlacier, - /// Gray Glacier: . - GrayGlacier, - /// Paris: . - Paris, - /// Bedrock: . - #[cfg(feature = "optimism")] - Bedrock, - /// Regolith: . - #[cfg(feature = "optimism")] - Regolith, - /// Shanghai: . - Shanghai, - /// Canyon: - /// . - #[cfg(feature = "optimism")] - Canyon, - // ArbOS11, - /// Cancun. - Cancun, - /// Ecotone: . - #[cfg(feature = "optimism")] - Ecotone, - // ArbOS20Atlas, - - // Upcoming - /// Prague: - Prague, - /// Fjord: - #[cfg(feature = "optimism")] - Fjord, -} - -impl Hardfork { - /// Retrieves the consensus type for the specified hardfork. - pub fn consensus_type(&self) -> ConsensusType { - if *self >= Self::Paris { - ConsensusType::ProofOfStake - } else { - ConsensusType::ProofOfWork - } - } - - /// Checks if the hardfork uses Proof of Stake consensus. - pub fn is_proof_of_stake(&self) -> bool { - matches!(self.consensus_type(), ConsensusType::ProofOfStake) - } - - /// Checks if the hardfork uses Proof of Work consensus. - pub fn is_proof_of_work(&self) -> bool { - matches!(self.consensus_type(), ConsensusType::ProofOfWork) - } - - /// Retrieves the activation block for the specified hardfork on the given chain. - pub fn activation_block(&self, chain: Chain) -> Option { - if chain == Chain::mainnet() { - return self.mainnet_activation_block() - } - if chain == Chain::sepolia() { - return self.sepolia_activation_block() - } - if chain == Chain::holesky() { - return self.holesky_activation_block() - } - - #[cfg(feature = "optimism")] - { - if chain == Chain::base_sepolia() { - return self.base_sepolia_activation_block() - } - if chain == Chain::base_mainnet() { - return self.base_mainnet_activation_block() - } - } - - None - } - - /// Retrieves the activation block for the specified hardfork on the Ethereum mainnet. - pub const fn mainnet_activation_block(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier => Some(0), - Self::Homestead => Some(1150000), - Self::Dao => Some(1920000), - Self::Tangerine => Some(2463000), - Self::SpuriousDragon => Some(2675000), - Self::Byzantium => Some(4370000), - Self::Constantinople | Self::Petersburg => Some(7280000), - Self::Istanbul => Some(9069000), - Self::MuirGlacier => Some(9200000), - Self::Berlin => Some(12244000), - Self::London => Some(12965000), - Self::ArrowGlacier => Some(13773000), - Self::GrayGlacier => Some(15050000), - Self::Paris => Some(15537394), - Self::Shanghai => Some(17034870), - Self::Cancun => Some(19426587), - - _ => None, - } - } - - /// Retrieves the activation block for the specified hardfork on the Sepolia testnet. - pub const fn sepolia_activation_block(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Paris => Some(1735371), - Self::Shanghai => Some(2990908), - Self::Cancun => Some(5187023), - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier => Some(0), - _ => None, - } - } - - /// Retrieves the activation block for the specified hardfork on the Arbitrum Sepolia testnet. - pub const fn arbitrum_sepolia_activation_block(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris => Some(0), - Self::Shanghai => Some(10653737), - // Hardfork::ArbOS11 => Some(10653737), - Self::Cancun => Some(18683405), - // Hardfork::ArbOS20Atlas => Some(18683405), - _ => None, - } - } - - /// Retrieves the activation block for the specified hardfork on the Arbitrum One mainnet. - pub const fn arbitrum_activation_block(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris => Some(0), - Self::Shanghai => Some(184097479), - // Hardfork::ArbOS11 => Some(184097479), - Self::Cancun => Some(190301729), - // Hardfork::ArbOS20Atlas => Some(190301729), - _ => None, - } - } - - /// Retrieves the activation block for the specified hardfork on the Base Sepolia testnet. - #[cfg(feature = "optimism")] - pub const fn base_sepolia_activation_block(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris | - Self::Bedrock | - Self::Regolith => Some(0), - Self::Shanghai | Self::Canyon => Some(2106456), - Self::Cancun | Self::Ecotone => Some(6383256), - Self::Fjord => Some(10615056), - _ => None, - } - } - - /// Retrieves the activation block for the specified hardfork on the Base mainnet. - #[cfg(feature = "optimism")] - pub const fn base_mainnet_activation_block(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris | - Self::Bedrock | - Self::Regolith => Some(0), - Self::Shanghai | Self::Canyon => Some(9101527), - Self::Cancun | Self::Ecotone => Some(11188936), - _ => None, - } - } - - /// Retrieves the activation block for the specified hardfork on the holesky testnet. - const fn holesky_activation_block(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris => Some(0), - Self::Shanghai => Some(6698), - Self::Cancun => Some(894733), - _ => None, - } - } - - /// Retrieves the activation timestamp for the specified hardfork on the given chain. - pub fn activation_timestamp(&self, chain: Chain) -> Option { - if chain == Chain::mainnet() { - return self.mainnet_activation_timestamp() - } - if chain == Chain::sepolia() { - return self.sepolia_activation_timestamp() - } - if chain == Chain::holesky() { - return self.holesky_activation_timestamp() - } - #[cfg(feature = "optimism")] - { - if chain == Chain::base_sepolia() { - return self.base_sepolia_activation_timestamp() - } - if chain == Chain::base_mainnet() { - return self.base_mainnet_activation_timestamp() - } - } - - None - } - - /// Retrieves the activation timestamp for the specified hardfork on the Ethereum mainnet. - pub const fn mainnet_activation_timestamp(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier => Some(1438226773), - Self::Homestead => Some(1457938193), - Self::Dao => Some(1468977640), - Self::Tangerine => Some(1476753571), - Self::SpuriousDragon => Some(1479788144), - Self::Byzantium => Some(1508131331), - Self::Constantinople | Self::Petersburg => Some(1551340324), - Self::Istanbul => Some(1575807909), - Self::MuirGlacier => Some(1577953849), - Self::Berlin => Some(1618481223), - Self::London => Some(1628166822), - Self::ArrowGlacier => Some(1639036523), - Self::GrayGlacier => Some(1656586444), - Self::Paris => Some(1663224162), - Self::Shanghai => Some(1681338455), - Self::Cancun => Some(1710338135), - - // upcoming hardforks - _ => None, - } - } - - /// Retrieves the activation timestamp for the specified hardfork on the Sepolia testnet. - pub const fn sepolia_activation_timestamp(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris => Some(1633267481), - Self::Shanghai => Some(1677557088), - Self::Cancun => Some(1706655072), - _ => None, - } - } - - /// Retrieves the activation timestamp for the specified hardfork on the Holesky testnet. - pub const fn holesky_activation_timestamp(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Shanghai => Some(1696000704), - Self::Cancun => Some(1707305664), - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris => Some(1695902100), - _ => None, - } - } - - /// Retrieves the activation timestamp for the specified hardfork on the Arbitrum Sepolia - /// testnet. - pub const fn arbitrum_sepolia_activation_timestamp(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris => Some(1692726996), - Self::Shanghai => Some(1706634000), - // Hardfork::ArbOS11 => Some(1706634000), - Self::Cancun => Some(1709229600), - // Hardfork::ArbOS20Atlas => Some(1709229600), - _ => None, - } - } - - /// Retrieves the activation timestamp for the specified hardfork on the Arbitrum One mainnet. - pub const fn arbitrum_activation_timestamp(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris => Some(1622240000), - Self::Shanghai => Some(1708804873), - // Hardfork::ArbOS11 => Some(1708804873), - Self::Cancun => Some(1710424089), - // Hardfork::ArbOS20Atlas => Some(1710424089), - _ => None, - } - } - - /// Retrieves the activation timestamp for the specified hardfork on the Base Sepolia testnet. - #[cfg(feature = "optimism")] - pub const fn base_sepolia_activation_timestamp(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris | - Self::Bedrock | - Self::Regolith => Some(1695768288), - Self::Shanghai | Self::Canyon => Some(1699981200), - Self::Cancun | Self::Ecotone => Some(1708534800), - Self::Fjord => Some(1716998400), - _ => None, - } - } - - /// Retrieves the activation timestamp for the specified hardfork on the Base mainnet. - #[cfg(feature = "optimism")] - pub const fn base_mainnet_activation_timestamp(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris | - Self::Bedrock | - Self::Regolith => Some(1686789347), - Self::Shanghai | Self::Canyon => Some(1704992401), - Self::Cancun | Self::Ecotone => Some(1710374401), - Self::Fjord => Some(1720627201), - _ => None, - } - } -} - -impl FromStr for Hardfork { - type Err = String; - - fn from_str(s: &str) -> Result { - Ok(match s.to_lowercase().as_str() { - "frontier" => Self::Frontier, - "homestead" => Self::Homestead, - "dao" => Self::Dao, - "tangerine" => Self::Tangerine, - "spuriousdragon" => Self::SpuriousDragon, - "byzantium" => Self::Byzantium, - "constantinople" => Self::Constantinople, - "petersburg" => Self::Petersburg, - "istanbul" => Self::Istanbul, - "muirglacier" => Self::MuirGlacier, - "berlin" => Self::Berlin, - "london" => Self::London, - "arrowglacier" => Self::ArrowGlacier, - "grayglacier" => Self::GrayGlacier, - "paris" => Self::Paris, - "shanghai" => Self::Shanghai, - "cancun" => Self::Cancun, - #[cfg(feature = "optimism")] - "bedrock" => Self::Bedrock, - #[cfg(feature = "optimism")] - "regolith" => Self::Regolith, - #[cfg(feature = "optimism")] - "canyon" => Self::Canyon, - #[cfg(feature = "optimism")] - "ecotone" => Self::Ecotone, - #[cfg(feature = "optimism")] - "fjord" => Self::Fjord, - "prague" => Self::Prague, - // "arbos11" => Hardfork::ArbOS11, - // "arbos20atlas" => Hardfork::ArbOS20Atlas, - _ => return Err(format!("Unknown hardfork: {s}")), - }) - } -} - -impl Display for Hardfork { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{self:?}") - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn check_hardfork_from_str() { - let hardfork_str = [ - "frOntier", - "homEstead", - "dao", - "tAngerIne", - "spurIousdrAgon", - "byzAntium", - "constantinople", - "petersburg", - "istanbul", - "muirglacier", - "bErlin", - "lonDon", - "arrowglacier", - "grayglacier", - "PARIS", - "ShAnGhAI", - "CaNcUn", - "PrAguE", - ]; - let expected_hardforks = [ - Hardfork::Frontier, - Hardfork::Homestead, - Hardfork::Dao, - Hardfork::Tangerine, - Hardfork::SpuriousDragon, - Hardfork::Byzantium, - Hardfork::Constantinople, - Hardfork::Petersburg, - Hardfork::Istanbul, - Hardfork::MuirGlacier, - Hardfork::Berlin, - Hardfork::London, - Hardfork::ArrowGlacier, - Hardfork::GrayGlacier, - Hardfork::Paris, - Hardfork::Shanghai, - Hardfork::Cancun, - Hardfork::Prague, - ]; - - let hardforks: Vec = - hardfork_str.iter().map(|h| Hardfork::from_str(h).unwrap()).collect(); - - assert_eq!(hardforks, expected_hardforks); - } - - #[test] - #[cfg(feature = "optimism")] - fn check_op_hardfork_from_str() { - let hardfork_str = ["beDrOck", "rEgOlITH", "cAnYoN", "eCoToNe", "FJorD"]; - let expected_hardforks = [ - Hardfork::Bedrock, - Hardfork::Regolith, - Hardfork::Canyon, - Hardfork::Ecotone, - Hardfork::Fjord, - ]; - - let hardforks: Vec = - hardfork_str.iter().map(|h| Hardfork::from_str(h).unwrap()).collect(); - - assert_eq!(hardforks, expected_hardforks); - } - - #[test] - fn check_nonexistent_hardfork_from_str() { - assert!(Hardfork::from_str("not a hardfork").is_err()); - } - - #[test] - fn check_consensus_type() { - let pow_hardforks = [ - Hardfork::Frontier, - Hardfork::Homestead, - Hardfork::Dao, - Hardfork::Tangerine, - Hardfork::SpuriousDragon, - Hardfork::Byzantium, - Hardfork::Constantinople, - Hardfork::Petersburg, - Hardfork::Istanbul, - Hardfork::MuirGlacier, - Hardfork::Berlin, - Hardfork::London, - Hardfork::ArrowGlacier, - Hardfork::GrayGlacier, - ]; - - let pos_hardforks = [Hardfork::Paris, Hardfork::Shanghai, Hardfork::Cancun]; - - #[cfg(feature = "optimism")] - let op_hardforks = [ - Hardfork::Bedrock, - Hardfork::Regolith, - Hardfork::Canyon, - Hardfork::Ecotone, - Hardfork::Fjord, - ]; - - for hardfork in &pow_hardforks { - assert_eq!(hardfork.consensus_type(), ConsensusType::ProofOfWork); - assert!(!hardfork.is_proof_of_stake()); - assert!(hardfork.is_proof_of_work()); - } - - for hardfork in &pos_hardforks { - assert_eq!(hardfork.consensus_type(), ConsensusType::ProofOfStake); - assert!(hardfork.is_proof_of_stake()); - assert!(!hardfork.is_proof_of_work()); - } - - #[cfg(feature = "optimism")] - for hardfork in &op_hardforks { - assert_eq!(hardfork.consensus_type(), ConsensusType::ProofOfStake); - assert!(hardfork.is_proof_of_stake()); - assert!(!hardfork.is_proof_of_work()); - } - } -} diff --git a/crates/ethereum-forks/src/hardfork/dev.rs b/crates/ethereum-forks/src/hardfork/dev.rs new file mode 100644 index 000000000..4b422141b --- /dev/null +++ b/crates/ethereum-forks/src/hardfork/dev.rs @@ -0,0 +1,32 @@ +use crate::{ChainHardforks, EthereumHardfork, ForkCondition}; +use alloy_primitives::U256; +use once_cell::sync::Lazy; + +/// Dev hardforks +pub static DEV_HARDFORKS: Lazy = Lazy::new(|| { + ChainHardforks::new(vec![ + (EthereumHardfork::Frontier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Homestead.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Dao.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Tangerine.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::SpuriousDragon.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Byzantium.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Constantinople.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Petersburg.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Istanbul.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Berlin.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::London.boxed(), ForkCondition::Block(0)), + ( + EthereumHardfork::Paris.boxed(), + ForkCondition::TTD { fork_block: None, total_difficulty: U256::ZERO }, + ), + (EthereumHardfork::Shanghai.boxed(), ForkCondition::Timestamp(0)), + (EthereumHardfork::Cancun.boxed(), ForkCondition::Timestamp(0)), + #[cfg(feature = "optimism")] + (crate::OptimismHardfork::Regolith.boxed(), ForkCondition::Timestamp(0)), + #[cfg(feature = "optimism")] + (crate::OptimismHardfork::Bedrock.boxed(), ForkCondition::Block(0)), + #[cfg(feature = "optimism")] + (crate::OptimismHardfork::Ecotone.boxed(), ForkCondition::Timestamp(0)), + ]) +}); diff --git a/crates/ethereum-forks/src/hardfork/ethereum.rs b/crates/ethereum-forks/src/hardfork/ethereum.rs new file mode 100644 index 000000000..9e2a8a111 --- /dev/null +++ b/crates/ethereum-forks/src/hardfork/ethereum.rs @@ -0,0 +1,441 @@ +use crate::{hardfork, ChainHardforks, ForkCondition, Hardfork}; +use alloy_chains::Chain; +use alloy_primitives::{uint, U256}; +use core::{ + fmt, + fmt::{Display, Formatter}, + str::FromStr, +}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +hardfork!( + /// The name of an Ethereum hardfork. + EthereumHardfork { + /// Frontier: . + Frontier, + /// Homestead: . + Homestead, + /// The DAO fork: . + Dao, + /// Tangerine: . + Tangerine, + /// Spurious Dragon: . + SpuriousDragon, + /// Byzantium: . + Byzantium, + /// Constantinople: . + Constantinople, + /// Petersburg: . + Petersburg, + /// Istanbul: . + Istanbul, + /// Muir Glacier: . + MuirGlacier, + /// Berlin: . + Berlin, + /// London: . + London, + /// Arrow Glacier: . + ArrowGlacier, + /// Gray Glacier: . + GrayGlacier, + /// Paris: . + Paris, + /// Shanghai: . + Shanghai, + /// Cancun. + Cancun, + /// Prague: + Prague, + } +); + +impl EthereumHardfork { + /// Retrieves the activation block for the specified hardfork on the given chain. + pub fn activation_block(&self, chain: Chain) -> Option { + if chain == Chain::mainnet() { + return self.mainnet_activation_block() + } + if chain == Chain::sepolia() { + return self.sepolia_activation_block() + } + if chain == Chain::holesky() { + return self.holesky_activation_block() + } + + None + } + + /// Retrieves the activation block for the specified hardfork on the Ethereum mainnet. + pub const fn mainnet_activation_block(&self) -> Option { + match self { + Self::Frontier => Some(0), + Self::Homestead => Some(1150000), + Self::Dao => Some(1920000), + Self::Tangerine => Some(2463000), + Self::SpuriousDragon => Some(2675000), + Self::Byzantium => Some(4370000), + Self::Constantinople | Self::Petersburg => Some(7280000), + Self::Istanbul => Some(9069000), + Self::MuirGlacier => Some(9200000), + Self::Berlin => Some(12244000), + Self::London => Some(12965000), + Self::ArrowGlacier => Some(13773000), + Self::GrayGlacier => Some(15050000), + Self::Paris => Some(15537394), + Self::Shanghai => Some(17034870), + Self::Cancun => Some(19426587), + _ => None, + } + } + + /// Retrieves the activation block for the specified hardfork on the Sepolia testnet. + pub const fn sepolia_activation_block(&self) -> Option { + match self { + Self::Paris => Some(1735371), + Self::Shanghai => Some(2990908), + Self::Cancun => Some(5187023), + Self::Frontier | + Self::Homestead | + Self::Dao | + Self::Tangerine | + Self::SpuriousDragon | + Self::Byzantium | + Self::Constantinople | + Self::Petersburg | + Self::Istanbul | + Self::MuirGlacier | + Self::Berlin | + Self::London | + Self::ArrowGlacier | + Self::GrayGlacier => Some(0), + _ => None, + } + } + + /// Retrieves the activation block for the specified hardfork on the holesky testnet. + const fn holesky_activation_block(&self) -> Option { + match self { + Self::Dao | + Self::Tangerine | + Self::SpuriousDragon | + Self::Byzantium | + Self::Constantinople | + Self::Petersburg | + Self::Istanbul | + Self::MuirGlacier | + Self::Berlin | + Self::London | + Self::ArrowGlacier | + Self::GrayGlacier | + Self::Paris => Some(0), + Self::Shanghai => Some(6698), + Self::Cancun => Some(894733), + _ => None, + } + } + + /// Retrieves the activation block for the specified hardfork on the Arbitrum Sepolia testnet. + pub const fn arbitrum_sepolia_activation_block(&self) -> Option { + match self { + Self::Frontier | + Self::Homestead | + Self::Dao | + Self::Tangerine | + Self::SpuriousDragon | + Self::Byzantium | + Self::Constantinople | + Self::Petersburg | + Self::Istanbul | + Self::MuirGlacier | + Self::Berlin | + Self::London | + Self::ArrowGlacier | + Self::GrayGlacier | + Self::Paris => Some(0), + Self::Shanghai => Some(10653737), + // Hardfork::ArbOS11 => Some(10653737), + Self::Cancun => Some(18683405), + // Hardfork::ArbOS20Atlas => Some(18683405), + _ => None, + } + } + + /// Retrieves the activation block for the specified hardfork on the Arbitrum One mainnet. + pub const fn arbitrum_activation_block(&self) -> Option { + match self { + Self::Frontier | + Self::Homestead | + Self::Dao | + Self::Tangerine | + Self::SpuriousDragon | + Self::Byzantium | + Self::Constantinople | + Self::Petersburg | + Self::Istanbul | + Self::MuirGlacier | + Self::Berlin | + Self::London | + Self::ArrowGlacier | + Self::GrayGlacier | + Self::Paris => Some(0), + Self::Shanghai => Some(184097479), + // Hardfork::ArbOS11 => Some(184097479), + Self::Cancun => Some(190301729), + // Hardfork::ArbOS20Atlas => Some(190301729), + _ => None, + } + } + + /// Retrieves the activation timestamp for the specified hardfork on the given chain. + pub fn activation_timestamp(&self, chain: Chain) -> Option { + if chain == Chain::mainnet() { + return self.mainnet_activation_timestamp() + } + if chain == Chain::sepolia() { + return self.sepolia_activation_timestamp() + } + if chain == Chain::holesky() { + return self.holesky_activation_timestamp() + } + + None + } + + /// Retrieves the activation timestamp for the specified hardfork on the Ethereum mainnet. + pub const fn mainnet_activation_timestamp(&self) -> Option { + match self { + Self::Frontier => Some(1438226773), + Self::Homestead => Some(1457938193), + Self::Dao => Some(1468977640), + Self::Tangerine => Some(1476753571), + Self::SpuriousDragon => Some(1479788144), + Self::Byzantium => Some(1508131331), + Self::Constantinople | Self::Petersburg => Some(1551340324), + Self::Istanbul => Some(1575807909), + Self::MuirGlacier => Some(1577953849), + Self::Berlin => Some(1618481223), + Self::London => Some(1628166822), + Self::ArrowGlacier => Some(1639036523), + Self::GrayGlacier => Some(1656586444), + Self::Paris => Some(1663224162), + Self::Shanghai => Some(1681338455), + Self::Cancun => Some(1710338135), + + // upcoming hardforks + _ => None, + } + } + + /// Retrieves the activation timestamp for the specified hardfork on the Sepolia testnet. + pub const fn sepolia_activation_timestamp(&self) -> Option { + match self { + Self::Frontier | + Self::Homestead | + Self::Dao | + Self::Tangerine | + Self::SpuriousDragon | + Self::Byzantium | + Self::Constantinople | + Self::Petersburg | + Self::Istanbul | + Self::MuirGlacier | + Self::Berlin | + Self::London | + Self::ArrowGlacier | + Self::GrayGlacier | + Self::Paris => Some(1633267481), + Self::Shanghai => Some(1677557088), + Self::Cancun => Some(1706655072), + _ => None, + } + } + + /// Retrieves the activation timestamp for the specified hardfork on the Holesky testnet. + pub const fn holesky_activation_timestamp(&self) -> Option { + match self { + Self::Shanghai => Some(1696000704), + Self::Cancun => Some(1707305664), + Self::Frontier | + Self::Homestead | + Self::Dao | + Self::Tangerine | + Self::SpuriousDragon | + Self::Byzantium | + Self::Constantinople | + Self::Petersburg | + Self::Istanbul | + Self::MuirGlacier | + Self::Berlin | + Self::London | + Self::ArrowGlacier | + Self::GrayGlacier | + Self::Paris => Some(1695902100), + _ => None, + } + } + + /// Retrieves the activation timestamp for the specified hardfork on the Arbitrum Sepolia + /// testnet. + pub const fn arbitrum_sepolia_activation_timestamp(&self) -> Option { + match self { + Self::Frontier | + Self::Homestead | + Self::Dao | + Self::Tangerine | + Self::SpuriousDragon | + Self::Byzantium | + Self::Constantinople | + Self::Petersburg | + Self::Istanbul | + Self::MuirGlacier | + Self::Berlin | + Self::London | + Self::ArrowGlacier | + Self::GrayGlacier | + Self::Paris => Some(1692726996), + Self::Shanghai => Some(1706634000), + // Hardfork::ArbOS11 => Some(1706634000), + Self::Cancun => Some(1709229600), + // Hardfork::ArbOS20Atlas => Some(1709229600), + _ => None, + } + } + + /// Retrieves the activation timestamp for the specified hardfork on the Arbitrum One mainnet. + pub const fn arbitrum_activation_timestamp(&self) -> Option { + match self { + Self::Frontier | + Self::Homestead | + Self::Dao | + Self::Tangerine | + Self::SpuriousDragon | + Self::Byzantium | + Self::Constantinople | + Self::Petersburg | + Self::Istanbul | + Self::MuirGlacier | + Self::Berlin | + Self::London | + Self::ArrowGlacier | + Self::GrayGlacier | + Self::Paris => Some(1622240000), + Self::Shanghai => Some(1708804873), + // Hardfork::ArbOS11 => Some(1708804873), + Self::Cancun => Some(1710424089), + // Hardfork::ArbOS20Atlas => Some(1710424089), + _ => None, + } + } + + /// Ethereum mainnet list of hardforks. + pub const fn mainnet() -> [(Self, ForkCondition); 17] { + [ + (Self::Frontier, ForkCondition::Block(0)), + (Self::Homestead, ForkCondition::Block(1150000)), + (Self::Dao, ForkCondition::Block(1920000)), + (Self::Tangerine, ForkCondition::Block(2463000)), + (Self::SpuriousDragon, ForkCondition::Block(2675000)), + (Self::Byzantium, ForkCondition::Block(4370000)), + (Self::Constantinople, ForkCondition::Block(7280000)), + (Self::Petersburg, ForkCondition::Block(7280000)), + (Self::Istanbul, ForkCondition::Block(9069000)), + (Self::MuirGlacier, ForkCondition::Block(9200000)), + (Self::Berlin, ForkCondition::Block(12244000)), + (Self::London, ForkCondition::Block(12965000)), + (Self::ArrowGlacier, ForkCondition::Block(13773000)), + (Self::GrayGlacier, ForkCondition::Block(15050000)), + ( + Self::Paris, + ForkCondition::TTD { + fork_block: None, + total_difficulty: uint!(58_750_000_000_000_000_000_000_U256), + }, + ), + (Self::Shanghai, ForkCondition::Timestamp(1681338455)), + (Self::Cancun, ForkCondition::Timestamp(1710338135)), + ] + } + + /// Ethereum goerli list of hardforks. + pub const fn goerli() -> [(Self, ForkCondition); 14] { + [ + (Self::Frontier, ForkCondition::Block(0)), + (Self::Homestead, ForkCondition::Block(0)), + (Self::Dao, ForkCondition::Block(0)), + (Self::Tangerine, ForkCondition::Block(0)), + (Self::SpuriousDragon, ForkCondition::Block(0)), + (Self::Byzantium, ForkCondition::Block(0)), + (Self::Constantinople, ForkCondition::Block(0)), + (Self::Petersburg, ForkCondition::Block(0)), + (Self::Istanbul, ForkCondition::Block(1561651)), + (Self::Berlin, ForkCondition::Block(4460644)), + (Self::London, ForkCondition::Block(5062605)), + ( + Self::Paris, + ForkCondition::TTD { fork_block: None, total_difficulty: uint!(10_790_000_U256) }, + ), + (Self::Shanghai, ForkCondition::Timestamp(1678832736)), + (Self::Cancun, ForkCondition::Timestamp(1705473120)), + ] + } + + /// Ethereum sepolia list of hardforks. + pub const fn sepolia() -> [(Self, ForkCondition); 15] { + [ + (Self::Frontier, ForkCondition::Block(0)), + (Self::Homestead, ForkCondition::Block(0)), + (Self::Dao, ForkCondition::Block(0)), + (Self::Tangerine, ForkCondition::Block(0)), + (Self::SpuriousDragon, ForkCondition::Block(0)), + (Self::Byzantium, ForkCondition::Block(0)), + (Self::Constantinople, ForkCondition::Block(0)), + (Self::Petersburg, ForkCondition::Block(0)), + (Self::Istanbul, ForkCondition::Block(0)), + (Self::MuirGlacier, ForkCondition::Block(0)), + (Self::Berlin, ForkCondition::Block(0)), + (Self::London, ForkCondition::Block(0)), + ( + Self::Paris, + ForkCondition::TTD { + fork_block: Some(1735371), + total_difficulty: uint!(17_000_000_000_000_000_U256), + }, + ), + (Self::Shanghai, ForkCondition::Timestamp(1677557088)), + (Self::Cancun, ForkCondition::Timestamp(1706655072)), + ] + } + + /// Ethereum holesky list of hardforks. + pub const fn holesky() -> [(Self, ForkCondition); 15] { + [ + (Self::Frontier, ForkCondition::Block(0)), + (Self::Homestead, ForkCondition::Block(0)), + (Self::Dao, ForkCondition::Block(0)), + (Self::Tangerine, ForkCondition::Block(0)), + (Self::SpuriousDragon, ForkCondition::Block(0)), + (Self::Byzantium, ForkCondition::Block(0)), + (Self::Constantinople, ForkCondition::Block(0)), + (Self::Petersburg, ForkCondition::Block(0)), + (Self::Istanbul, ForkCondition::Block(0)), + (Self::MuirGlacier, ForkCondition::Block(0)), + (Self::Berlin, ForkCondition::Block(0)), + (Self::London, ForkCondition::Block(0)), + (Self::Paris, ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO }), + (Self::Shanghai, ForkCondition::Timestamp(1696000704)), + (Self::Cancun, ForkCondition::Timestamp(1707305664)), + ] + } +} + +impl From<[(EthereumHardfork, ForkCondition); N]> for ChainHardforks { + fn from(list: [(EthereumHardfork, ForkCondition); N]) -> Self { + Self::new( + list.into_iter() + .map(|(fork, cond)| (Box::new(fork) as Box, cond)) + .collect(), + ) + } +} diff --git a/crates/ethereum-forks/src/hardfork/macros.rs b/crates/ethereum-forks/src/hardfork/macros.rs new file mode 100644 index 000000000..780c15f6e --- /dev/null +++ b/crates/ethereum-forks/src/hardfork/macros.rs @@ -0,0 +1,52 @@ +/// Macro that defines different variants of a chain specific enum. See [`crate::Hardfork`] as an +/// example. +#[macro_export] +macro_rules! hardfork { + ($(#[$enum_meta:meta])* $enum:ident { $( $(#[$meta:meta])* $variant:ident ),* $(,)? }) => { + $(#[$enum_meta])* + #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] + #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] + pub enum $enum { + $( $(#[$meta])* $variant ),* + } + + impl $enum { + /// Returns variant as `str`. + pub const fn name(&self) -> &'static str { + match self { + $( $enum::$variant => stringify!($variant), )* + } + } + + /// Boxes `self` and returns it as `Box`. + pub fn boxed(self) -> Box { + Box::new(self) + } + } + + impl FromStr for $enum { + type Err = String; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + $( + s if s == stringify!($variant).to_lowercase() => Ok($enum::$variant), + )* + _ => return Err(format!("Unknown hardfork: {s}")), + } + } + } + + impl Hardfork for $enum { + fn name(&self) -> &'static str { + self.name() + } + } + + impl Display for $enum { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{self:?}") + } + } + } +} diff --git a/crates/ethereum-forks/src/hardfork/mod.rs b/crates/ethereum-forks/src/hardfork/mod.rs new file mode 100644 index 000000000..b6faef6ec --- /dev/null +++ b/crates/ethereum-forks/src/hardfork/mod.rs @@ -0,0 +1,126 @@ +mod macros; + +mod ethereum; +pub use ethereum::EthereumHardfork; + +mod optimism; +pub use optimism::OptimismHardfork; + +mod dev; +pub use dev::DEV_HARDFORKS; + +use core::{ + any::Any, + hash::{Hash, Hasher}, +}; +use dyn_clone::DynClone; + +#[cfg(not(feature = "std"))] +use alloc::{format, string::String}; + +/// Generic hardfork trait. +#[auto_impl::auto_impl(&, Box)] +pub trait Hardfork: Any + DynClone + Send + Sync + 'static { + /// Fork name. + fn name(&self) -> &'static str; +} + +dyn_clone::clone_trait_object!(Hardfork); + +impl core::fmt::Debug for dyn Hardfork + 'static { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct(self.name()).finish() + } +} + +impl PartialEq for dyn Hardfork + 'static { + fn eq(&self, other: &Self) -> bool { + self.name() == other.name() + } +} + +impl Eq for dyn Hardfork + 'static {} + +impl Hash for dyn Hardfork + 'static { + fn hash(&self, state: &mut H) { + self.name().hash(state) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::hardfork::optimism::OptimismHardfork; + use std::str::FromStr; + + #[test] + fn check_hardfork_from_str() { + let hardfork_str = [ + "frOntier", + "homEstead", + "dao", + "tAngerIne", + "spurIousdrAgon", + "byzAntium", + "constantinople", + "petersburg", + "istanbul", + "muirglacier", + "bErlin", + "lonDon", + "arrowglacier", + "grayglacier", + "PARIS", + "ShAnGhAI", + "CaNcUn", + "PrAguE", + ]; + let expected_hardforks = [ + EthereumHardfork::Frontier, + EthereumHardfork::Homestead, + EthereumHardfork::Dao, + EthereumHardfork::Tangerine, + EthereumHardfork::SpuriousDragon, + EthereumHardfork::Byzantium, + EthereumHardfork::Constantinople, + EthereumHardfork::Petersburg, + EthereumHardfork::Istanbul, + EthereumHardfork::MuirGlacier, + EthereumHardfork::Berlin, + EthereumHardfork::London, + EthereumHardfork::ArrowGlacier, + EthereumHardfork::GrayGlacier, + EthereumHardfork::Paris, + EthereumHardfork::Shanghai, + EthereumHardfork::Cancun, + EthereumHardfork::Prague, + ]; + + let hardforks: Vec = + hardfork_str.iter().map(|h| EthereumHardfork::from_str(h).unwrap()).collect(); + + assert_eq!(hardforks, expected_hardforks); + } + + #[test] + fn check_op_hardfork_from_str() { + let hardfork_str = ["beDrOck", "rEgOlITH", "cAnYoN", "eCoToNe", "FJorD"]; + let expected_hardforks = [ + OptimismHardfork::Bedrock, + OptimismHardfork::Regolith, + OptimismHardfork::Canyon, + OptimismHardfork::Ecotone, + OptimismHardfork::Fjord, + ]; + + let hardforks: Vec = + hardfork_str.iter().map(|h| OptimismHardfork::from_str(h).unwrap()).collect(); + + assert_eq!(hardforks, expected_hardforks); + } + + #[test] + fn check_nonexistent_hardfork_from_str() { + assert!(EthereumHardfork::from_str("not a hardfork").is_err()); + } +} diff --git a/crates/ethereum-forks/src/hardfork/optimism.rs b/crates/ethereum-forks/src/hardfork/optimism.rs new file mode 100644 index 000000000..6933b7fed --- /dev/null +++ b/crates/ethereum-forks/src/hardfork/optimism.rs @@ -0,0 +1,337 @@ +use crate::{hardfork, ChainHardforks, EthereumHardfork, ForkCondition, Hardfork}; +use alloy_chains::Chain; +use alloy_primitives::U256; +use core::{ + any::Any, + fmt::{self, Display, Formatter}, + str::FromStr, +}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +hardfork!( + /// The name of an optimism hardfork. + /// + /// When building a list of hardforks for a chain, it's still expected to mix with [`EthereumHardfork`]. + OptimismHardfork { + /// Bedrock: . + Bedrock, + /// Regolith: . + Regolith, + /// . + Canyon, + /// Ecotone: . + Ecotone, + /// Fjord: + Fjord, + } +); + +impl OptimismHardfork { + /// Retrieves the activation block for the specified hardfork on the given chain. + pub fn activation_block(self, fork: H, chain: Chain) -> Option { + if chain == Chain::base_sepolia() { + return Self::base_sepolia_activation_block(fork) + } + if chain == Chain::base_mainnet() { + return Self::base_mainnet_activation_block(fork) + } + + None + } + + /// Retrieves the activation timestamp for the specified hardfork on the given chain. + pub fn activation_timestamp(self, fork: H, chain: Chain) -> Option { + if chain == Chain::base_sepolia() { + return Self::base_sepolia_activation_timestamp(fork) + } + if chain == Chain::base_mainnet() { + return Self::base_mainnet_activation_timestamp(fork) + } + + None + } + + /// Retrieves the activation block for the specified hardfork on the Base Sepolia testnet. + pub fn base_sepolia_activation_block(fork: H) -> Option { + match_hardfork( + fork, + |fork| match fork { + EthereumHardfork::Frontier | + EthereumHardfork::Homestead | + EthereumHardfork::Dao | + EthereumHardfork::Tangerine | + EthereumHardfork::SpuriousDragon | + EthereumHardfork::Byzantium | + EthereumHardfork::Constantinople | + EthereumHardfork::Petersburg | + EthereumHardfork::Istanbul | + EthereumHardfork::MuirGlacier | + EthereumHardfork::Berlin | + EthereumHardfork::London | + EthereumHardfork::ArrowGlacier | + EthereumHardfork::GrayGlacier | + EthereumHardfork::Paris | + EthereumHardfork::Shanghai => Some(2106456), + EthereumHardfork::Cancun => Some(6383256), + _ => None, + }, + |fork| match fork { + Self::Bedrock | Self::Regolith => Some(0), + Self::Canyon => Some(2106456), + Self::Ecotone => Some(6383256), + Self::Fjord => Some(10615056), + }, + ) + } + + /// Retrieves the activation block for the specified hardfork on the Base mainnet. + pub fn base_mainnet_activation_block(fork: H) -> Option { + match_hardfork( + fork, + |fork| match fork { + EthereumHardfork::Frontier | + EthereumHardfork::Homestead | + EthereumHardfork::Dao | + EthereumHardfork::Tangerine | + EthereumHardfork::SpuriousDragon | + EthereumHardfork::Byzantium | + EthereumHardfork::Constantinople | + EthereumHardfork::Petersburg | + EthereumHardfork::Istanbul | + EthereumHardfork::MuirGlacier | + EthereumHardfork::Berlin | + EthereumHardfork::London | + EthereumHardfork::ArrowGlacier | + EthereumHardfork::GrayGlacier | + EthereumHardfork::Paris | + EthereumHardfork::Shanghai => Some(9101527), + EthereumHardfork::Cancun => Some(11188936), + _ => None, + }, + |fork| match fork { + Self::Bedrock | Self::Regolith => Some(0), + Self::Canyon => Some(9101527), + Self::Ecotone => Some(11188936), + _ => None, + }, + ) + } + + /// Retrieves the activation timestamp for the specified hardfork on the Base Sepolia testnet. + pub fn base_sepolia_activation_timestamp(fork: H) -> Option { + match_hardfork( + fork, + |fork| match fork { + EthereumHardfork::Frontier | + EthereumHardfork::Homestead | + EthereumHardfork::Dao | + EthereumHardfork::Tangerine | + EthereumHardfork::SpuriousDragon | + EthereumHardfork::Byzantium | + EthereumHardfork::Constantinople | + EthereumHardfork::Petersburg | + EthereumHardfork::Istanbul | + EthereumHardfork::MuirGlacier | + EthereumHardfork::Berlin | + EthereumHardfork::London | + EthereumHardfork::ArrowGlacier | + EthereumHardfork::GrayGlacier | + EthereumHardfork::Paris | + EthereumHardfork::Shanghai => Some(1699981200), + EthereumHardfork::Cancun => Some(1708534800), + _ => None, + }, + |fork| match fork { + Self::Bedrock | Self::Regolith => Some(1695768288), + Self::Canyon => Some(1699981200), + Self::Ecotone => Some(1708534800), + Self::Fjord => Some(1716998400), + }, + ) + } + + /// Retrieves the activation timestamp for the specified hardfork on the Base mainnet. + pub fn base_mainnet_activation_timestamp(fork: H) -> Option { + match_hardfork( + fork, + |fork| match fork { + EthereumHardfork::Frontier | + EthereumHardfork::Homestead | + EthereumHardfork::Dao | + EthereumHardfork::Tangerine | + EthereumHardfork::SpuriousDragon | + EthereumHardfork::Byzantium | + EthereumHardfork::Constantinople | + EthereumHardfork::Petersburg | + EthereumHardfork::Istanbul | + EthereumHardfork::MuirGlacier | + EthereumHardfork::Berlin | + EthereumHardfork::London | + EthereumHardfork::ArrowGlacier | + EthereumHardfork::GrayGlacier | + EthereumHardfork::Paris | + EthereumHardfork::Shanghai => Some(1704992401), + EthereumHardfork::Cancun => Some(1710374401), + _ => None, + }, + |fork| match fork { + Self::Bedrock | Self::Regolith => Some(1686789347), + Self::Canyon => Some(1704992401), + Self::Ecotone => Some(1710374401), + Self::Fjord => Some(1720627201), + }, + ) + } + + /// Optimism mainnet list of hardforks. + pub fn op_mainnet() -> ChainHardforks { + ChainHardforks::new(vec![ + (EthereumHardfork::Frontier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Homestead.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Tangerine.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::SpuriousDragon.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Byzantium.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Constantinople.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Petersburg.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Istanbul.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::MuirGlacier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Berlin.boxed(), ForkCondition::Block(3950000)), + (EthereumHardfork::London.boxed(), ForkCondition::Block(105235063)), + (EthereumHardfork::ArrowGlacier.boxed(), ForkCondition::Block(105235063)), + (EthereumHardfork::GrayGlacier.boxed(), ForkCondition::Block(105235063)), + ( + EthereumHardfork::Paris.boxed(), + ForkCondition::TTD { fork_block: Some(105235063), total_difficulty: U256::ZERO }, + ), + (Self::Bedrock.boxed(), ForkCondition::Block(105235063)), + (Self::Regolith.boxed(), ForkCondition::Timestamp(0)), + (EthereumHardfork::Shanghai.boxed(), ForkCondition::Timestamp(1704992401)), + (Self::Canyon.boxed(), ForkCondition::Timestamp(1704992401)), + (EthereumHardfork::Cancun.boxed(), ForkCondition::Timestamp(1710374401)), + (Self::Ecotone.boxed(), ForkCondition::Timestamp(1710374401)), + (Self::Fjord.boxed(), ForkCondition::Timestamp(1720627201)), + ]) + } + + /// Optimism sepolia list of hardforks. + pub fn op_sepolia() -> ChainHardforks { + ChainHardforks::new(vec![ + (EthereumHardfork::Frontier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Homestead.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Tangerine.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::SpuriousDragon.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Byzantium.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Constantinople.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Petersburg.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Istanbul.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::MuirGlacier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Berlin.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::London.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::ArrowGlacier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::GrayGlacier.boxed(), ForkCondition::Block(0)), + ( + EthereumHardfork::Paris.boxed(), + ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO }, + ), + (Self::Bedrock.boxed(), ForkCondition::Block(0)), + (Self::Regolith.boxed(), ForkCondition::Timestamp(0)), + (EthereumHardfork::Shanghai.boxed(), ForkCondition::Timestamp(1699981200)), + (Self::Canyon.boxed(), ForkCondition::Timestamp(1699981200)), + (EthereumHardfork::Cancun.boxed(), ForkCondition::Timestamp(1708534800)), + (Self::Ecotone.boxed(), ForkCondition::Timestamp(1708534800)), + (Self::Fjord.boxed(), ForkCondition::Timestamp(1716998400)), + ]) + } + + /// Base sepolia list of hardforks. + pub fn base_sepolia() -> ChainHardforks { + ChainHardforks::new(vec![ + (EthereumHardfork::Frontier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Homestead.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Tangerine.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::SpuriousDragon.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Byzantium.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Constantinople.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Petersburg.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Istanbul.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::MuirGlacier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Berlin.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::London.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::ArrowGlacier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::GrayGlacier.boxed(), ForkCondition::Block(0)), + ( + EthereumHardfork::Paris.boxed(), + ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO }, + ), + (Self::Bedrock.boxed(), ForkCondition::Block(0)), + (Self::Regolith.boxed(), ForkCondition::Timestamp(0)), + (EthereumHardfork::Shanghai.boxed(), ForkCondition::Timestamp(1699981200)), + (Self::Canyon.boxed(), ForkCondition::Timestamp(1699981200)), + (EthereumHardfork::Cancun.boxed(), ForkCondition::Timestamp(1708534800)), + (Self::Ecotone.boxed(), ForkCondition::Timestamp(1708534800)), + (Self::Fjord.boxed(), ForkCondition::Timestamp(1716998400)), + ]) + } + + /// Base mainnet list of hardforks. + pub fn base_mainnet() -> ChainHardforks { + ChainHardforks::new(vec![ + (EthereumHardfork::Frontier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Homestead.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Tangerine.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::SpuriousDragon.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Byzantium.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Constantinople.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Petersburg.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Istanbul.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::MuirGlacier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Berlin.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::London.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::ArrowGlacier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::GrayGlacier.boxed(), ForkCondition::Block(0)), + ( + EthereumHardfork::Paris.boxed(), + ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO }, + ), + (Self::Bedrock.boxed(), ForkCondition::Block(0)), + (Self::Regolith.boxed(), ForkCondition::Timestamp(0)), + (EthereumHardfork::Shanghai.boxed(), ForkCondition::Timestamp(1704992401)), + (Self::Canyon.boxed(), ForkCondition::Timestamp(1704992401)), + (EthereumHardfork::Cancun.boxed(), ForkCondition::Timestamp(1710374401)), + (Self::Ecotone.boxed(), ForkCondition::Timestamp(1710374401)), + (Self::Fjord.boxed(), ForkCondition::Timestamp(1720627201)), + ]) + } +} + +/// Match helper method since it's not possible to match on `dyn Hardfork` +fn match_hardfork(fork: H, hardfork_fn: HF, optimism_hardfork_fn: OHF) -> Option +where + H: Hardfork, + HF: Fn(&EthereumHardfork) -> Option, + OHF: Fn(&OptimismHardfork) -> Option, +{ + let fork: &dyn Any = ⋔ + if let Some(fork) = fork.downcast_ref::() { + return hardfork_fn(fork) + } + fork.downcast_ref::().and_then(optimism_hardfork_fn) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_match_hardfork() { + assert_eq!( + OptimismHardfork::base_mainnet_activation_block(EthereumHardfork::Cancun), + Some(11188936) + ); + assert_eq!( + OptimismHardfork::base_mainnet_activation_block(OptimismHardfork::Canyon), + Some(9101527) + ); + } +} diff --git a/crates/ethereum-forks/src/hardforks/ethereum.rs b/crates/ethereum-forks/src/hardforks/ethereum.rs new file mode 100644 index 000000000..3b4c860ad --- /dev/null +++ b/crates/ethereum-forks/src/hardforks/ethereum.rs @@ -0,0 +1,56 @@ +use crate::{ + hardforks::{ChainHardforks, Hardforks}, + EthereumHardfork, ForkCondition, +}; + +/// Helper methods for Ethereum forks. +pub trait EthereumHardforks: Hardforks { + /// Convenience method to check if [`EthereumHardfork::Shanghai`] is active at a given + /// timestamp. + fn is_shanghai_active_at_timestamp(&self, timestamp: u64) -> bool { + self.is_fork_active_at_timestamp(EthereumHardfork::Shanghai, timestamp) + } + + /// Convenience method to check if [`EthereumHardfork::Cancun`] is active at a given timestamp. + fn is_cancun_active_at_timestamp(&self, timestamp: u64) -> bool { + self.is_fork_active_at_timestamp(EthereumHardfork::Cancun, timestamp) + } + + /// Convenience method to check if [`EthereumHardfork::Prague`] is active at a given timestamp. + fn is_prague_active_at_timestamp(&self, timestamp: u64) -> bool { + self.is_fork_active_at_timestamp(EthereumHardfork::Prague, timestamp) + } + + /// Convenience method to check if [`EthereumHardfork::Byzantium`] is active at a given block + /// number. + fn is_byzantium_active_at_block(&self, block_number: u64) -> bool { + self.fork(EthereumHardfork::Byzantium).active_at_block(block_number) + } + + /// Convenience method to check if [`EthereumHardfork::SpuriousDragon`] is active at a given + /// block number. + fn is_spurious_dragon_active_at_block(&self, block_number: u64) -> bool { + self.fork(EthereumHardfork::SpuriousDragon).active_at_block(block_number) + } + + /// Convenience method to check if [`EthereumHardfork::Homestead`] is active at a given block + /// number. + fn is_homestead_active_at_block(&self, block_number: u64) -> bool { + self.fork(EthereumHardfork::Homestead).active_at_block(block_number) + } + + /// The Paris hardfork (merge) is activated via block number. If we have knowledge of the block, + /// this function will return true if the block number is greater than or equal to the Paris + /// (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 { fork_block, .. } => { + fork_block.map(|paris_block| block_number >= paris_block) + } + _ => None, + } + } +} + +impl EthereumHardforks for ChainHardforks {} diff --git a/crates/ethereum-forks/src/hardforks/mod.rs b/crates/ethereum-forks/src/hardforks/mod.rs new file mode 100644 index 000000000..121a189e0 --- /dev/null +++ b/crates/ethereum-forks/src/hardforks/mod.rs @@ -0,0 +1,131 @@ +/// Ethereum helper methods +mod ethereum; +pub use ethereum::EthereumHardforks; + +/// Optimism helper methods +mod optimism; +pub use optimism::OptimismHardforks; + +use crate::{ForkCondition, Hardfork}; +use rustc_hash::FxHashMap; + +/// Generic trait over a set of ordered hardforks +pub trait Hardforks: Default + Clone { + /// Retrieves [`ForkCondition`] from `fork`. If `fork` is not present, returns + /// [`ForkCondition::Never`]. + fn fork(&self, fork: H) -> ForkCondition; + + /// Get an iterator of all hardforks with their respective activation conditions. + fn forks_iter(&self) -> impl Iterator; + + /// Convenience method to check if a fork is active at a given timestamp. + fn is_fork_active_at_timestamp(&self, fork: H, timestamp: u64) -> bool { + self.fork(fork).active_at_timestamp(timestamp) + } + + /// Convenience method to check if a fork is active at a given block number. + fn is_fork_active_at_block(&self, fork: H, block_number: u64) -> bool { + self.fork(fork).active_at_block(block_number) + } +} + +/// Ordered list of a chain hardforks that implement [`Hardfork`]. +#[derive(Default, Clone, PartialEq, Eq)] +pub struct ChainHardforks { + forks: Vec<(Box, ForkCondition)>, + map: FxHashMap<&'static str, ForkCondition>, +} + +impl ChainHardforks { + /// Creates a new [`ChainHardforks`] from a list which **must be ordered** by activation. + /// + /// Equivalent Ethereum hardforks **must be included** as well. + pub fn new(forks: Vec<(Box, ForkCondition)>) -> Self { + let map = forks.iter().map(|(fork, condition)| (fork.name(), *condition)).collect(); + + Self { forks, map } + } + + /// Total number of hardforks. + pub fn len(&self) -> usize { + self.forks.len() + } + + /// Checks if the fork list is empty. + pub fn is_empty(&self) -> bool { + self.forks.is_empty() + } + + /// Retrieves [`ForkCondition`] from `fork`. If `fork` is not present, returns + /// [`ForkCondition::Never`]. + pub fn fork(&self, fork: H) -> ForkCondition { + self.get(fork).unwrap_or(ForkCondition::Never) + } + + /// Retrieves [`ForkCondition`] from `fork` if it exists, otherwise `None`. + pub fn get(&self, fork: H) -> Option { + self.map.get(fork.name()).copied() + } + + /// Get an iterator of all hardforks with their respective activation conditions. + pub fn forks_iter(&self) -> impl Iterator { + self.forks.iter().map(|(f, b)| (&**f, *b)) + } + + /// Get last hardfork from the list. + pub fn last(&self) -> Option<(Box, ForkCondition)> { + self.forks.last().map(|(f, b)| (f.clone(), *b)) + } + + /// Convenience method to check if a fork is active at a given timestamp. + pub fn is_fork_active_at_timestamp(&self, fork: H, timestamp: u64) -> bool { + self.fork(fork).active_at_timestamp(timestamp) + } + + /// Convenience method to check if a fork is active at a given block number. + pub fn is_fork_active_at_block(&self, fork: H, block_number: u64) -> bool { + self.fork(fork).active_at_block(block_number) + } + + /// Inserts `fork` into list, updating with a new [`ForkCondition`] if it already exists. + pub fn insert(&mut self, fork: H, condition: ForkCondition) { + match self.map.entry(fork.name()) { + std::collections::hash_map::Entry::Occupied(mut entry) => { + *entry.get_mut() = condition; + if let Some((_, inner)) = + self.forks.iter_mut().find(|(inner, _)| inner.name() == fork.name()) + { + *inner = condition; + } + } + std::collections::hash_map::Entry::Vacant(entry) => { + entry.insert(condition); + self.forks.push((Box::new(fork), condition)); + } + } + } + + /// Removes `fork` from list. + pub fn remove(&mut self, fork: H) { + self.forks.retain(|(inner_fork, _)| inner_fork.name() != fork.name()); + self.map.remove(fork.name()); + } +} + +impl Hardforks for ChainHardforks { + fn fork(&self, fork: H) -> ForkCondition { + self.fork(fork) + } + + fn forks_iter(&self) -> impl Iterator { + self.forks_iter() + } +} + +impl core::fmt::Debug for ChainHardforks { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("ChainHardforks") + .field("0", &self.forks_iter().map(|(hf, cond)| (hf.name(), cond)).collect::>()) + .finish() + } +} diff --git a/crates/ethereum-forks/src/hardforks/optimism.rs b/crates/ethereum-forks/src/hardforks/optimism.rs new file mode 100644 index 000000000..39b2bf4ab --- /dev/null +++ b/crates/ethereum-forks/src/hardforks/optimism.rs @@ -0,0 +1,12 @@ +use crate::{ChainHardforks, EthereumHardforks, OptimismHardfork}; + +/// Extends [`crate::EthereumHardforks`] with optimism helper methods. +pub trait OptimismHardforks: EthereumHardforks { + /// Convenience method to check if [`OptimismHardfork::Bedrock`] is active at a given block + /// number. + fn is_bedrock_active_at_block(&self, block_number: u64) -> bool { + self.fork(OptimismHardfork::Bedrock).active_at_block(block_number) + } +} + +impl OptimismHardforks for ChainHardforks {} diff --git a/crates/ethereum-forks/src/lib.rs b/crates/ethereum-forks/src/lib.rs index 37e9b8710..51e619f4d 100644 --- a/crates/ethereum-forks/src/lib.rs +++ b/crates/ethereum-forks/src/lib.rs @@ -22,19 +22,18 @@ mod display; mod forkcondition; mod forkid; mod hardfork; +mod hardforks; mod head; pub use forkid::{ EnrForkIdEntry, ForkFilter, ForkFilterKey, ForkHash, ForkId, ForkTransition, ValidationError, }; -pub use hardfork::Hardfork; +pub use hardfork::{EthereumHardfork, Hardfork, OptimismHardfork, DEV_HARDFORKS}; pub use head::Head; pub use display::DisplayHardforks; pub use forkcondition::ForkCondition; - -/// Chains hardforks -pub mod chains; +pub use hardforks::*; #[cfg(any(test, feature = "arbitrary"))] pub use arbitrary; diff --git a/crates/ethereum/consensus/src/lib.rs b/crates/ethereum/consensus/src/lib.rs index 210f54461..2027fd539 100644 --- a/crates/ethereum/consensus/src/lib.rs +++ b/crates/ethereum/consensus/src/lib.rs @@ -8,7 +8,7 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -use reth_chainspec::{Chain, ChainSpec, Hardfork}; +use reth_chainspec::{Chain, ChainSpec, EthereumHardfork, EthereumHardforks}; use reth_consensus::{Consensus, ConsensusError, PostExecutionInput}; use reth_consensus_common::validation::{ validate_4844_header_standalone, validate_against_parent_4844, @@ -51,7 +51,7 @@ impl EthBeaconConsensus { ) -> Result<(), ConsensusError> { // Determine the parent gas limit, considering elasticity multiplier on the London fork. let parent_gas_limit = - if self.chain_spec.fork(Hardfork::London).transitions_at_block(header.number) { + if self.chain_spec.fork(EthereumHardfork::London).transitions_at_block(header.number) { parent.gas_limit * self.chain_spec .base_fee_params_at_timestamp(header.timestamp) @@ -153,7 +153,7 @@ impl Consensus for EthBeaconConsensus { ) -> Result<(), ConsensusError> { let is_post_merge = self .chain_spec - .fork(Hardfork::Paris) + .fork(EthereumHardfork::Paris) .active_at_ttd(total_difficulty, header.difficulty); if is_post_merge { diff --git a/crates/ethereum/consensus/src/validation.rs b/crates/ethereum/consensus/src/validation.rs index 1566ec176..fafd0ee42 100644 --- a/crates/ethereum/consensus/src/validation.rs +++ b/crates/ethereum/consensus/src/validation.rs @@ -1,4 +1,4 @@ -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_consensus::ConsensusError; use reth_primitives::{ gas_spent_by_transactions, BlockWithSenders, Bloom, GotExpected, Receipt, Request, B256, diff --git a/crates/ethereum/engine-primitives/src/payload.rs b/crates/ethereum/engine-primitives/src/payload.rs index 8976f0caa..7a4129963 100644 --- a/crates/ethereum/engine-primitives/src/payload.rs +++ b/crates/ethereum/engine-primitives/src/payload.rs @@ -5,7 +5,7 @@ use reth_chainspec::ChainSpec; use reth_payload_primitives::{BuiltPayload, PayloadBuilderAttributes}; use reth_primitives::{ constants::EIP1559_INITIAL_BASE_FEE, revm::config::revm_spec_by_timestamp_after_merge, Address, - BlobTransactionSidecar, Hardfork, Header, SealedBlock, Withdrawals, B256, U256, + BlobTransactionSidecar, EthereumHardfork, Header, SealedBlock, Withdrawals, B256, U256, }; use reth_rpc_types::engine::{ ExecutionPayloadEnvelopeV2, ExecutionPayloadEnvelopeV3, ExecutionPayloadEnvelopeV4, @@ -266,7 +266,7 @@ impl PayloadBuilderAttributes for EthPayloadBuilderAttributes { // 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. - if chain_spec.fork(Hardfork::London).transitions_at_block(parent.number + 1) { + if chain_spec.fork(EthereumHardfork::London).transitions_at_block(parent.number + 1) { let elasticity_multiplier = chain_spec.base_fee_params_at_timestamp(self.timestamp()).elasticity_multiplier; diff --git a/crates/ethereum/evm/src/execute.rs b/crates/ethereum/evm/src/execute.rs index d4cc8be77..503034e1a 100644 --- a/crates/ethereum/evm/src/execute.rs +++ b/crates/ethereum/evm/src/execute.rs @@ -4,9 +4,7 @@ use crate::{ dao_fork::{DAO_HARDFORK_BENEFICIARY, DAO_HARDKFORK_ACCOUNTS}, EthEvmConfig, }; -#[cfg(not(feature = "std"))] -use alloc::{sync::Arc, vec, vec::Vec}; -use reth_chainspec::{ChainSpec, MAINNET}; +use reth_chainspec::{ChainSpec, EthereumHardforks, MAINNET}; use reth_ethereum_consensus::validate_block_post_execution; use reth_evm::{ execute::{ @@ -17,7 +15,7 @@ use reth_evm::{ }; use reth_execution_types::ExecutionOutcome; use reth_primitives::{ - BlockNumber, BlockWithSenders, Hardfork, Header, Receipt, Request, Withdrawals, U256, + BlockNumber, BlockWithSenders, EthereumHardfork, Header, Receipt, Request, Withdrawals, U256, }; use reth_prune_types::PruneModes; use reth_revm::{ @@ -35,7 +33,7 @@ use revm_primitives::{ }; #[cfg(feature = "std")] -use std::{fmt::Display, sync::Arc}; +use std::{fmt::Display, sync::Arc, vec, vec::Vec}; /// Provides executors to execute regular ethereum blocks #[derive(Debug, Clone)] pub struct EthExecutorProvider { @@ -342,7 +340,7 @@ where ); // Irregular state change at Ethereum DAO hardfork - if self.chain_spec().fork(Hardfork::Dao).transitions_at_block(block.number) { + if self.chain_spec().fork(EthereumHardfork::Dao).transitions_at_block(block.number) { // drain balances from hardcoded addresses. let drained_balance: u128 = self .state @@ -539,7 +537,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Cancun, ForkCondition::Timestamp(1)) + .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(1)) .build(), ); @@ -636,7 +634,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Cancun, ForkCondition::Timestamp(1)) + .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(1)) .build(), ); @@ -679,7 +677,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Cancun, ForkCondition::Timestamp(1)) + .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(1)) .build(), ); @@ -732,7 +730,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Cancun, ForkCondition::Timestamp(0)) + .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(0)) .build(), ); @@ -819,7 +817,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Cancun, ForkCondition::Timestamp(1)) + .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(1)) .build(), ); @@ -889,7 +887,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Prague, ForkCondition::Never) + .with_fork(EthereumHardfork::Prague, ForkCondition::Never) .build(), ); @@ -942,7 +940,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Prague, ForkCondition::Timestamp(0)) + .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(0)) .build(), ); @@ -994,7 +992,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Prague, ForkCondition::Timestamp(1)) + .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(1)) .build(), ); @@ -1057,7 +1055,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Prague, ForkCondition::Timestamp(1)) + .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(1)) .build(), ); @@ -1116,7 +1114,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Prague, ForkCondition::Timestamp(0)) + .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(0)) .build(), ); @@ -1253,7 +1251,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Prague, ForkCondition::Timestamp(0)) + .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(0)) .build(), ); @@ -1334,7 +1332,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Prague, ForkCondition::Timestamp(0)) + .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(0)) .build(), ); diff --git a/crates/ethereum/payload/src/lib.rs b/crates/ethereum/payload/src/lib.rs index 1e53180d9..43a00fb98 100644 --- a/crates/ethereum/payload/src/lib.rs +++ b/crates/ethereum/payload/src/lib.rs @@ -28,7 +28,8 @@ use reth_primitives::{ eip4844::calculate_excess_blob_gas, proofs::{self, calculate_requests_root}, revm::env::tx_env_with_recovered, - Block, Header, IntoRecoveredTransaction, Receipt, EMPTY_OMMER_ROOT_HASH, U256, + Block, EthereumHardforks, Header, IntoRecoveredTransaction, Receipt, EMPTY_OMMER_ROOT_HASH, + U256, }; use reth_provider::StateProviderFactory; use reth_revm::{database::StateProviderDatabase, state_change::apply_blockhashes_update}; diff --git a/crates/net/discv5/src/enr.rs b/crates/net/discv5/src/enr.rs index eb8b6be00..bb49f72e8 100644 --- a/crates/net/discv5/src/enr.rs +++ b/crates/net/discv5/src/enr.rs @@ -58,7 +58,7 @@ mod tests { use super::*; use alloy_rlp::Encodable; use discv5::enr::{CombinedKey, EnrKey}; - use reth_chainspec::{Hardfork, MAINNET}; + use reth_chainspec::{EthereumHardfork, MAINNET}; use reth_network_peers::NodeRecord; #[test] @@ -84,7 +84,7 @@ mod tests { let key = CombinedKey::generate_secp256k1(); let mut buf = Vec::new(); - let fork_id = MAINNET.hardfork_fork_id(Hardfork::Frontier); + let fork_id = MAINNET.hardfork_fork_id(EthereumHardfork::Frontier); fork_id.unwrap().encode(&mut buf); let enr = Enr::builder() diff --git a/crates/net/dns/src/lib.rs b/crates/net/dns/src/lib.rs index f07fde2e4..55d93c459 100644 --- a/crates/net/dns/src/lib.rs +++ b/crates/net/dns/src/lib.rs @@ -415,7 +415,7 @@ mod tests { use alloy_rlp::{Decodable, Encodable}; use enr::EnrKey; use reth_chainspec::MAINNET; - use reth_ethereum_forks::{ForkHash, Hardfork}; + use reth_ethereum_forks::{EthereumHardfork, ForkHash}; use secp256k1::rand::thread_rng; use std::{future::poll_fn, net::Ipv4Addr}; @@ -513,7 +513,7 @@ mod tests { resolver.insert(link.domain.clone(), root.to_string()); let mut builder = Enr::builder(); - let fork_id = MAINNET.hardfork_fork_id(Hardfork::Frontier).unwrap(); + let fork_id = MAINNET.hardfork_fork_id(EthereumHardfork::Frontier).unwrap(); builder .ip4(Ipv4Addr::LOCALHOST) .udp4(30303) diff --git a/crates/net/eth-wire-types/src/status.rs b/crates/net/eth-wire-types/src/status.rs index 95e5aa84a..873af2227 100644 --- a/crates/net/eth-wire-types/src/status.rs +++ b/crates/net/eth-wire-types/src/status.rs @@ -3,7 +3,7 @@ use alloy_genesis::Genesis; use alloy_rlp::{RlpDecodable, RlpEncodable}; use reth_chainspec::{Chain, ChainSpec, NamedChain, MAINNET}; use reth_codecs_derive::derive_arbitrary; -use reth_primitives::{hex, ForkId, Hardfork, Head, B256, U256}; +use reth_primitives::{hex, EthereumHardfork, ForkId, Head, B256, U256}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use std::fmt::{Debug, Display}; @@ -142,7 +142,7 @@ impl Default for Status { blockhash: mainnet_genesis, genesis: mainnet_genesis, forkid: MAINNET - .hardfork_fork_id(Hardfork::Frontier) + .hardfork_fork_id(EthereumHardfork::Frontier) .expect("The Frontier hardfork should always exist"), } } @@ -152,7 +152,7 @@ impl Default for Status { /// /// # Example /// ``` -/// use reth_chainspec::{Chain, Hardfork, MAINNET}; +/// use reth_chainspec::{Chain, EthereumHardfork, MAINNET}; /// use reth_eth_wire_types::{EthVersion, Status}; /// use reth_primitives::{B256, MAINNET_GENESIS_HASH, U256}; /// @@ -163,7 +163,7 @@ impl Default for Status { /// .total_difficulty(U256::from(100)) /// .blockhash(B256::from(MAINNET_GENESIS_HASH)) /// .genesis(B256::from(MAINNET_GENESIS_HASH)) -/// .forkid(MAINNET.hardfork_fork_id(Hardfork::Paris).unwrap()) +/// .forkid(MAINNET.hardfork_fork_id(EthereumHardfork::Paris).unwrap()) /// .build(); /// /// assert_eq!( @@ -174,7 +174,7 @@ impl Default for Status { /// total_difficulty: U256::from(100), /// blockhash: B256::from(MAINNET_GENESIS_HASH), /// genesis: B256::from(MAINNET_GENESIS_HASH), -/// forkid: MAINNET.hardfork_fork_id(Hardfork::Paris).unwrap(), +/// forkid: MAINNET.hardfork_fork_id(EthereumHardfork::Paris).unwrap(), /// } /// ); /// ``` @@ -233,7 +233,7 @@ mod tests { use alloy_rlp::{Decodable, Encodable}; use rand::Rng; use reth_chainspec::{Chain, ChainSpec, ForkCondition, NamedChain}; - use reth_primitives::{hex, ForkHash, ForkId, Hardfork, Head, B256, U256}; + use reth_primitives::{hex, EthereumHardfork, ForkHash, ForkId, Head, B256, U256}; use std::str::FromStr; #[test] @@ -368,12 +368,12 @@ mod tests { // add a few hardforks let hardforks = vec![ - (Hardfork::Tangerine, ForkCondition::Block(1)), - (Hardfork::SpuriousDragon, ForkCondition::Block(2)), - (Hardfork::Byzantium, ForkCondition::Block(3)), - (Hardfork::MuirGlacier, ForkCondition::Block(5)), - (Hardfork::London, ForkCondition::Block(8)), - (Hardfork::Shanghai, ForkCondition::Timestamp(13)), + (EthereumHardfork::Tangerine, ForkCondition::Block(1)), + (EthereumHardfork::SpuriousDragon, ForkCondition::Block(2)), + (EthereumHardfork::Byzantium, ForkCondition::Block(3)), + (EthereumHardfork::MuirGlacier, ForkCondition::Block(5)), + (EthereumHardfork::London, ForkCondition::Block(8)), + (EthereumHardfork::Shanghai, ForkCondition::Timestamp(13)), ]; let mut chainspec = ChainSpec::builder().genesis(genesis).chain(Chain::from_id(1337)); diff --git a/crates/net/network/src/config.rs b/crates/net/network/src/config.rs index 2b5d36cdb..5edded5d6 100644 --- a/crates/net/network/src/config.rs +++ b/crates/net/network/src/config.rs @@ -563,7 +563,6 @@ mod tests { use reth_dns_discovery::tree::LinkEntry; use reth_primitives::ForkHash; use reth_provider::test_utils::NoopProvider; - use std::collections::BTreeMap; fn builder() -> NetworkConfigBuilder { let secret_key = SecretKey::new(&mut thread_rng()); @@ -587,7 +586,7 @@ mod tests { let mut chain_spec = Arc::clone(&MAINNET); // remove any `next` fields we would have by removing all hardforks - Arc::make_mut(&mut chain_spec).hardforks = BTreeMap::new(); + Arc::make_mut(&mut chain_spec).hardforks = Default::default(); // check that the forkid is initialized with the genesis and no other forks let genesis_fork_hash = ForkHash::from(chain_spec.genesis_hash()); diff --git a/crates/net/network/src/session/active.rs b/crates/net/network/src/session/active.rs index 97ccaf2c6..1cd090105 100644 --- a/crates/net/network/src/session/active.rs +++ b/crates/net/network/src/session/active.rs @@ -768,7 +768,7 @@ mod tests { }; use reth_network_peers::pk2id; use reth_network_types::session::config::PROTOCOL_BREACH_REQUEST_TIMEOUT; - use reth_primitives::{ForkFilter, Hardfork}; + use reth_primitives::{EthereumHardfork, ForkFilter}; use secp256k1::{SecretKey, SECP256K1}; use tokio::{ net::{TcpListener, TcpStream}, @@ -918,7 +918,7 @@ mod tests { local_peer_id, status: StatusBuilder::default().build(), fork_filter: MAINNET - .hardfork_fork_filter(Hardfork::Frontier) + .hardfork_fork_filter(EthereumHardfork::Frontier) .expect("The Frontier fork filter should exist on mainnet"), } } diff --git a/crates/optimism/consensus/src/lib.rs b/crates/optimism/consensus/src/lib.rs index 0c5439bf7..61aa23bde 100644 --- a/crates/optimism/consensus/src/lib.rs +++ b/crates/optimism/consensus/src/lib.rs @@ -9,7 +9,7 @@ // The `optimism` feature must be enabled to use this crate. #![cfg(feature = "optimism")] -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, EthereumHardforks, OptimismHardforks}; use reth_consensus::{Consensus, ConsensusError, PostExecutionInput}; use reth_consensus_common::validation::{ validate_against_parent_4844, validate_against_parent_eip1559_base_fee, diff --git a/crates/optimism/consensus/src/validation.rs b/crates/optimism/consensus/src/validation.rs index 8aa00c53c..d7bb7681c 100644 --- a/crates/optimism/consensus/src/validation.rs +++ b/crates/optimism/consensus/src/validation.rs @@ -1,4 +1,4 @@ -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_consensus::ConsensusError; use reth_primitives::{ gas_spent_by_transactions, proofs::calculate_receipt_root_optimism, BlockWithSenders, Bloom, diff --git a/crates/optimism/evm/src/execute.rs b/crates/optimism/evm/src/execute.rs index 3580c9108..bf9fbc57f 100644 --- a/crates/optimism/evm/src/execute.rs +++ b/crates/optimism/evm/src/execute.rs @@ -1,7 +1,7 @@ //! Optimism block executor. use crate::{l1::ensure_create2_deployer, OptimismBlockExecutionError, OptimismEvmConfig}; -use reth_chainspec::{ChainSpec, Hardfork}; +use reth_chainspec::{ChainSpec, EthereumHardforks, OptimismHardfork}; use reth_evm::{ execute::{ BatchExecutor, BlockExecutionError, BlockExecutionInput, BlockExecutionOutput, @@ -133,7 +133,7 @@ where // execute transactions let is_regolith = - self.chain_spec.fork(Hardfork::Regolith).active_at_timestamp(block.timestamp); + self.chain_spec.fork(OptimismHardfork::Regolith).active_at_timestamp(block.timestamp); // 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), @@ -220,7 +220,7 @@ where // this is only set for post-Canyon deposit transactions. deposit_receipt_version: (transaction.is_deposit() && self.chain_spec - .is_fork_active_at_timestamp(Hardfork::Canyon, block.timestamp)) + .is_fork_active_at_timestamp(OptimismHardfork::Canyon, block.timestamp)) .then_some(1), }); } diff --git a/crates/optimism/evm/src/l1.rs b/crates/optimism/evm/src/l1.rs index a750c8f4f..62b412891 100644 --- a/crates/optimism/evm/src/l1.rs +++ b/crates/optimism/evm/src/l1.rs @@ -1,7 +1,7 @@ //! Optimism-specific implementation and utilities for the executor use crate::OptimismBlockExecutionError; -use reth_chainspec::{ChainSpec, Hardfork}; +use reth_chainspec::{ChainSpec, OptimismHardfork}; use reth_execution_errors::BlockExecutionError; use reth_primitives::{address, b256, hex, Address, Block, Bytes, B256, U256}; use revm::{ @@ -191,13 +191,14 @@ impl RethL1BlockInfo for L1BlockInfo { return Ok(U256::ZERO) } - let spec_id = if chain_spec.is_fork_active_at_timestamp(Hardfork::Fjord, timestamp) { + let spec_id = if chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Fjord, timestamp) + { SpecId::FJORD - } else if chain_spec.is_fork_active_at_timestamp(Hardfork::Ecotone, timestamp) { + } else if chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Ecotone, timestamp) { SpecId::ECOTONE - } else if chain_spec.is_fork_active_at_timestamp(Hardfork::Regolith, timestamp) { + } else if chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Regolith, timestamp) { SpecId::REGOLITH - } else if chain_spec.is_fork_active_at_timestamp(Hardfork::Bedrock, timestamp) { + } else if chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Bedrock, timestamp) { SpecId::BEDROCK } else { return Err(OptimismBlockExecutionError::L1BlockInfoError { @@ -214,11 +215,12 @@ impl RethL1BlockInfo for L1BlockInfo { timestamp: u64, input: &[u8], ) -> Result { - let spec_id = if chain_spec.is_fork_active_at_timestamp(Hardfork::Fjord, timestamp) { + let spec_id = if chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Fjord, timestamp) + { SpecId::FJORD - } else if chain_spec.is_fork_active_at_timestamp(Hardfork::Regolith, timestamp) { + } else if chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Regolith, timestamp) { SpecId::REGOLITH - } else if chain_spec.is_fork_active_at_timestamp(Hardfork::Bedrock, timestamp) { + } else if chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Bedrock, timestamp) { SpecId::BEDROCK } else { return Err(OptimismBlockExecutionError::L1BlockInfoError { @@ -245,8 +247,9 @@ where // previous block timestamp (heuristically, block time is not perfectly constant at 2s), and the // chain is an optimism chain, then we need to force-deploy the create2 deployer contract. if chain_spec.is_optimism() && - chain_spec.is_fork_active_at_timestamp(Hardfork::Canyon, timestamp) && - !chain_spec.is_fork_active_at_timestamp(Hardfork::Canyon, timestamp.saturating_sub(2)) + chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Canyon, timestamp) && + !chain_spec + .is_fork_active_at_timestamp(OptimismHardfork::Canyon, timestamp.saturating_sub(2)) { trace!(target: "evm", "Forcing create2 deployer contract deployment on Canyon transition"); diff --git a/crates/optimism/node/src/engine.rs b/crates/optimism/node/src/engine.rs index 6507d5c92..d0fc9b53e 100644 --- a/crates/optimism/node/src/engine.rs +++ b/crates/optimism/node/src/engine.rs @@ -1,4 +1,4 @@ -use reth_chainspec::{ChainSpec, Hardfork}; +use reth_chainspec::{ChainSpec, OptimismHardfork}; use reth_node_api::{ payload::{ validate_parent_beacon_block_root_presence, EngineApiMessageVersion, @@ -69,7 +69,7 @@ pub fn validate_withdrawals_presence( timestamp: u64, has_withdrawals: bool, ) -> Result<(), EngineObjectValidationError> { - let is_shanghai = chain_spec.fork(Hardfork::Canyon).active_at_timestamp(timestamp); + let is_shanghai = chain_spec.fork(OptimismHardfork::Canyon).active_at_timestamp(timestamp); match version { EngineApiMessageVersion::V1 => { diff --git a/crates/optimism/payload/src/builder.rs b/crates/optimism/payload/src/builder.rs index fa17982cb..3b08b8df0 100644 --- a/crates/optimism/payload/src/builder.rs +++ b/crates/optimism/payload/src/builder.rs @@ -5,7 +5,7 @@ use crate::{ payload::{OptimismBuiltPayload, OptimismPayloadBuilderAttributes}, }; use reth_basic_payload_builder::*; -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, EthereumHardforks, OptimismHardfork}; use reth_evm::ConfigureEvm; use reth_execution_types::ExecutionOutcome; use reth_payload_builder::error::PayloadBuilderError; @@ -14,8 +14,7 @@ use reth_primitives::{ eip4844::calculate_excess_blob_gas, proofs, revm::env::tx_env_with_recovered, - Block, Hardfork, Header, IntoRecoveredTransaction, Receipt, TxType, EMPTY_OMMER_ROOT_HASH, - U256, + Block, Header, IntoRecoveredTransaction, Receipt, TxType, EMPTY_OMMER_ROOT_HASH, U256, }; use reth_provider::StateProviderFactory; use reth_revm::database::StateProviderDatabase; @@ -281,8 +280,10 @@ where let block_number = initialized_block_env.number.to::(); - let is_regolith = chain_spec - .is_fork_active_at_timestamp(Hardfork::Regolith, attributes.payload_attributes.timestamp); + let is_regolith = chain_spec.is_fork_active_at_timestamp( + OptimismHardfork::Regolith, + attributes.payload_attributes.timestamp, + ); // apply eip-4788 pre block contract call pre_block_beacon_root_contract_call( @@ -393,7 +394,7 @@ where // ensures this is only set for post-Canyon deposit transactions. deposit_receipt_version: chain_spec .is_fork_active_at_timestamp( - Hardfork::Canyon, + OptimismHardfork::Canyon, attributes.payload_attributes.timestamp, ) .then_some(1), diff --git a/crates/optimism/payload/src/payload.rs b/crates/optimism/payload/src/payload.rs index ae6324655..1cdc1f6c4 100644 --- a/crates/optimism/payload/src/payload.rs +++ b/crates/optimism/payload/src/payload.rs @@ -3,7 +3,7 @@ //! Optimism builder support use alloy_rlp::Encodable; -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_payload_builder::EthPayloadBuilderAttributes; use reth_payload_primitives::{BuiltPayload, PayloadBuilderAttributes}; use reth_primitives::{ diff --git a/crates/payload/basic/src/lib.rs b/crates/payload/basic/src/lib.rs index 26dc06293..d677ce842 100644 --- a/crates/payload/basic/src/lib.rs +++ b/crates/payload/basic/src/lib.rs @@ -11,7 +11,7 @@ use crate::metrics::PayloadBuilderMetrics; use futures_core::ready; use futures_util::FutureExt; -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_payload_builder::{ database::CachedReads, error::PayloadBuilderError, KeepPayloadJobAlive, PayloadId, PayloadJob, PayloadJobGenerator, diff --git a/crates/payload/primitives/src/lib.rs b/crates/payload/primitives/src/lib.rs index 52029a3c4..996013017 100644 --- a/crates/payload/primitives/src/lib.rs +++ b/crates/payload/primitives/src/lib.rs @@ -20,8 +20,7 @@ pub use traits::{BuiltPayload, PayloadAttributes, PayloadBuilderAttributes}; mod payload; pub use payload::PayloadOrAttributes; -use reth_chainspec::ChainSpec; - +use reth_chainspec::{ChainSpec, EthereumHardforks}; /// The types that are used by the engine API. pub trait PayloadTypes: Send + Sync + Unpin + core::fmt::Debug + Clone { /// The built payload type. diff --git a/crates/payload/validator/src/lib.rs b/crates/payload/validator/src/lib.rs index afc190377..e71d2b58d 100644 --- a/crates/payload/validator/src/lib.rs +++ b/crates/payload/validator/src/lib.rs @@ -8,7 +8,7 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_primitives::SealedBlock; use reth_rpc_types::{engine::MaybeCancunPayloadFields, ExecutionPayload, PayloadError}; use reth_rpc_types_compat::engine::payload::try_into_block; diff --git a/crates/primitives/src/proofs.rs b/crates/primitives/src/proofs.rs index 5521fedec..9e0a03579 100644 --- a/crates/primitives/src/proofs.rs +++ b/crates/primitives/src/proofs.rs @@ -4,9 +4,8 @@ use crate::{ constants::EMPTY_OMMER_ROOT_HASH, keccak256, Header, Receipt, ReceiptWithBloom, ReceiptWithBloomRef, Request, TransactionSigned, Withdrawal, B256, }; -use reth_trie_common::root::{ordered_trie_root, ordered_trie_root_with_encoder}; - use alloy_eips::eip7685::Encodable7685; +use reth_trie_common::root::{ordered_trie_root, ordered_trie_root_with_encoder}; #[cfg(not(feature = "std"))] use alloc::vec::Vec; @@ -50,8 +49,9 @@ pub fn calculate_receipt_root_optimism( // encoding. In the Regolith Hardfork, we must strip the deposit nonce from the // receipts before calculating the receipt root. This was corrected in the Canyon // hardfork. - if chain_spec.is_fork_active_at_timestamp(reth_chainspec::Hardfork::Regolith, timestamp) && - !chain_spec.is_fork_active_at_timestamp(reth_chainspec::Hardfork::Canyon, timestamp) + if chain_spec.is_fork_active_at_timestamp(reth_chainspec::OptimismHardfork::Regolith, timestamp) && + !chain_spec + .is_fork_active_at_timestamp(reth_chainspec::OptimismHardfork::Canyon, timestamp) { let receipts = receipts .iter() @@ -98,8 +98,9 @@ pub fn calculate_receipt_root_no_memo_optimism( // encoding. In the Regolith Hardfork, we must strip the deposit nonce from the // receipts before calculating the receipt root. This was corrected in the Canyon // hardfork. - if chain_spec.is_fork_active_at_timestamp(reth_chainspec::Hardfork::Regolith, timestamp) && - !chain_spec.is_fork_active_at_timestamp(reth_chainspec::Hardfork::Canyon, timestamp) + if chain_spec.is_fork_active_at_timestamp(reth_chainspec::OptimismHardfork::Regolith, timestamp) && + !chain_spec + .is_fork_active_at_timestamp(reth_chainspec::OptimismHardfork::Canyon, timestamp) { let receipts = receipts .iter() diff --git a/crates/primitives/src/revm/config.rs b/crates/primitives/src/revm/config.rs index 5914dbf59..9ed265092 100644 --- a/crates/primitives/src/revm/config.rs +++ b/crates/primitives/src/revm/config.rs @@ -1,5 +1,7 @@ -use reth_chainspec::ChainSpec; -use reth_ethereum_forks::{Hardfork, Head}; +#[cfg(feature = "optimism")] +use reth_chainspec::OptimismHardfork; +use reth_chainspec::{ChainSpec, EthereumHardforks}; +use reth_ethereum_forks::{EthereumHardfork, Head}; /// Returns the spec id at the given timestamp. /// @@ -11,13 +13,13 @@ pub fn revm_spec_by_timestamp_after_merge( ) -> revm_primitives::SpecId { #[cfg(feature = "optimism")] if chain_spec.is_optimism() { - return if chain_spec.fork(Hardfork::Fjord).active_at_timestamp(timestamp) { + return if chain_spec.fork(OptimismHardfork::Fjord).active_at_timestamp(timestamp) { revm_primitives::FJORD - } else if chain_spec.fork(Hardfork::Ecotone).active_at_timestamp(timestamp) { + } else if chain_spec.fork(OptimismHardfork::Ecotone).active_at_timestamp(timestamp) { revm_primitives::ECOTONE - } else if chain_spec.fork(Hardfork::Canyon).active_at_timestamp(timestamp) { + } else if chain_spec.fork(OptimismHardfork::Canyon).active_at_timestamp(timestamp) { revm_primitives::CANYON - } else if chain_spec.fork(Hardfork::Regolith).active_at_timestamp(timestamp) { + } else if chain_spec.fork(OptimismHardfork::Regolith).active_at_timestamp(timestamp) { revm_primitives::REGOLITH } else { revm_primitives::BEDROCK @@ -39,44 +41,44 @@ pub fn revm_spec_by_timestamp_after_merge( pub fn revm_spec(chain_spec: &ChainSpec, block: Head) -> revm_primitives::SpecId { #[cfg(feature = "optimism")] if chain_spec.is_optimism() { - if chain_spec.fork(Hardfork::Fjord).active_at_head(&block) { + if chain_spec.fork(OptimismHardfork::Fjord).active_at_head(&block) { return revm_primitives::FJORD - } else if chain_spec.fork(Hardfork::Ecotone).active_at_head(&block) { + } else if chain_spec.fork(OptimismHardfork::Ecotone).active_at_head(&block) { return revm_primitives::ECOTONE - } else if chain_spec.fork(Hardfork::Canyon).active_at_head(&block) { + } else if chain_spec.fork(OptimismHardfork::Canyon).active_at_head(&block) { return revm_primitives::CANYON - } else if chain_spec.fork(Hardfork::Regolith).active_at_head(&block) { + } else if chain_spec.fork(OptimismHardfork::Regolith).active_at_head(&block) { return revm_primitives::REGOLITH - } else if chain_spec.fork(Hardfork::Bedrock).active_at_head(&block) { + } else if chain_spec.fork(OptimismHardfork::Bedrock).active_at_head(&block) { return revm_primitives::BEDROCK } } - if chain_spec.fork(Hardfork::Prague).active_at_head(&block) { + if chain_spec.fork(EthereumHardfork::Prague).active_at_head(&block) { revm_primitives::PRAGUE - } else if chain_spec.fork(Hardfork::Cancun).active_at_head(&block) { + } else if chain_spec.fork(EthereumHardfork::Cancun).active_at_head(&block) { revm_primitives::CANCUN - } else if chain_spec.fork(Hardfork::Shanghai).active_at_head(&block) { + } else if chain_spec.fork(EthereumHardfork::Shanghai).active_at_head(&block) { revm_primitives::SHANGHAI - } else if chain_spec.fork(Hardfork::Paris).active_at_head(&block) { + } else if chain_spec.fork(EthereumHardfork::Paris).active_at_head(&block) { revm_primitives::MERGE - } else if chain_spec.fork(Hardfork::London).active_at_head(&block) { + } else if chain_spec.fork(EthereumHardfork::London).active_at_head(&block) { revm_primitives::LONDON - } else if chain_spec.fork(Hardfork::Berlin).active_at_head(&block) { + } else if chain_spec.fork(EthereumHardfork::Berlin).active_at_head(&block) { revm_primitives::BERLIN - } else if chain_spec.fork(Hardfork::Istanbul).active_at_head(&block) { + } else if chain_spec.fork(EthereumHardfork::Istanbul).active_at_head(&block) { revm_primitives::ISTANBUL - } else if chain_spec.fork(Hardfork::Petersburg).active_at_head(&block) { + } else if chain_spec.fork(EthereumHardfork::Petersburg).active_at_head(&block) { revm_primitives::PETERSBURG - } else if chain_spec.fork(Hardfork::Byzantium).active_at_head(&block) { + } else if chain_spec.fork(EthereumHardfork::Byzantium).active_at_head(&block) { revm_primitives::BYZANTIUM - } else if chain_spec.fork(Hardfork::SpuriousDragon).active_at_head(&block) { + } else if chain_spec.fork(EthereumHardfork::SpuriousDragon).active_at_head(&block) { revm_primitives::SPURIOUS_DRAGON - } else if chain_spec.fork(Hardfork::Tangerine).active_at_head(&block) { + } else if chain_spec.fork(EthereumHardfork::Tangerine).active_at_head(&block) { revm_primitives::TANGERINE - } else if chain_spec.fork(Hardfork::Homestead).active_at_head(&block) { + } else if chain_spec.fork(EthereumHardfork::Homestead).active_at_head(&block) { revm_primitives::HOMESTEAD - } else if chain_spec.fork(Hardfork::Frontier).active_at_head(&block) { + } else if chain_spec.fork(EthereumHardfork::Frontier).active_at_head(&block) { revm_primitives::FRONTIER } else { panic!( diff --git a/crates/revm/src/state_change.rs b/crates/revm/src/state_change.rs index 4505d2ee9..fdbb4c461 100644 --- a/crates/revm/src/state_change.rs +++ b/crates/revm/src/state_change.rs @@ -3,7 +3,7 @@ use alloy_eips::{ eip7002::WithdrawalRequest, }; use alloy_rlp::Buf; -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_consensus_common::calc; use reth_execution_errors::{BlockExecutionError, BlockValidationError}; use reth_primitives::{ diff --git a/crates/rpc/rpc-engine-api/src/engine_api.rs b/crates/rpc/rpc-engine-api/src/engine_api.rs index 8185bbe8c..11bde1c74 100644 --- a/crates/rpc/rpc-engine-api/src/engine_api.rs +++ b/crates/rpc/rpc-engine-api/src/engine_api.rs @@ -10,7 +10,7 @@ use reth_payload_primitives::{ validate_payload_timestamp, EngineApiMessageVersion, PayloadAttributes, PayloadBuilderAttributes, PayloadOrAttributes, }; -use reth_primitives::{BlockHash, BlockHashOrNumber, BlockNumber, Hardfork, B256, U64}; +use reth_primitives::{BlockHash, BlockHashOrNumber, BlockNumber, EthereumHardfork, B256, U64}; use reth_rpc_api::EngineApiServer; use reth_rpc_types::engine::{ CancunPayloadFields, ClientVersionV1, ExecutionPayload, ExecutionPayloadBodiesV1, @@ -457,7 +457,7 @@ where let merge_terminal_td = self .inner .chain_spec - .fork(Hardfork::Paris) + .fork(EthereumHardfork::Paris) .ttd() .expect("the engine API should not be running for chains w/o paris"); @@ -1036,7 +1036,11 @@ mod tests { let (handle, api) = setup_engine_api(); let transition_config = TransitionConfiguration { - terminal_total_difficulty: handle.chain_spec.fork(Hardfork::Paris).ttd().unwrap() + + terminal_total_difficulty: handle + .chain_spec + .fork(EthereumHardfork::Paris) + .ttd() + .unwrap() + U256::from(1), ..Default::default() }; @@ -1046,7 +1050,7 @@ mod tests { assert_matches!( res, Err(EngineApiError::TerminalTD { execution, consensus }) - if execution == handle.chain_spec.fork(Hardfork::Paris).ttd().unwrap() && consensus == U256::from(transition_config.terminal_total_difficulty) + if execution == handle.chain_spec.fork(EthereumHardfork::Paris).ttd().unwrap() && consensus == U256::from(transition_config.terminal_total_difficulty) ); } @@ -1063,7 +1067,11 @@ mod tests { random_block(&mut rng, terminal_block_number, None, None, None); let transition_config = TransitionConfiguration { - terminal_total_difficulty: handle.chain_spec.fork(Hardfork::Paris).ttd().unwrap(), + terminal_total_difficulty: handle + .chain_spec + .fork(EthereumHardfork::Paris) + .ttd() + .unwrap(), terminal_block_hash: consensus_terminal_block.hash(), terminal_block_number: U64::from(terminal_block_number), }; @@ -1101,7 +1109,11 @@ mod tests { random_block(&mut generators::rng(), terminal_block_number, None, None, None); let transition_config = TransitionConfiguration { - terminal_total_difficulty: handle.chain_spec.fork(Hardfork::Paris).ttd().unwrap(), + terminal_total_difficulty: handle + .chain_spec + .fork(EthereumHardfork::Paris) + .ttd() + .unwrap(), terminal_block_hash: terminal_block.hash(), terminal_block_number: U64::from(terminal_block_number), }; diff --git a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs index c7036f4be..f30e397e0 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs @@ -4,6 +4,7 @@ use std::time::{Duration, Instant}; use futures::Future; +use reth_chainspec::EthereumHardforks; use reth_evm::ConfigureEvm; use reth_execution_types::ExecutionOutcome; use reth_primitives::{ diff --git a/crates/rpc/rpc/src/debug.rs b/crates/rpc/rpc/src/debug.rs index 5a098feb7..2658547b1 100644 --- a/crates/rpc/rpc/src/debug.rs +++ b/crates/rpc/rpc/src/debug.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use alloy_rlp::{Decodable, Encodable}; use async_trait::async_trait; use jsonrpsee::core::RpcResult; +use reth_chainspec::EthereumHardforks; use reth_primitives::{ revm::env::tx_env_with_recovered, Address, Block, BlockId, BlockNumberOrTag, Bytes, TransactionSignedEcRecovered, Withdrawals, B256, U256, diff --git a/crates/rpc/rpc/src/trace.rs b/crates/rpc/rpc/src/trace.rs index bf1e7020c..110f35dbd 100644 --- a/crates/rpc/rpc/src/trace.rs +++ b/crates/rpc/rpc/src/trace.rs @@ -2,6 +2,7 @@ use std::{collections::HashSet, sync::Arc}; use async_trait::async_trait; use jsonrpsee::core::RpcResult as Result; +use reth_chainspec::EthereumHardforks; use reth_consensus_common::calc::{ base_block_reward, base_block_reward_pre_merge, block_reward, ommer_reward, }; diff --git a/crates/storage/db-common/src/init.rs b/crates/storage/db-common/src/init.rs index c6b4802b7..76314f0c8 100644 --- a/crates/storage/db-common/src/init.rs +++ b/crates/storage/db-common/src/init.rs @@ -620,7 +620,7 @@ mod tests { ]), ..Default::default() }, - hardforks: BTreeMap::default(), + hardforks: Default::default(), genesis_hash: None, paris_block_and_final_difficulty: None, deposit_contract: None, diff --git a/crates/storage/provider/src/providers/database/provider.rs b/crates/storage/provider/src/providers/database/provider.rs index 22260cc9c..e5fa31642 100644 --- a/crates/storage/provider/src/providers/database/provider.rs +++ b/crates/storage/provider/src/providers/database/provider.rs @@ -14,7 +14,7 @@ use crate::{ WithdrawalsProvider, }; use itertools::{izip, Itertools}; -use reth_chainspec::{ChainInfo, ChainSpec}; +use reth_chainspec::{ChainInfo, ChainSpec, EthereumHardforks}; use reth_db::{tables, BlockNumberList}; use reth_db_api::{ common::KeyValue, diff --git a/crates/transaction-pool/src/validate/eth.rs b/crates/transaction-pool/src/validate/eth.rs index 79a93cf2e..36413709f 100644 --- a/crates/transaction-pool/src/validate/eth.rs +++ b/crates/transaction-pool/src/validate/eth.rs @@ -9,7 +9,7 @@ use crate::{ EthBlobTransactionSidecar, EthPoolTransaction, LocalTransactionConfig, PoolTransaction, TransactionValidationOutcome, TransactionValidationTaskExecutor, TransactionValidator, }; -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_primitives::{ constants::{eip4844::MAX_BLOBS_PER_BLOCK, ETHEREUM_BLOCK_GAS_LIMIT}, Address, GotExpected, InvalidTransactionError, SealedBlock, TxKind, EIP1559_TX_TYPE_ID, diff --git a/examples/bsc-p2p/src/chainspec.rs b/examples/bsc-p2p/src/chainspec.rs index d9c3a8682..8983a2ef3 100644 --- a/examples/bsc-p2p/src/chainspec.rs +++ b/examples/bsc-p2p/src/chainspec.rs @@ -1,7 +1,10 @@ -use reth_chainspec::{net::NodeRecord, BaseFeeParams, Chain, ChainSpec, ForkCondition, Hardfork}; +use reth_chainspec::{ + net::NodeRecord, BaseFeeParams, Chain, ChainHardforks, ChainSpec, EthereumHardfork, + ForkCondition, +}; use reth_primitives::{b256, B256}; -use std::{collections::BTreeMap, sync::Arc}; +use std::sync::Arc; pub const SHANGHAI_TIME: u64 = 1705996800; @@ -13,7 +16,10 @@ pub(crate) fn bsc_chain_spec() -> Arc { genesis: serde_json::from_str(include_str!("./genesis.json")).expect("deserialize genesis"), genesis_hash: Some(GENESIS), paris_block_and_final_difficulty: None, - hardforks: BTreeMap::from([(Hardfork::Shanghai, ForkCondition::Timestamp(SHANGHAI_TIME))]), + hardforks: ChainHardforks::new(vec![( + EthereumHardfork::Shanghai.boxed(), + ForkCondition::Timestamp(SHANGHAI_TIME), + )]), deposit_contract: None, base_fee_params: reth_chainspec::BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()), prune_delete_limit: 0, diff --git a/examples/exex/rollup/src/execution.rs b/examples/exex/rollup/src/execution.rs index cc5b716bd..2f755183f 100644 --- a/examples/exex/rollup/src/execution.rs +++ b/examples/exex/rollup/src/execution.rs @@ -12,8 +12,8 @@ use reth_primitives::{ keccak256, revm::env::fill_tx_env, revm_primitives::{CfgEnvWithHandlerCfg, EVMError, ExecutionResult, ResultAndState}, - Address, Block, BlockWithSenders, Bytes, Hardfork, Header, Receipt, TransactionSigned, TxType, - B256, U256, + Address, Block, BlockWithSenders, Bytes, EthereumHardfork, Header, Receipt, TransactionSigned, + TxType, B256, U256, }; use reth_revm::{ db::{states::bundle_state::BundleRetention, BundleState}, @@ -69,16 +69,17 @@ fn construct_header(db: &Database, header: &RollupContract::BlockHeader) -> eyre let block_number = u64::try_from(header.sequence)?; // Calculate base fee per gas for EIP-1559 transactions - let base_fee_per_gas = if CHAIN_SPEC.fork(Hardfork::London).transitions_at_block(block_number) { - constants::EIP1559_INITIAL_BASE_FEE - } else { - parent_block - .as_ref() - .ok_or(eyre::eyre!("parent block not found"))? - .header - .next_block_base_fee(CHAIN_SPEC.base_fee_params_at_block(block_number)) - .ok_or(eyre::eyre!("failed to calculate base fee"))? - }; + let base_fee_per_gas = + if CHAIN_SPEC.fork(EthereumHardfork::London).transitions_at_block(block_number) { + constants::EIP1559_INITIAL_BASE_FEE + } else { + parent_block + .as_ref() + .ok_or(eyre::eyre!("parent block not found"))? + .header + .next_block_base_fee(CHAIN_SPEC.base_fee_params_at_block(block_number)) + .ok_or(eyre::eyre!("failed to calculate base fee"))? + }; // Construct header Ok(Header { @@ -103,7 +104,7 @@ fn configure_evm<'a>( .build(), ); evm.db_mut().set_state_clear_flag( - CHAIN_SPEC.fork(Hardfork::SpuriousDragon).active_at_block(header.number), + CHAIN_SPEC.fork(EthereumHardfork::SpuriousDragon).active_at_block(header.number), ); let mut cfg = CfgEnvWithHandlerCfg::new_with_spec_id(evm.cfg().clone(), evm.spec_id()); diff --git a/examples/manual-p2p/src/main.rs b/examples/manual-p2p/src/main.rs index 2b89b5539..7379aa4e7 100644 --- a/examples/manual-p2p/src/main.rs +++ b/examples/manual-p2p/src/main.rs @@ -18,7 +18,7 @@ use reth_eth_wire::{ }; use reth_network::config::rng_secret_key; use reth_network_peers::{pk2id, NodeRecord}; -use reth_primitives::{Hardfork, Head, MAINNET_GENESIS_HASH}; +use reth_primitives::{EthereumHardfork, Head, MAINNET_GENESIS_HASH}; use secp256k1::{SecretKey, SECP256K1}; use tokio::net::TcpStream; @@ -95,14 +95,14 @@ async fn handshake_p2p( // Perform a ETH Wire handshake with a peer async fn handshake_eth(p2p_stream: AuthedP2PStream) -> eyre::Result<(AuthedEthStream, Status)> { let fork_filter = MAINNET.fork_filter(Head { - timestamp: MAINNET.fork(Hardfork::Shanghai).as_timestamp().unwrap(), + timestamp: MAINNET.fork(EthereumHardfork::Shanghai).as_timestamp().unwrap(), ..Default::default() }); let status = Status::builder() .chain(Chain::mainnet()) .genesis(MAINNET_GENESIS_HASH) - .forkid(MAINNET.hardfork_fork_id(Hardfork::Shanghai).unwrap()) + .forkid(MAINNET.hardfork_fork_id(EthereumHardfork::Shanghai).unwrap()) .build(); let status = Status { version: p2p_stream.shared_capabilities().eth()?.version(), ..status }; diff --git a/examples/polygon-p2p/src/chain_cfg.rs b/examples/polygon-p2p/src/chain_cfg.rs index b178d1349..92256a1be 100644 --- a/examples/polygon-p2p/src/chain_cfg.rs +++ b/examples/polygon-p2p/src/chain_cfg.rs @@ -1,8 +1,10 @@ -use reth_chainspec::{BaseFeeParams, Chain, ChainSpec, ForkCondition, Hardfork}; +use reth_chainspec::{ + BaseFeeParams, Chain, ChainHardforks, ChainSpec, EthereumHardfork, ForkCondition, +}; use reth_discv4::NodeRecord; use reth_primitives::{b256, Head, B256}; -use std::{collections::BTreeMap, sync::Arc}; +use std::sync::Arc; const SHANGAI_BLOCK: u64 = 50523000; @@ -15,13 +17,13 @@ pub(crate) fn polygon_chain_spec() -> Arc { genesis: serde_json::from_str(include_str!("./genesis.json")).expect("deserialize genesis"), genesis_hash: Some(GENESIS), paris_block_and_final_difficulty: None, - hardforks: BTreeMap::from([ - (Hardfork::Petersburg, ForkCondition::Block(0)), - (Hardfork::Istanbul, ForkCondition::Block(3395000)), - (Hardfork::MuirGlacier, ForkCondition::Block(3395000)), - (Hardfork::Berlin, ForkCondition::Block(14750000)), - (Hardfork::London, ForkCondition::Block(23850000)), - (Hardfork::Shanghai, ForkCondition::Block(SHANGAI_BLOCK)), + hardforks: ChainHardforks::new(vec![ + (EthereumHardfork::Petersburg.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Istanbul.boxed(), ForkCondition::Block(3395000)), + (EthereumHardfork::MuirGlacier.boxed(), ForkCondition::Block(3395000)), + (EthereumHardfork::Berlin.boxed(), ForkCondition::Block(14750000)), + (EthereumHardfork::London.boxed(), ForkCondition::Block(23850000)), + (EthereumHardfork::Shanghai.boxed(), ForkCondition::Block(SHANGAI_BLOCK)), ]), deposit_contract: None, base_fee_params: reth_chainspec::BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()),