foundry_evm_core/
hardfork.rs1use alloy_rpc_types::BlockNumberOrTag;
2use op_revm::OpSpecId;
3use revm::primitives::hardfork::SpecId;
4
5pub use alloy_hardforks::EthereumHardfork;
6pub use alloy_op_hardforks::OpHardfork;
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub enum FoundryHardfork {
10 Ethereum(EthereumHardfork),
11 Optimism(OpHardfork),
12}
13
14impl FoundryHardfork {
15 pub fn ethereum(h: EthereumHardfork) -> Self {
16 Self::Ethereum(h)
17 }
18
19 pub fn optimism(h: OpHardfork) -> Self {
20 Self::Optimism(h)
21 }
22}
23
24impl From<EthereumHardfork> for FoundryHardfork {
25 fn from(value: EthereumHardfork) -> Self {
26 Self::Ethereum(value)
27 }
28}
29
30impl From<OpHardfork> for FoundryHardfork {
31 fn from(value: OpHardfork) -> Self {
32 Self::Optimism(value)
33 }
34}
35
36impl From<FoundryHardfork> for SpecId {
37 fn from(fork: FoundryHardfork) -> Self {
38 match fork {
39 FoundryHardfork::Ethereum(hardfork) => spec_id_from_ethereum_hardfork(hardfork),
40 FoundryHardfork::Optimism(hardfork) => spec_id_from_optimism_hardfork(hardfork).into(),
41 }
42 }
43}
44
45pub fn spec_id_from_ethereum_hardfork(hardfork: EthereumHardfork) -> SpecId {
47 match hardfork {
48 EthereumHardfork::Frontier => SpecId::FRONTIER,
49 EthereumHardfork::Homestead => SpecId::HOMESTEAD,
50 EthereumHardfork::Dao => SpecId::DAO_FORK,
51 EthereumHardfork::Tangerine => SpecId::TANGERINE,
52 EthereumHardfork::SpuriousDragon => SpecId::SPURIOUS_DRAGON,
53 EthereumHardfork::Byzantium => SpecId::BYZANTIUM,
54 EthereumHardfork::Constantinople => SpecId::CONSTANTINOPLE,
55 EthereumHardfork::Petersburg => SpecId::PETERSBURG,
56 EthereumHardfork::Istanbul => SpecId::ISTANBUL,
57 EthereumHardfork::MuirGlacier => SpecId::MUIR_GLACIER,
58 EthereumHardfork::Berlin => SpecId::BERLIN,
59 EthereumHardfork::London => SpecId::LONDON,
60 EthereumHardfork::ArrowGlacier => SpecId::ARROW_GLACIER,
61 EthereumHardfork::GrayGlacier => SpecId::GRAY_GLACIER,
62 EthereumHardfork::Paris => SpecId::MERGE,
63 EthereumHardfork::Shanghai => SpecId::SHANGHAI,
64 EthereumHardfork::Cancun => SpecId::CANCUN,
65 EthereumHardfork::Prague => SpecId::PRAGUE,
66 EthereumHardfork::Osaka => SpecId::OSAKA,
67 EthereumHardfork::Bpo1 | EthereumHardfork::Bpo2 => SpecId::OSAKA,
68 EthereumHardfork::Bpo3 | EthereumHardfork::Bpo4 | EthereumHardfork::Bpo5 => {
69 unimplemented!()
70 }
71 f => unreachable!("unimplemented {}", f),
72 }
73}
74
75pub fn spec_id_from_optimism_hardfork(hardfork: OpHardfork) -> OpSpecId {
77 match hardfork {
78 OpHardfork::Bedrock => OpSpecId::BEDROCK,
79 OpHardfork::Regolith => OpSpecId::REGOLITH,
80 OpHardfork::Canyon => OpSpecId::CANYON,
81 OpHardfork::Ecotone => OpSpecId::ECOTONE,
82 OpHardfork::Fjord => OpSpecId::FJORD,
83 OpHardfork::Granite => OpSpecId::GRANITE,
84 OpHardfork::Holocene => OpSpecId::HOLOCENE,
85 OpHardfork::Isthmus => OpSpecId::ISTHMUS,
86 OpHardfork::Interop => OpSpecId::INTEROP,
87 OpHardfork::Jovian => OpSpecId::JOVIAN,
88 f => unreachable!("unimplemented {}", f),
89 }
90}
91
92pub fn ethereum_hardfork_from_block_tag(block: impl Into<BlockNumberOrTag>) -> EthereumHardfork {
94 let num = match block.into() {
95 BlockNumberOrTag::Earliest => 0,
96 BlockNumberOrTag::Number(num) => num,
97 _ => u64::MAX,
98 };
99
100 EthereumHardfork::from_mainnet_block_number(num)
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106 use alloy_hardforks::ethereum::mainnet::*;
107
108 #[test]
109 fn test_ethereum_spec_id_mapping() {
110 assert_eq!(spec_id_from_ethereum_hardfork(EthereumHardfork::Frontier), SpecId::FRONTIER);
111 assert_eq!(spec_id_from_ethereum_hardfork(EthereumHardfork::Homestead), SpecId::HOMESTEAD);
112
113 assert_eq!(spec_id_from_ethereum_hardfork(EthereumHardfork::Cancun), SpecId::CANCUN);
115 assert_eq!(spec_id_from_ethereum_hardfork(EthereumHardfork::Prague), SpecId::PRAGUE);
116 }
117
118 #[test]
119 fn test_optimism_spec_id_mapping() {
120 assert_eq!(spec_id_from_optimism_hardfork(OpHardfork::Bedrock), OpSpecId::BEDROCK);
121 assert_eq!(spec_id_from_optimism_hardfork(OpHardfork::Regolith), OpSpecId::REGOLITH);
122
123 assert_eq!(spec_id_from_optimism_hardfork(OpHardfork::Holocene), OpSpecId::HOLOCENE);
125 assert_eq!(spec_id_from_optimism_hardfork(OpHardfork::Interop), OpSpecId::INTEROP);
126 }
127
128 #[test]
129 fn test_hardfork_from_block_tag_numbers() {
130 assert_eq!(
131 ethereum_hardfork_from_block_tag(MAINNET_HOMESTEAD_BLOCK - 1),
132 EthereumHardfork::Frontier
133 );
134 assert_eq!(
135 ethereum_hardfork_from_block_tag(MAINNET_LONDON_BLOCK + 1),
136 EthereumHardfork::London
137 );
138 }
139}