1#![allow(non_camel_case_types)]
2
3pub use SpecId::*;
4
5#[cfg(not(feature = "optimism"))]
9#[repr(u8)]
10#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, enumn::N)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub enum SpecId {
13 FRONTIER = 0, FRONTIER_THAWING = 1, HOMESTEAD = 2, DAO_FORK = 3, TANGERINE = 4, SPURIOUS_DRAGON = 5, BYZANTIUM = 6, CONSTANTINOPLE = 7, PETERSBURG = 8, ISTANBUL = 9, MUIR_GLACIER = 10, BERLIN = 11, LONDON = 12, ARROW_GLACIER = 13, GRAY_GLACIER = 14, MERGE = 15, SHANGHAI = 16, CANCUN = 17, PRAGUE = 18, #[default]
33 LATEST = u8::MAX,
34}
35
36#[cfg(feature = "optimism")]
40#[repr(u8)]
41#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, enumn::N)]
42#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
43pub enum SpecId {
44 FRONTIER = 0,
45 FRONTIER_THAWING = 1,
46 HOMESTEAD = 2,
47 DAO_FORK = 3,
48 TANGERINE = 4,
49 SPURIOUS_DRAGON = 5,
50 BYZANTIUM = 6,
51 CONSTANTINOPLE = 7,
52 PETERSBURG = 8,
53 ISTANBUL = 9,
54 MUIR_GLACIER = 10,
55 BERLIN = 11,
56 LONDON = 12,
57 ARROW_GLACIER = 13,
58 GRAY_GLACIER = 14,
59 MERGE = 15,
60 BEDROCK = 16,
61 REGOLITH = 17,
62 SHANGHAI = 18,
63 CANYON = 19,
64 CANCUN = 20,
65 ECOTONE = 21,
66 PRAGUE = 22,
67 #[default]
68 LATEST = u8::MAX,
69}
70
71impl SpecId {
72 #[inline]
74 pub fn try_from_u8(spec_id: u8) -> Option<Self> {
75 Self::n(spec_id)
76 }
77
78 #[inline]
80 pub const fn is_enabled_in(self, other: Self) -> bool {
81 Self::enabled(self, other)
82 }
83
84 #[inline]
86 pub const fn enabled(our: SpecId, other: SpecId) -> bool {
87 our as u8 >= other as u8
88 }
89}
90
91impl From<&str> for SpecId {
92 fn from(name: &str) -> Self {
93 match name {
94 "Frontier" => Self::FRONTIER,
95 "Homestead" => Self::HOMESTEAD,
96 "Tangerine" => Self::TANGERINE,
97 "Spurious" => Self::SPURIOUS_DRAGON,
98 "Byzantium" => Self::BYZANTIUM,
99 "Constantinople" => Self::CONSTANTINOPLE,
100 "Petersburg" => Self::PETERSBURG,
101 "Istanbul" => Self::ISTANBUL,
102 "MuirGlacier" => Self::MUIR_GLACIER,
103 "Berlin" => Self::BERLIN,
104 "London" => Self::LONDON,
105 "Merge" => Self::MERGE,
106 "Shanghai" => Self::SHANGHAI,
107 "Cancun" => Self::CANCUN,
108 "Prague" => Self::PRAGUE,
109 #[cfg(feature = "optimism")]
110 "Bedrock" => SpecId::BEDROCK,
111 #[cfg(feature = "optimism")]
112 "Regolith" => SpecId::REGOLITH,
113 #[cfg(feature = "optimism")]
114 "Canyon" => SpecId::CANYON,
115 #[cfg(feature = "optimism")]
116 "Ecotone" => SpecId::ECOTONE,
117 _ => Self::LATEST,
118 }
119 }
120}
121
122impl From<SpecId> for &'static str {
123 fn from(spec_id: SpecId) -> Self {
124 match spec_id {
125 SpecId::FRONTIER => "Frontier",
126 SpecId::FRONTIER_THAWING => "Frontier Thawing",
127 SpecId::HOMESTEAD => "Homestead",
128 SpecId::DAO_FORK => "DAO Fork",
129 SpecId::TANGERINE => "Tangerine",
130 SpecId::SPURIOUS_DRAGON => "Spurious",
131 SpecId::BYZANTIUM => "Byzantium",
132 SpecId::CONSTANTINOPLE => "Constantinople",
133 SpecId::PETERSBURG => "Petersburg",
134 SpecId::ISTANBUL => "Istanbul",
135 SpecId::MUIR_GLACIER => "MuirGlacier",
136 SpecId::BERLIN => "Berlin",
137 SpecId::LONDON => "London",
138 SpecId::ARROW_GLACIER => "Arrow Glacier",
139 SpecId::GRAY_GLACIER => "Gray Glacier",
140 SpecId::MERGE => "Merge",
141 SpecId::SHANGHAI => "Shanghai",
142 SpecId::CANCUN => "Cancun",
143 SpecId::PRAGUE => "Prague",
144 #[cfg(feature = "optimism")]
145 SpecId::BEDROCK => "Bedrock",
146 #[cfg(feature = "optimism")]
147 SpecId::REGOLITH => "Regolith",
148 #[cfg(feature = "optimism")]
149 SpecId::CANYON => "Canyon",
150 #[cfg(feature = "optimism")]
151 SpecId::ECOTONE => "Ecotone",
152 SpecId::LATEST => "Latest",
153 }
154 }
155}
156
157pub trait Spec: Sized + 'static {
158 const SPEC_ID: SpecId;
160
161 #[inline]
163 fn enabled(spec_id: SpecId) -> bool {
164 SpecId::enabled(Self::SPEC_ID, spec_id)
165 }
166}
167
168macro_rules! spec {
169 ($spec_id:ident, $spec_name:ident) => {
170 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
171 pub struct $spec_name;
172
173 impl Spec for $spec_name {
174 const SPEC_ID: SpecId = $spec_id;
175 }
176 };
177}
178
179spec!(FRONTIER, FrontierSpec);
180spec!(HOMESTEAD, HomesteadSpec);
182spec!(TANGERINE, TangerineSpec);
184spec!(SPURIOUS_DRAGON, SpuriousDragonSpec);
185spec!(BYZANTIUM, ByzantiumSpec);
186spec!(PETERSBURG, PetersburgSpec);
188spec!(ISTANBUL, IstanbulSpec);
189spec!(BERLIN, BerlinSpec);
191spec!(LONDON, LondonSpec);
192spec!(MERGE, MergeSpec);
195spec!(SHANGHAI, ShanghaiSpec);
196spec!(CANCUN, CancunSpec);
197spec!(PRAGUE, PragueSpec);
198
199spec!(LATEST, LatestSpec);
200
201#[cfg(feature = "optimism")]
203spec!(BEDROCK, BedrockSpec);
204#[cfg(feature = "optimism")]
205spec!(REGOLITH, RegolithSpec);
206#[cfg(feature = "optimism")]
207spec!(CANYON, CanyonSpec);
208#[cfg(feature = "optimism")]
209spec!(ECOTONE, EcotoneSpec);
210
211#[macro_export]
212macro_rules! spec_to_generic {
213 ($spec_id:expr, $e:expr) => {{
214 match $spec_id {
216 $crate::SpecId::FRONTIER | SpecId::FRONTIER_THAWING => {
217 use $crate::FrontierSpec as SPEC;
218 $e
219 }
220 $crate::SpecId::HOMESTEAD | SpecId::DAO_FORK => {
221 use $crate::HomesteadSpec as SPEC;
222 $e
223 }
224 $crate::SpecId::TANGERINE => {
225 use $crate::TangerineSpec as SPEC;
226 $e
227 }
228 $crate::SpecId::SPURIOUS_DRAGON => {
229 use $crate::SpuriousDragonSpec as SPEC;
230 $e
231 }
232 $crate::SpecId::BYZANTIUM => {
233 use $crate::ByzantiumSpec as SPEC;
234 $e
235 }
236 $crate::SpecId::PETERSBURG | $crate::SpecId::CONSTANTINOPLE => {
237 use $crate::PetersburgSpec as SPEC;
238 $e
239 }
240 $crate::SpecId::ISTANBUL | $crate::SpecId::MUIR_GLACIER => {
241 use $crate::IstanbulSpec as SPEC;
242 $e
243 }
244 $crate::SpecId::BERLIN => {
245 use $crate::BerlinSpec as SPEC;
246 $e
247 }
248 $crate::SpecId::LONDON
249 | $crate::SpecId::ARROW_GLACIER
250 | $crate::SpecId::GRAY_GLACIER => {
251 use $crate::LondonSpec as SPEC;
252 $e
253 }
254 $crate::SpecId::MERGE => {
255 use $crate::MergeSpec as SPEC;
256 $e
257 }
258 $crate::SpecId::SHANGHAI => {
259 use $crate::ShanghaiSpec as SPEC;
260 $e
261 }
262 $crate::SpecId::CANCUN => {
263 use $crate::CancunSpec as SPEC;
264 $e
265 }
266 $crate::SpecId::LATEST => {
267 use $crate::LatestSpec as SPEC;
268 $e
269 }
270 $crate::SpecId::PRAGUE => {
271 use $crate::PragueSpec as SPEC;
272 $e
273 }
274 #[cfg(feature = "optimism")]
275 $crate::SpecId::BEDROCK => {
276 use $crate::BedrockSpec as SPEC;
277 $e
278 }
279 #[cfg(feature = "optimism")]
280 $crate::SpecId::REGOLITH => {
281 use $crate::RegolithSpec as SPEC;
282 $e
283 }
284 #[cfg(feature = "optimism")]
285 $crate::SpecId::CANYON => {
286 use $crate::CanyonSpec as SPEC;
287 $e
288 }
289 #[cfg(feature = "optimism")]
290 $crate::SpecId::ECOTONE => {
291 use $crate::EcotoneSpec as SPEC;
292 $e
293 }
294 }
295 }};
296}
297
298#[cfg(test)]
299mod tests {
300 use super::*;
301
302 #[test]
303 fn spec_to_generic() {
304 use SpecId::*;
305
306 spec_to_generic!(FRONTIER, assert_eq!(SPEC::SPEC_ID, FRONTIER));
307 spec_to_generic!(FRONTIER_THAWING, assert_eq!(SPEC::SPEC_ID, FRONTIER));
308 spec_to_generic!(HOMESTEAD, assert_eq!(SPEC::SPEC_ID, HOMESTEAD));
309 spec_to_generic!(DAO_FORK, assert_eq!(SPEC::SPEC_ID, HOMESTEAD));
310 spec_to_generic!(TANGERINE, assert_eq!(SPEC::SPEC_ID, TANGERINE));
311 spec_to_generic!(SPURIOUS_DRAGON, assert_eq!(SPEC::SPEC_ID, SPURIOUS_DRAGON));
312 spec_to_generic!(BYZANTIUM, assert_eq!(SPEC::SPEC_ID, BYZANTIUM));
313 spec_to_generic!(CONSTANTINOPLE, assert_eq!(SPEC::SPEC_ID, PETERSBURG));
314 spec_to_generic!(PETERSBURG, assert_eq!(SPEC::SPEC_ID, PETERSBURG));
315 spec_to_generic!(ISTANBUL, assert_eq!(SPEC::SPEC_ID, ISTANBUL));
316 spec_to_generic!(MUIR_GLACIER, assert_eq!(SPEC::SPEC_ID, ISTANBUL));
317 spec_to_generic!(BERLIN, assert_eq!(SPEC::SPEC_ID, BERLIN));
318 spec_to_generic!(LONDON, assert_eq!(SPEC::SPEC_ID, LONDON));
319 spec_to_generic!(ARROW_GLACIER, assert_eq!(SPEC::SPEC_ID, LONDON));
320 spec_to_generic!(GRAY_GLACIER, assert_eq!(SPEC::SPEC_ID, LONDON));
321 spec_to_generic!(MERGE, assert_eq!(SPEC::SPEC_ID, MERGE));
322 #[cfg(feature = "optimism")]
323 spec_to_generic!(BEDROCK, assert_eq!(SPEC::SPEC_ID, BEDROCK));
324 #[cfg(feature = "optimism")]
325 spec_to_generic!(REGOLITH, assert_eq!(SPEC::SPEC_ID, REGOLITH));
326 spec_to_generic!(SHANGHAI, assert_eq!(SPEC::SPEC_ID, SHANGHAI));
327 #[cfg(feature = "optimism")]
328 spec_to_generic!(CANYON, assert_eq!(SPEC::SPEC_ID, CANYON));
329 spec_to_generic!(CANCUN, assert_eq!(SPEC::SPEC_ID, CANCUN));
330 spec_to_generic!(PRAGUE, assert_eq!(SPEC::SPEC_ID, PRAGUE));
331 spec_to_generic!(LATEST, assert_eq!(SPEC::SPEC_ID, LATEST));
332 }
333}
334
335#[cfg(feature = "optimism")]
336#[cfg(test)]
337mod optimism_tests {
338 use super::*;
339
340 #[test]
341 fn test_bedrock_post_merge_hardforks() {
342 assert!(BedrockSpec::enabled(SpecId::MERGE));
343 assert!(!BedrockSpec::enabled(SpecId::SHANGHAI));
344 assert!(!BedrockSpec::enabled(SpecId::CANCUN));
345 assert!(!BedrockSpec::enabled(SpecId::LATEST));
346 assert!(BedrockSpec::enabled(SpecId::BEDROCK));
347 assert!(!BedrockSpec::enabled(SpecId::REGOLITH));
348 }
349
350 #[test]
351 fn test_regolith_post_merge_hardforks() {
352 assert!(RegolithSpec::enabled(SpecId::MERGE));
353 assert!(!RegolithSpec::enabled(SpecId::SHANGHAI));
354 assert!(!RegolithSpec::enabled(SpecId::CANCUN));
355 assert!(!RegolithSpec::enabled(SpecId::LATEST));
356 assert!(RegolithSpec::enabled(SpecId::BEDROCK));
357 assert!(RegolithSpec::enabled(SpecId::REGOLITH));
358 }
359
360 #[test]
361 fn test_bedrock_post_merge_hardforks_spec_id() {
362 assert!(SpecId::enabled(SpecId::BEDROCK, SpecId::MERGE));
363 assert!(!SpecId::enabled(SpecId::BEDROCK, SpecId::SHANGHAI));
364 assert!(!SpecId::enabled(SpecId::BEDROCK, SpecId::CANCUN));
365 assert!(!SpecId::enabled(SpecId::BEDROCK, SpecId::LATEST));
366 assert!(SpecId::enabled(SpecId::BEDROCK, SpecId::BEDROCK));
367 assert!(!SpecId::enabled(SpecId::BEDROCK, SpecId::REGOLITH));
368 }
369
370 #[test]
371 fn test_regolith_post_merge_hardforks_spec_id() {
372 assert!(SpecId::enabled(SpecId::REGOLITH, SpecId::MERGE));
373 assert!(!SpecId::enabled(SpecId::REGOLITH, SpecId::SHANGHAI));
374 assert!(!SpecId::enabled(SpecId::REGOLITH, SpecId::CANCUN));
375 assert!(!SpecId::enabled(SpecId::REGOLITH, SpecId::LATEST));
376 assert!(SpecId::enabled(SpecId::REGOLITH, SpecId::BEDROCK));
377 assert!(SpecId::enabled(SpecId::REGOLITH, SpecId::REGOLITH));
378 }
379
380 #[test]
381 fn test_canyon_post_merge_hardforks() {
382 assert!(CanyonSpec::enabled(SpecId::MERGE));
383 assert!(CanyonSpec::enabled(SpecId::SHANGHAI));
384 assert!(!CanyonSpec::enabled(SpecId::CANCUN));
385 assert!(!CanyonSpec::enabled(SpecId::LATEST));
386 assert!(CanyonSpec::enabled(SpecId::BEDROCK));
387 assert!(CanyonSpec::enabled(SpecId::REGOLITH));
388 assert!(CanyonSpec::enabled(SpecId::CANYON));
389 }
390
391 #[test]
392 fn test_canyon_post_merge_hardforks_spec_id() {
393 assert!(SpecId::enabled(SpecId::CANYON, SpecId::MERGE));
394 assert!(SpecId::enabled(SpecId::CANYON, SpecId::SHANGHAI));
395 assert!(!SpecId::enabled(SpecId::CANYON, SpecId::CANCUN));
396 assert!(!SpecId::enabled(SpecId::CANYON, SpecId::LATEST));
397 assert!(SpecId::enabled(SpecId::CANYON, SpecId::BEDROCK));
398 assert!(SpecId::enabled(SpecId::CANYON, SpecId::REGOLITH));
399 assert!(SpecId::enabled(SpecId::CANYON, SpecId::CANYON));
400 }
401
402 #[test]
403 fn test_ecotone_post_merge_hardforks() {
404 assert!(EcotoneSpec::enabled(SpecId::MERGE));
405 assert!(EcotoneSpec::enabled(SpecId::SHANGHAI));
406 assert!(EcotoneSpec::enabled(SpecId::CANCUN));
407 assert!(!EcotoneSpec::enabled(SpecId::LATEST));
408 assert!(EcotoneSpec::enabled(SpecId::BEDROCK));
409 assert!(EcotoneSpec::enabled(SpecId::REGOLITH));
410 assert!(EcotoneSpec::enabled(SpecId::CANYON));
411 assert!(EcotoneSpec::enabled(SpecId::ECOTONE));
412 }
413
414 #[test]
415 fn test_ecotone_post_merge_hardforks_spec_id() {
416 assert!(SpecId::enabled(SpecId::ECOTONE, SpecId::MERGE));
417 assert!(SpecId::enabled(SpecId::ECOTONE, SpecId::SHANGHAI));
418 assert!(SpecId::enabled(SpecId::ECOTONE, SpecId::CANCUN));
419 assert!(!SpecId::enabled(SpecId::ECOTONE, SpecId::LATEST));
420 assert!(SpecId::enabled(SpecId::ECOTONE, SpecId::BEDROCK));
421 assert!(SpecId::enabled(SpecId::ECOTONE, SpecId::REGOLITH));
422 assert!(SpecId::enabled(SpecId::ECOTONE, SpecId::CANYON));
423 assert!(SpecId::enabled(SpecId::ECOTONE, SpecId::ECOTONE));
424 }
425}