feat: use new ChainHardforks type on ChainSpec (#9065)

This commit is contained in:
joshieDo
2024-06-27 19:39:35 +02:00
committed by GitHub
parent c23fe39dd3
commit 50ee497c75
57 changed files with 1708 additions and 1465 deletions

4
Cargo.lock generated
View File

@ -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",
]

View File

@ -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 {

File diff suppressed because it is too large Load Diff

View File

@ -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};

View File

@ -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;

View File

@ -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<u128> {
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

View File

@ -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

View File

@ -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"] }

View File

@ -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)),
];

View File

@ -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)),
];

View File

@ -1,9 +0,0 @@
/// Ethereum chains
pub mod ethereum;
/// Optimism chains
#[cfg(feature = "optimism")]
pub mod optimism;
/// Dev chain
pub mod dev;

View File

@ -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)),
];

View File

@ -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<Hardfork, ForkCondition>,
known_paris_block: Option<u64>,
) -> Self {
pub fn new<H: Hardforks>(hardforks: &H, known_paris_block: Option<u64>) -> 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(_) => {

View File

@ -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: <https://blog.ethereum.org/2015/03/03/ethereum-launch-process>.
Frontier,
/// Homestead: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/homestead.md>.
Homestead,
/// The DAO fork: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/dao-fork.md>.
Dao,
/// Tangerine: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/tangerine-whistle.md>.
Tangerine,
/// Spurious Dragon: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/spurious-dragon.md>.
SpuriousDragon,
/// Byzantium: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/byzantium.md>.
Byzantium,
/// Constantinople: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/constantinople.md>.
Constantinople,
/// Petersburg: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/petersburg.md>.
Petersburg,
/// Istanbul: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/istanbul.md>.
Istanbul,
/// Muir Glacier: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/muir-glacier.md>.
MuirGlacier,
/// Berlin: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/berlin.md>.
Berlin,
/// London: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/london.md>.
London,
/// Arrow Glacier: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/arrow-glacier.md>.
ArrowGlacier,
/// Gray Glacier: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/gray-glacier.md>.
GrayGlacier,
/// Paris: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md>.
Paris,
/// Bedrock: <https://blog.oplabs.co/introducing-optimism-bedrock>.
#[cfg(feature = "optimism")]
Bedrock,
/// Regolith: <https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/superchain-upgrades.md#regolith>.
#[cfg(feature = "optimism")]
Regolith,
/// Shanghai: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md>.
Shanghai,
/// Canyon:
/// <https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/superchain-upgrades.md#canyon>.
#[cfg(feature = "optimism")]
Canyon,
// ArbOS11,
/// Cancun.
Cancun,
/// Ecotone: <https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/superchain-upgrades.md#ecotone>.
#[cfg(feature = "optimism")]
Ecotone,
// ArbOS20Atlas,
// Upcoming
/// Prague: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/prague.md>
Prague,
/// Fjord: <https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/superchain-upgrades.md#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<u64> {
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<u64> {
#[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<u64> {
#[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<u64> {
#[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<u64> {
#[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<u64> {
#[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<u64> {
#[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<u64> {
#[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<u64> {
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<u64> {
#[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<u64> {
#[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<u64> {
#[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<u64> {
#[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<u64> {
#[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<u64> {
#[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<u64> {
#[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<Self, Self::Err> {
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> =
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> =
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());
}
}
}

View File

@ -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<ChainHardforks> = 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)),
])
});

View File

