mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: use new ChainHardforks type on ChainSpec (#9065)
This commit is contained in:
@ -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"] }
|
||||
|
||||
@ -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)),
|
||||
];
|
||||
@ -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)),
|
||||
];
|
||||
@ -1,9 +0,0 @@
|
||||
/// Ethereum chains
|
||||
pub mod ethereum;
|
||||
|
||||
/// Optimism chains
|
||||
#[cfg(feature = "optimism")]
|
||||
pub mod optimism;
|
||||
|
||||
/// Dev chain
|
||||
pub mod dev;
|
||||
@ -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)),
|
||||
];
|
||||
@ -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(_) => {
|
||||
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
32
crates/ethereum-forks/src/hardfork/dev.rs
Normal file
32
crates/ethereum-forks/src/hardfork/dev.rs
Normal 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)),
|
||||
])
|
||||
});
|
||||
441
crates/ethereum-forks/src/hardfork/ethereum.rs
Normal file
441
crates/ethereum-forks/src/hardfork/ethereum.rs
Normal 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(),
|
||||
)
|
||||
}
|
||||
}
|
||||
52
crates/ethereum-forks/src/hardfork/macros.rs
Normal file
52
crates/ethereum-forks/src/hardfork/macros.rs
Normal 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:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
126
crates/ethereum-forks/src/hardfork/mod.rs
Normal file
126
crates/ethereum-forks/src/hardfork/mod.rs
Normal 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());
|
||||
}
|
||||
}
|
||||
337
crates/ethereum-forks/src/hardfork/optimism.rs
Normal file
337
crates/ethereum-forks/src/hardfork/optimism.rs
Normal 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 = ⋔
|
||||
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)
|
||||
);
|
||||
}
|
||||
}
|
||||
56
crates/ethereum-forks/src/hardforks/ethereum.rs
Normal file
56
crates/ethereum-forks/src/hardforks/ethereum.rs
Normal 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 {}
|
||||
131
crates/ethereum-forks/src/hardforks/mod.rs
Normal file
131
crates/ethereum-forks/src/hardforks/mod.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
12
crates/ethereum-forks/src/hardforks/optimism.rs
Normal file
12
crates/ethereum-forks/src/hardforks/optimism.rs
Normal 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 {}
|
||||
@ -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;
|
||||
|
||||
Reference in New Issue
Block a user