//! 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; }