From 76d0a6d41a97b110c442284dc4f111b10b3fa085 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 24 May 2025 15:20:50 +0200 Subject: [PATCH 1/6] Chained Etable --- interpreter/src/error/exit.rs | 2 - interpreter/src/etable.rs | 72 ++++++--------------------- interpreter/src/interpreter/etable.rs | 4 +- jsontests/src/run.rs | 6 ++- src/standard/gasometer/mod.rs | 2 +- tests/eip_6780.rs | 4 +- 6 files changed, 22 insertions(+), 68 deletions(-) diff --git a/interpreter/src/error/exit.rs b/interpreter/src/error/exit.rs index fda6eb080..dcf797168 100644 --- a/interpreter/src/error/exit.rs +++ b/interpreter/src/error/exit.rs @@ -161,8 +161,6 @@ pub enum ExitFatal { AlreadyExited, /// Unfinished execution. Unfinished, - /// Unknown etable, indication of incorrect EVM config. - UnknownEtable, /// Other fatal errors. Other(Cow<'static, str>), diff --git a/interpreter/src/etable.rs b/interpreter/src/etable.rs index 4c9df02b1..4e406ea2f 100644 --- a/interpreter/src/etable.rs +++ b/interpreter/src/etable.rs @@ -4,7 +4,7 @@ use core::{ }; use crate::{ - error::{CallCreateTrap, ExitFatal, ExitResult, TrapConstruct}, + error::{CallCreateTrap, ExitResult, TrapConstruct}, eval::*, machine::Machine, opcode::Opcode, @@ -46,46 +46,14 @@ where } } -impl EtableSet for (Etable, Etable) -where - F1: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, - F2: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, -{ - type State = S; - type Handle = H; - type Trap = Tr; +/// A chained Etable, stopping at the first if it does not return +/// `Control::NoAction`. +pub struct Chained(pub E1, pub E2); - fn eval( - &self, - machine: &mut Machine, - handle: &mut H, - opcode: Opcode, - position: usize, - ) -> Control { - let mut ret = self.0[opcode.as_usize()](machine, handle, opcode, position); - - if let Control::NextEtable(n) = ret { - if n == 0 { - ret = self.1[opcode.as_usize()](machine, handle, opcode, position); - } else { - ret = Control::Exit(ExitFatal::UnknownEtable.into()); - } - } - - ret - } -} - -impl EtableSet - for ( - Etable, - Etable, - [Etable; F3N], - ) +impl EtableSet for Chained where - F1: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, - F2: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, - F3: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, + E1: EtableSet, + E2: EtableSet, { type State = S; type Handle = H; @@ -98,25 +66,13 @@ where opcode: Opcode, position: usize, ) -> Control { - let mut ret = self.0[opcode.as_usize()](machine, handle, opcode, position); - - if let Control::NextEtable(n) = ret { - if n == 0 { - ret = self.1[opcode.as_usize()](machine, handle, opcode, position); - } else { - ret = Control::Exit(ExitFatal::UnknownEtable.into()); - } - } + let ret1 = self.0.eval(machine, handle, opcode, position); - if let Control::NextEtable(n) = ret { - if n < self.2.len() { - ret = self.2[n][opcode.as_usize()](machine, handle, opcode, position); - } else { - ret = Control::Exit(ExitFatal::UnknownEtable.into()); - } + if let Control::NoAction = ret1 { + self.1.eval(machine, handle, opcode, position) + } else { + ret1 } - - ret } } @@ -382,8 +338,8 @@ where /// Control state. #[derive(Clone, Eq, PartialEq, Debug)] pub enum Control { - /// Hand off control to the next etable. - NextEtable(usize), + /// No action. + NoAction, /// Continue the execution, increase the PC by N. Continue(usize), /// Exit the execution. diff --git a/interpreter/src/interpreter/etable.rs b/interpreter/src/interpreter/etable.rs index e4000f011..59731528e 100644 --- a/interpreter/src/interpreter/etable.rs +++ b/interpreter/src/interpreter/etable.rs @@ -146,12 +146,10 @@ where .eval(&mut self.machine, handle, opcode, self.position); match control { + Control::NoAction => (), Control::Continue(p) => { self.position = position + p; } - Control::NextEtable(_) => { - return Err(Capture::Exit(ExitFatal::UnknownEtable.into())); - } Control::Exit(e) => { self.position = self.code.len(); return Err(Capture::Exit(e)); diff --git a/jsontests/src/run.rs b/jsontests/src/run.rs index 5211cd98f..20b38bff6 100644 --- a/jsontests/src/run.rs +++ b/jsontests/src/run.rs @@ -6,7 +6,9 @@ use std::{ use evm::{ backend::OverlayedBackend, - interpreter::{error::Capture, runtime::GasState, utils::u256_to_h256, Interpreter}, + interpreter::{ + error::Capture, etable::Chained, runtime::GasState, utils::u256_to_h256, Interpreter, + }, standard::{Config, Etable, EtableResolver, Invoker, TransactArgs}, }; use evm_precompile::StandardPrecompileSet; @@ -152,7 +154,7 @@ pub fn run_test( let gas_etable = Etable::single(evm::standard::eval_gasometer); let exec_etable = Etable::runtime(); - let etable = (gas_etable, exec_etable); + let etable = Chained(gas_etable, exec_etable); let precompiles = StandardPrecompileSet::new(&config); let resolver = EtableResolver::new(&config, &precompiles, &etable); let invoker = Invoker::new(&config, &resolver); diff --git a/src/standard/gasometer/mod.rs b/src/standard/gasometer/mod.rs index 1e634c9a0..f47bcaacb 100644 --- a/src/standard/gasometer/mod.rs +++ b/src/standard/gasometer/mod.rs @@ -217,7 +217,7 @@ where H: RuntimeBackend, { match eval_to_result(machine, handler, opcode, position) { - Ok(()) => Control::NextEtable(0), + Ok(()) => Control::NoAction, Err(err) => Control::Exit(Err(err)), } } diff --git a/tests/eip_6780.rs b/tests/eip_6780.rs index 5f847217d..3b48a0058 100644 --- a/tests/eip_6780.rs +++ b/tests/eip_6780.rs @@ -1,7 +1,7 @@ mod mock; use evm::{ backend::{OverlayedBackend, RuntimeBaseBackend}, - interpreter::error::ExitError, + interpreter::{error::ExitError, etable::Chained}, standard::{Config, Etable, EtableResolver, Invoker, TransactArgs, TransactValue}, }; use mock::{MockAccount, MockBackend}; @@ -17,7 +17,7 @@ fn transact( ) -> Result { let gas_etable = Etable::single(evm::standard::eval_gasometer); let exec_etable = Etable::runtime(); - let etable = (gas_etable, exec_etable); + let etable = Chained(gas_etable, exec_etable); let resolver = EtableResolver::new(config, &(), &etable); let invoker = Invoker::new(config, &resolver); From 3a83a6c49e11eb0512fa425242b859d255930f5c Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 24 May 2025 15:24:15 +0200 Subject: [PATCH 2/6] Tracing Etable --- interpreter/src/etable.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/interpreter/src/etable.rs b/interpreter/src/etable.rs index 4e406ea2f..4992e61b2 100644 --- a/interpreter/src/etable.rs +++ b/interpreter/src/etable.rs @@ -76,6 +76,34 @@ where } } +/// A tracing Etable, with pre and post actions. +pub struct Tracing(pub EPre, pub E, pub EPost); + +impl EtableSet for Tracing +where + EPre: EtableSet, + E: EtableSet, + EPost: EtableSet, +{ + type State = S; + type Handle = H; + type Trap = Tr; + + fn eval( + &self, + machine: &mut Machine, + handle: &mut H, + opcode: Opcode, + position: usize, + ) -> Control { + let _ = self.0.eval(machine, handle, opcode, position); + let ret = self.1.eval(machine, handle, opcode, position); + let _ = self.2.eval(machine, handle, opcode, position); + + ret + } +} + /// Evaluation function type. pub type Efn = fn(&mut Machine, &mut H, Opcode, usize) -> Control; From 850ed6fdc607b09a7278942054d76c049d3ccc5f Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 24 May 2025 15:30:03 +0200 Subject: [PATCH 3/6] Decode opcode in Etable rather than in interpreter --- interpreter/src/etable.rs | 42 ++++++++++----------------- interpreter/src/interpreter/etable.rs | 5 +--- 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/interpreter/src/etable.rs b/interpreter/src/etable.rs index 4992e61b2..bb61b6c1f 100644 --- a/interpreter/src/etable.rs +++ b/interpreter/src/etable.rs @@ -18,11 +18,15 @@ pub trait EtableSet { type Handle; type Trap; + /// Evaluate the etable. + /// + /// ### Safety + /// + /// The interpreter guarantee that the byte at `position` exists. fn eval( &self, machine: &mut Machine, handle: &mut Self::Handle, - opcode: Opcode, position: usize, ) -> Control; } @@ -35,13 +39,9 @@ where type Handle = H; type Trap = Tr; - fn eval( - &self, - machine: &mut Machine, - handle: &mut H, - opcode: Opcode, - position: usize, - ) -> Control { + fn eval(&self, machine: &mut Machine, handle: &mut H, position: usize) -> Control { + let opcode = Opcode(machine.code[position]); + self[opcode.as_usize()](machine, handle, opcode, position) } } @@ -59,17 +59,11 @@ where type Handle = H; type Trap = Tr; - fn eval( - &self, - machine: &mut Machine, - handle: &mut H, - opcode: Opcode, - position: usize, - ) -> Control { - let ret1 = self.0.eval(machine, handle, opcode, position); + fn eval(&self, machine: &mut Machine, handle: &mut H, position: usize) -> Control { + let ret1 = self.0.eval(machine, handle, position); if let Control::NoAction = ret1 { - self.1.eval(machine, handle, opcode, position) + self.1.eval(machine, handle, position) } else { ret1 } @@ -89,16 +83,10 @@ where type Handle = H; type Trap = Tr; - fn eval( - &self, - machine: &mut Machine, - handle: &mut H, - opcode: Opcode, - position: usize, - ) -> Control { - let _ = self.0.eval(machine, handle, opcode, position); - let ret = self.1.eval(machine, handle, opcode, position); - let _ = self.2.eval(machine, handle, opcode, position); + fn eval(&self, machine: &mut Machine, handle: &mut H, position: usize) -> Control { + let _ = self.0.eval(machine, handle, position); + let ret = self.1.eval(machine, handle, position); + let _ = self.2.eval(machine, handle, position); ret } diff --git a/interpreter/src/interpreter/etable.rs b/interpreter/src/interpreter/etable.rs index 59731528e..9a0904a41 100644 --- a/interpreter/src/interpreter/etable.rs +++ b/interpreter/src/interpreter/etable.rs @@ -140,10 +140,7 @@ where return Err(Capture::Exit(ExitFatal::AlreadyExited.into())); } - let opcode = Opcode(self.code[position]); - let control = self - .etable - .eval(&mut self.machine, handle, opcode, self.position); + let control = self.etable.eval(&mut self.machine, handle, self.position); match control { Control::NoAction => (), From e76c3e802412aeeb13944c95f3195c5c8b6d3575 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 24 May 2025 16:09:19 +0200 Subject: [PATCH 4/6] Remove Opcode parameter and add etable::Single --- interpreter/src/etable.rs | 66 ++++++++++++++++++++----- interpreter/src/eval/mod.rs | 90 +++------------------------------- interpreter/tests/usability.rs | 15 +++--- jsontests/src/run.rs | 8 ++- src/standard/gasometer/mod.rs | 10 ++-- tests/eip_6780.rs | 7 ++- 6 files changed, 84 insertions(+), 112 deletions(-) diff --git a/interpreter/src/etable.rs b/interpreter/src/etable.rs index bb61b6c1f..faaea639b 100644 --- a/interpreter/src/etable.rs +++ b/interpreter/src/etable.rs @@ -33,16 +33,16 @@ pub trait EtableSet { impl EtableSet for Etable where - F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, + F: Fn(&mut Machine, &mut H, usize) -> Control, { type State = S; type Handle = H; type Trap = Tr; fn eval(&self, machine: &mut Machine, handle: &mut H, position: usize) -> Control { - let opcode = Opcode(machine.code[position]); + let opcode = Opcode(machine.code()[position]); - self[opcode.as_usize()](machine, handle, opcode, position) + self[opcode.as_usize()](machine, handle, position) } } @@ -93,7 +93,47 @@ where } /// Evaluation function type. -pub type Efn = fn(&mut Machine, &mut H, Opcode, usize) -> Control; +pub type Efn = fn(&mut Machine, &mut H, usize) -> Control; + +/// Etable with only one function. +pub struct Single>(F, PhantomData<(S, H, Tr)>); + +unsafe impl Send for Single {} +unsafe impl Sync for Single {} + +impl Deref for Single { + type Target = F; + + fn deref(&self) -> &F { + &self.0 + } +} + +impl DerefMut for Single { + fn deref_mut(&mut self) -> &mut F { + &mut self.0 + } +} + +impl Single { + /// Create a new single Etable. + pub fn new(single: F) -> Self { + Self(single, PhantomData) + } +} + +impl EtableSet for Single +where + F: Fn(&mut Machine, &mut H, usize) -> Control, +{ + type State = S; + type Handle = H; + type Trap = Tr; + + fn eval(&self, machine: &mut Machine, handle: &mut H, position: usize) -> Control { + self.0(machine, handle, position) + } +} /// The evaluation table for the EVM. pub struct Etable>([F; 256], PhantomData<(S, H, Tr)>); @@ -115,22 +155,24 @@ impl DerefMut for Etable { } } -impl Etable +impl From> for Etable where - F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, + F: Copy, { - pub const fn single(f: F) -> Self - where - F: Copy, - { - Self([f; 256], PhantomData) + fn from(single: Single) -> Self { + Self([single.0; 256], PhantomData) } +} +impl Etable +where + F: Fn(&mut Machine, &mut H, usize) -> Control, +{ /// Wrap to create a new Etable. pub fn wrap(self, wrapper: FW) -> Etable where FW: Fn(F, Opcode) -> FR, - FR: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, + FR: Fn(&mut Machine, &mut H, usize) -> Control, { let mut current_opcode = Opcode(0); Etable( diff --git a/interpreter/src/eval/mod.rs b/interpreter/src/eval/mod.rs index 559a4a608..0b25c5fa0 100644 --- a/interpreter/src/eval/mod.rs +++ b/interpreter/src/eval/mod.rs @@ -20,7 +20,6 @@ use crate::{ pub fn eval_pass( _machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { Control::Continue(1) @@ -29,7 +28,6 @@ pub fn eval_pass( pub fn eval_stop( _machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { Control::Exit(ExitSucceed::Stopped.into()) @@ -38,7 +36,6 @@ pub fn eval_stop( pub fn eval_add( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op2_u256_tuple!(machine, overflowing_add) @@ -47,7 +44,6 @@ pub fn eval_add( pub fn eval_mul( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op2_u256_tuple!(machine, overflowing_mul) @@ -56,7 +52,6 @@ pub fn eval_mul( pub fn eval_sub( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op2_u256_tuple!(machine, overflowing_sub) @@ -65,7 +60,6 @@ pub fn eval_sub( pub fn eval_div( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op2_u256_fn!(machine, self::arithmetic::div) @@ -74,7 +68,6 @@ pub fn eval_div( pub fn eval_sdiv( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op2_u256_fn!(machine, self::arithmetic::sdiv) @@ -83,7 +76,6 @@ pub fn eval_sdiv( pub fn eval_mod( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op2_u256_fn!(machine, self::arithmetic::rem) @@ -92,7 +84,6 @@ pub fn eval_mod( pub fn eval_smod( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op2_u256_fn!(machine, self::arithmetic::srem) @@ -101,7 +92,6 @@ pub fn eval_smod( pub fn eval_addmod( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op3_u256_fn!(machine, self::arithmetic::addmod) @@ -110,7 +100,6 @@ pub fn eval_addmod( pub fn eval_mulmod( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op3_u256_fn!(machine, self::arithmetic::mulmod) @@ -119,7 +108,6 @@ pub fn eval_mulmod( pub fn eval_exp( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op2_u256_fn!(machine, self::arithmetic::exp) @@ -128,7 +116,6 @@ pub fn eval_exp( pub fn eval_signextend( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op2_u256_fn!(machine, self::arithmetic::signextend) @@ -137,7 +124,6 @@ pub fn eval_signextend( pub fn eval_lt( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op2_u256_bool_ref!(machine, lt) @@ -146,7 +132,6 @@ pub fn eval_lt( pub fn eval_gt( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op2_u256_bool_ref!(machine, gt) @@ -155,7 +140,6 @@ pub fn eval_gt( pub fn eval_slt( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op2_u256_fn!(machine, self::bitwise::slt) @@ -164,7 +148,6 @@ pub fn eval_slt( pub fn eval_sgt( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op2_u256_fn!(machine, self::bitwise::sgt) @@ -173,7 +156,6 @@ pub fn eval_sgt( pub fn eval_eq( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op2_u256_bool_ref!(machine, eq) @@ -182,7 +164,6 @@ pub fn eval_eq( pub fn eval_iszero( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op1_u256_fn!(machine, self::bitwise::iszero) @@ -191,7 +172,6 @@ pub fn eval_iszero( pub fn eval_and( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op2_u256!(machine, bitand) @@ -200,7 +180,6 @@ pub fn eval_and( pub fn eval_or( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op2_u256!(machine, bitor) @@ -209,7 +188,6 @@ pub fn eval_or( pub fn eval_xor( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op2_u256!(machine, bitxor) @@ -218,7 +196,6 @@ pub fn eval_xor( pub fn eval_not( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op1_u256_fn!(machine, self::bitwise::not) @@ -227,7 +204,6 @@ pub fn eval_not( pub fn eval_byte( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op2_u256_fn!(machine, self::bitwise::byte) @@ -236,7 +212,6 @@ pub fn eval_byte( pub fn eval_shl( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op2_u256_fn!(machine, self::bitwise::shl) @@ -245,7 +220,6 @@ pub fn eval_shl( pub fn eval_shr( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op2_u256_fn!(machine, self::bitwise::shr) @@ -254,7 +228,6 @@ pub fn eval_shr( pub fn eval_sar( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { op2_u256_fn!(machine, self::bitwise::sar) @@ -263,7 +236,6 @@ pub fn eval_sar( pub fn eval_codesize( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::misc::codesize(machine) @@ -272,7 +244,6 @@ pub fn eval_codesize( pub fn eval_codecopy( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::misc::codecopy(machine) @@ -281,7 +252,6 @@ pub fn eval_codecopy( pub fn eval_calldataload( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::misc::calldataload(machine) @@ -290,7 +260,6 @@ pub fn eval_calldataload( pub fn eval_calldatasize( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::misc::calldatasize(machine) @@ -299,7 +268,6 @@ pub fn eval_calldatasize( pub fn eval_calldatacopy( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::misc::calldatacopy(machine) @@ -308,7 +276,6 @@ pub fn eval_calldatacopy( pub fn eval_pop( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::misc::pop(machine) @@ -317,7 +284,6 @@ pub fn eval_pop( pub fn eval_mload( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::misc::mload(machine) @@ -326,7 +292,6 @@ pub fn eval_mload( pub fn eval_mstore( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::misc::mstore(machine) @@ -335,7 +300,6 @@ pub fn eval_mstore( pub fn eval_mstore8( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::misc::mstore8(machine) @@ -344,7 +308,6 @@ pub fn eval_mstore8( pub fn eval_jump( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::misc::jump(machine) @@ -353,7 +316,6 @@ pub fn eval_jump( pub fn eval_jumpi( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::misc::jumpi(machine) @@ -362,7 +324,6 @@ pub fn eval_jumpi( pub fn eval_pc( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, position: usize, ) -> Control { self::misc::pc(machine, position) @@ -371,7 +332,6 @@ pub fn eval_pc( pub fn eval_msize( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::misc::msize(machine) @@ -380,7 +340,6 @@ pub fn eval_msize( pub fn eval_jumpdest( _machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { Control::Continue(1) @@ -389,7 +348,6 @@ pub fn eval_jumpdest( pub fn eval_mcopy( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::misc::mcopy(machine) @@ -401,7 +359,6 @@ macro_rules! eval_push { pub fn []( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, position: usize, ) -> Control { self::misc::push(machine, $num, position) @@ -421,7 +378,6 @@ macro_rules! eval_dup { pub fn []( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::misc::dup(machine, $num) @@ -438,7 +394,6 @@ macro_rules! eval_swap { pub fn []( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::misc::swap(machine, $num) @@ -452,7 +407,6 @@ eval_swap! { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 } pub fn eval_return( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::misc::ret(machine) @@ -461,7 +415,6 @@ pub fn eval_return( pub fn eval_revert( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::misc::revert(machine) @@ -470,25 +423,22 @@ pub fn eval_revert( pub fn eval_invalid( _machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { Control::Exit(ExitException::DesignatedInvalid.into()) } pub fn eval_unknown( - _machine: &mut Machine, + machine: &mut Machine, _handle: &mut H, - opcode: Opcode, - _position: usize, + position: usize, ) -> Control { - Control::Exit(ExitException::InvalidOpcode(opcode).into()) + Control::Exit(ExitException::InvalidOpcode(Opcode(machine.code()[position])).into()) } pub fn eval_sha3, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::sha3(machine) @@ -497,7 +447,6 @@ pub fn eval_sha3, H: RuntimeEnvironment + RuntimeBackend, pub fn eval_address, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::address(machine) @@ -506,7 +455,6 @@ pub fn eval_address, H: RuntimeEnvironment + RuntimeBacke pub fn eval_balance, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::balance(machine, handle) @@ -515,7 +463,6 @@ pub fn eval_balance, H: RuntimeEnvironment + RuntimeBacke pub fn eval_selfbalance, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::selfbalance(machine, handle) @@ -524,7 +471,6 @@ pub fn eval_selfbalance, H: RuntimeEnvironment + RuntimeB pub fn eval_origin, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::origin(machine, handle) @@ -533,7 +479,6 @@ pub fn eval_origin, H: RuntimeEnvironment + RuntimeBacken pub fn eval_caller, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::caller(machine) @@ -542,7 +487,6 @@ pub fn eval_caller, H: RuntimeEnvironment + RuntimeBacken pub fn eval_callvalue, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::callvalue(machine) @@ -551,7 +495,6 @@ pub fn eval_callvalue, H: RuntimeEnvironment + RuntimeBac pub fn eval_gasprice, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::gasprice(machine, handle) @@ -560,7 +503,6 @@ pub fn eval_gasprice, H: RuntimeEnvironment + RuntimeBack pub fn eval_extcodesize, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::extcodesize(machine, handle) @@ -569,7 +511,6 @@ pub fn eval_extcodesize, H: RuntimeEnvironment + RuntimeB pub fn eval_extcodehash, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::extcodehash(machine, handle) @@ -578,7 +519,6 @@ pub fn eval_extcodehash, H: RuntimeEnvironment + RuntimeB pub fn eval_extcodecopy, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::extcodecopy(machine, handle) @@ -587,7 +527,6 @@ pub fn eval_extcodecopy, H: RuntimeEnvironment + RuntimeB pub fn eval_returndatasize, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::returndatasize(machine) @@ -596,7 +535,6 @@ pub fn eval_returndatasize, H: RuntimeEnvironment + Runti pub fn eval_returndatacopy, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, _handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::returndatacopy(machine) @@ -605,7 +543,6 @@ pub fn eval_returndatacopy, H: RuntimeEnvironment + Runti pub fn eval_blockhash, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::blockhash(machine, handle) @@ -614,7 +551,6 @@ pub fn eval_blockhash, H: RuntimeEnvironment + RuntimeBac pub fn eval_coinbase, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::coinbase(machine, handle) @@ -623,7 +559,6 @@ pub fn eval_coinbase, H: RuntimeEnvironment + RuntimeBack pub fn eval_timestamp, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::timestamp(machine, handle) @@ -632,7 +567,6 @@ pub fn eval_timestamp, H: RuntimeEnvironment + RuntimeBac pub fn eval_number, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::number(machine, handle) @@ -641,7 +575,6 @@ pub fn eval_number, H: RuntimeEnvironment + RuntimeBacken pub fn eval_difficulty, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::prevrandao(machine, handle) @@ -650,7 +583,6 @@ pub fn eval_difficulty, H: RuntimeEnvironment + RuntimeBa pub fn eval_gaslimit, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::gaslimit(machine, handle) @@ -659,7 +591,6 @@ pub fn eval_gaslimit, H: RuntimeEnvironment + RuntimeBack pub fn eval_sload, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::sload(machine, handle) @@ -668,7 +599,6 @@ pub fn eval_sload, H: RuntimeEnvironment + RuntimeBackend pub fn eval_sstore, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::sstore(machine, handle) @@ -677,7 +607,6 @@ pub fn eval_sstore, H: RuntimeEnvironment + RuntimeBacken pub fn eval_gas( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::gas(machine, handle) @@ -686,7 +615,6 @@ pub fn eval_gas( pub fn eval_tload, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::tload(machine, handle) @@ -695,7 +623,6 @@ pub fn eval_tload, H: RuntimeEnvironment + RuntimeBackend pub fn eval_tstore, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::tstore(machine, handle) @@ -707,7 +634,6 @@ macro_rules! eval_log { pub fn [], H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::log(machine, $num, handle) @@ -721,7 +647,6 @@ eval_log! { 0, 1, 2, 3, 4 } pub fn eval_suicide, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::suicide(machine, handle) @@ -730,7 +655,6 @@ pub fn eval_suicide, H: RuntimeEnvironment + RuntimeBacke pub fn eval_chainid, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::chainid(machine, handle) @@ -739,18 +663,18 @@ pub fn eval_chainid, H: RuntimeEnvironment + RuntimeBacke pub fn eval_basefee, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, - _opcode: Opcode, _position: usize, ) -> Control { self::system::basefee(machine, handle) } pub fn eval_call_create_trap>( - _machine: &mut Machine, + machine: &mut Machine, _handle: &mut H, - opcode: Opcode, - _position: usize, + position: usize, ) -> Control { + let opcode = Opcode(machine.code()[position]); + let trap = match opcode { Opcode::CREATE => CallCreateTrap::Create, Opcode::CREATE2 => CallCreateTrap::Create2, diff --git a/interpreter/tests/usability.rs b/interpreter/tests/usability.rs index 28c267b8c..b7076fe67 100644 --- a/interpreter/tests/usability.rs +++ b/interpreter/tests/usability.rs @@ -22,10 +22,11 @@ fn etable_wrap() { let data = hex::decode(DATA1).unwrap(); let wrapped_etable = Etable::<_, _, Opcode>::core().wrap(|f, opcode_t| { - move |machine, handle, opcode, position| { + move |machine, handle, position| { + let opcode = Opcode(machine.code()[position]); assert_eq!(opcode_t, opcode); println!("opcode: {:?}", opcode); - f(machine, handle, opcode, position) + f(machine, handle, position) } }); @@ -43,15 +44,17 @@ fn etable_wrap2() { let data = hex::decode(DATA1).unwrap(); let wrapped_etable = Etable::core().wrap( - |f, opcode_t| -> Box, &mut (), Opcode, usize) -> Control> { + |f, opcode_t| -> Box, &mut (), usize) -> Control> { if opcode_t != Opcode(0x50) { - Box::new(move |machine, handle, opcode, position| { + Box::new(move |machine, handle, position| { + let opcode = Opcode(machine.code()[position]); assert_eq!(opcode_t, opcode); println!("opcode: {:?}", opcode); - f(machine, handle, opcode, position) + f(machine, handle, position) }) } else { - Box::new(|_machine, _handle, opcode, _position| { + Box::new(|machine, _handle, position| { + let opcode = Opcode(machine.code()[position]); println!("disabled!"); Control::Trap(opcode) }) diff --git a/jsontests/src/run.rs b/jsontests/src/run.rs index 20b38bff6..d4a0034b5 100644 --- a/jsontests/src/run.rs +++ b/jsontests/src/run.rs @@ -7,7 +7,11 @@ use std::{ use evm::{ backend::OverlayedBackend, interpreter::{ - error::Capture, etable::Chained, runtime::GasState, utils::u256_to_h256, Interpreter, + error::Capture, + etable::{Chained, Single}, + runtime::GasState, + utils::u256_to_h256, + Interpreter, }, standard::{Config, Etable, EtableResolver, Invoker, TransactArgs}, }; @@ -152,7 +156,7 @@ pub fn run_test( }) .collect::>(); - let gas_etable = Etable::single(evm::standard::eval_gasometer); + let gas_etable = Single::new(evm::standard::eval_gasometer); let exec_etable = Etable::runtime(); let etable = Chained(gas_etable, exec_etable); let precompiles = StandardPrecompileSet::new(&config); diff --git a/src/standard/gasometer/mod.rs b/src/standard/gasometer/mod.rs index f47bcaacb..8b9eb82e2 100644 --- a/src/standard/gasometer/mod.rs +++ b/src/standard/gasometer/mod.rs @@ -209,14 +209,13 @@ impl<'config> GasometerState<'config> { pub fn eval<'config, S, H, Tr>( machine: &mut Machine, handler: &mut H, - opcode: Opcode, position: usize, ) -> Control where S: AsRef> + AsMut> + AsRef, H: RuntimeBackend, { - match eval_to_result(machine, handler, opcode, position) { + match eval_to_result(machine, handler, position) { Ok(()) => Control::NoAction, Err(err) => Control::Exit(Err(err)), } @@ -225,16 +224,13 @@ where fn eval_to_result<'config, S, H>( machine: &mut Machine, handler: &mut H, - opcode: Opcode, - _position: usize, + position: usize, ) -> Result<(), ExitError> where S: AsRef> + AsMut> + AsRef, H: RuntimeBackend, { - if machine.code().is_empty() { - return Ok(()); - } + let opcode = Opcode(machine.code()[position]); let address = AsRef::::as_ref(&machine.state) .context diff --git a/tests/eip_6780.rs b/tests/eip_6780.rs index 3b48a0058..9a47cbea5 100644 --- a/tests/eip_6780.rs +++ b/tests/eip_6780.rs @@ -1,7 +1,10 @@ mod mock; use evm::{ backend::{OverlayedBackend, RuntimeBaseBackend}, - interpreter::{error::ExitError, etable::Chained}, + interpreter::{ + error::ExitError, + etable::{Chained, Single}, + }, standard::{Config, Etable, EtableResolver, Invoker, TransactArgs, TransactValue}, }; use mock::{MockAccount, MockBackend}; @@ -15,7 +18,7 @@ fn transact( args: TransactArgs, overlayed_backend: &mut OverlayedBackend, ) -> Result { - let gas_etable = Etable::single(evm::standard::eval_gasometer); + let gas_etable = Single::new(evm::standard::eval_gasometer); let exec_etable = Etable::runtime(); let etable = Chained(gas_etable, exec_etable); let resolver = EtableResolver::new(config, &(), &etable); From 443985ea34954bb56c2ee5ae7af56a59f095500d Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 24 May 2025 16:59:39 +0200 Subject: [PATCH 5/6] Rework MultiEtable support --- interpreter/src/etable.rs | 100 +++++++++++++++++++++++++++------ interpreter/tests/usability.rs | 57 ++++++++++++++++++- 2 files changed, 140 insertions(+), 17 deletions(-) diff --git a/interpreter/src/etable.rs b/interpreter/src/etable.rs index faaea639b..051f48c2c 100644 --- a/interpreter/src/etable.rs +++ b/interpreter/src/etable.rs @@ -4,7 +4,7 @@ use core::{ }; use crate::{ - error::{CallCreateTrap, ExitResult, TrapConstruct}, + error::{CallCreateTrap, ExitException, ExitResult, TrapConstruct}, eval::*, machine::Machine, opcode::Opcode, @@ -31,21 +31,6 @@ pub trait EtableSet { ) -> Control; } -impl EtableSet for Etable -where - F: Fn(&mut Machine, &mut H, usize) -> Control, -{ - type State = S; - type Handle = H; - type Trap = Tr; - - fn eval(&self, machine: &mut Machine, handle: &mut H, position: usize) -> Control { - let opcode = Opcode(machine.code()[position]); - - self[opcode.as_usize()](machine, handle, position) - } -} - /// A chained Etable, stopping at the first if it does not return /// `Control::NoAction`. pub struct Chained(pub E1, pub E2); @@ -135,6 +120,74 @@ where } } +/// Nested evaluation function. +pub enum MultiEfn> { + /// Leaf function. + Leaf(F), + /// Node function. + Node(Box>), +} + +unsafe impl Send for MultiEfn {} +unsafe impl Sync for MultiEfn {} + +/// Nested evaluation table. +pub struct MultiEtable>( + [MultiEfn; 256], + PhantomData<(S, H, Tr)>, +); + +unsafe impl Send for MultiEtable {} +unsafe impl Sync for MultiEtable {} + +impl Deref for MultiEtable { + type Target = [MultiEfn; 256]; + + fn deref(&self) -> &[MultiEfn; 256] { + &self.0 + } +} + +impl DerefMut for MultiEtable { + fn deref_mut(&mut self) -> &mut [MultiEfn; 256] { + &mut self.0 + } +} + +impl From> for MultiEtable { + fn from(etable: Etable) -> Self { + Self(etable.0.map(|v| MultiEfn::Leaf(v)), PhantomData) + } +} + +impl EtableSet for MultiEtable +where + F: Fn(&mut Machine, &mut H, usize) -> Control, +{ + type State = S; + type Handle = H; + type Trap = Tr; + + fn eval(&self, machine: &mut Machine, handle: &mut H, position: usize) -> Control { + let opcode = Opcode(machine.code()[position]); + + match &self[opcode.as_usize()] { + MultiEfn::Leaf(f) => f(machine, handle, position), + MultiEfn::Node(n) => { + let nextpos = position + 1; + if nextpos >= machine.code.len() { + return Control::Exit(ExitException::PCUnderflow.into()); + } + + match n.eval(machine, handle, nextpos) { + Control::Continue(c) => Control::Continue(c + 1), + ctrl => ctrl, + } + } + } + } +} + /// The evaluation table for the EVM. pub struct Etable>([F; 256], PhantomData<(S, H, Tr)>); @@ -164,6 +217,21 @@ where } } +impl EtableSet for Etable +where + F: Fn(&mut Machine, &mut H, usize) -> Control, +{ + type State = S; + type Handle = H; + type Trap = Tr; + + fn eval(&self, machine: &mut Machine, handle: &mut H, position: usize) -> Control { + let opcode = Opcode(machine.code()[position]); + + self[opcode.as_usize()](machine, handle, position) + } +} + impl Etable where F: Fn(&mut Machine, &mut H, usize) -> Control, diff --git a/interpreter/tests/usability.rs b/interpreter/tests/usability.rs index b7076fe67..1c718a47f 100644 --- a/interpreter/tests/usability.rs +++ b/interpreter/tests/usability.rs @@ -1,6 +1,6 @@ use evm_interpreter::{ error::{CallCreateTrap, Capture, ExitError, ExitSucceed}, - etable::{Control, Etable}, + etable::{Control, Etable, MultiEfn, MultiEtable}, machine::Machine, opcode::Opcode, runtime::{ @@ -235,3 +235,58 @@ fn etable_runtime() { assert_eq!(res, Ok(ExitSucceed::Returned)); assert_eq!(vm.retval, hex::decode(RET1).unwrap()); } + +#[test] +fn etable_multi() { + let prefix = Opcode(0xc1); + let orig_code = hex::decode("600d60005260206000f3").unwrap(); + let mut code = Vec::new(); + let mut skip = 0; + for c in orig_code { + if skip > 0 { + code.push(c); + skip -= 1; + } else { + code.push(prefix.0); + code.push(c); + if let Some(p) = Opcode(c).is_push() { + skip += p as usize; + } + } + } + + let data = hex::decode(DATA1).unwrap(); + let mut handler = UnimplementedHandler; + + let etable: Etable = Etable::runtime(); + let mut multi_etable: MultiEtable = + etable.into(); + let prefix_etable = + MultiEtable::from(Etable::::runtime()); + multi_etable[prefix.as_usize()] = MultiEfn::Node(Box::new(prefix_etable)); + + let machine = Machine::new( + Rc::new(code), + Rc::new(data), + 1024, + 10000, + RuntimeState { + context: Context { + address: H160::default(), + caller: H160::default(), + apparent_value: U256::default(), + }, + transaction_context: TransactionContext { + gas_price: U256::default(), + origin: H160::default(), + } + .into(), + retbuf: Vec::new(), + }, + ); + let mut vm = EtableInterpreter::new(machine, &multi_etable); + + let res = vm.run(&mut handler).exit().unwrap(); + assert_eq!(res, Ok(ExitSucceed::Returned)); + assert_eq!(vm.retval, hex::decode(RET1).unwrap()); +} From d13d4632c7984a7e44ba1d5da60d09e253b07e8f Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 24 May 2025 17:05:56 +0200 Subject: [PATCH 6/6] Fix no-std build --- interpreter/src/etable.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/interpreter/src/etable.rs b/interpreter/src/etable.rs index 051f48c2c..acdcb5757 100644 --- a/interpreter/src/etable.rs +++ b/interpreter/src/etable.rs @@ -1,3 +1,4 @@ +use alloc::boxed::Box; use core::{ marker::PhantomData, ops::{Deref, DerefMut},