evm_opcodes/
lib.rs

1//! Ethereum virtual machine opcode
2#![deny(missing_docs)]
3
4mod cancun;
5mod shanghai;
6
7pub use cancun::Cancun;
8pub use shanghai::ShangHai;
9
10/// Ethereum virtual machine opcode generator.
11#[macro_export]
12macro_rules! opcodes {
13    ($name:ident, $desc:literal) => {
14        #[doc = $desc]
15        $name
16    };
17    {
18        $version:ident,
19        $((
20            $opcode:expr,
21            $name:ident,
22            $gas:expr,
23            $input:expr,
24            $output:expr,
25            $desc:literal,
26            $since:ident,
27            $group:ident
28        )),+
29    } => {
30        /// Ethereum virtual machine opcode.
31        #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
32        pub enum $version {
33            #[cfg(feature = "data")]
34            /// No operation but provides a byte for serializing.
35            Data(u8),
36            $(
37                #[doc = concat!(" ", $desc)]
38                $name,
39            )*
40        }
41
42        impl From<u8> for $version {
43            fn from(value: u8) -> Self {
44                match value {
45                    $(
46                        $opcode => Self::$name,
47                    )*
48                    _ => unreachable!("Invalid opcode."),
49                }
50            }
51        }
52
53        impl From<$version> for u8 {
54            fn from(version: $version) -> Self {
55                match version {
56                    #[cfg(feature = "data")]
57                    $version::Data(data) => data,
58                    $(
59                        $version::$name => $opcode,
60                    )*
61                }
62            }
63        }
64
65        impl OpCode for $version {
66            fn group(&self) -> Group {
67                match self {
68                    #[cfg(feature = "data")]
69                    Self::Data(_) => Group::StopArithmetic,
70                    $(
71                        Self::$name => Group::$group,
72                    )*
73                }
74            }
75
76            fn gas(&self) -> u16 {
77                match self {
78                    #[cfg(feature = "data")]
79                    Self::Data(_) => 0,
80                    $(
81                        Self::$name => $gas,
82                    )*
83                }
84            }
85
86            fn since(&self) -> Upgrade {
87                match self {
88                    #[cfg(feature = "data")]
89                    Self::Data(_) => Upgrade::Shanghai,
90                    $(
91                        Self::$name => Upgrade::$since,
92                    )*
93                }
94            }
95
96            fn stack_in(&self) -> u16 {
97                match self {
98                    #[cfg(feature = "data")]
99                    Self::Data(_) => 0,
100                    $(
101                        Self::$name => $input,
102                    )*
103                }
104            }
105
106            fn stack_out(&self) -> u16 {
107                match self {
108                    #[cfg(feature = "data")]
109                    Self::Data(_) => 0,
110                    $(
111                        Self::$name => $output,
112                    )*
113                }
114            }
115        }
116
117        impl core::str::FromStr for $version {
118            type Err = ();
119
120            fn from_str(s: &str) -> Result<Self, Self::Err> {
121                paste::paste! {
122                    match s {
123                        $(
124                            stringify!([< $name:lower >]) => Ok(Self::$name),
125                        )*
126                            _ => Err(()),
127                    }
128                }
129            }
130        }
131
132        paste::paste! {
133            #[doc = concat!(" For each ", stringify!($version), " operator.")]
134            #[macro_export]
135            macro_rules! [<for_each_ $version:lower _operator>] {
136                ($mac:ident) => {
137                    $mac! {
138                        $([<_ $name:lower>] => $name),+
139                    }
140                }
141            }
142        }
143    };
144}
145
146/// EVM opcode groups
147#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
148pub enum Group {
149    /// Stop and Arithmetic Operations
150    StopArithmetic,
151    /// Comparison & Bitwise Logic Operations
152    ComparisonBitwiseLogic,
153    /// SHA3
154    Sha3,
155    /// Environmental Information
156    EnvironmentalInformation,
157    /// Block Information
158    BlockInformation,
159    /// Stack, Memory, Storage and Flow Operations
160    StackMemoryStorageFlow,
161    /// Push Operations
162    Push,
163    /// Duplication Operations
164    Duplication,
165    /// Exchange Operations
166    Exchange,
167    /// Logging Operations
168    Logging,
169    /// System operations
170    System,
171}
172
173/// Ethereum upgrades.
174#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
175pub enum Upgrade {
176    /// Frontier
177    Frontier,
178    /// Byzantium
179    Byzantium,
180    /// Constantinople
181    Constantinople,
182    /// Istanbul
183    Istanbul,
184    /// Berlin
185    Berlin,
186    /// London
187    London,
188    /// Shanghai
189    Shanghai,
190    /// Cancun
191    Cancun,
192}
193
194/// Ethereum virtual machine opcode.
195pub trait OpCode: From<u8> + Into<u8> {
196    /// The stack input count.
197    fn stack_in(&self) -> u16;
198
199    /// The stack output count.
200    fn stack_out(&self) -> u16;
201
202    /// The OpCode is available since.
203    fn since(&self) -> Upgrade;
204
205    /// The group of the OpCode.
206    fn group(&self) -> Group;
207
208    /// The basic gas cost of the OpCode.
209    fn gas(&self) -> u16;
210}