Skip to main content

anvil/
hardfork.rs

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
35/// Map an EthereumHardfork enum into its corresponding SpecId.
36pub 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
60/// Map an OptimismHardfork enum into its corresponding OpSpecId.
61pub 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
76/// Convert a `BlockNumberOrTag` into an `EthereumHardfork`.
77pub 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        // Test latest hardforks
100        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        // Test latest hardforks
110        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}