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