rtvm_primitives/
specification.rs

1#![allow(non_camel_case_types)]
2
3pub use SpecId::*;
4
5/// Specification IDs and their activation block.
6///
7/// Information was obtained from the [Ethereum Execution Specifications](https://github.com/ethereum/execution-specs)
8#[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               0
14    FRONTIER_THAWING = 1, // Frontier Thawing       200000
15    HOMESTEAD = 2,        // Homestead              1150000
16    DAO_FORK = 3,         // DAO Fork               1920000
17    TANGERINE = 4,        // Tangerine Whistle      2463000
18    SPURIOUS_DRAGON = 5,  // Spurious Dragon        2675000
19    BYZANTIUM = 6,        // Byzantium              4370000
20    CONSTANTINOPLE = 7,   // Constantinople         7280000 is overwritten with PETERSBURG
21    PETERSBURG = 8,       // Petersburg             7280000
22    ISTANBUL = 9,         // Istanbul	            9069000
23    MUIR_GLACIER = 10,    // Muir Glacier           9200000
24    BERLIN = 11,          // Berlin	                12244000
25    LONDON = 12,          // London	                12965000
26    ARROW_GLACIER = 13,   // Arrow Glacier          13773000
27    GRAY_GLACIER = 14,    // Gray Glacier           15050000
28    MERGE = 15,           // Paris/Merge            15537394 (TTD: 58750000000000000000000)
29    SHANGHAI = 16,        // Shanghai               17034870 (Timestamp: 1681338455)
30    CANCUN = 17,          // Cancun                 19426587 (Timestamp: 1710338135)
31    PRAGUE = 18,          // Praque                 TBD
32    #[default]
33    LATEST = u8::MAX,
34}
35
36/// Specification IDs and their activation block.
37///
38/// Information was obtained from the [Ethereum Execution Specifications](https://github.com/ethereum/execution-specs)
39#[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    /// Returns the `SpecId` for the given `u8`.
73    #[inline]
74    pub fn try_from_u8(spec_id: u8) -> Option<Self> {
75        Self::n(spec_id)
76    }
77
78    /// Returns `true` if the given specification ID is enabled in this spec.
79    #[inline]
80    pub const fn is_enabled_in(self, other: Self) -> bool {
81        Self::enabled(self, other)
82    }
83
84    /// Returns `true` if the given specification ID is enabled in this spec.
85    #[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    /// The specification ID.
159    const SPEC_ID: SpecId;
160
161    /// Returns `true` if the given specification ID is enabled in this spec.
162    #[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);
180// FRONTIER_THAWING no EVM spec change
181spec!(HOMESTEAD, HomesteadSpec);
182// DAO_FORK no EVM spec change
183spec!(TANGERINE, TangerineSpec);
184spec!(SPURIOUS_DRAGON, SpuriousDragonSpec);
185spec!(BYZANTIUM, ByzantiumSpec);
186// CONSTANTINOPLE was overridden with PETERSBURG
187spec!(PETERSBURG, PetersburgSpec);
188spec!(ISTANBUL, IstanbulSpec);
189// MUIR_GLACIER no EVM spec change
190spec!(BERLIN, BerlinSpec);
191spec!(LONDON, LondonSpec);
192// ARROW_GLACIER no EVM spec change
193// GRAY_GLACIER no EVM spec change
194spec!(MERGE, MergeSpec);
195spec!(SHANGHAI, ShanghaiSpec);
196spec!(CANCUN, CancunSpec);
197spec!(PRAGUE, PragueSpec);
198
199spec!(LATEST, LatestSpec);
200
201// Optimism Hardforks
202#[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        // We are transitioning from var to generic spec.
215        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}