Skip to main content

huff_neo_utils/
evm_version.rs

1use std::cmp::PartialOrd;
2use std::fmt::Display;
3
4/// EIP-170 runtime code size limit (24 KiB)
5pub const EIP170_MAX_CODE_SIZE: usize = 0x6000;
6/// EIP-3860 initcode size limit (48 KiB)
7pub const EIP3860_MAX_INITCODE_SIZE: usize = 2 * EIP170_MAX_CODE_SIZE;
8/// EIP-7954 runtime code size limit (64 KiB), active from Amsterdam
9pub const EIP7954_MAX_CODE_SIZE: usize = 0x10000;
10/// EIP-7954 initcode size limit (128 KiB), active from Amsterdam
11pub const EIP7954_MAX_INITCODE_SIZE: usize = 2 * EIP7954_MAX_CODE_SIZE;
12
13/// Evm Version
14///
15/// Determines which features will be available when compiling.
16
17#[derive(Debug, Default, Clone, Copy, PartialEq, PartialOrd)]
18pub enum SupportedEVMVersions {
19    /// Introduced PREVRANDAO, disallow difficulty opcode (does not affect codegen)
20    Paris,
21    /// Introduced PUSH0
22    Shanghai,
23    /// Deneb/Cancun - Introduced TLOAD, TSTORE, MCOPY, BLOBHASH, and BLOBBASEFEE
24    ///
25    /// Meta: <https://eips.ethereum.org/EIPS/eip-7569>
26    /// TLOAD/TSTORE: <https://eips.ethereum.org/EIPS/eip-1153>
27    /// MCOPY: <https://eips.ethereum.org/EIPS/eip-5656>
28    /// BLOBHASH: <https://eips.ethereum.org/EIPS/eip-4844>
29    /// BLOBBASEFEE: <https://eips.ethereum.org/EIPS/eip-7516>
30    Cancun,
31    /// Prague/Electra - No new opcodes
32    ///
33    /// Meta: <https://eips.ethereum.org/EIPS/eip-7600>
34    Prague,
35    /// Fulu/Osaka - Introduced CLZ
36    ///
37    ///
38    /// Meta: <https://eips.ethereum.org/EIPS/eip-7607>
39    /// CLZ: <https://eips.ethereum.org/EIPS/eip-7939>
40    #[default]
41    Osaka,
42    /// Glamsterdam/Amsterdam - Introduced SLOTNUM, DUPN, SWAPN, EXCHANGE and raised the
43    /// contract size limits
44    ///
45    /// Meta: <https://eips.ethereum.org/EIPS/eip-7773>
46    /// SLOTNUM: <https://eips.ethereum.org/EIPS/eip-7843>
47    /// DUPN/SWAPN/EXCHANGE: <https://eips.ethereum.org/EIPS/eip-8024>
48    /// Contract size limits: <https://eips.ethereum.org/EIPS/eip-7954>
49    Amsterdam,
50}
51
52/// Display SupportedEVMVersions as string
53impl Display for SupportedEVMVersions {
54    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55        let version_str = match self {
56            SupportedEVMVersions::Shanghai => "shanghai",
57            SupportedEVMVersions::Paris => "paris",
58            SupportedEVMVersions::Cancun => "cancun",
59            SupportedEVMVersions::Prague => "prague",
60            SupportedEVMVersions::Osaka => "osaka",
61            SupportedEVMVersions::Amsterdam => "amsterdam",
62        };
63        write!(f, "{}", version_str)
64    }
65}
66
67#[derive(Debug, Default, Clone, Copy)]
68/// EVM Version
69pub struct EVMVersion {
70    version: SupportedEVMVersions,
71}
72
73impl EVMVersion {
74    /// Create a new EVM Version with the specified value
75    pub fn new(version: SupportedEVMVersions) -> Self {
76        Self { version }
77    }
78
79    /// Get the current EVM version
80    pub fn version(&self) -> &SupportedEVMVersions {
81        &self.version
82    }
83
84    /// As PartialOrd is implemented in the struct, all versions after shanghai will support this
85    pub fn has_push0(&self) -> bool {
86        self.version >= SupportedEVMVersions::Shanghai
87    }
88
89    /// Check if the EVM version supports prevrandao - Paris or later
90    pub fn has_prevrandao(&self) -> bool {
91        self.version >= SupportedEVMVersions::Paris
92    }
93
94    /// Check if the EVM version supports transient storage (TLOAD, TSTORE) - Cancun or later
95    pub fn has_transient_storage(&self) -> bool {
96        self.version >= SupportedEVMVersions::Cancun
97    }
98
99    /// Check if the EVM version supports MCOPY opcode - Cancun or later
100    pub fn has_mcopy(&self) -> bool {
101        self.version >= SupportedEVMVersions::Cancun
102    }
103
104    /// Check if the EVM version supports blob opcodes (BLOBHASH, BLOBBASEFEE) - Cancun or later
105    pub fn has_blob_opcodes(&self) -> bool {
106        self.version >= SupportedEVMVersions::Cancun
107    }
108
109    /// Check if the EVM version supports CLZ opcode - Osaka or later
110    pub fn has_clz(&self) -> bool {
111        self.version >= SupportedEVMVersions::Osaka
112    }
113
114    /// Check if the EVM version supports the SLOTNUM opcode - Amsterdam or later
115    pub fn has_slotnum(&self) -> bool {
116        self.version >= SupportedEVMVersions::Amsterdam
117    }
118
119    /// Check if the EVM version supports DUPN, SWAPN and EXCHANGE - Amsterdam or later
120    pub fn has_stack_immediates(&self) -> bool {
121        self.version >= SupportedEVMVersions::Amsterdam
122    }
123
124    /// Maximum size in bytes of deployed (runtime) contract code
125    ///
126    /// EIP-170 (24 KiB) before Amsterdam, EIP-7954 (64 KiB) from Amsterdam on.
127    pub fn max_code_size(&self) -> usize {
128        if self.version >= SupportedEVMVersions::Amsterdam { EIP7954_MAX_CODE_SIZE } else { EIP170_MAX_CODE_SIZE }
129    }
130
131    /// Maximum size in bytes of contract creation (init) code
132    ///
133    /// EIP-3860 (48 KiB) before Amsterdam, EIP-7954 (128 KiB) from Amsterdam on.
134    pub fn max_initcode_size(&self) -> usize {
135        if self.version >= SupportedEVMVersions::Amsterdam { EIP7954_MAX_INITCODE_SIZE } else { EIP3860_MAX_INITCODE_SIZE }
136    }
137}
138
139/// Convert from `Option<String>` to EVMVersion
140impl From<Option<String>> for EVMVersion {
141    fn from(version: Option<String>) -> Self {
142        match version {
143            Some(version) => Self::from(version),
144            None => Self::default(),
145        }
146    }
147}
148
149/// Convert from String to EVMVersion
150impl From<String> for EVMVersion {
151    fn from(version: String) -> Self {
152        match version.as_str() {
153            "shanghai" => Self::new(SupportedEVMVersions::Shanghai),
154            "paris" => Self::new(SupportedEVMVersions::Paris),
155            "cancun" => Self::new(SupportedEVMVersions::Cancun),
156            "prague" => Self::new(SupportedEVMVersions::Prague),
157            "osaka" => Self::new(SupportedEVMVersions::Osaka),
158            "amsterdam" => Self::new(SupportedEVMVersions::Amsterdam),
159            _ => Self::default(),
160        }
161    }
162}
163
164/// Display EVMVersion as string
165impl Display for EVMVersion {
166    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
167        write!(f, "{}", self.version)
168    }
169}