Skip to main content

revm_primitives/
hardfork.rs

1//! Ethereum hardfork specification IDs.
2
3#![expect(non_camel_case_types)]
4
5use core::str::FromStr;
6pub use std::string::{String, ToString};
7pub use SpecId::*;
8
9/// Specification IDs and their activation points.
10///
11/// Information was obtained from the [Ethereum Execution Specifications](https://github.com/ethereum/execution-specs).
12#[repr(u8)]
13#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub enum SpecId {
16    /// Frontier
17    ///
18    /// Activated at block 1
19    FRONTIER = 0,
20    /// Homestead
21    ///
22    /// Activated at block 1150000
23    HOMESTEAD,
24    /// Tangerine Whistle
25    ///
26    /// Activated at block 2463000
27    TANGERINE,
28    /// Spurious Dragon
29    ///
30    /// Activated at block 2675000
31    SPURIOUS_DRAGON,
32    /// Byzantium
33    ///
34    /// Activated at block 4370000
35    BYZANTIUM,
36    /// Petersburg
37    ///
38    /// Activated at block 7280000
39    PETERSBURG,
40    /// Istanbul
41    ///
42    /// Activated at block 9069000
43    ISTANBUL,
44    /// Berlin
45    ///
46    /// Activated at block 12244000
47    BERLIN,
48    /// London
49    ///
50    /// Activated at block 12965000
51    LONDON,
52    /// Paris/Merge
53    ///
54    /// Activated at block 15537394
55    MERGE,
56    /// Shanghai
57    ///
58    /// Activated at block 17034870 (timestamp 1681338455)
59    SHANGHAI,
60    /// Cancun
61    ///
62    /// Activated at block 19426587 (timestamp 1710338135)
63    CANCUN,
64    /// Prague
65    ///
66    /// Activated at block 22431084
67    PRAGUE,
68    /// Osaka
69    ///
70    /// Activated at block 23935694
71    #[default]
72    OSAKA,
73    /// Amsterdam
74    ///
75    /// Activated at block TBD
76    AMSTERDAM,
77}
78
79impl SpecId {
80    /// The latest known spec. This may refer to a highly experimental hard fork
81    /// that is not yet finalized or deployed on any network.
82    ///
83    /// **Warning**: This value will change between minor versions as new hard forks are added.
84    /// Do not rely on it for stable behavior.
85    #[doc(alias = "MAX")]
86    pub const NEXT: Self = Self::AMSTERDAM;
87
88    /// Returns the [`SpecId`] for the given [`u8`].
89    #[inline]
90    pub const fn try_from_u8(spec_id: u8) -> Option<Self> {
91        if spec_id <= Self::NEXT as u8 {
92            // SAFETY: `spec_id` is within the valid range.
93            Some(unsafe { core::mem::transmute::<u8, Self>(spec_id) })
94        } else {
95            None
96        }
97    }
98
99    /// Returns `true` if the given specification ID is enabled in this spec.
100    #[inline]
101    pub const fn is_enabled_in(self, other: Self) -> bool {
102        self as u8 >= other as u8
103    }
104}
105
106impl From<SpecId> for u8 {
107    #[inline]
108    fn from(spec_id: SpecId) -> Self {
109        spec_id as u8
110    }
111}
112
113impl TryFrom<u8> for SpecId {
114    type Error = u8;
115
116    #[inline]
117    fn try_from(value: u8) -> Result<Self, Self::Error> {
118        Self::try_from_u8(value).ok_or(value)
119    }
120}
121
122/// String identifiers for hardforks.
123pub mod name {
124    /// String identifier for the Frontier hardfork
125    pub const FRONTIER: &str = "Frontier";
126    /// String identifier for the Homestead hardfork
127    pub const HOMESTEAD: &str = "Homestead";
128    /// String identifier for the Tangerine Whistle hardfork
129    pub const TANGERINE: &str = "Tangerine";
130    /// String identifier for the Spurious Dragon hardfork
131    pub const SPURIOUS_DRAGON: &str = "Spurious";
132    /// String identifier for the Byzantium hardfork
133    pub const BYZANTIUM: &str = "Byzantium";
134    /// String identifier for the Petersburg hardfork
135    pub const PETERSBURG: &str = "Petersburg";
136    /// String identifier for the Istanbul hardfork
137    pub const ISTANBUL: &str = "Istanbul";
138    /// String identifier for the Berlin hardfork
139    pub const BERLIN: &str = "Berlin";
140    /// String identifier for the London hardfork
141    pub const LONDON: &str = "London";
142    /// String identifier for the Paris/Merge hardfork
143    pub const MERGE: &str = "Merge";
144    /// String identifier for the Shanghai hardfork
145    pub const SHANGHAI: &str = "Shanghai";
146    /// String identifier for the Cancun hardfork
147    pub const CANCUN: &str = "Cancun";
148    /// String identifier for the Prague hardfork
149    pub const PRAGUE: &str = "Prague";
150    /// String identifier for the Osaka hardfork
151    pub const OSAKA: &str = "Osaka";
152    /// String identifier for the Amsterdam hardfork
153    pub const AMSTERDAM: &str = "Amsterdam";
154    /// String identifier for the latest hardfork
155    pub const LATEST: &str = "Latest";
156}
157
158/// Error type for unknown hardfork names. Returned by [`SpecId::from_str`].
159#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
160pub struct UnknownHardfork;
161
162impl FromStr for SpecId {
163    type Err = UnknownHardfork;
164
165    fn from_str(s: &str) -> Result<Self, Self::Err> {
166        match s {
167            name::FRONTIER => Ok(Self::FRONTIER),
168            name::HOMESTEAD => Ok(Self::HOMESTEAD),
169            name::TANGERINE => Ok(Self::TANGERINE),
170            name::SPURIOUS_DRAGON => Ok(Self::SPURIOUS_DRAGON),
171            name::BYZANTIUM => Ok(Self::BYZANTIUM),
172            name::PETERSBURG => Ok(Self::PETERSBURG),
173            name::ISTANBUL => Ok(Self::ISTANBUL),
174            name::BERLIN => Ok(Self::BERLIN),
175            name::LONDON => Ok(Self::LONDON),
176            name::MERGE => Ok(Self::MERGE),
177            name::SHANGHAI => Ok(Self::SHANGHAI),
178            name::CANCUN => Ok(Self::CANCUN),
179            name::PRAGUE => Ok(Self::PRAGUE),
180            name::OSAKA => Ok(Self::OSAKA),
181            name::AMSTERDAM => Ok(Self::AMSTERDAM),
182            _ => Err(UnknownHardfork),
183        }
184    }
185}
186
187impl From<SpecId> for &'static str {
188    fn from(spec_id: SpecId) -> Self {
189        match spec_id {
190            SpecId::FRONTIER => name::FRONTIER,
191            SpecId::HOMESTEAD => name::HOMESTEAD,
192            SpecId::TANGERINE => name::TANGERINE,
193            SpecId::SPURIOUS_DRAGON => name::SPURIOUS_DRAGON,
194            SpecId::BYZANTIUM => name::BYZANTIUM,
195            SpecId::PETERSBURG => name::PETERSBURG,
196            SpecId::ISTANBUL => name::ISTANBUL,
197            SpecId::BERLIN => name::BERLIN,
198            SpecId::LONDON => name::LONDON,
199            SpecId::MERGE => name::MERGE,
200            SpecId::SHANGHAI => name::SHANGHAI,
201            SpecId::CANCUN => name::CANCUN,
202            SpecId::PRAGUE => name::PRAGUE,
203            SpecId::OSAKA => name::OSAKA,
204            SpecId::AMSTERDAM => name::AMSTERDAM,
205        }
206    }
207}
208
209impl core::fmt::Display for SpecId {
210    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
211        write!(f, "{}", <&'static str>::from(*self))
212    }
213}