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