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    }
73}
74
75/// Convert a `BlockNumberOrTag` into an `EthereumHardfork`.
76pub fn ethereum_hardfork_from_block_tag(block: impl Into<BlockNumberOrTag>) -> EthereumHardfork {
77    let num = match block.into() {
78        BlockNumberOrTag::Earliest => 0,
79        BlockNumberOrTag::Number(num) => num,
80        _ => u64::MAX,
81    };
82
83    EthereumHardfork::from_mainnet_block_number(num)
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89    use alloy_hardforks::ethereum::mainnet::*;
90    #[allow(unused_imports)]
91    use alloy_rpc_types::BlockNumberOrTag;
92
93    #[test]
94    fn test_ethereum_spec_id_mapping() {
95        assert_eq!(spec_id_from_ethereum_hardfork(EthereumHardfork::Frontier), SpecId::FRONTIER);
96        assert_eq!(spec_id_from_ethereum_hardfork(EthereumHardfork::Homestead), SpecId::HOMESTEAD);
97
98        // Test latest hardforks
99        assert_eq!(spec_id_from_ethereum_hardfork(EthereumHardfork::Cancun), SpecId::CANCUN);
100        assert_eq!(spec_id_from_ethereum_hardfork(EthereumHardfork::Prague), SpecId::PRAGUE);
101    }
102
103    #[test]
104    fn test_optimism_spec_id_mapping() {
105        assert_eq!(spec_id_from_optimism_hardfork(OpHardfork::Bedrock), OpSpecId::BEDROCK);
106        assert_eq!(spec_id_from_optimism_hardfork(OpHardfork::Regolith), OpSpecId::REGOLITH);
107
108        // Test latest hardforks
109        assert_eq!(spec_id_from_optimism_hardfork(OpHardfork::Holocene), OpSpecId::HOLOCENE);
110        assert_eq!(spec_id_from_optimism_hardfork(OpHardfork::Interop), OpSpecId::INTEROP);
111    }
112
113    #[test]
114    fn test_hardfork_from_block_tag_numbers() {
115        assert_eq!(
116            ethereum_hardfork_from_block_tag(MAINNET_HOMESTEAD_BLOCK - 1),
117            EthereumHardfork::Frontier
118        );
119        assert_eq!(
120            ethereum_hardfork_from_block_tag(MAINNET_LONDON_BLOCK + 1),
121            EthereumHardfork::London
122        );
123    }
124}