1use revm::specification::hardfork::SpecId;
2
3#[repr(u8)]
4#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Default)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6#[allow(non_camel_case_types)]
7pub enum OpSpecId {
8 BEDROCK = 100,
9 REGOLITH,
10 CANYON,
11 ECOTONE,
12 FJORD,
13 GRANITE,
14 HOLOCENE,
15 #[default]
16 ISTHMUS,
17 INTEROP,
18}
19
20impl OpSpecId {
21 pub const fn into_eth_spec(self) -> SpecId {
23 match self {
24 Self::BEDROCK | Self::REGOLITH => SpecId::MERGE,
25 Self::CANYON => SpecId::SHANGHAI,
26 Self::ECOTONE | Self::FJORD | Self::GRANITE | Self::HOLOCENE => SpecId::CANCUN,
27 Self::ISTHMUS | Self::INTEROP => SpecId::PRAGUE,
28 }
29 }
30
31 pub const fn is_enabled_in(self, other: OpSpecId) -> bool {
32 other as u8 <= self as u8
33 }
34}
35
36impl From<OpSpecId> for SpecId {
37 fn from(spec: OpSpecId) -> Self {
38 spec.into_eth_spec()
39 }
40}
41
42impl TryFrom<&str> for OpSpecId {
43 type Error = ();
44
45 fn try_from(name: &str) -> Result<Self, Self::Error> {
46 match name {
47 name::BEDROCK => Ok(OpSpecId::BEDROCK),
48 name::REGOLITH => Ok(OpSpecId::REGOLITH),
49 name::CANYON => Ok(OpSpecId::CANYON),
50 name::ECOTONE => Ok(OpSpecId::ECOTONE),
51 name::FJORD => Ok(OpSpecId::FJORD),
52 name::GRANITE => Ok(OpSpecId::GRANITE),
53 _ => Err(()),
54 }
55 }
56}
57
58impl From<OpSpecId> for &'static str {
59 fn from(spec_id: OpSpecId) -> Self {
60 match spec_id {
61 OpSpecId::BEDROCK => name::BEDROCK,
62 OpSpecId::REGOLITH => name::REGOLITH,
63 OpSpecId::CANYON => name::CANYON,
64 OpSpecId::ECOTONE => name::ECOTONE,
65 OpSpecId::FJORD => name::FJORD,
66 OpSpecId::GRANITE => name::GRANITE,
67 OpSpecId::HOLOCENE => name::HOLOCENE,
68 OpSpecId::ISTHMUS => name::ISTHMUS,
69 OpSpecId::INTEROP => name::INTEROP,
70 }
71 }
72}
73
74pub mod name {
76 pub const BEDROCK: &str = "Bedrock";
77 pub const REGOLITH: &str = "Regolith";
78 pub const CANYON: &str = "Canyon";
79 pub const ECOTONE: &str = "Ecotone";
80 pub const FJORD: &str = "Fjord";
81 pub const GRANITE: &str = "Granite";
82 pub const HOLOCENE: &str = "Holocene";
83 pub const ISTHMUS: &str = "Isthmus";
84 pub const INTEROP: &str = "Interop";
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn test_bedrock_post_merge_hardforks() {
93 assert!(OpSpecId::BEDROCK
94 .into_eth_spec()
95 .is_enabled_in(SpecId::MERGE));
96 assert!(!OpSpecId::BEDROCK
97 .into_eth_spec()
98 .is_enabled_in(SpecId::SHANGHAI));
99 assert!(!OpSpecId::BEDROCK
100 .into_eth_spec()
101 .is_enabled_in(SpecId::CANCUN));
102 assert!(!OpSpecId::BEDROCK
103 .into_eth_spec()
104 .is_enabled_in(SpecId::LATEST));
105 assert!(OpSpecId::BEDROCK.is_enabled_in(OpSpecId::BEDROCK));
106 assert!(!OpSpecId::BEDROCK.is_enabled_in(OpSpecId::REGOLITH));
107 }
108
109 #[test]
110 fn test_regolith_post_merge_hardforks() {
111 assert!(OpSpecId::REGOLITH
112 .into_eth_spec()
113 .is_enabled_in(SpecId::MERGE));
114 assert!(!OpSpecId::REGOLITH
115 .into_eth_spec()
116 .is_enabled_in(SpecId::SHANGHAI));
117 assert!(!OpSpecId::REGOLITH
118 .into_eth_spec()
119 .is_enabled_in(SpecId::CANCUN));
120 assert!(!OpSpecId::REGOLITH
121 .into_eth_spec()
122 .is_enabled_in(SpecId::LATEST));
123 assert!(OpSpecId::REGOLITH.is_enabled_in(OpSpecId::BEDROCK));
124 assert!(OpSpecId::REGOLITH.is_enabled_in(OpSpecId::REGOLITH));
125 }
126
127 #[test]
128 fn test_canyon_post_merge_hardforks() {
129 assert!(OpSpecId::CANYON
130 .into_eth_spec()
131 .is_enabled_in(SpecId::MERGE));
132 assert!(OpSpecId::CANYON
133 .into_eth_spec()
134 .is_enabled_in(SpecId::SHANGHAI));
135 assert!(!OpSpecId::CANYON
136 .into_eth_spec()
137 .is_enabled_in(SpecId::CANCUN));
138 assert!(!OpSpecId::CANYON
139 .into_eth_spec()
140 .is_enabled_in(SpecId::LATEST));
141 assert!(OpSpecId::CANYON.is_enabled_in(OpSpecId::BEDROCK));
142 assert!(OpSpecId::CANYON.is_enabled_in(OpSpecId::REGOLITH));
143 assert!(OpSpecId::CANYON.is_enabled_in(OpSpecId::CANYON));
144 }
145
146 #[test]
147 fn test_ecotone_post_merge_hardforks() {
148 assert!(OpSpecId::ECOTONE
149 .into_eth_spec()
150 .is_enabled_in(SpecId::MERGE));
151 assert!(OpSpecId::ECOTONE
152 .into_eth_spec()
153 .is_enabled_in(SpecId::SHANGHAI));
154 assert!(OpSpecId::ECOTONE
155 .into_eth_spec()
156 .is_enabled_in(SpecId::CANCUN));
157 assert!(!OpSpecId::ECOTONE
158 .into_eth_spec()
159 .is_enabled_in(SpecId::LATEST));
160 assert!(OpSpecId::ECOTONE.is_enabled_in(OpSpecId::BEDROCK));
161 assert!(OpSpecId::ECOTONE.is_enabled_in(OpSpecId::REGOLITH));
162 assert!(OpSpecId::ECOTONE.is_enabled_in(OpSpecId::CANYON));
163 assert!(OpSpecId::ECOTONE.is_enabled_in(OpSpecId::ECOTONE));
164 }
165
166 #[test]
167 fn test_fjord_post_merge_hardforks() {
168 assert!(OpSpecId::FJORD.into_eth_spec().is_enabled_in(SpecId::MERGE));
169 assert!(OpSpecId::FJORD
170 .into_eth_spec()
171 .is_enabled_in(SpecId::SHANGHAI));
172 assert!(OpSpecId::FJORD
173 .into_eth_spec()
174 .is_enabled_in(SpecId::CANCUN));
175 assert!(!OpSpecId::FJORD
176 .into_eth_spec()
177 .is_enabled_in(SpecId::LATEST));
178 assert!(OpSpecId::FJORD.is_enabled_in(OpSpecId::BEDROCK));
179 assert!(OpSpecId::FJORD.is_enabled_in(OpSpecId::REGOLITH));
180 assert!(OpSpecId::FJORD.is_enabled_in(OpSpecId::CANYON));
181 assert!(OpSpecId::FJORD.is_enabled_in(OpSpecId::ECOTONE));
182 assert!(OpSpecId::FJORD.is_enabled_in(OpSpecId::FJORD));
183 }
184}