@ -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: <https://blog.ethereum.org/2015/03/03/ethereum-launch-process>.
Frontier,
/// Homestead: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/homestead.md>.
Homestead,
/// The DAO fork: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/dao-fork.md>.
Dao,
/// Tangerine: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/tangerine-whistle.md>.
Tangerine,
/// Spurious Dragon: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/spurious-dragon.md>.
SpuriousDragon,
/// Byzantium: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/byzantium.md>.
Byzantium,
/// Constantinople: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/constantinople.md>.
Constantinople,
/// Petersburg: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/petersburg.md>.
Petersburg,
/// Istanbul: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/istanbul.md>.
Istanbul,
/// Muir Glacier: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/muir-glacier.md>.
MuirGlacier,
/// Berlin: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/berlin.md>.
Berlin,
/// London: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/london.md>.
London,
/// Arrow Glacier: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/arrow-glacier.md>.
ArrowGlacier,
/// Gray Glacier: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/gray-glacier.md>.
GrayGlacier,
/// Paris: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md>.
Paris,
/// Shanghai: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md>.
Shanghai,
/// Cancun.
Cancun,
/// Prague: <https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/prague.md>
Prague,
}
);
impl EthereumHardfork {
/// Retrieves the activation block for the specified hardfork on the given chain.
pub fn activation_block(&self, chain: Chain) -> Option<u64> {
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<u64> {
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<u64> {
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<u64> {
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<u64> {
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<u64> {
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<u64> {
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<u64> {
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<u64> {
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<u64> {
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<u64> {
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<u64> {
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<const N: usize> 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<dyn Hardfork>, cond))
.collect(),
)
}
}

View File

@ -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<dyn Hardfork>`.
pub fn boxed(self) -> Box<dyn Hardfork> {
Box::new(self)
}
}
impl FromStr for $enum {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
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:?}")
}
}
}
}

View File

@ -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<H: Hasher>(&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<EthereumHardfork> =
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<OptimismHardfork> =
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());
}
}

View File

@ -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: <https://blog.oplabs.co/introducing-optimism-bedrock>.
Bedrock,
/// Regolith: <https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/superchain-upgrades.md#regolith>.
Regolith,
/// <https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/superchain-upgrades.md#canyon>.
Canyon,
/// Ecotone: <https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/superchain-upgrades.md#ecotone>.
Ecotone,
/// Fjord: <https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/superchain-upgrades.md#fjord>
Fjord,
}
);
impl OptimismHardfork {
/// Retrieves the activation block for the specified hardfork on the given chain.
pub fn activation_block<H: Hardfork>(self, fork: H, chain: Chain) -> Option<u64> {
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<H: Hardfork>(self, fork: H, chain: Chain) -> Option<u64> {
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<H: Hardfork>(fork: H) -> Option<u64> {
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<H: Hardfork>(fork: H) -> Option<u64> {
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<H: Hardfork>(fork: H) -> Option<u64> {
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<H: Hardfork>(fork: H) -> Option<u64> {
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<H, HF, OHF>(fork: H, hardfork_fn: HF, optimism_hardfork_fn: OHF) -> Option<u64>
where
H: Hardfork,
HF: Fn(&EthereumHardfork) -> Option<u64>,
OHF: Fn(&OptimismHardfork) -> Option<u64>,
{
let fork: &dyn Any = &fork;
if let Some(fork) = fork.downcast_ref::<EthereumHardfork>() {
return hardfork_fn(fork)
}
fork.downcast_ref::<OptimismHardfork>().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)
);
}
}

View File

@ -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<bool> {
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 {}

View File

@ -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<H: Hardfork>(&self, fork: H) -> ForkCondition;
/// Get an iterator of all hardforks with their respective activation conditions.
fn forks_iter(&self) -> impl Iterator<Item = (&dyn Hardfork, ForkCondition)>;
/// Convenience method to check if a fork is active at a given timestamp.
fn is_fork_active_at_timestamp<H: Hardfork>(&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<H: Hardfork>(&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<dyn Hardfork>, 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<dyn Hardfork>, 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<H: Hardfork>(&self, fork: H) -> ForkCondition {
self.get(fork).unwrap_or(ForkCondition::Never)
}
/// Retrieves [`ForkCondition`] from `fork` if it exists, otherwise `None`.
pub fn get<H: Hardfork>(&self, fork: H) -> Option<ForkCondition> {
self.map.get(fork.name()).copied()
}
/// Get an iterator of all hardforks with their respective activation conditions.
pub fn forks_iter(&self) -> impl Iterator<Item = (&dyn Hardfork, ForkCondition)> {
self.forks.iter().map(|(f, b)| (&**f, *b))
}
/// Get last hardfork from the list.
pub fn last(&self) -> Option<(Box<dyn Hardfork>, 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<H: Hardfork>(&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<H: Hardfork>(&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<H: Hardfork>(&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<H: Hardfork>(&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<H: Hardfork>(&self, fork: H) -> ForkCondition {
self.fork(fork)
}
fn forks_iter(&self) -> impl Iterator<Item = (&dyn Hardfork, ForkCondition)> {
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::<Vec<_>>())
.finish()
}
}

View File

@ -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 {}

View File

@ -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;

View File

@ -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 {

View File

@ -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,

View File

@ -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;

View File

@ -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<EvmConfig = EthEvmConfig> {
@ -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(),
);

View File

@ -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};

View File

@ -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()

View File

@ -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)

View File

@ -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));

View File

@ -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());

View File

@ -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"),
}
}

View File

@ -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,

View File

@ -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,

View File

@ -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),
});
}

View File

@ -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<U256, BlockExecutionError> {
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");

View File

@ -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 => {

View File

@ -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::<u64>();
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),

View File

@ -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::{

View File

@ -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,

View File

@ -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.

View File

@ -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;

View File

@ -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()

View File

@ -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!(

View File

@ -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::{

View File

@ -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),
};

View File

@ -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::{

View File

@ -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,

View File

@ -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,
};

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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<ChainSpec> {
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,

View File

@ -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());

View File

@ -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 };

View File

@ -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<ChainSpec> {
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()),