From d2249013a607b4aa43b07244e8d2af79887f6d64 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 5 Dec 2023 05:38:19 +0100 Subject: [PATCH] refactor: introduce Interpreter trait and merge RuntimeState/GasometerState (#250) * refactor: introduce Interpreter trait and merge RuntimeState/GasometerState * Fix no-std compile * Fix clippy warnings * More clippy fixes --- interpreter/src/call_create.rs | 10 +- interpreter/src/etable.rs | 297 +++++++++++++++ interpreter/src/eval/misc.rs | 12 +- interpreter/src/eval/mod.rs | 522 ++++++++------------------ interpreter/src/eval/system.rs | 8 +- interpreter/src/interpreter/etable.rs | 171 +++++++++ interpreter/src/interpreter/mod.rs | 19 + interpreter/src/lib.rs | 147 +------- interpreter/src/runtime.rs | 13 +- interpreter/tests/performance.rs | 7 +- interpreter/tests/usability.rs | 21 +- jsontests/src/run.rs | 17 +- precompile/src/blake2/mod.rs | 13 +- precompile/src/bn128.rs | 37 +- precompile/src/lib.rs | 33 +- precompile/src/modexp.rs | 15 +- precompile/src/simple.rs | 41 +- src/call_stack.rs | 118 +++--- src/color.rs | 126 ------- src/gasometer.rs | 27 +- src/invoker.rs | 50 +-- src/lib.rs | 6 +- src/standard/gasometer/mod.rs | 225 ++++++----- src/standard/invoker/mod.rs | 177 +++++---- src/standard/invoker/resolver.rs | 115 ++---- src/standard/invoker/routines.rs | 78 ++-- src/standard/invoker/state.rs | 35 ++ src/standard/mod.rs | 157 +++++--- tracer/src/standard.rs | 6 +- 29 files changed, 1228 insertions(+), 1275 deletions(-) create mode 100644 interpreter/src/etable.rs create mode 100644 interpreter/src/interpreter/etable.rs create mode 100644 interpreter/src/interpreter/mod.rs delete mode 100644 src/color.rs create mode 100644 src/standard/invoker/state.rs diff --git a/interpreter/src/call_create.rs b/interpreter/src/call_create.rs index 784bc8bfa..a05af2fbf 100644 --- a/interpreter/src/call_create.rs +++ b/interpreter/src/call_create.rs @@ -273,7 +273,7 @@ impl CallTrapData { let target_len = min(self.out_len, U256::from(retbuf.len())); let out_offset = self.out_offset; - let ret = machine.perform(|machine| match reason { + let ret = match reason { Ok(_) => { match machine .memory @@ -313,13 +313,12 @@ impl CallTrapData { Err(e.into()) } - }); + }; match ret { Ok(()) => { machine.state.as_mut().retbuf = retbuf; - machine.advance(); Ok(()) } Err(e) => Err(e), @@ -430,7 +429,7 @@ impl CreateTrapData { retbuf: Vec, machine: &mut Machine, ) -> Result<(), ExitError> { - let ret = machine.perform(|machine| match reason { + let ret = match reason { Ok(address) => { machine.stack.push(address.into())?; Ok(()) @@ -447,13 +446,12 @@ impl CreateTrapData { machine.stack.push(H256::default())?; Err(e.into()) } - }); + }; match ret { Ok(()) => { machine.state.as_mut().retbuf = retbuf; - machine.advance(); Ok(()) } Err(e) => Err(e), diff --git a/interpreter/src/etable.rs b/interpreter/src/etable.rs new file mode 100644 index 000000000..0311466bc --- /dev/null +++ b/interpreter/src/etable.rs @@ -0,0 +1,297 @@ +use crate::{ + eval::*, CallCreateTrap, ExitResult, GasState, Machine, Opcode, RuntimeBackend, + RuntimeEnvironment, RuntimeState, +}; +use core::marker::PhantomData; +use core::ops::{Deref, DerefMut}; + +pub trait EtableSet { + fn eval( + &self, + machine: &mut Machine, + handle: &mut H, + opcode: Opcode, + position: usize, + ) -> Control; +} + +impl EtableSet for Etable +where + F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, +{ + fn eval( + &self, + machine: &mut Machine, + handle: &mut H, + opcode: Opcode, + position: usize, + ) -> Control { + self[opcode.as_usize()](machine, handle, opcode, position) + } +} + +impl EtableSet for (Etable, Etable) +where + F1: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, + F2: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, +{ + 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 matches!(ret, Control::Continue) { + ret = self.1[opcode.as_usize()](machine, handle, opcode, position); + } + + ret + } +} + +/// Evaluation function type. +pub type Efn = fn(&mut Machine, &mut H, Opcode, usize) -> Control; + +/// The evaluation table for the EVM. +pub struct Etable>([F; 256], PhantomData<(S, H, Tr)>); + +unsafe impl Send for Etable {} +unsafe impl Sync for Etable {} + +impl Deref for Etable { + type Target = [F; 256]; + + fn deref(&self) -> &[F; 256] { + &self.0 + } +} + +impl DerefMut for Etable { + fn deref_mut(&mut self) -> &mut [F; 256] { + &mut self.0 + } +} + +impl Etable +where + F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, +{ + pub const fn single(f: F) -> Self + where + F: Copy, + { + Self([f; 256], PhantomData) + } + + /// 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, + { + let mut current_opcode = Opcode(0); + Etable( + self.0.map(|f| { + let fr = wrapper(f, current_opcode); + if current_opcode != Opcode(255) { + current_opcode.0 += 1; + } + fr + }), + PhantomData, + ) + } +} + +impl Etable { + pub const fn none() -> Self { + Self([eval_unknown as _; 256], PhantomData) + } + + pub const fn pass() -> Self { + Self([eval_pass as _; 256], PhantomData) + } + + /// Default core value for Etable. + pub const fn core() -> Self { + let mut table = [eval_unknown as _; 256]; + + table[Opcode::STOP.as_usize()] = eval_stop as _; + table[Opcode::ADD.as_usize()] = eval_add as _; + table[Opcode::MUL.as_usize()] = eval_mul as _; + table[Opcode::SUB.as_usize()] = eval_sub as _; + table[Opcode::DIV.as_usize()] = eval_div as _; + table[Opcode::SDIV.as_usize()] = eval_sdiv as _; + table[Opcode::MOD.as_usize()] = eval_mod as _; + table[Opcode::SMOD.as_usize()] = eval_smod as _; + table[Opcode::ADDMOD.as_usize()] = eval_addmod as _; + table[Opcode::MULMOD.as_usize()] = eval_mulmod as _; + table[Opcode::EXP.as_usize()] = eval_exp as _; + table[Opcode::SIGNEXTEND.as_usize()] = eval_signextend as _; + table[Opcode::LT.as_usize()] = eval_lt as _; + table[Opcode::GT.as_usize()] = eval_gt as _; + table[Opcode::SLT.as_usize()] = eval_slt as _; + table[Opcode::SGT.as_usize()] = eval_sgt as _; + table[Opcode::EQ.as_usize()] = eval_eq as _; + table[Opcode::ISZERO.as_usize()] = eval_iszero as _; + table[Opcode::AND.as_usize()] = eval_and as _; + table[Opcode::OR.as_usize()] = eval_or as _; + table[Opcode::XOR.as_usize()] = eval_xor as _; + table[Opcode::NOT.as_usize()] = eval_not as _; + table[Opcode::BYTE.as_usize()] = eval_byte as _; + table[Opcode::SHL.as_usize()] = eval_shl as _; + table[Opcode::SHR.as_usize()] = eval_shr as _; + table[Opcode::SAR.as_usize()] = eval_sar as _; + table[Opcode::CODESIZE.as_usize()] = eval_codesize as _; + table[Opcode::CODECOPY.as_usize()] = eval_codecopy as _; + table[Opcode::CALLDATALOAD.as_usize()] = eval_calldataload as _; + table[Opcode::CALLDATASIZE.as_usize()] = eval_calldatasize as _; + table[Opcode::CALLDATACOPY.as_usize()] = eval_calldatacopy as _; + table[Opcode::POP.as_usize()] = eval_pop as _; + table[Opcode::MLOAD.as_usize()] = eval_mload as _; + table[Opcode::MSTORE.as_usize()] = eval_mstore as _; + table[Opcode::MSTORE8.as_usize()] = eval_mstore8 as _; + table[Opcode::JUMP.as_usize()] = eval_jump as _; + table[Opcode::JUMPI.as_usize()] = eval_jumpi as _; + table[Opcode::PC.as_usize()] = eval_pc as _; + table[Opcode::MSIZE.as_usize()] = eval_msize as _; + table[Opcode::JUMPDEST.as_usize()] = eval_jumpdest as _; + + table[Opcode::PUSH0.as_usize()] = eval_push0 as _; + table[Opcode::PUSH1.as_usize()] = eval_push1 as _; + table[Opcode::PUSH2.as_usize()] = eval_push2 as _; + table[Opcode::PUSH3.as_usize()] = eval_push3 as _; + table[Opcode::PUSH4.as_usize()] = eval_push4 as _; + table[Opcode::PUSH5.as_usize()] = eval_push5 as _; + table[Opcode::PUSH6.as_usize()] = eval_push6 as _; + table[Opcode::PUSH7.as_usize()] = eval_push7 as _; + table[Opcode::PUSH8.as_usize()] = eval_push8 as _; + table[Opcode::PUSH9.as_usize()] = eval_push9 as _; + table[Opcode::PUSH10.as_usize()] = eval_push10 as _; + table[Opcode::PUSH11.as_usize()] = eval_push11 as _; + table[Opcode::PUSH12.as_usize()] = eval_push12 as _; + table[Opcode::PUSH13.as_usize()] = eval_push13 as _; + table[Opcode::PUSH14.as_usize()] = eval_push14 as _; + table[Opcode::PUSH15.as_usize()] = eval_push15 as _; + table[Opcode::PUSH16.as_usize()] = eval_push16 as _; + table[Opcode::PUSH17.as_usize()] = eval_push17 as _; + table[Opcode::PUSH18.as_usize()] = eval_push18 as _; + table[Opcode::PUSH19.as_usize()] = eval_push19 as _; + table[Opcode::PUSH20.as_usize()] = eval_push20 as _; + table[Opcode::PUSH21.as_usize()] = eval_push21 as _; + table[Opcode::PUSH22.as_usize()] = eval_push22 as _; + table[Opcode::PUSH23.as_usize()] = eval_push23 as _; + table[Opcode::PUSH24.as_usize()] = eval_push24 as _; + table[Opcode::PUSH25.as_usize()] = eval_push25 as _; + table[Opcode::PUSH26.as_usize()] = eval_push26 as _; + table[Opcode::PUSH27.as_usize()] = eval_push27 as _; + table[Opcode::PUSH28.as_usize()] = eval_push28 as _; + table[Opcode::PUSH29.as_usize()] = eval_push29 as _; + table[Opcode::PUSH30.as_usize()] = eval_push30 as _; + table[Opcode::PUSH31.as_usize()] = eval_push31 as _; + table[Opcode::PUSH32.as_usize()] = eval_push32 as _; + + table[Opcode::DUP1.as_usize()] = eval_dup1 as _; + table[Opcode::DUP2.as_usize()] = eval_dup2 as _; + table[Opcode::DUP3.as_usize()] = eval_dup3 as _; + table[Opcode::DUP4.as_usize()] = eval_dup4 as _; + table[Opcode::DUP5.as_usize()] = eval_dup5 as _; + table[Opcode::DUP6.as_usize()] = eval_dup6 as _; + table[Opcode::DUP7.as_usize()] = eval_dup7 as _; + table[Opcode::DUP8.as_usize()] = eval_dup8 as _; + table[Opcode::DUP9.as_usize()] = eval_dup9 as _; + table[Opcode::DUP10.as_usize()] = eval_dup10 as _; + table[Opcode::DUP11.as_usize()] = eval_dup11 as _; + table[Opcode::DUP12.as_usize()] = eval_dup12 as _; + table[Opcode::DUP13.as_usize()] = eval_dup13 as _; + table[Opcode::DUP14.as_usize()] = eval_dup14 as _; + table[Opcode::DUP15.as_usize()] = eval_dup15 as _; + table[Opcode::DUP16.as_usize()] = eval_dup16 as _; + + table[Opcode::SWAP1.as_usize()] = eval_swap1 as _; + table[Opcode::SWAP2.as_usize()] = eval_swap2 as _; + table[Opcode::SWAP3.as_usize()] = eval_swap3 as _; + table[Opcode::SWAP4.as_usize()] = eval_swap4 as _; + table[Opcode::SWAP5.as_usize()] = eval_swap5 as _; + table[Opcode::SWAP6.as_usize()] = eval_swap6 as _; + table[Opcode::SWAP7.as_usize()] = eval_swap7 as _; + table[Opcode::SWAP8.as_usize()] = eval_swap8 as _; + table[Opcode::SWAP9.as_usize()] = eval_swap9 as _; + table[Opcode::SWAP10.as_usize()] = eval_swap10 as _; + table[Opcode::SWAP11.as_usize()] = eval_swap11 as _; + table[Opcode::SWAP12.as_usize()] = eval_swap12 as _; + table[Opcode::SWAP13.as_usize()] = eval_swap13 as _; + table[Opcode::SWAP14.as_usize()] = eval_swap14 as _; + table[Opcode::SWAP15.as_usize()] = eval_swap15 as _; + table[Opcode::SWAP16.as_usize()] = eval_swap16 as _; + + table[Opcode::RETURN.as_usize()] = eval_return as _; + table[Opcode::REVERT.as_usize()] = eval_revert as _; + table[Opcode::INVALID.as_usize()] = eval_invalid as _; + + Self(table, PhantomData) + } +} + +impl Etable +where + S: AsRef + GasState, +{ + /// Runtime Etable. + pub const fn runtime() -> Self { + let mut table = Self::core(); + + table.0[Opcode::SHA3.as_usize()] = eval_sha3 as _; + table.0[Opcode::ADDRESS.as_usize()] = eval_address as _; + table.0[Opcode::BALANCE.as_usize()] = eval_balance as _; + table.0[Opcode::SELFBALANCE.as_usize()] = eval_selfbalance as _; + table.0[Opcode::ORIGIN.as_usize()] = eval_origin as _; + table.0[Opcode::CALLER.as_usize()] = eval_caller as _; + table.0[Opcode::CALLVALUE.as_usize()] = eval_callvalue as _; + table.0[Opcode::GASPRICE.as_usize()] = eval_gasprice as _; + table.0[Opcode::EXTCODESIZE.as_usize()] = eval_extcodesize as _; + table.0[Opcode::EXTCODEHASH.as_usize()] = eval_extcodehash as _; + table.0[Opcode::EXTCODECOPY.as_usize()] = eval_extcodecopy as _; + table.0[Opcode::RETURNDATASIZE.as_usize()] = eval_returndatasize as _; + table.0[Opcode::RETURNDATACOPY.as_usize()] = eval_returndatacopy as _; + table.0[Opcode::BLOCKHASH.as_usize()] = eval_blockhash as _; + table.0[Opcode::COINBASE.as_usize()] = eval_coinbase as _; + table.0[Opcode::TIMESTAMP.as_usize()] = eval_timestamp as _; + table.0[Opcode::NUMBER.as_usize()] = eval_number as _; + table.0[Opcode::DIFFICULTY.as_usize()] = eval_difficulty as _; + table.0[Opcode::GASLIMIT.as_usize()] = eval_gaslimit as _; + table.0[Opcode::SLOAD.as_usize()] = eval_sload as _; + table.0[Opcode::SSTORE.as_usize()] = eval_sstore as _; + table.0[Opcode::GAS.as_usize()] = eval_gas as _; + table.0[Opcode::LOG0.as_usize()] = eval_log0 as _; + table.0[Opcode::LOG1.as_usize()] = eval_log1 as _; + table.0[Opcode::LOG2.as_usize()] = eval_log2 as _; + table.0[Opcode::LOG3.as_usize()] = eval_log3 as _; + table.0[Opcode::LOG4.as_usize()] = eval_log4 as _; + table.0[Opcode::SUICIDE.as_usize()] = eval_suicide as _; + table.0[Opcode::CHAINID.as_usize()] = eval_chainid as _; + table.0[Opcode::BASEFEE.as_usize()] = eval_basefee as _; + + table.0[Opcode::CREATE.as_usize()] = eval_call_create_trap as _; + table.0[Opcode::CREATE2.as_usize()] = eval_call_create_trap as _; + table.0[Opcode::CALL.as_usize()] = eval_call_create_trap as _; + table.0[Opcode::CALLCODE.as_usize()] = eval_call_create_trap as _; + table.0[Opcode::DELEGATECALL.as_usize()] = eval_call_create_trap as _; + table.0[Opcode::STATICCALL.as_usize()] = eval_call_create_trap as _; + + table + } +} + +/// Control state. +#[derive(Clone, Eq, PartialEq, Debug)] +pub enum Control { + Continue, + ContinueN(usize), + Exit(ExitResult), + Jump(usize), + Trap(Trap), +} diff --git a/interpreter/src/eval/misc.rs b/interpreter/src/eval/misc.rs index 32a642def..4cd20d9e4 100644 --- a/interpreter/src/eval/misc.rs +++ b/interpreter/src/eval/misc.rs @@ -123,11 +123,7 @@ pub fn jump(state: &mut Machine) -> Control { pop_u256!(state, dest); let dest = as_usize_or_fail!(dest, ExitException::InvalidJump); - if state.valids.is_valid(dest) { - Control::Jump(dest) - } else { - Control::Exit(ExitException::InvalidJump.into()) - } + Control::Jump(dest) } #[inline] @@ -137,11 +133,7 @@ pub fn jumpi(state: &mut Machine) -> Control { if value != H256::zero() { let dest = as_usize_or_fail!(dest, ExitException::InvalidJump); - if state.valids.is_valid(dest) { - Control::Jump(dest) - } else { - Control::Exit(ExitException::InvalidJump.into()) - } + Control::Jump(dest) } else { Control::Continue } diff --git a/interpreter/src/eval/mod.rs b/interpreter/src/eval/mod.rs index fcbc5272c..df07a6f7a 100644 --- a/interpreter/src/eval/mod.rs +++ b/interpreter/src/eval/mod.rs @@ -6,242 +6,22 @@ mod misc; mod system; use crate::{ - CallCreateTrap, ExitException, ExitResult, ExitSucceed, Machine, Opcode, RuntimeBackend, + CallCreateTrap, Control, ExitException, ExitSucceed, GasState, Machine, Opcode, RuntimeBackend, RuntimeEnvironment, RuntimeState, }; -use core::marker::PhantomData; -use core::ops::{BitAnd, BitOr, BitXor, Deref, DerefMut}; +use core::ops::{BitAnd, BitOr, BitXor}; use primitive_types::{H256, U256}; -/// Evaluation function type. -pub type Efn = fn(&mut Machine, &mut H, Opcode, usize) -> Control; - -/// The evaluation table for the EVM. -pub struct Etable>([F; 256], PhantomData<(S, H, Tr)>); - -unsafe impl Send for Etable {} -unsafe impl Sync for Etable {} - -impl Deref for Etable { - type Target = [F; 256]; - - fn deref(&self) -> &[F; 256] { - &self.0 - } -} - -impl DerefMut for Etable { - fn deref_mut(&mut self) -> &mut [F; 256] { - &mut self.0 - } -} - -impl Etable -where - F: Fn(&mut Machine, &mut H, Opcode, 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, - { - let mut current_opcode = Opcode(0); - Etable( - self.0.map(|f| { - let fr = wrapper(f, current_opcode); - if current_opcode != Opcode(255) { - current_opcode.0 += 1; - } - fr - }), - PhantomData, - ) - } -} - -impl Etable { - /// Default core value for Etable. - pub const fn core() -> Self { - let mut table = [eval_unknown as _; 256]; - - table[Opcode::STOP.as_usize()] = eval_stop as _; - table[Opcode::ADD.as_usize()] = eval_add as _; - table[Opcode::MUL.as_usize()] = eval_mul as _; - table[Opcode::SUB.as_usize()] = eval_sub as _; - table[Opcode::DIV.as_usize()] = eval_div as _; - table[Opcode::SDIV.as_usize()] = eval_sdiv as _; - table[Opcode::MOD.as_usize()] = eval_mod as _; - table[Opcode::SMOD.as_usize()] = eval_smod as _; - table[Opcode::ADDMOD.as_usize()] = eval_addmod as _; - table[Opcode::MULMOD.as_usize()] = eval_mulmod as _; - table[Opcode::EXP.as_usize()] = eval_exp as _; - table[Opcode::SIGNEXTEND.as_usize()] = eval_signextend as _; - table[Opcode::LT.as_usize()] = eval_lt as _; - table[Opcode::GT.as_usize()] = eval_gt as _; - table[Opcode::SLT.as_usize()] = eval_slt as _; - table[Opcode::SGT.as_usize()] = eval_sgt as _; - table[Opcode::EQ.as_usize()] = eval_eq as _; - table[Opcode::ISZERO.as_usize()] = eval_iszero as _; - table[Opcode::AND.as_usize()] = eval_and as _; - table[Opcode::OR.as_usize()] = eval_or as _; - table[Opcode::XOR.as_usize()] = eval_xor as _; - table[Opcode::NOT.as_usize()] = eval_not as _; - table[Opcode::BYTE.as_usize()] = eval_byte as _; - table[Opcode::SHL.as_usize()] = eval_shl as _; - table[Opcode::SHR.as_usize()] = eval_shr as _; - table[Opcode::SAR.as_usize()] = eval_sar as _; - table[Opcode::CODESIZE.as_usize()] = eval_codesize as _; - table[Opcode::CODECOPY.as_usize()] = eval_codecopy as _; - table[Opcode::CALLDATALOAD.as_usize()] = eval_calldataload as _; - table[Opcode::CALLDATASIZE.as_usize()] = eval_calldatasize as _; - table[Opcode::CALLDATACOPY.as_usize()] = eval_calldatacopy as _; - table[Opcode::POP.as_usize()] = eval_pop as _; - table[Opcode::MLOAD.as_usize()] = eval_mload as _; - table[Opcode::MSTORE.as_usize()] = eval_mstore as _; - table[Opcode::MSTORE8.as_usize()] = eval_mstore8 as _; - table[Opcode::JUMP.as_usize()] = eval_jump as _; - table[Opcode::JUMPI.as_usize()] = eval_jumpi as _; - table[Opcode::PC.as_usize()] = eval_pc as _; - table[Opcode::MSIZE.as_usize()] = eval_msize as _; - table[Opcode::JUMPDEST.as_usize()] = eval_jumpdest as _; - - table[Opcode::PUSH0.as_usize()] = eval_push0 as _; - table[Opcode::PUSH1.as_usize()] = eval_push1 as _; - table[Opcode::PUSH2.as_usize()] = eval_push2 as _; - table[Opcode::PUSH3.as_usize()] = eval_push3 as _; - table[Opcode::PUSH4.as_usize()] = eval_push4 as _; - table[Opcode::PUSH5.as_usize()] = eval_push5 as _; - table[Opcode::PUSH6.as_usize()] = eval_push6 as _; - table[Opcode::PUSH7.as_usize()] = eval_push7 as _; - table[Opcode::PUSH8.as_usize()] = eval_push8 as _; - table[Opcode::PUSH9.as_usize()] = eval_push9 as _; - table[Opcode::PUSH10.as_usize()] = eval_push10 as _; - table[Opcode::PUSH11.as_usize()] = eval_push11 as _; - table[Opcode::PUSH12.as_usize()] = eval_push12 as _; - table[Opcode::PUSH13.as_usize()] = eval_push13 as _; - table[Opcode::PUSH14.as_usize()] = eval_push14 as _; - table[Opcode::PUSH15.as_usize()] = eval_push15 as _; - table[Opcode::PUSH16.as_usize()] = eval_push16 as _; - table[Opcode::PUSH17.as_usize()] = eval_push17 as _; - table[Opcode::PUSH18.as_usize()] = eval_push18 as _; - table[Opcode::PUSH19.as_usize()] = eval_push19 as _; - table[Opcode::PUSH20.as_usize()] = eval_push20 as _; - table[Opcode::PUSH21.as_usize()] = eval_push21 as _; - table[Opcode::PUSH22.as_usize()] = eval_push22 as _; - table[Opcode::PUSH23.as_usize()] = eval_push23 as _; - table[Opcode::PUSH24.as_usize()] = eval_push24 as _; - table[Opcode::PUSH25.as_usize()] = eval_push25 as _; - table[Opcode::PUSH26.as_usize()] = eval_push26 as _; - table[Opcode::PUSH27.as_usize()] = eval_push27 as _; - table[Opcode::PUSH28.as_usize()] = eval_push28 as _; - table[Opcode::PUSH29.as_usize()] = eval_push29 as _; - table[Opcode::PUSH30.as_usize()] = eval_push30 as _; - table[Opcode::PUSH31.as_usize()] = eval_push31 as _; - table[Opcode::PUSH32.as_usize()] = eval_push32 as _; - - table[Opcode::DUP1.as_usize()] = eval_dup1 as _; - table[Opcode::DUP2.as_usize()] = eval_dup2 as _; - table[Opcode::DUP3.as_usize()] = eval_dup3 as _; - table[Opcode::DUP4.as_usize()] = eval_dup4 as _; - table[Opcode::DUP5.as_usize()] = eval_dup5 as _; - table[Opcode::DUP6.as_usize()] = eval_dup6 as _; - table[Opcode::DUP7.as_usize()] = eval_dup7 as _; - table[Opcode::DUP8.as_usize()] = eval_dup8 as _; - table[Opcode::DUP9.as_usize()] = eval_dup9 as _; - table[Opcode::DUP10.as_usize()] = eval_dup10 as _; - table[Opcode::DUP11.as_usize()] = eval_dup11 as _; - table[Opcode::DUP12.as_usize()] = eval_dup12 as _; - table[Opcode::DUP13.as_usize()] = eval_dup13 as _; - table[Opcode::DUP14.as_usize()] = eval_dup14 as _; - table[Opcode::DUP15.as_usize()] = eval_dup15 as _; - table[Opcode::DUP16.as_usize()] = eval_dup16 as _; - - table[Opcode::SWAP1.as_usize()] = eval_swap1 as _; - table[Opcode::SWAP2.as_usize()] = eval_swap2 as _; - table[Opcode::SWAP3.as_usize()] = eval_swap3 as _; - table[Opcode::SWAP4.as_usize()] = eval_swap4 as _; - table[Opcode::SWAP5.as_usize()] = eval_swap5 as _; - table[Opcode::SWAP6.as_usize()] = eval_swap6 as _; - table[Opcode::SWAP7.as_usize()] = eval_swap7 as _; - table[Opcode::SWAP8.as_usize()] = eval_swap8 as _; - table[Opcode::SWAP9.as_usize()] = eval_swap9 as _; - table[Opcode::SWAP10.as_usize()] = eval_swap10 as _; - table[Opcode::SWAP11.as_usize()] = eval_swap11 as _; - table[Opcode::SWAP12.as_usize()] = eval_swap12 as _; - table[Opcode::SWAP13.as_usize()] = eval_swap13 as _; - table[Opcode::SWAP14.as_usize()] = eval_swap14 as _; - table[Opcode::SWAP15.as_usize()] = eval_swap15 as _; - table[Opcode::SWAP16.as_usize()] = eval_swap16 as _; - - table[Opcode::RETURN.as_usize()] = eval_return as _; - table[Opcode::REVERT.as_usize()] = eval_revert as _; - table[Opcode::INVALID.as_usize()] = eval_invalid as _; - - Self(table, PhantomData) - } -} - -impl, H: RuntimeEnvironment + RuntimeBackend, Tr: CallCreateTrap> - Etable -{ - /// Runtime Etable. - pub const fn runtime() -> Self { - let mut table = Self::core(); - - table.0[Opcode::SHA3.as_usize()] = eval_sha3 as _; - table.0[Opcode::ADDRESS.as_usize()] = eval_address as _; - table.0[Opcode::BALANCE.as_usize()] = eval_balance as _; - table.0[Opcode::SELFBALANCE.as_usize()] = eval_selfbalance as _; - table.0[Opcode::ORIGIN.as_usize()] = eval_origin as _; - table.0[Opcode::CALLER.as_usize()] = eval_caller as _; - table.0[Opcode::CALLVALUE.as_usize()] = eval_callvalue as _; - table.0[Opcode::GASPRICE.as_usize()] = eval_gasprice as _; - table.0[Opcode::EXTCODESIZE.as_usize()] = eval_extcodesize as _; - table.0[Opcode::EXTCODEHASH.as_usize()] = eval_extcodehash as _; - table.0[Opcode::EXTCODECOPY.as_usize()] = eval_extcodecopy as _; - table.0[Opcode::RETURNDATASIZE.as_usize()] = eval_returndatasize as _; - table.0[Opcode::RETURNDATACOPY.as_usize()] = eval_returndatacopy as _; - table.0[Opcode::BLOCKHASH.as_usize()] = eval_blockhash as _; - table.0[Opcode::COINBASE.as_usize()] = eval_coinbase as _; - table.0[Opcode::TIMESTAMP.as_usize()] = eval_timestamp as _; - table.0[Opcode::NUMBER.as_usize()] = eval_number as _; - table.0[Opcode::DIFFICULTY.as_usize()] = eval_difficulty as _; - table.0[Opcode::GASLIMIT.as_usize()] = eval_gaslimit as _; - table.0[Opcode::SLOAD.as_usize()] = eval_sload as _; - table.0[Opcode::SSTORE.as_usize()] = eval_sstore as _; - table.0[Opcode::GAS.as_usize()] = eval_gas as _; - table.0[Opcode::LOG0.as_usize()] = eval_log0 as _; - table.0[Opcode::LOG1.as_usize()] = eval_log1 as _; - table.0[Opcode::LOG2.as_usize()] = eval_log2 as _; - table.0[Opcode::LOG3.as_usize()] = eval_log3 as _; - table.0[Opcode::LOG4.as_usize()] = eval_log4 as _; - table.0[Opcode::SUICIDE.as_usize()] = eval_suicide as _; - table.0[Opcode::CHAINID.as_usize()] = eval_chainid as _; - table.0[Opcode::BASEFEE.as_usize()] = eval_basefee as _; - - table.0[Opcode::CREATE.as_usize()] = eval_call_create_trap as _; - table.0[Opcode::CREATE2.as_usize()] = eval_call_create_trap as _; - table.0[Opcode::CALL.as_usize()] = eval_call_create_trap as _; - table.0[Opcode::CALLCODE.as_usize()] = eval_call_create_trap as _; - table.0[Opcode::DELEGATECALL.as_usize()] = eval_call_create_trap as _; - table.0[Opcode::STATICCALL.as_usize()] = eval_call_create_trap as _; - - table - } -} - -/// Control state. -#[derive(Clone, Eq, PartialEq, Debug)] -pub enum Control { - Continue, - ContinueN(usize), - Exit(ExitResult), - Jump(usize), - Trap(Trap), -} - -fn eval_stop( +pub fn eval_pass( + _machine: &mut Machine, + _handle: &mut H, + _opcode: Opcode, + _position: usize, +) -> Control { + Control::Continue +} + +pub fn eval_stop( _machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -250,7 +30,7 @@ fn eval_stop( Control::Exit(ExitSucceed::Stopped.into()) } -fn eval_add( +pub fn eval_add( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -259,7 +39,7 @@ fn eval_add( op2_u256_tuple!(machine, overflowing_add) } -fn eval_mul( +pub fn eval_mul( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -268,7 +48,7 @@ fn eval_mul( op2_u256_tuple!(machine, overflowing_mul) } -fn eval_sub( +pub fn eval_sub( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -277,7 +57,7 @@ fn eval_sub( op2_u256_tuple!(machine, overflowing_sub) } -fn eval_div( +pub fn eval_div( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -286,7 +66,7 @@ fn eval_div( op2_u256_fn!(machine, self::arithmetic::div) } -fn eval_sdiv( +pub fn eval_sdiv( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -295,7 +75,7 @@ fn eval_sdiv( op2_u256_fn!(machine, self::arithmetic::sdiv) } -fn eval_mod( +pub fn eval_mod( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -304,7 +84,7 @@ fn eval_mod( op2_u256_fn!(machine, self::arithmetic::rem) } -fn eval_smod( +pub fn eval_smod( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -313,7 +93,7 @@ fn eval_smod( op2_u256_fn!(machine, self::arithmetic::srem) } -fn eval_addmod( +pub fn eval_addmod( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -322,7 +102,7 @@ fn eval_addmod( op3_u256_fn!(machine, self::arithmetic::addmod) } -fn eval_mulmod( +pub fn eval_mulmod( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -331,7 +111,7 @@ fn eval_mulmod( op3_u256_fn!(machine, self::arithmetic::mulmod) } -fn eval_exp( +pub fn eval_exp( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -340,7 +120,7 @@ fn eval_exp( op2_u256_fn!(machine, self::arithmetic::exp) } -fn eval_signextend( +pub fn eval_signextend( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -349,7 +129,7 @@ fn eval_signextend( op2_u256_fn!(machine, self::arithmetic::signextend) } -fn eval_lt( +pub fn eval_lt( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -358,7 +138,7 @@ fn eval_lt( op2_u256_bool_ref!(machine, lt) } -fn eval_gt( +pub fn eval_gt( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -367,7 +147,7 @@ fn eval_gt( op2_u256_bool_ref!(machine, gt) } -fn eval_slt( +pub fn eval_slt( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -376,7 +156,7 @@ fn eval_slt( op2_u256_fn!(machine, self::bitwise::slt) } -fn eval_sgt( +pub fn eval_sgt( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -385,7 +165,7 @@ fn eval_sgt( op2_u256_fn!(machine, self::bitwise::sgt) } -fn eval_eq( +pub fn eval_eq( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -394,7 +174,7 @@ fn eval_eq( op2_u256_bool_ref!(machine, eq) } -fn eval_iszero( +pub fn eval_iszero( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -403,7 +183,7 @@ fn eval_iszero( op1_u256_fn!(machine, self::bitwise::iszero) } -fn eval_and( +pub fn eval_and( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -412,7 +192,7 @@ fn eval_and( op2_u256!(machine, bitand) } -fn eval_or( +pub fn eval_or( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -421,7 +201,7 @@ fn eval_or( op2_u256!(machine, bitor) } -fn eval_xor( +pub fn eval_xor( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -430,7 +210,7 @@ fn eval_xor( op2_u256!(machine, bitxor) } -fn eval_not( +pub fn eval_not( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -439,7 +219,7 @@ fn eval_not( op1_u256_fn!(machine, self::bitwise::not) } -fn eval_byte( +pub fn eval_byte( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -448,7 +228,7 @@ fn eval_byte( op2_u256_fn!(machine, self::bitwise::byte) } -fn eval_shl( +pub fn eval_shl( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -457,7 +237,7 @@ fn eval_shl( op2_u256_fn!(machine, self::bitwise::shl) } -fn eval_shr( +pub fn eval_shr( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -466,7 +246,7 @@ fn eval_shr( op2_u256_fn!(machine, self::bitwise::shr) } -fn eval_sar( +pub fn eval_sar( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -475,7 +255,7 @@ fn eval_sar( op2_u256_fn!(machine, self::bitwise::sar) } -fn eval_codesize( +pub fn eval_codesize( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -484,7 +264,7 @@ fn eval_codesize( self::misc::codesize(machine) } -fn eval_codecopy( +pub fn eval_codecopy( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -493,7 +273,7 @@ fn eval_codecopy( self::misc::codecopy(machine) } -fn eval_calldataload( +pub fn eval_calldataload( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -502,7 +282,7 @@ fn eval_calldataload( self::misc::calldataload(machine) } -fn eval_calldatasize( +pub fn eval_calldatasize( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -511,7 +291,7 @@ fn eval_calldatasize( self::misc::calldatasize(machine) } -fn eval_calldatacopy( +pub fn eval_calldatacopy( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -520,7 +300,7 @@ fn eval_calldatacopy( self::misc::calldatacopy(machine) } -fn eval_pop( +pub fn eval_pop( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -529,7 +309,7 @@ fn eval_pop( self::misc::pop(machine) } -fn eval_mload( +pub fn eval_mload( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -538,7 +318,7 @@ fn eval_mload( self::misc::mload(machine) } -fn eval_mstore( +pub fn eval_mstore( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -547,7 +327,7 @@ fn eval_mstore( self::misc::mstore(machine) } -fn eval_mstore8( +pub fn eval_mstore8( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -556,7 +336,7 @@ fn eval_mstore8( self::misc::mstore8(machine) } -fn eval_jump( +pub fn eval_jump( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -565,7 +345,7 @@ fn eval_jump( self::misc::jump(machine) } -fn eval_jumpi( +pub fn eval_jumpi( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -574,7 +354,7 @@ fn eval_jumpi( self::misc::jumpi(machine) } -fn eval_pc( +pub fn eval_pc( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -583,7 +363,7 @@ fn eval_pc( self::misc::pc(machine, position) } -fn eval_msize( +pub fn eval_msize( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -592,7 +372,7 @@ fn eval_msize( self::misc::msize(machine) } -fn eval_jumpdest( +pub fn eval_jumpdest( _machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -601,7 +381,7 @@ fn eval_jumpdest( Control::Continue } -fn eval_push0( +pub fn eval_push0( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -610,7 +390,7 @@ fn eval_push0( self::misc::push(machine, 0, position) } -fn eval_push1( +pub fn eval_push1( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -619,7 +399,7 @@ fn eval_push1( self::misc::push(machine, 1, position) } -fn eval_push2( +pub fn eval_push2( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -628,7 +408,7 @@ fn eval_push2( self::misc::push(machine, 2, position) } -fn eval_push3( +pub fn eval_push3( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -637,7 +417,7 @@ fn eval_push3( self::misc::push(machine, 3, position) } -fn eval_push4( +pub fn eval_push4( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -646,7 +426,7 @@ fn eval_push4( self::misc::push(machine, 4, position) } -fn eval_push5( +pub fn eval_push5( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -655,7 +435,7 @@ fn eval_push5( self::misc::push(machine, 5, position) } -fn eval_push6( +pub fn eval_push6( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -664,7 +444,7 @@ fn eval_push6( self::misc::push(machine, 6, position) } -fn eval_push7( +pub fn eval_push7( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -673,7 +453,7 @@ fn eval_push7( self::misc::push(machine, 7, position) } -fn eval_push8( +pub fn eval_push8( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -682,7 +462,7 @@ fn eval_push8( self::misc::push(machine, 8, position) } -fn eval_push9( +pub fn eval_push9( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -691,7 +471,7 @@ fn eval_push9( self::misc::push(machine, 9, position) } -fn eval_push10( +pub fn eval_push10( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -700,7 +480,7 @@ fn eval_push10( self::misc::push(machine, 10, position) } -fn eval_push11( +pub fn eval_push11( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -709,7 +489,7 @@ fn eval_push11( self::misc::push(machine, 11, position) } -fn eval_push12( +pub fn eval_push12( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -718,7 +498,7 @@ fn eval_push12( self::misc::push(machine, 12, position) } -fn eval_push13( +pub fn eval_push13( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -727,7 +507,7 @@ fn eval_push13( self::misc::push(machine, 13, position) } -fn eval_push14( +pub fn eval_push14( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -736,7 +516,7 @@ fn eval_push14( self::misc::push(machine, 14, position) } -fn eval_push15( +pub fn eval_push15( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -745,7 +525,7 @@ fn eval_push15( self::misc::push(machine, 15, position) } -fn eval_push16( +pub fn eval_push16( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -754,7 +534,7 @@ fn eval_push16( self::misc::push(machine, 16, position) } -fn eval_push17( +pub fn eval_push17( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -763,7 +543,7 @@ fn eval_push17( self::misc::push(machine, 17, position) } -fn eval_push18( +pub fn eval_push18( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -772,7 +552,7 @@ fn eval_push18( self::misc::push(machine, 18, position) } -fn eval_push19( +pub fn eval_push19( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -781,7 +561,7 @@ fn eval_push19( self::misc::push(machine, 19, position) } -fn eval_push20( +pub fn eval_push20( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -790,7 +570,7 @@ fn eval_push20( self::misc::push(machine, 20, position) } -fn eval_push21( +pub fn eval_push21( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -799,7 +579,7 @@ fn eval_push21( self::misc::push(machine, 21, position) } -fn eval_push22( +pub fn eval_push22( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -808,7 +588,7 @@ fn eval_push22( self::misc::push(machine, 22, position) } -fn eval_push23( +pub fn eval_push23( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -817,7 +597,7 @@ fn eval_push23( self::misc::push(machine, 23, position) } -fn eval_push24( +pub fn eval_push24( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -826,7 +606,7 @@ fn eval_push24( self::misc::push(machine, 24, position) } -fn eval_push25( +pub fn eval_push25( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -835,7 +615,7 @@ fn eval_push25( self::misc::push(machine, 25, position) } -fn eval_push26( +pub fn eval_push26( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -844,7 +624,7 @@ fn eval_push26( self::misc::push(machine, 26, position) } -fn eval_push27( +pub fn eval_push27( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -853,7 +633,7 @@ fn eval_push27( self::misc::push(machine, 27, position) } -fn eval_push28( +pub fn eval_push28( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -862,7 +642,7 @@ fn eval_push28( self::misc::push(machine, 28, position) } -fn eval_push29( +pub fn eval_push29( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -871,7 +651,7 @@ fn eval_push29( self::misc::push(machine, 29, position) } -fn eval_push30( +pub fn eval_push30( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -880,7 +660,7 @@ fn eval_push30( self::misc::push(machine, 30, position) } -fn eval_push31( +pub fn eval_push31( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -889,7 +669,7 @@ fn eval_push31( self::misc::push(machine, 31, position) } -fn eval_push32( +pub fn eval_push32( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -898,7 +678,7 @@ fn eval_push32( self::misc::push(machine, 32, position) } -fn eval_dup1( +pub fn eval_dup1( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -907,7 +687,7 @@ fn eval_dup1( self::misc::dup(machine, 1) } -fn eval_dup2( +pub fn eval_dup2( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -916,7 +696,7 @@ fn eval_dup2( self::misc::dup(machine, 2) } -fn eval_dup3( +pub fn eval_dup3( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -925,7 +705,7 @@ fn eval_dup3( self::misc::dup(machine, 3) } -fn eval_dup4( +pub fn eval_dup4( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -934,7 +714,7 @@ fn eval_dup4( self::misc::dup(machine, 4) } -fn eval_dup5( +pub fn eval_dup5( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -943,7 +723,7 @@ fn eval_dup5( self::misc::dup(machine, 5) } -fn eval_dup6( +pub fn eval_dup6( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -952,7 +732,7 @@ fn eval_dup6( self::misc::dup(machine, 6) } -fn eval_dup7( +pub fn eval_dup7( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -961,7 +741,7 @@ fn eval_dup7( self::misc::dup(machine, 7) } -fn eval_dup8( +pub fn eval_dup8( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -970,7 +750,7 @@ fn eval_dup8( self::misc::dup(machine, 8) } -fn eval_dup9( +pub fn eval_dup9( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -979,7 +759,7 @@ fn eval_dup9( self::misc::dup(machine, 9) } -fn eval_dup10( +pub fn eval_dup10( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -988,7 +768,7 @@ fn eval_dup10( self::misc::dup(machine, 10) } -fn eval_dup11( +pub fn eval_dup11( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -997,7 +777,7 @@ fn eval_dup11( self::misc::dup(machine, 11) } -fn eval_dup12( +pub fn eval_dup12( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1006,7 +786,7 @@ fn eval_dup12( self::misc::dup(machine, 12) } -fn eval_dup13( +pub fn eval_dup13( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1015,7 +795,7 @@ fn eval_dup13( self::misc::dup(machine, 13) } -fn eval_dup14( +pub fn eval_dup14( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1024,7 +804,7 @@ fn eval_dup14( self::misc::dup(machine, 14) } -fn eval_dup15( +pub fn eval_dup15( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1033,7 +813,7 @@ fn eval_dup15( self::misc::dup(machine, 15) } -fn eval_dup16( +pub fn eval_dup16( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1042,7 +822,7 @@ fn eval_dup16( self::misc::dup(machine, 16) } -fn eval_swap1( +pub fn eval_swap1( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1051,7 +831,7 @@ fn eval_swap1( self::misc::swap(machine, 1) } -fn eval_swap2( +pub fn eval_swap2( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1060,7 +840,7 @@ fn eval_swap2( self::misc::swap(machine, 2) } -fn eval_swap3( +pub fn eval_swap3( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1069,7 +849,7 @@ fn eval_swap3( self::misc::swap(machine, 3) } -fn eval_swap4( +pub fn eval_swap4( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1078,7 +858,7 @@ fn eval_swap4( self::misc::swap(machine, 4) } -fn eval_swap5( +pub fn eval_swap5( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1087,7 +867,7 @@ fn eval_swap5( self::misc::swap(machine, 5) } -fn eval_swap6( +pub fn eval_swap6( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1096,7 +876,7 @@ fn eval_swap6( self::misc::swap(machine, 6) } -fn eval_swap7( +pub fn eval_swap7( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1105,7 +885,7 @@ fn eval_swap7( self::misc::swap(machine, 7) } -fn eval_swap8( +pub fn eval_swap8( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1114,7 +894,7 @@ fn eval_swap8( self::misc::swap(machine, 8) } -fn eval_swap9( +pub fn eval_swap9( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1123,7 +903,7 @@ fn eval_swap9( self::misc::swap(machine, 9) } -fn eval_swap10( +pub fn eval_swap10( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1132,7 +912,7 @@ fn eval_swap10( self::misc::swap(machine, 10) } -fn eval_swap11( +pub fn eval_swap11( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1141,7 +921,7 @@ fn eval_swap11( self::misc::swap(machine, 11) } -fn eval_swap12( +pub fn eval_swap12( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1150,7 +930,7 @@ fn eval_swap12( self::misc::swap(machine, 12) } -fn eval_swap13( +pub fn eval_swap13( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1159,7 +939,7 @@ fn eval_swap13( self::misc::swap(machine, 13) } -fn eval_swap14( +pub fn eval_swap14( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1168,7 +948,7 @@ fn eval_swap14( self::misc::swap(machine, 14) } -fn eval_swap15( +pub fn eval_swap15( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1177,7 +957,7 @@ fn eval_swap15( self::misc::swap(machine, 15) } -fn eval_swap16( +pub fn eval_swap16( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1186,7 +966,7 @@ fn eval_swap16( self::misc::swap(machine, 16) } -fn eval_return( +pub fn eval_return( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1195,7 +975,7 @@ fn eval_return( self::misc::ret(machine) } -fn eval_revert( +pub fn eval_revert( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1204,7 +984,7 @@ fn eval_revert( self::misc::revert(machine) } -fn eval_invalid( +pub fn eval_invalid( _machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1213,7 +993,7 @@ fn eval_invalid( Control::Exit(ExitException::DesignatedInvalid.into()) } -fn eval_unknown( +pub fn eval_unknown( _machine: &mut Machine, _handle: &mut H, opcode: Opcode, @@ -1222,7 +1002,7 @@ fn eval_unknown( Control::Exit(ExitException::InvalidOpcode(opcode).into()) } -fn eval_sha3, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_sha3, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1231,7 +1011,7 @@ fn eval_sha3, H: RuntimeEnvironment + RuntimeBackend, Tr> self::system::sha3(machine) } -fn eval_address, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_address, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1240,7 +1020,7 @@ fn eval_address, H: RuntimeEnvironment + RuntimeBackend, self::system::address(machine) } -fn eval_balance, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_balance, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1249,7 +1029,7 @@ fn eval_balance, H: RuntimeEnvironment + RuntimeBackend, self::system::balance(machine, handle) } -fn eval_selfbalance, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_selfbalance, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1258,7 +1038,7 @@ fn eval_selfbalance, H: RuntimeEnvironment + RuntimeBacke self::system::selfbalance(machine, handle) } -fn eval_origin, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_origin, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1267,7 +1047,7 @@ fn eval_origin, H: RuntimeEnvironment + RuntimeBackend, T self::system::origin(machine, handle) } -fn eval_caller, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_caller, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1276,7 +1056,7 @@ fn eval_caller, H: RuntimeEnvironment + RuntimeBackend, T self::system::caller(machine) } -fn eval_callvalue, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_callvalue, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1285,7 +1065,7 @@ fn eval_callvalue, H: RuntimeEnvironment + RuntimeBackend self::system::callvalue(machine) } -fn eval_gasprice, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_gasprice, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1294,7 +1074,7 @@ fn eval_gasprice, H: RuntimeEnvironment + RuntimeBackend, self::system::gasprice(machine, handle) } -fn eval_extcodesize, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_extcodesize, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1303,7 +1083,7 @@ fn eval_extcodesize, H: RuntimeEnvironment + RuntimeBacke self::system::extcodesize(machine, handle) } -fn eval_extcodehash, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_extcodehash, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1312,7 +1092,7 @@ fn eval_extcodehash, H: RuntimeEnvironment + RuntimeBacke self::system::extcodehash(machine, handle) } -fn eval_extcodecopy, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_extcodecopy, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1321,7 +1101,7 @@ fn eval_extcodecopy, H: RuntimeEnvironment + RuntimeBacke self::system::extcodecopy(machine, handle) } -fn eval_returndatasize, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_returndatasize, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1330,7 +1110,7 @@ fn eval_returndatasize, H: RuntimeEnvironment + RuntimeBa self::system::returndatasize(machine) } -fn eval_returndatacopy, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_returndatacopy, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1339,7 +1119,7 @@ fn eval_returndatacopy, H: RuntimeEnvironment + RuntimeBa self::system::returndatacopy(machine) } -fn eval_blockhash, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_blockhash, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1348,7 +1128,7 @@ fn eval_blockhash, H: RuntimeEnvironment + RuntimeBackend self::system::blockhash(machine, handle) } -fn eval_coinbase, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_coinbase, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1357,7 +1137,7 @@ fn eval_coinbase, H: RuntimeEnvironment + RuntimeBackend, self::system::coinbase(machine, handle) } -fn eval_timestamp, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_timestamp, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1366,7 +1146,7 @@ fn eval_timestamp, H: RuntimeEnvironment + RuntimeBackend self::system::timestamp(machine, handle) } -fn eval_number, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_number, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1375,7 +1155,7 @@ fn eval_number, H: RuntimeEnvironment + RuntimeBackend, T self::system::number(machine, handle) } -fn eval_difficulty, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_difficulty, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1384,7 +1164,7 @@ fn eval_difficulty, H: RuntimeEnvironment + RuntimeBacken self::system::prevrandao(machine, handle) } -fn eval_gaslimit, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_gaslimit, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1393,7 +1173,7 @@ fn eval_gaslimit, H: RuntimeEnvironment + RuntimeBackend, self::system::gaslimit(machine, handle) } -fn eval_sload, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_sload, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1402,7 +1182,7 @@ fn eval_sload, H: RuntimeEnvironment + RuntimeBackend, Tr self::system::sload(machine, handle) } -fn eval_sstore, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_sstore, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1411,7 +1191,7 @@ fn eval_sstore, H: RuntimeEnvironment + RuntimeBackend, T self::system::sstore(machine, handle) } -fn eval_gas, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_gas( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1420,7 +1200,7 @@ fn eval_gas, H: RuntimeEnvironment + RuntimeBackend, Tr>( self::system::gas(machine, handle) } -fn eval_log0, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_log0, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1429,7 +1209,7 @@ fn eval_log0, H: RuntimeEnvironment + RuntimeBackend, Tr> self::system::log(machine, 0, handle) } -fn eval_log1, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_log1, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1438,7 +1218,7 @@ fn eval_log1, H: RuntimeEnvironment + RuntimeBackend, Tr> self::system::log(machine, 1, handle) } -fn eval_log2, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_log2, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1447,7 +1227,7 @@ fn eval_log2, H: RuntimeEnvironment + RuntimeBackend, Tr> self::system::log(machine, 2, handle) } -fn eval_log3, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_log3, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1456,7 +1236,7 @@ fn eval_log3, H: RuntimeEnvironment + RuntimeBackend, Tr> self::system::log(machine, 3, handle) } -fn eval_log4, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_log4, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1465,7 +1245,7 @@ fn eval_log4, H: RuntimeEnvironment + RuntimeBackend, Tr> self::system::log(machine, 4, handle) } -fn eval_suicide, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_suicide, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1474,7 +1254,7 @@ fn eval_suicide, H: RuntimeEnvironment + RuntimeBackend, self::system::suicide(machine, handle) } -fn eval_chainid, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_chainid, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1483,7 +1263,7 @@ fn eval_chainid, H: RuntimeEnvironment + RuntimeBackend, self::system::chainid(machine, handle) } -fn eval_basefee, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn eval_basefee, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1492,7 +1272,7 @@ fn eval_basefee, H: RuntimeEnvironment + RuntimeBackend, self::system::basefee(machine, handle) } -fn eval_call_create_trap( +pub fn eval_call_create_trap( _machine: &mut Machine, _handle: &mut H, opcode: Opcode, diff --git a/interpreter/src/eval/system.rs b/interpreter/src/eval/system.rs index c74dd0e87..1dc0ad324 100644 --- a/interpreter/src/eval/system.rs +++ b/interpreter/src/eval/system.rs @@ -1,7 +1,7 @@ use super::Control; use crate::{ - ExitException, ExitFatal, ExitSucceed, Log, Machine, RuntimeBackend, RuntimeEnvironment, - RuntimeState, Transfer, + ExitException, ExitFatal, ExitSucceed, GasState, Log, Machine, RuntimeBackend, + RuntimeEnvironment, RuntimeState, Transfer, }; use alloc::vec::Vec; use primitive_types::{H256, U256}; @@ -285,11 +285,11 @@ pub fn sstore, H: RuntimeEnvironment + RuntimeBackend, Tr } } -pub fn gas, H: RuntimeEnvironment + RuntimeBackend, Tr>( +pub fn gas( machine: &mut Machine, _handler: &H, ) -> Control { - push_u256!(machine, machine.state.as_ref().gas); + push_u256!(machine, machine.state.gas()); Control::Continue } diff --git a/interpreter/src/interpreter/etable.rs b/interpreter/src/interpreter/etable.rs new file mode 100644 index 000000000..170cb81ed --- /dev/null +++ b/interpreter/src/interpreter/etable.rs @@ -0,0 +1,171 @@ +use crate::{ + Capture, Control, EtableSet, ExitError, ExitException, ExitFatal, ExitResult, ExitSucceed, + Interpreter, Machine, Opcode, Stack, StepInterpreter, Valids, +}; +use alloc::vec::Vec; +use core::marker::PhantomData; +use core::ops::{Deref, DerefMut}; + +pub struct EtableInterpreter<'etable, S, H, Tr, ES> { + valids: Valids, + position: usize, + machine: Machine, + etable: &'etable ES, + _marker: PhantomData<(H, Tr)>, +} + +impl<'etable, S, H, Tr, ES> Deref for EtableInterpreter<'etable, S, H, Tr, ES> { + type Target = Machine; + + fn deref(&self) -> &Machine { + &self.machine + } +} + +impl<'etable, S, H, Tr, ES> DerefMut for EtableInterpreter<'etable, S, H, Tr, ES> { + fn deref_mut(&mut self) -> &mut Machine { + &mut self.machine + } +} + +impl<'etable, S, H, Tr, ES> EtableInterpreter<'etable, S, H, Tr, ES> +where + ES: EtableSet, +{ + /// Return a reference of the program counter. + pub const fn position(&self) -> usize { + self.position + } + + pub fn new(machine: Machine, etable: &'etable ES) -> Self { + let valids = Valids::new(&machine.code[..]); + + Self { + machine, + valids, + position: 0, + etable, + _marker: PhantomData, + } + } + + pub fn deconstruct(self) -> Machine { + self.machine + } + + /// Explicit exit of the machine. Further step will return error. + pub fn exit(&mut self) { + self.position = self.code.len(); + } + + /// Inspect the machine's next opcode and current stack. + pub fn inspect(&self) -> Option<(Opcode, &Stack)> { + self.code + .get(self.position) + .map(|v| (Opcode(*v), &self.stack)) + } + + /// Perform any operation. If the operation fails, then set the machine + /// status to already exited. + pub fn perform Result>( + &mut self, + f: F, + ) -> Result { + match f(self) { + Ok(r) => Ok(r), + Err(e) => { + self.exit(); + Err(e) + } + } + } + + /// Pick the next opcode. + pub fn peek_opcode(&self) -> Option { + self.code.get(self.position).map(|opcode| Opcode(*opcode)) + } +} + +impl<'etable, S, H, Tr, ES> Interpreter for EtableInterpreter<'etable, S, H, Tr, ES> +where + ES: EtableSet, +{ + fn machine(&self) -> &Machine { + &self.machine + } + + fn machine_mut(&mut self) -> &mut Machine { + &mut self.machine + } + + fn deconstruct(self) -> (S, Vec) { + (self.machine.state, self.machine.retval) + } + + fn run(&mut self, handle: &mut H) -> Capture { + loop { + match self.step(handle) { + Ok(()) => (), + Err(res) => return res, + } + } + } + + fn advance(&mut self) { + if self.position == self.code.len() { + return; + } + + self.position += 1; + } +} + +impl<'etable, S, H, Tr, ES> StepInterpreter for EtableInterpreter<'etable, S, H, Tr, ES> +where + ES: EtableSet, +{ + #[inline] + fn step(&mut self, handle: &mut H) -> Result<(), Capture> { + if self.is_empty() { + return Err(Capture::Exit(ExitSucceed::Stopped.into())); + } + + let position = self.position; + if position >= self.code.len() { + 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); + + match control { + Control::Continue => { + self.position += 1; + } + Control::ContinueN(p) => { + self.position = position + p; + } + Control::Exit(e) => { + self.position = self.code.len(); + return Err(Capture::Exit(e)); + } + Control::Jump(p) => { + if self.valids.is_valid(p) { + self.position = p; + } else { + self.position = self.code.len(); + return Err(Capture::Exit(ExitException::InvalidJump.into())); + } + } + Control::Trap(opcode) => return Err(Capture::Trap(opcode)), + }; + + if self.position >= self.code.len() { + return Err(Capture::Exit(ExitSucceed::Stopped.into())); + } + + Ok(()) + } +} diff --git a/interpreter/src/interpreter/mod.rs b/interpreter/src/interpreter/mod.rs new file mode 100644 index 000000000..8de9b7cd6 --- /dev/null +++ b/interpreter/src/interpreter/mod.rs @@ -0,0 +1,19 @@ +mod etable; + +pub use self::etable::EtableInterpreter; + +use crate::{Capture, ExitResult, Machine}; +use alloc::vec::Vec; + +pub trait Interpreter { + fn machine(&self) -> &Machine; + fn machine_mut(&mut self) -> &mut Machine; + + fn deconstruct(self) -> (S, Vec); + fn run(&mut self, handle: &mut H) -> Capture; + fn advance(&mut self); +} + +pub trait StepInterpreter: Interpreter { + fn step(&mut self, handle: &mut H) -> Result<(), Capture>; +} diff --git a/interpreter/src/lib.rs b/interpreter/src/lib.rs index a032885c1..045e16a61 100644 --- a/interpreter/src/lib.rs +++ b/interpreter/src/lib.rs @@ -8,7 +8,9 @@ extern crate alloc; pub mod call_create; mod error; -mod eval; +mod etable; +pub mod eval; +mod interpreter; mod memory; mod opcode; mod runtime; @@ -17,11 +19,12 @@ pub mod utils; mod valids; pub use crate::error::{Capture, ExitError, ExitException, ExitFatal, ExitResult, ExitSucceed}; -pub use crate::eval::{Control, Efn, Etable}; +pub use crate::etable::{Control, Efn, Etable, EtableSet}; +pub use crate::interpreter::{EtableInterpreter, Interpreter, StepInterpreter}; pub use crate::memory::Memory; pub use crate::opcode::Opcode; pub use crate::runtime::{ - CallCreateTrap, Context, Log, RuntimeBackend, RuntimeBaseBackend, RuntimeEnvironment, + CallCreateTrap, Context, GasState, Log, RuntimeBackend, RuntimeBaseBackend, RuntimeEnvironment, RuntimeState, TransactionContext, Transfer, }; pub use crate::stack::Stack; @@ -36,10 +39,6 @@ pub struct Machine { data: Rc>, /// Program code. code: Rc>, - /// Program counter. - position: usize, - /// Code validity maps. - valids: Valids, /// Return value. Note the difference between `retbuf`. /// A `retval` holds what's returned by the current machine, with `RETURN` or `REVERT` opcode. /// A `retbuf` holds the buffer of returned value by sub-calls. @@ -53,11 +52,6 @@ pub struct Machine { } impl Machine { - /// Return a reference of the program counter. - pub const fn position(&self) -> usize { - self.position - } - /// Machine code. pub fn code(&self) -> &[u8] { &self.code @@ -71,13 +65,9 @@ impl Machine { memory_limit: usize, state: S, ) -> Self { - let valids = Valids::new(&code[..]); - Self { data, code, - position: 0, - valids, retval: Vec::new(), memory: Memory::new(memory_limit), stack: Stack::new(stack_limit), @@ -85,133 +75,8 @@ impl Machine { } } - /// Perform any operation. If the operation fails, then set the machine - /// status to already exited. - pub fn perform Result>( - &mut self, - f: F, - ) -> Result { - match f(self) { - Ok(r) => Ok(r), - Err(e) => { - self.exit(); - Err(e) - } - } - } - - /// Explicit exit of the machine. Further step will return error. - pub fn exit(&mut self) { - self.position = self.code.len(); - } - - /// Inspect the machine's next opcode and current stack. - pub fn inspect(&self) -> Option<(Opcode, &Stack)> { - self.code - .get(self.position) - .map(|v| (Opcode(*v), &self.stack)) - } - - /// Loop stepping the machine, until it stops. - pub fn run( - &mut self, - handle: &mut H, - etable: &Etable, - ) -> Capture - where - F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, - { - loop { - match self.step(handle, etable) { - Ok(()) => (), - Err(res) => return res, - } - } - } - - #[inline] - /// Step the machine N times. - pub fn stepn( - &mut self, - n: usize, - handle: &mut H, - etable: &Etable, - ) -> Result<(), Capture> - where - F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, - { - for _ in 0..n { - match self.step(handle, etable) { - Ok(()) => (), - Err(res) => return Err(res), - } - } - - Ok(()) - } - - #[inline] - /// Step the machine, executing one opcode. It then returns. - pub fn step( - &mut self, - handle: &mut H, - etable: &Etable, - ) -> Result<(), Capture> - where - F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, - { - if self.is_empty() { - return Err(Capture::Exit(ExitSucceed::Stopped.into())); - } - - let position = self.position; - if position >= self.code.len() { - return Err(Capture::Exit(ExitFatal::AlreadyExited.into())); - } - - let opcode = Opcode(self.code[position]); - let control = etable[opcode.as_usize()](self, handle, opcode, self.position); - - match control { - Control::Continue => { - self.position += 1; - } - Control::ContinueN(p) => { - self.position = position + p; - } - Control::Exit(e) => { - self.position = self.code.len(); - return Err(Capture::Exit(e)); - } - Control::Jump(p) => { - self.position = p; - } - Control::Trap(opcode) => return Err(Capture::Trap(opcode)), - }; - - if self.position >= self.code.len() { - return Err(Capture::Exit(ExitSucceed::Stopped.into())); - } - - Ok(()) - } - - /// Pick the next opcode. - pub fn peek_opcode(&self) -> Option { - self.code.get(self.position).map(|opcode| Opcode(*opcode)) - } - /// Whether the machine has empty code. pub fn is_empty(&self) -> bool { self.code.is_empty() } - - /// Advance the PC to the next opcode. - pub fn advance(&mut self) { - if self.position == self.code.len() { - return; - } - - self.position += 1; - } } diff --git a/interpreter/src/runtime.rs b/interpreter/src/runtime.rs index e0d390436..84342bb29 100644 --- a/interpreter/src/runtime.rs +++ b/interpreter/src/runtime.rs @@ -4,6 +4,11 @@ use alloc::vec::Vec; use primitive_types::{H160, H256, U256}; use sha3::{Digest, Keccak256}; +/// Gas state. +pub trait GasState { + fn gas(&self) -> U256; +} + /// Runtime state. #[derive(Clone, Debug)] pub struct RuntimeState { @@ -12,8 +17,6 @@ pub struct RuntimeState { pub transaction_context: Rc, /// Return data buffer. pub retbuf: Vec, - /// Current gas. - pub gas: U256, } impl AsRef for RuntimeState { @@ -28,6 +31,12 @@ impl AsMut for RuntimeState { } } +impl GasState for RuntimeState { + fn gas(&self) -> U256 { + U256::zero() + } +} + /// Context of the runtime. #[derive(Clone, Debug)] pub struct Context { diff --git a/interpreter/tests/performance.rs b/interpreter/tests/performance.rs index acbb7cebf..aa69af9ca 100644 --- a/interpreter/tests/performance.rs +++ b/interpreter/tests/performance.rs @@ -1,4 +1,4 @@ -use evm_interpreter::{Capture, Etable, ExitSucceed, Machine}; +use evm_interpreter::{Capture, Etable, EtableInterpreter, ExitSucceed, Interpreter, Machine}; use std::rc::Rc; static ETABLE: Etable<(), (), ()> = Etable::core(); @@ -10,9 +10,10 @@ macro_rules! ret_test { let code = hex::decode($code).unwrap(); let data = hex::decode($data).unwrap(); - let mut vm = Machine::new(Rc::new(code), Rc::new(data), 1024, 10000, ()); + let machine = Machine::new(Rc::new(code), Rc::new(data), 1024, 10000, ()); + let mut vm = EtableInterpreter::new(machine, &ETABLE); assert_eq!( - vm.run(&mut (), &ETABLE), + vm.run(&mut ()), Capture::Exit(Ok(ExitSucceed::Returned.into())) ); assert_eq!(vm.retval, hex::decode($ret).unwrap()); diff --git a/interpreter/tests/usability.rs b/interpreter/tests/usability.rs index 0ac85d1b7..d21cdb471 100644 --- a/interpreter/tests/usability.rs +++ b/interpreter/tests/usability.rs @@ -1,6 +1,7 @@ use evm_interpreter::{ - Capture, Context, Control, Etable, ExitError, ExitSucceed, Log, Machine, Opcode, - RuntimeBackend, RuntimeBaseBackend, RuntimeEnvironment, RuntimeState, TransactionContext, + Capture, Context, Control, Etable, EtableInterpreter, ExitError, ExitSucceed, Interpreter, Log, + Machine, Opcode, RuntimeBackend, RuntimeBaseBackend, RuntimeEnvironment, RuntimeState, + TransactionContext, }; use primitive_types::{H160, H256, U256}; use std::rc::Rc; @@ -22,8 +23,9 @@ fn etable_wrap() { } }); - let mut vm = Machine::new(Rc::new(code), Rc::new(data), 1024, 10000, ()); - let result = vm.run(&mut (), &wrapped_etable); + let machine = Machine::new(Rc::new(code), Rc::new(data), 1024, 10000, ()); + let mut vm = EtableInterpreter::new(machine, &wrapped_etable); + let result = vm.run(&mut ()); assert_eq!(result, Capture::Exit(Ok(ExitSucceed::Returned))); assert_eq!(vm.retval, hex::decode(RET1).unwrap()); } @@ -51,8 +53,9 @@ fn etable_wrap2() { }, ); - let mut vm = Machine::new(Rc::new(code), Rc::new(data), 1024, 10000, ()); - let result = vm.run(&mut (), &wrapped_etable); + let machine = Machine::new(Rc::new(code), Rc::new(data), 1024, 10000, ()); + let mut vm = EtableInterpreter::new(machine, &wrapped_etable); + let result = vm.run(&mut ()); assert_eq!(result, Capture::Trap(Opcode(0x50))); } @@ -172,7 +175,7 @@ fn etable_runtime() { let data = hex::decode(DATA1).unwrap(); let mut handler = UnimplementedHandler; - let mut vm = Machine::new( + let machine = Machine::new( Rc::new(code), Rc::new(data), 1024, @@ -189,11 +192,11 @@ fn etable_runtime() { } .into(), retbuf: Vec::new(), - gas: U256::zero(), }, ); + let mut vm = EtableInterpreter::new(machine, &RUNTIME_ETABLE); - let res = vm.run(&mut handler, &RUNTIME_ETABLE).exit().unwrap(); + let res = vm.run(&mut handler).exit().unwrap(); assert_eq!(res, Ok(ExitSucceed::Returned)); assert_eq!(vm.retval, hex::decode(RET1).unwrap()); } diff --git a/jsontests/src/run.rs b/jsontests/src/run.rs index 60bf4ced7..7ee51edf7 100644 --- a/jsontests/src/run.rs +++ b/jsontests/src/run.rs @@ -1,9 +1,10 @@ use crate::error::{Error, TestError}; use crate::in_memory::{InMemoryAccount, InMemoryBackend, InMemoryEnvironment, InMemoryLayer}; use crate::types::*; -use evm::standard::{Config, Etable, EtableResolver, Gasometer, Invoker, TransactArgs}; +use evm::standard::{Config, Etable, EtableResolver, Invoker, TransactArgs}; use evm::utils::u256_to_h256; use evm::Capture; +use evm::{GasState, Interpreter}; use evm_precompile::StandardPrecompileSet; use primitive_types::U256; use std::collections::{BTreeMap, BTreeSet}; @@ -57,10 +58,12 @@ pub fn run_test(_filename: &str, _test_name: &str, test: Test, debug: bool) -> R }) .collect::>(); - let etable = Etable::runtime(); + let gas_etable = Etable::single(evm::standard::eval_gasometer); + let exec_etable = Etable::runtime(); + let etable = (gas_etable, exec_etable); let precompiles = StandardPrecompileSet::new(&config); let resolver = EtableResolver::new(&config, &precompiles, &etable); - let invoker = Invoker::<_, Gasometer, _, _, _>::new(&config, &resolver); + let invoker = Invoker::new(&config, &resolver); let args = TransactArgs::Call { caller: test.transaction.sender, address: test.transaction.to, @@ -102,12 +105,12 @@ pub fn run_test(_filename: &str, _test_name: &str, test: Test, debug: bool) -> R let _step_result = evm::HeapTransact::new(args, &invoker, &mut step_backend).and_then( |mut stepper| loop { { - if let Some(machine) = stepper.last_machine() { + if let Some(machine) = stepper.last_interpreter() { println!( "pc: {}, opcode: {:?}, gas: 0x{:x}", - machine.machine.position(), - machine.machine.peek_opcode(), - machine.gasometer.gas(), + machine.position(), + machine.peek_opcode(), + machine.machine().state.gas(), ); } } diff --git a/precompile/src/blake2/mod.rs b/precompile/src/blake2/mod.rs index 8b0c6c370..a5c19892b 100644 --- a/precompile/src/blake2/mod.rs +++ b/precompile/src/blake2/mod.rs @@ -1,7 +1,7 @@ mod eip152; use crate::PurePrecompile; -use evm::{ExitException, ExitResult, ExitSucceed, RuntimeState, StaticGasometer}; +use evm::{standard::GasMutState, ExitException, ExitResult, ExitSucceed}; pub struct Blake2F; @@ -9,15 +9,10 @@ impl Blake2F { const GAS_COST_PER_ROUND: u64 = 1; // https://eips.ethereum.org/EIPS/eip-152#gas-costs-and-benchmarks } -impl PurePrecompile for Blake2F { +impl PurePrecompile for Blake2F { /// Format of `input`: /// [4 bytes for rounds][64 bytes for h][128 bytes for m][8 bytes for t_0][8 bytes for t_1][1 byte for f] - fn execute( - &self, - input: &[u8], - _state: &RuntimeState, - gasometer: &mut G, - ) -> (ExitResult, Vec) { + fn execute(&self, input: &[u8], gasometer: &mut G) -> (ExitResult, Vec) { const BLAKE2_F_ARG_LEN: usize = 213; if input.len() != BLAKE2_F_ARG_LEN { @@ -35,7 +30,7 @@ impl PurePrecompile for Blake2F { let rounds: u32 = u32::from_be_bytes(rounds_buf); let gas_cost: u64 = (rounds as u64) * Blake2F::GAS_COST_PER_ROUND; - try_some!(gasometer.record_cost(gas_cost.into())); + try_some!(gasometer.record_gas(gas_cost.into())); // we use from_le_bytes below to effectively swap byte order to LE if architecture is BE let mut h_buf: [u8; 64] = [0; 64]; diff --git a/precompile/src/bn128.rs b/precompile/src/bn128.rs index 4bd97eadb..b82c76a55 100644 --- a/precompile/src/bn128.rs +++ b/precompile/src/bn128.rs @@ -1,6 +1,6 @@ use crate::PurePrecompile; use alloc::vec::Vec; -use evm::{ExitError, ExitException, ExitResult, ExitSucceed, RuntimeState, StaticGasometer}; +use evm::{standard::GasMutState, ExitError, ExitException, ExitResult, ExitSucceed}; use primitive_types::U256; /// Copy bytes from input to target. @@ -54,16 +54,11 @@ impl Bn128Add { const GAS_COST: u64 = 150; // https://eips.ethereum.org/EIPS/eip-1108 } -impl PurePrecompile for Bn128Add { - fn execute( - &self, - input: &[u8], - _state: &RuntimeState, - gasometer: &mut G, - ) -> (ExitResult, Vec) { +impl PurePrecompile for Bn128Add { + fn execute(&self, input: &[u8], gasometer: &mut G) -> (ExitResult, Vec) { use bn::AffineG1; - try_some!(gasometer.record_cost(Bn128Add::GAS_COST.into())); + try_some!(gasometer.record_gas(Bn128Add::GAS_COST.into())); let p1 = try_some!(read_point(input, 0)); let p2 = try_some!(read_point(input, 64)); @@ -93,16 +88,11 @@ impl Bn128Mul { const GAS_COST: u64 = 6_000; // https://eips.ethereum.org/EIPS/eip-1108 } -impl PurePrecompile for Bn128Mul { - fn execute( - &self, - input: &[u8], - _state: &RuntimeState, - gasometer: &mut G, - ) -> (ExitResult, Vec) { +impl PurePrecompile for Bn128Mul { + fn execute(&self, input: &[u8], gasometer: &mut G) -> (ExitResult, Vec) { use bn::AffineG1; - try_some!(gasometer.record_cost(Bn128Mul::GAS_COST.into())); + try_some!(gasometer.record_gas(Bn128Mul::GAS_COST.into())); let p = try_some!(read_point(input, 0)); let fr = try_some!(read_fr(input, 64)); @@ -134,17 +124,12 @@ impl Bn128Pairing { const GAS_COST_PER_PAIRING: u64 = 34_000; } -impl PurePrecompile for Bn128Pairing { - fn execute( - &self, - input: &[u8], - _state: &RuntimeState, - gasometer: &mut G, - ) -> (ExitResult, Vec) { +impl PurePrecompile for Bn128Pairing { + fn execute(&self, input: &[u8], gasometer: &mut G) -> (ExitResult, Vec) { use bn::{pairing_batch, AffineG1, AffineG2, Fq, Fq2, Group, Gt, G1, G2}; let ret_val = if input.is_empty() { - try_some!(gasometer.record_cost(Bn128Pairing::BASE_GAS_COST.into())); + try_some!(gasometer.record_gas(Bn128Pairing::BASE_GAS_COST.into())); U256::one() } else { if input.len() % 192 > 0 { @@ -160,7 +145,7 @@ impl PurePrecompile for Bn128Pairing { let gas_cost: u64 = Bn128Pairing::BASE_GAS_COST + (elements as u64 * Bn128Pairing::GAS_COST_PER_PAIRING); - try_some!(gasometer.record_cost(gas_cost.into())); + try_some!(gasometer.record_gas(gas_cost.into())); let mut vals = Vec::new(); for idx in 0..elements { diff --git a/precompile/src/lib.rs b/precompile/src/lib.rs index c519a0f44..d7c42f0c2 100644 --- a/precompile/src/lib.rs +++ b/precompile/src/lib.rs @@ -26,18 +26,13 @@ pub use crate::modexp::Modexp; pub use crate::simple::{ECRecover, Identity, Ripemd160, Sha256}; use alloc::vec::Vec; -use evm::standard::{Config, PrecompileSet}; -use evm::{ExitError, ExitException, ExitResult, RuntimeState, StaticGasometer}; +use evm::standard::{Config, GasMutState, PrecompileSet}; +use evm::{ExitError, ExitException, ExitResult, RuntimeState}; use primitive_types::H160; pub trait PurePrecompile { - fn execute( - &self, - input: &[u8], - state: &RuntimeState, - gasometer: &mut G, - ) -> (ExitResult, Vec); + fn execute(&self, input: &[u8], gasometer: &mut G) -> (ExitResult, Vec); } pub struct StandardPrecompileSet<'config> { @@ -50,38 +45,36 @@ impl<'config> StandardPrecompileSet<'config> { } } -impl<'config, S: AsRef, G: StaticGasometer, H> PrecompileSet +impl<'config, G: AsRef + GasMutState, H> PrecompileSet for StandardPrecompileSet<'config> { fn execute( &self, code_address: H160, input: &[u8], - _is_static: bool, - state: &mut S, gasometer: &mut G, _handler: &mut H, ) -> Option<(ExitResult, Vec)> { // TODO: selectively disable precompiles based on config. if code_address == address(1) { - Some(ECRecover.execute(input, state.as_ref(), gasometer)) + Some(ECRecover.execute(input, gasometer)) } else if code_address == address(2) { - Some(Sha256.execute(input, state.as_ref(), gasometer)) + Some(Sha256.execute(input, gasometer)) } else if code_address == address(3) { - Some(Ripemd160.execute(input, state.as_ref(), gasometer)) + Some(Ripemd160.execute(input, gasometer)) } else if code_address == address(4) { - Some(Identity.execute(input, state.as_ref(), gasometer)) + Some(Identity.execute(input, gasometer)) } else if code_address == address(5) { - Some(Modexp.execute(input, state.as_ref(), gasometer)) + Some(Modexp.execute(input, gasometer)) } else if code_address == address(6) { - Some(Bn128Add.execute(input, state.as_ref(), gasometer)) + Some(Bn128Add.execute(input, gasometer)) } else if code_address == address(7) { - Some(Bn128Mul.execute(input, state.as_ref(), gasometer)) + Some(Bn128Mul.execute(input, gasometer)) } else if code_address == address(8) { - Some(Bn128Pairing.execute(input, state.as_ref(), gasometer)) + Some(Bn128Pairing.execute(input, gasometer)) } else if code_address == address(9) { - Some(Blake2F.execute(input, state.as_ref(), gasometer)) + Some(Blake2F.execute(input, gasometer)) } else { None } diff --git a/precompile/src/modexp.rs b/precompile/src/modexp.rs index d1d1f6fc9..3053e586e 100644 --- a/precompile/src/modexp.rs +++ b/precompile/src/modexp.rs @@ -1,7 +1,7 @@ use crate::PurePrecompile; use alloc::{vec, vec::Vec}; use core::cmp::max; -use evm::{ExitException, ExitResult, ExitSucceed, RuntimeState, StaticGasometer}; +use evm::{standard::GasMutState, ExitException, ExitResult, ExitSucceed}; use num::{BigUint, FromPrimitive, Integer, One, ToPrimitive, Zero}; pub struct Modexp; @@ -86,13 +86,8 @@ fn read_input(source: &[u8], target: &mut [u8], source_offset: &mut usize) { target[..len].copy_from_slice(&source[offset..][..len]); } -impl PurePrecompile for Modexp { - fn execute( - &self, - input: &[u8], - _state: &RuntimeState, - gasometer: &mut G, - ) -> (ExitResult, Vec) { +impl PurePrecompile for Modexp { + fn execute(&self, input: &[u8], gasometer: &mut G) -> (ExitResult, Vec) { let mut input_offset = 0; // Yellowpaper: whenever the input is too short, the missing bytes are @@ -140,7 +135,7 @@ impl PurePrecompile for Modexp { // Gas formula allows arbitrary large exp_len when base and modulus are empty, so we need to handle empty base first. let r = if base_len == 0 && mod_len == 0 { - try_some!(gasometer.record_cost(MIN_GAS_COST.into())); + try_some!(gasometer.record_gas(MIN_GAS_COST.into())); BigUint::zero() } else { // read the numbers themselves. @@ -165,7 +160,7 @@ impl PurePrecompile for Modexp { modulus.is_even(), ); - try_some!(gasometer.record_cost(gas_cost.into())); + try_some!(gasometer.record_gas(gas_cost.into())); if modulus.is_zero() || modulus.is_one() { BigUint::zero() diff --git a/precompile/src/simple.rs b/precompile/src/simple.rs index d2efae35f..431b42dd9 100644 --- a/precompile/src/simple.rs +++ b/precompile/src/simple.rs @@ -1,17 +1,17 @@ use crate::{linear_cost, PurePrecompile}; use core::cmp::min; -use evm::{ExitException, ExitResult, ExitSucceed, RuntimeState, StaticGasometer}; +use evm::{standard::GasMutState, ExitException, ExitResult, ExitSucceed}; use k256::ecdsa::{RecoveryId, Signature, VerifyingKey}; use primitive_types::{H256, U256}; use sha3::{Digest, Keccak256}; pub struct ECRecover; -impl PurePrecompile for ECRecover { - fn execute(&self, i: &[u8], _state: &RuntimeState, gasometer: &mut G) -> (ExitResult, Vec) { +impl PurePrecompile for ECRecover { + fn execute(&self, i: &[u8], gasometer: &mut G) -> (ExitResult, Vec) { const COST_BASE: u64 = 3000; const COST_WORD: u64 = 0; - try_some!(gasometer.record_cost(U256::from(try_some!(linear_cost( + try_some!(gasometer.record_gas(U256::from(try_some!(linear_cost( i.len() as u64, COST_BASE, COST_WORD @@ -49,16 +49,11 @@ impl PurePrecompile for ECRecover { pub struct Sha256; -impl PurePrecompile for Sha256 { - fn execute( - &self, - input: &[u8], - _state: &RuntimeState, - gasometer: &mut G, - ) -> (ExitResult, Vec) { +impl PurePrecompile for Sha256 { + fn execute(&self, input: &[u8], gasometer: &mut G) -> (ExitResult, Vec) { const COST_BASE: u64 = 600; const COST_WORD: u64 = 120; - try_some!(gasometer.record_cost(U256::from(try_some!(linear_cost( + try_some!(gasometer.record_gas(U256::from(try_some!(linear_cost( input.len() as u64, COST_BASE, COST_WORD @@ -74,16 +69,11 @@ impl PurePrecompile for Sha256 { pub struct Ripemd160; -impl PurePrecompile for Ripemd160 { - fn execute( - &self, - input: &[u8], - _state: &RuntimeState, - gasometer: &mut G, - ) -> (ExitResult, Vec) { +impl PurePrecompile for Ripemd160 { + fn execute(&self, input: &[u8], gasometer: &mut G) -> (ExitResult, Vec) { const COST_BASE: u64 = 60; const COST_WORD: u64 = 12; - try_some!(gasometer.record_cost(U256::from(try_some!(linear_cost( + try_some!(gasometer.record_gas(U256::from(try_some!(linear_cost( input.len() as u64, COST_BASE, COST_WORD @@ -97,16 +87,11 @@ impl PurePrecompile for Ripemd160 { pub struct Identity; -impl PurePrecompile for Identity { - fn execute( - &self, - input: &[u8], - _state: &RuntimeState, - gasometer: &mut G, - ) -> (ExitResult, Vec) { +impl PurePrecompile for Identity { + fn execute(&self, input: &[u8], gasometer: &mut G) -> (ExitResult, Vec) { const COST_BASE: u64 = 15; const COST_WORD: u64 = 3; - try_some!(gasometer.record_cost(U256::from(try_some!(linear_cost( + try_some!(gasometer.record_gas(U256::from(try_some!(linear_cost( input.len() as u64, COST_BASE, COST_WORD diff --git a/src/call_stack.rs b/src/call_stack.rs index 72a23a9fb..2c0670f23 100644 --- a/src/call_stack.rs +++ b/src/call_stack.rs @@ -1,4 +1,7 @@ -use crate::{Capture, ExitError, ExitFatal, ExitResult, Invoker, InvokerControl, InvokerMachine}; +use crate::{ + Capture, ExitError, ExitFatal, ExitResult, Interpreter, Invoker, InvokerControl, + StepInterpreter, +}; use alloc::vec::Vec; use core::convert::Infallible; @@ -20,20 +23,20 @@ enum LastSubstackStatus { // Note: this should not be exposed to public because it does not implement // Drop. -struct CallStack<'backend, 'invoker, H, Tr, I: Invoker> { - stack: Vec>, - last: Option>, +struct CallStack<'backend, 'invoker, S, H, Tr, I: Invoker> { + stack: Vec>, + last: Option>, initial_depth: usize, backend: &'backend mut H, invoker: &'invoker I, } -impl<'backend, 'invoker, H, Tr, I> CallStack<'backend, 'invoker, H, Tr, I> +impl<'backend, 'invoker, S, H, Tr, I> CallStack<'backend, 'invoker, S, H, Tr, I> where - I: Invoker, + I: Invoker, { pub fn new( - machine: I::Machine, + machine: I::Interpreter, initial_depth: usize, backend: &'backend mut H, invoker: &'invoker I, @@ -51,7 +54,9 @@ where } #[allow(clippy::type_complexity)] - pub fn run(&mut self) -> Capture, I::Interrupt> { + pub fn run( + &mut self, + ) -> Capture, I::Interrupt> { loop { let step_ret = self.step_run(); @@ -61,23 +66,10 @@ where } } - #[allow(clippy::type_complexity)] - pub fn step( - &mut self, - ) -> Result<(), Capture, I::Interrupt>> { - self.step_with(|machine, handler| { - let result = machine.step(handler); - match result { - Ok(()) => LastSubstackStatus::Running, - Err(result) => LastSubstackStatus::Exited(result), - } - }) - } - #[allow(clippy::type_complexity)] pub fn step_run( &mut self, - ) -> Result<(), Capture, I::Interrupt>> { + ) -> Result<(), Capture, I::Interrupt>> { self.step_with(|machine, handler| { let result = machine.run(handler); LastSubstackStatus::Exited(result) @@ -88,9 +80,9 @@ where fn step_with( &mut self, fs: FS, - ) -> Result<(), Capture, I::Interrupt>> + ) -> Result<(), Capture, I::Interrupt>> where - FS: Fn(&mut I::Machine, &mut H) -> LastSubstackStatus, + FS: Fn(&mut I::Interpreter, &mut H) -> LastSubstackStatus, { let mut step_ret = None; @@ -214,15 +206,34 @@ where } } -fn execute( - mut machine: I::Machine, +impl<'backend, 'invoker, S, H, Tr, I> CallStack<'backend, 'invoker, S, H, Tr, I> +where + I: Invoker, + I::Interpreter: StepInterpreter, +{ + #[allow(clippy::type_complexity)] + pub fn step( + &mut self, + ) -> Result<(), Capture, I::Interrupt>> { + self.step_with(|machine, handler| { + let result = machine.step(handler); + match result { + Ok(()) => LastSubstackStatus::Running, + Err(result) => LastSubstackStatus::Exited(result), + } + }) + } +} + +fn execute( + mut machine: I::Interpreter, initial_depth: usize, heap_depth: Option, backend: &mut H, invoker: &I, -) -> Result<(ExitResult, I::Machine), ExitFatal> +) -> Result<(ExitResult, I::Interpreter), ExitFatal> where - I: Invoker, + I: Invoker, { let mut result = machine.run(backend); @@ -284,14 +295,14 @@ where } } -enum HeapTransactState<'backend, 'invoker, H, Tr, I: Invoker> { +enum HeapTransactState<'backend, 'invoker, S, H, Tr, I: Invoker> { Created { args: I::TransactArgs, invoker: &'invoker I, backend: &'backend mut H, }, Running { - call_stack: CallStack<'backend, 'invoker, H, Tr, I>, + call_stack: CallStack<'backend, 'invoker, S, H, Tr, I>, transact_invoke: I::TransactInvoke, }, } @@ -299,13 +310,13 @@ enum HeapTransactState<'backend, 'invoker, H, Tr, I: Invoker> { /// Heap-based call stack for a transaction. This is suitable for single /// stepping or debugging. The hybrid version [transact] uses a heap-based call /// stack internally after certain depth. -pub struct HeapTransact<'backend, 'invoker, H, Tr, I: Invoker>( - Option>, +pub struct HeapTransact<'backend, 'invoker, S, H, Tr, I: Invoker>( + Option>, ); -impl<'backend, 'invoker, H, Tr, I> HeapTransact<'backend, 'invoker, H, Tr, I> +impl<'backend, 'invoker, S, H, Tr, I> HeapTransact<'backend, 'invoker, S, H, Tr, I> where - I: Invoker, + I: Invoker, { /// Create a new heap-based call stack. pub fn new( @@ -327,8 +338,11 @@ where ) -> Result<(), Capture, I::Interrupt>> where FS: Fn( - &mut CallStack<'backend, 'invoker, H, Tr, I>, - ) -> Result<(), Capture, I::Interrupt>>, + &mut CallStack<'backend, 'invoker, S, H, Tr, I>, + ) -> Result< + (), + Capture, I::Interrupt>, + >, { let ret; @@ -401,14 +415,6 @@ where self.step_with(|call_stack| call_stack.step_run()) } - /// Step the call stack, and step the interpreter inside. - #[allow(clippy::type_complexity)] - pub fn step( - &mut self, - ) -> Result<(), Capture, I::Interrupt>> { - self.step_with(|call_stack| call_stack.step()) - } - /// Run the call stack until it exits or receives interrupts. pub fn run(&mut self) -> Capture, I::Interrupt> { loop { @@ -422,7 +428,7 @@ where /// The machine of the last item on the call stack. This will be `None` if /// the heap stack is just created. - pub fn last_machine(&self) -> Option<&I::Machine> { + pub fn last_interpreter(&self) -> Option<&I::Interpreter> { match &self.0 { Some(HeapTransactState::Running { call_stack, .. }) => match &call_stack.last { Some(last) => Some(&last.machine), @@ -433,9 +439,23 @@ where } } -impl<'backend, 'invoker, H, Tr, I> Drop for HeapTransact<'backend, 'invoker, H, Tr, I> +impl<'backend, 'invoker, S, H, Tr, I> HeapTransact<'backend, 'invoker, S, H, Tr, I> +where + I: Invoker, + I::Interpreter: StepInterpreter, +{ + /// Step the call stack, and step the interpreter inside. + #[allow(clippy::type_complexity)] + pub fn step( + &mut self, + ) -> Result<(), Capture, I::Interrupt>> { + self.step_with(|call_stack| call_stack.step()) + } +} + +impl<'backend, 'invoker, S, H, Tr, I> Drop for HeapTransact<'backend, 'invoker, S, H, Tr, I> where - I: Invoker, + I: Invoker, { fn drop(&mut self) { if let Some(HeapTransactState::Running { @@ -486,14 +506,14 @@ where /// /// Because a stack-based call stack cannot handle interrupts, the [Invoker] /// type must have its `Interrupt` type set to [Infallible]. -pub fn transact( +pub fn transact( args: I::TransactArgs, heap_depth: Option, backend: &mut H, invoker: &I, ) -> Result where - I: Invoker, + I: Invoker, { let (transact_invoke, control) = invoker.new_transact(args, backend)?; diff --git a/src/color.rs b/src/color.rs deleted file mode 100644 index d5e0fb153..000000000 --- a/src/color.rs +++ /dev/null @@ -1,126 +0,0 @@ -use crate::{ - Capture, Control, Etable, ExitResult, Gasometer, InvokerMachine, Machine, Opcode, RuntimeState, -}; -use alloc::vec::Vec; - -/// # Colored machine. -/// -/// A colored machine combines the machine interpreter, the gasometer, as well -/// as a [Color]. It's the machine type that is pushed into a standard -/// [crate::standard::Invoker] call stack. -/// -/// ## About the color field -/// -/// A color is anything that implements the [Color] trait, defining how the -/// combined machine should be stepped or ran. -/// -/// The standard color for a machine is an [Etable] (resolved by the standard -/// [crate::standard::EtableResolver]). The machine will use the opcode handler -/// defined in the etable for the machine invocation. -/// -/// A customized color can allow you to implement account versioning or a -/// complex precompile that invoke subcalls. -pub struct ColoredMachine { - /// The interpreter machine. - pub machine: Machine, - /// The gasometer. - pub gasometer: G, - /// Whether the current call stack is static. - pub is_static: bool, - /// The color of the machine. - pub color: C, -} - -impl InvokerMachine for ColoredMachine -where - C: Color, -{ - type Deconstruct = (S, G, Vec); - - fn step(&mut self, handler: &mut H) -> Result<(), Capture> { - self.color.step( - &mut self.machine, - &mut self.gasometer, - self.is_static, - handler, - ) - } - - fn run(&mut self, handler: &mut H) -> Capture { - self.color.run( - &mut self.machine, - &mut self.gasometer, - self.is_static, - handler, - ) - } - - fn deconstruct(self) -> Self::Deconstruct { - (self.machine.state, self.gasometer, self.machine.retval) - } -} - -/// A color of an machine. -pub trait Color { - /// Step the machine. - fn step( - &self, - machine: &mut Machine, - gasometer: &mut G, - is_static: bool, - handler: &mut H, - ) -> Result<(), Capture>; - - /// Run the machine. - fn run( - &self, - machine: &mut Machine, - gasometer: &mut G, - is_static: bool, - handler: &mut H, - ) -> Capture; -} - -impl<'etable, S, G, H, Tr, F> Color for &'etable Etable -where - S: AsMut, - G: Gasometer, - F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, -{ - fn step( - &self, - machine: &mut Machine, - gasometer: &mut G, - is_static: bool, - handler: &mut H, - ) -> Result<(), Capture> { - match gasometer.record_step(machine, is_static, handler) { - Ok(()) => { - machine.state.as_mut().gas = gasometer.gas(); - machine.step(handler, self) - } - Err(e) => Err(Capture::Exit(Err(e))), - } - } - - fn run( - &self, - machine: &mut Machine, - gasometer: &mut G, - is_static: bool, - handler: &mut H, - ) -> Capture { - loop { - match gasometer.record_stepn(machine, is_static, handler) { - Ok(stepn) => { - machine.state.as_mut().gas = gasometer.gas(); - match machine.stepn(stepn, handler, self) { - Ok(()) => (), - Err(c) => return c, - } - } - Err(e) => return Capture::Exit(Err(e)), - } - } - } -} diff --git a/src/gasometer.rs b/src/gasometer.rs index c3bef47f9..d28a9b96d 100644 --- a/src/gasometer.rs +++ b/src/gasometer.rs @@ -1,34 +1,11 @@ //! EVM gasometer. -use crate::{ExitError, Machine}; +use crate::{ExitError, GasState}; use primitive_types::U256; /// A static gasometer, exposing functions for precompile cost recording or for /// transactions. -pub trait StaticGasometer: Sized { +pub trait GasometerState: GasState { fn record_cost(&mut self, cost: U256) -> Result<(), ExitError>; fn record_codedeposit(&mut self, len: usize) -> Result<(), ExitError>; - fn gas(&self) -> U256; -} - -/// A gasometer that is suitable for an interpreter machine. -pub trait Gasometer: StaticGasometer { - /// Record gas cost for a single opcode step. - fn record_step( - &mut self, - machine: &Machine, - is_static: bool, - backend: &H, - ) -> Result<(), ExitError>; - /// Record gas cost, advancing as much as possible (possibly into the next - /// branch). Returns the number of advances. - fn record_stepn( - &mut self, - machine: &Machine, - is_static: bool, - backend: &H, - ) -> Result { - self.record_step(machine, is_static, backend)?; - Ok(1) - } } diff --git a/src/invoker.rs b/src/invoker.rs index 9ae829bef..f4d4ea321 100644 --- a/src/invoker.rs +++ b/src/invoker.rs @@ -1,4 +1,5 @@ -use crate::{Capture, ExitError, ExitResult}; +use crate::{Capture, ExitError, ExitResult, Interpreter}; +use alloc::vec::Vec; /// Control for an invoker. pub enum InvokerControl { @@ -8,28 +9,9 @@ pub enum InvokerControl { DirectExit(VD), } -/// A machine that is put onto the call stack. -pub trait InvokerMachine { - /// Deconstruct value of the machine. - /// - /// This type is needed bacause an invoker may not push a value onto the - /// call stack, but directly exit. In the latter case, it should return the - /// deconstruct value. When popping from the call stack, we also deconstruct - /// the machine to the deconstruct value, thus unifying the types. - type Deconstruct; - - /// Step the machine using a handler. - fn step(&mut self, handler: &mut H) -> Result<(), Capture>; - /// Run the machine until it returns. - fn run(&mut self, handler: &mut H) -> Capture; - /// Deconstruct the machine to its deconstruct value. - fn deconstruct(self) -> Self::Deconstruct; -} - /// An invoker, responsible for pushing/poping values in the call stack. -pub trait Invoker { - /// Machine type on the call stack. - type Machine: InvokerMachine; +pub trait Invoker { + type Interpreter: Interpreter; /// Possible interrupt type that may be returned by the call stack. type Interrupt; @@ -53,13 +35,7 @@ pub trait Invoker { ) -> Result< ( Self::TransactInvoke, - InvokerControl< - Self::Machine, - ( - ExitResult, - >::Deconstruct, - ), - >, + InvokerControl))>, ), ExitError, >; @@ -69,7 +45,7 @@ pub trait Invoker { &self, invoke: &Self::TransactInvoke, exit: ExitResult, - machine: >::Deconstruct, + machine: (S, Vec), handler: &mut H, ) -> Result; @@ -78,20 +54,14 @@ pub trait Invoker { fn enter_substack( &self, trap: Tr, - machine: &mut Self::Machine, + machine: &mut Self::Interpreter, handler: &mut H, depth: usize, ) -> Capture< Result< ( Self::SubstackInvoke, - InvokerControl< - Self::Machine, - ( - ExitResult, - >::Deconstruct, - ), - >, + InvokerControl))>, ), ExitError, >, @@ -102,9 +72,9 @@ pub trait Invoker { fn exit_substack( &self, result: ExitResult, - child: >::Deconstruct, + child: (S, Vec), trap_data: Self::SubstackInvoke, - parent: &mut Self::Machine, + parent: &mut Self::Interpreter, handler: &mut H, ) -> Result<(), ExitError>; } diff --git a/src/lib.rs b/src/lib.rs index 9018da0ce..1410334b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,7 +69,6 @@ pub mod backend; pub mod standard; mod call_stack; -mod color; mod gasometer; mod invoker; @@ -77,9 +76,8 @@ pub use evm_interpreter::*; pub use crate::backend::TransactionalBackend; pub use crate::call_stack::{transact, HeapTransact}; -pub use crate::color::{Color, ColoredMachine}; -pub use crate::gasometer::{Gasometer, StaticGasometer}; -pub use crate::invoker::{Invoker, InvokerControl, InvokerMachine}; +pub use crate::gasometer::GasometerState; +pub use crate::invoker::{Invoker, InvokerControl}; /// Merge strategy of a backend substate layer or a call stack gasometer layer. #[derive(Clone, Debug, Copy)] diff --git a/src/standard/gasometer/mod.rs b/src/standard/gasometer/mod.rs index d3ac5eb13..a526de53b 100644 --- a/src/standard/gasometer/mod.rs +++ b/src/standard/gasometer/mod.rs @@ -4,55 +4,23 @@ mod utils; use crate::standard::Config; use crate::{ - ExitError, ExitException, ExitFatal, Gasometer as GasometerT, Machine, MergeStrategy, Opcode, - RuntimeBackend, RuntimeState, Stack, StaticGasometer, + Control, ExitError, ExitException, Machine, MergeStrategy, Opcode, RuntimeBackend, + RuntimeState, Stack, }; use alloc::vec::Vec; use core::cmp::{max, min}; use primitive_types::{H160, H256, U256}; -/// A gasometer that handles transaction metering. -pub trait TransactGasometer<'config, S: AsRef>: Sized { - /// Create a new top-layer gasometer from a call transaction. - fn new_transact_call( - gas_limit: U256, - data: &[u8], - access_list: &[(H160, Vec)], - config: &'config Config, - ) -> Result; - - /// Create a new top-layer gasometer from a create transaction. - fn new_transact_create( - gas_limit: U256, - code: &[u8], - access_list: &[(H160, Vec)], - config: &'config Config, - ) -> Result; - - /// Effective gas, assuming the current gasometer is a top-layer gasometer, - /// reducing the amount of refunded gas. - fn effective_gas(&self) -> U256; - - /// Derive a sub-gasometer from the current one, pushing the call stack. - fn submeter(&mut self, gas_limit: U256, call_has_value: bool) -> Result; - - /// Merge a sub-gasometer using the given strategy, poping the call stack. - fn merge(&mut self, other: Self, strategy: MergeStrategy); - - /// Analyse the code so that the gasometer can apply further optimizations. - fn analyse_code(&mut self, _code: &[u8]) {} -} - -/// Standard gasometer implementation. -pub struct Gasometer<'config> { +pub struct GasometerState<'config> { gas_limit: u64, memory_gas: u64, used_gas: u64, refunded_gas: u64, - config: &'config Config, + pub is_static: bool, + pub config: &'config Config, } -impl<'config> Gasometer<'config> { +impl<'config> GasometerState<'config> { /// Perform any operation on the gasometer. Set the gasometer to `OutOfGas` /// if the operation fails. #[inline] @@ -82,12 +50,16 @@ impl<'config> Gasometer<'config> { } /// Left gas that is supposed to be available to the current interpreter. - pub fn gas(&self) -> u64 { + pub fn gas64(&self) -> u64 { self.gas_limit - self.memory_gas - self.used_gas } + pub fn gas(&self) -> U256 { + self.gas64().into() + } + /// Record an explicit cost. - pub fn record_cost(&mut self, cost: u64) -> Result<(), ExitError> { + pub fn record_gas64(&mut self, cost: u64) -> Result<(), ExitError> { let all_gas_cost = self.total_used_gas().checked_add(cost); if let Some(all_gas_cost) = all_gas_cost { if self.gas_limit < all_gas_cost { @@ -101,6 +73,22 @@ impl<'config> Gasometer<'config> { } } + pub fn record_gas(&mut self, cost: U256) -> Result<(), ExitError> { + if cost > U256::from(u64::MAX) { + return Err(ExitException::OutOfGas.into()); + } + + self.record_gas64(cost.as_u64()) + } + + pub fn record_codedeposit(&mut self, len: usize) -> Result<(), ExitError> { + self.perform(|gasometer| { + let cost = len as u64 * consts::G_CODEDEPOSIT; + gasometer.record_gas64(cost)?; + Ok(()) + }) + } + /// Set memory gas usage. pub fn set_memory_gas(&mut self, memory_cost: u64) -> Result<(), ExitError> { let all_gas_cost = self.used_gas.checked_add(memory_cost); @@ -117,19 +105,18 @@ impl<'config> Gasometer<'config> { } /// Create a new gasometer with the given gas limit and chain config. - pub fn new(gas_limit: u64, config: &'config Config) -> Self { + pub fn new(gas_limit: u64, is_static: bool, config: &'config Config) -> Self { Self { gas_limit, memory_gas: 0, used_gas: 0, refunded_gas: 0, + is_static, config, } } -} -impl<'config, S: AsRef> TransactGasometer<'config, S> for Gasometer<'config> { - fn new_transact_call( + pub fn new_transact_call( gas_limit: U256, data: &[u8], access_list: &[(H160, Vec)], @@ -141,14 +128,14 @@ impl<'config, S: AsRef> TransactGasometer<'config, S> for Gasomete gas_limit.as_u64() }; - let mut s = Self::new(gas_limit, config); + let mut s = Self::new(gas_limit, false, config); let transaction_cost = TransactionCost::call(data, access_list).cost(config); - s.record_cost(transaction_cost)?; + s.record_gas64(transaction_cost)?; Ok(s) } - fn new_transact_create( + pub fn new_transact_create( gas_limit: U256, code: &[u8], access_list: &[(H160, Vec)], @@ -160,14 +147,14 @@ impl<'config, S: AsRef> TransactGasometer<'config, S> for Gasomete gas_limit.as_u64() }; - let mut s = Self::new(gas_limit, config); + let mut s = Self::new(gas_limit, false, config); let transaction_cost = TransactionCost::create(code, access_list).cost(config); - s.record_cost(transaction_cost)?; + s.record_gas64(transaction_cost)?; Ok(s) } - fn effective_gas(&self) -> U256 { + pub fn effective_gas(&self) -> U256 { U256::from( self.gas_limit - (self.total_used_gas() @@ -178,107 +165,109 @@ impl<'config, S: AsRef> TransactGasometer<'config, S> for Gasomete ) } - fn submeter(&mut self, gas_limit: U256, call_has_value: bool) -> Result { + pub fn submeter( + &mut self, + gas_limit: U256, + is_static: bool, + call_has_value: bool, + ) -> Result { let mut gas_limit = if gas_limit > U256::from(u64::MAX) { return Err(ExitException::OutOfGas.into()); } else { gas_limit.as_u64() }; - self.record_cost(gas_limit)?; + self.record_gas64(gas_limit)?; if call_has_value { gas_limit = gas_limit.saturating_add(self.config.call_stipend); } - Ok(Self::new(gas_limit, self.config)) + Ok(Self::new(gas_limit, is_static, self.config)) } - fn merge(&mut self, other: Self, strategy: MergeStrategy) { + pub fn merge(&mut self, other: Self, strategy: MergeStrategy) { match strategy { MergeStrategy::Commit => { - self.used_gas -= other.gas(); + self.used_gas -= other.gas64(); self.refunded_gas += other.refunded_gas; } MergeStrategy::Revert => { - self.used_gas -= other.gas(); + self.used_gas -= other.gas64(); } MergeStrategy::Discard => {} } } } -impl<'config> StaticGasometer for Gasometer<'config> { - fn record_codedeposit(&mut self, len: usize) -> Result<(), ExitError> { - self.perform(|gasometer| { - let cost = len as u64 * consts::G_CODEDEPOSIT; - gasometer.record_cost(cost)?; - Ok(()) - }) - } - - fn record_cost(&mut self, cost: U256) -> Result<(), ExitError> { - if cost > U256::from(u64::MAX) { - return Err(ExitException::OutOfGas.into()); - } - - self.record_cost(cost.as_u64()) - } - - fn gas(&self) -> U256 { - self.gas().into() +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) { + Ok(()) => Control::Continue, + Err(err) => Control::Exit(Err(err)), } } -impl<'config, S: AsRef, H: RuntimeBackend> GasometerT for Gasometer<'config> { - fn record_step( - &mut self, - machine: &Machine, - is_static: bool, - handler: &H, - ) -> Result<(), ExitError> { - if machine.is_empty() { - return Ok(()); - } +fn eval_to_result<'config, S, H>( + machine: &mut Machine, + handler: &mut H, + opcode: Opcode, + _position: usize, +) -> Result<(), ExitError> +where + S: AsRef> + AsMut> + AsRef, + H: RuntimeBackend, +{ + if machine.code().is_empty() { + return Ok(()); + } - self.perform(|gasometer| { - let opcode = machine.peek_opcode().ok_or(ExitFatal::AlreadyExited)?; + let address = AsRef::::as_ref(&machine.state) + .context + .address; - if let Some(cost) = consts::STATIC_COST_TABLE[opcode.as_usize()] { - gasometer.record_cost(cost)?; + machine.state.as_mut().perform(|gasometer| { + if let Some(cost) = consts::STATIC_COST_TABLE[opcode.as_usize()] { + gasometer.record_gas64(cost)?; + } else { + let (gas, memory_gas) = dynamic_opcode_cost( + address, + opcode, + &machine.stack, + gasometer.is_static, + gasometer.config, + handler, + )?; + let cost = gas.cost(gasometer.gas64(), gasometer.config)?; + let refund = gas.refund(gasometer.config); + + gasometer.record_gas64(cost)?; + if refund >= 0 { + gasometer.refunded_gas += refund as u64; } else { - let address = machine.state.as_ref().context.address; - let (gas, memory_gas) = dynamic_opcode_cost( - address, - opcode, - &machine.stack, - is_static, - gasometer.config, - handler, - )?; - let cost = gas.cost(gasometer.gas(), gasometer.config)?; - let refund = gas.refund(gasometer.config); - - gasometer.record_cost(cost)?; - if refund >= 0 { - gasometer.refunded_gas += refund as u64; - } else { - gasometer.refunded_gas = gasometer.refunded_gas.saturating_sub(-refund as u64); - } - if let Some(memory_gas) = memory_gas { - let memory_cost = memory_gas.cost()?; - if let Some(memory_cost) = memory_cost { - gasometer.set_memory_gas(max(gasometer.memory_gas, memory_cost))?; - } + gasometer.refunded_gas = gasometer.refunded_gas.saturating_sub(-refund as u64); + } + if let Some(memory_gas) = memory_gas { + let memory_cost = memory_gas.cost()?; + if let Some(memory_cost) = memory_cost { + gasometer.set_memory_gas(max(gasometer.memory_gas, memory_cost))?; } - - let after_gas = gasometer.gas(); - gas.extra_check(after_gas, gasometer.config)?; } - Ok(()) - }) - } + let after_gas = gasometer.gas64(); + gas.extra_check(after_gas, gasometer.config)?; + } + + Ok(()) + }) } /// Calculate the opcode cost. diff --git a/src/standard/invoker/mod.rs b/src/standard/invoker/mod.rs index f677abfed..383b08c00 100644 --- a/src/standard/invoker/mod.rs +++ b/src/standard/invoker/mod.rs @@ -1,18 +1,19 @@ mod resolver; mod routines; +mod state; -use alloc::vec::Vec; -pub use resolver::{EtableResolver, PrecompileSet, Resolver}; +pub use self::resolver::{EtableResolver, PrecompileSet, Resolver}; +pub use self::state::InvokerState; -use super::{Config, MergeableRuntimeState, TransactGasometer}; +use super::Config; use crate::call_create::{CallCreateTrapData, CallTrapData, CreateScheme, CreateTrapData}; use crate::{ - Capture, ColoredMachine, Context, ExitError, ExitException, ExitResult, ExitSucceed, - Gasometer as GasometerT, Invoker as InvokerT, InvokerControl, MergeStrategy, Opcode, - RuntimeBackend, RuntimeEnvironment, RuntimeState, TransactionContext, TransactionalBackend, - Transfer, + Capture, Context, ExitError, ExitException, ExitResult, ExitSucceed, Interpreter, + Invoker as InvokerT, InvokerControl, MergeStrategy, Opcode, RuntimeBackend, RuntimeEnvironment, + RuntimeState, TransactionContext, TransactionalBackend, Transfer, }; use alloc::rc::Rc; +use alloc::vec::Vec; use core::cmp::min; use core::convert::Infallible; use core::marker::PhantomData; @@ -136,19 +137,17 @@ impl TransactArgs { /// /// The generic parameters are as follows: /// * `S`: The runtime state, usually [RuntimeState] but can be customized. -/// * `G`: Gasometer type, usually [crate::standard::Gasometer] but can be -/// customized. /// * `H`: Backend type. /// * `R`: Code resolver type, also handle precompiles. Usually /// [EtableResolver] but can be customized. /// * `Tr`: Trap type, usually [crate::Opcode] but can be customized. -pub struct Invoker<'config, 'resolver, S, G, H, R, Tr> { +pub struct Invoker<'config, 'resolver, S, H, R, Tr> { config: &'config Config, resolver: &'resolver R, - _marker: PhantomData<(S, G, H, Tr)>, + _marker: PhantomData<(S, H, Tr)>, } -impl<'config, 'resolver, S, G, H, R, Tr> Invoker<'config, 'resolver, S, G, H, R, Tr> { +impl<'config, 'resolver, S, H, R, Tr> Invoker<'config, 'resolver, S, H, R, Tr> { /// Create a new standard invoker with the given config and resolver. pub fn new(config: &'config Config, resolver: &'resolver R) -> Self { Self { @@ -159,16 +158,15 @@ impl<'config, 'resolver, S, G, H, R, Tr> Invoker<'config, 'resolver, S, G, H, R, } } -impl<'config, 'resolver, S, G, H, R, Tr> InvokerT - for Invoker<'config, 'resolver, S, G, H, R, Tr> +impl<'config, 'resolver, S, H, R, Tr> InvokerT + for Invoker<'config, 'resolver, S, H, R, Tr> where - S: MergeableRuntimeState>, - G: GasometerT + TransactGasometer<'config, S>, + S: InvokerState<'config> + AsRef + AsMut, H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, - R: Resolver, + R: Resolver, Tr: IntoCallCreateTrap, { - type Machine = ColoredMachine; + type Interpreter = R::Interpreter; type Interrupt = Tr::Interrupt; type TransactArgs = TransactArgs; type TransactInvoke = TransactInvoke; @@ -177,12 +175,12 @@ where fn new_transact( &self, - args: TransactArgs, + args: Self::TransactArgs, handler: &mut H, ) -> Result< ( - TransactInvoke, - InvokerControl, (ExitResult, (S, G, Vec))>, + Self::TransactInvoke, + InvokerControl))>, ), ExitError, > { @@ -262,23 +260,25 @@ where } } - let gasometer = - G::new_transact_call(gas_limit, &data, &access_list, self.config)?; + let state = S::new_transact_call( + RuntimeState { + context, + transaction_context: Rc::new(transaction_context), + retbuf: Vec::new(), + }, + gas_limit, + &data, + &access_list, + self.config, + )?; let machine = routines::make_enter_call_machine( self.config, self.resolver, address, data, - false, // is_static Some(transfer), - S::new_transact_call(RuntimeState { - context, - transaction_context: Rc::new(transaction_context), - retbuf: Vec::new(), - gas: gas_limit, - }), - gasometer, + state, handler, )?; @@ -300,23 +300,25 @@ where access_list, .. } => { - let gasometer = - G::new_transact_create(gas_limit, &init_code, &access_list, self.config)?; + let state = S::new_transact_create( + RuntimeState { + context, + transaction_context: Rc::new(transaction_context), + retbuf: Vec::new(), + }, + gas_limit, + &init_code, + &access_list, + self.config, + )?; let machine = routines::make_enter_create_machine( self.config, self.resolver, caller, init_code, - false, // is_static transfer, - S::new_transact_create(RuntimeState { - context, - transaction_context: Rc::new(transaction_context), - retbuf: Vec::new(), - gas: gas_limit, - }), - gasometer, + state, handler, )?; @@ -336,12 +338,12 @@ where fn finalize_transact( &self, - invoke: &TransactInvoke, + invoke: &Self::TransactInvoke, result: ExitResult, - (_substate, mut submeter, retval): (S, G, Vec), + (mut substate, retval): (S, Vec), handler: &mut H, ) -> Result { - let left_gas = submeter.effective_gas(); + let left_gas = substate.effective_gas(); let work = || -> Result { if result.is_ok() { @@ -351,8 +353,8 @@ where routines::deploy_create_code( self.config, address, - &retbuf, - &mut submeter, + retbuf, + &mut substate, handler, )?; } @@ -388,18 +390,18 @@ where fn enter_substack( &self, trap: Tr, - machine: &mut ColoredMachine, + machine: &mut Self::Interpreter, handler: &mut H, depth: usize, ) -> Capture< Result< ( - SubstackInvoke, - InvokerControl, (ExitResult, (S, G, Vec))>, + Self::SubstackInvoke, + InvokerControl))>, ), ExitError, >, - Tr::Interrupt, + Self::Interrupt, > { fn l64(gas: U256) -> U256 { gas - gas / U256::from(64) @@ -414,15 +416,15 @@ where return Capture::Exit(Err(ExitException::CallTooDeep.into())); } - let trap_data = match CallCreateTrapData::new_from(opcode, &mut machine.machine) { + let trap_data = match CallCreateTrapData::new_from(opcode, machine.machine_mut()) { Ok(trap_data) => trap_data, Err(err) => return Capture::Exit(Err(err)), }; let after_gas = if self.config.call_l64_after_gas { - l64(machine.gasometer.gas()) + l64(machine.machine().state.gas()) } else { - machine.gasometer.gas() + machine.machine().state.gas() }; let target_gas = trap_data.target_gas().unwrap_or(after_gas); let gas_limit = min(after_gas, target_gas); @@ -430,7 +432,7 @@ where let call_has_value = matches!(&trap_data, CallCreateTrapData::Call(call) if call.has_value()); - let is_static = if machine.is_static { + let is_static = if machine.machine().state.is_static() { true } else { match &trap_data { @@ -439,24 +441,23 @@ where } }; - let transaction_context = machine.machine.state.as_ref().transaction_context.clone(); + let transaction_context = machine.machine().state.as_ref().transaction_context.clone(); match trap_data { CallCreateTrapData::Call(call_trap_data) => { - let submeter = match machine.gasometer.submeter(gas_limit, call_has_value) { - Ok(submeter) => submeter, - Err(err) => return Capture::Exit(Err(err)), - }; - - let substate = machine.machine.state.substate( + let substate = match machine.machine_mut().state.substate( RuntimeState { context: call_trap_data.context.clone(), transaction_context, retbuf: Vec::new(), - gas: gas_limit, }, - machine, - ); + gas_limit, + is_static, + call_has_value, + ) { + Ok(submeter) => submeter, + Err(err) => return Capture::Exit(Err(err)), + }; let target = call_trap_data.target; @@ -465,22 +466,16 @@ where self.resolver, call_trap_data, target, - is_static, substate, - submeter, handler, )) } CallCreateTrapData::Create(create_trap_data) => { - let code = create_trap_data.code.clone(); - let submeter = match machine.gasometer.submeter(gas_limit, call_has_value) { - Ok(submeter) => submeter, - Err(err) => return Capture::Exit(Err(err)), - }; - let caller = create_trap_data.scheme.caller(); let address = create_trap_data.scheme.address(handler); - let substate = machine.machine.state.substate( + let code = create_trap_data.code.clone(); + + let substate = match machine.machine_mut().state.substate( RuntimeState { context: Context { address, @@ -489,19 +484,21 @@ where }, transaction_context, retbuf: Vec::new(), - gas: gas_limit, }, - machine, - ); + gas_limit, + is_static, + call_has_value, + ) { + Ok(submeter) => submeter, + Err(err) => return Capture::Exit(Err(err)), + }; Capture::Exit(routines::enter_create_substack( self.config, self.resolver, code, create_trap_data, - is_static, substate, - submeter, handler, )) } @@ -511,9 +508,9 @@ where fn exit_substack( &self, result: ExitResult, - (substate, submeter, retval): (S, G, Vec), - trap_data: SubstackInvoke, - parent: &mut ColoredMachine, + (mut substate, retval): (S, Vec), + trap_data: Self::SubstackInvoke, + parent: &mut Self::Interpreter, handler: &mut H, ) -> Result<(), ExitError> { let strategy = match &result { @@ -525,37 +522,35 @@ where match trap_data { SubstackInvoke::Create { address, trap } => { let retbuf = retval; - parent.machine.state.merge(substate, strategy); - let mut child_gasometer = submeter; let result = result.and_then(|_| { routines::deploy_create_code( self.config, address, - &retbuf, - &mut child_gasometer, + retbuf.clone(), + &mut substate, handler, )?; Ok(address) }); + parent.machine_mut().state.merge(substate, strategy); handler.pop_substate(strategy); - TransactGasometer::::merge(&mut parent.gasometer, child_gasometer, strategy); - trap.feedback(result, retbuf, &mut parent.machine)?; + trap.feedback(result, retbuf, parent.machine_mut())?; + parent.advance(); Ok(()) } SubstackInvoke::Call { trap } => { - parent.machine.state.merge(substate, strategy); - let retbuf = retval; + parent.machine_mut().state.merge(substate, strategy); handler.pop_substate(strategy); - TransactGasometer::::merge(&mut parent.gasometer, submeter, strategy); - trap.feedback(result, retbuf, &mut parent.machine)?; + trap.feedback(result, retbuf, parent.machine_mut())?; + parent.advance(); Ok(()) } diff --git a/src/standard/invoker/resolver.rs b/src/standard/invoker/resolver.rs index 93d4b4e22..1155bf60c 100644 --- a/src/standard/invoker/resolver.rs +++ b/src/standard/invoker/resolver.rs @@ -1,11 +1,9 @@ -use super::routines; -use crate::standard::{Config, TransactGasometer}; use crate::{ - Color, ColoredMachine, Control, Etable, ExitError, ExitResult, Gasometer, InvokerControl, - Machine, Opcode, RuntimeBackend, RuntimeState, + standard::Config, EtableInterpreter, EtableSet, ExitError, ExitResult, Interpreter, + InvokerControl, Machine, RuntimeBackend, RuntimeState, }; -use alloc::rc::Rc; -use alloc::vec::Vec; +use alloc::{rc::Rc, vec::Vec}; +use core::marker::PhantomData; use primitive_types::H160; /// A code resolver. @@ -14,9 +12,8 @@ use primitive_types::H160; /// (with the init code) is turned into a colored machine. The resolver can /// construct a machine, pushing the call stack, or directly exit, handling a /// precompile. -pub trait Resolver { - /// Color of the machine. See [ColoredMachine] for more information. - type Color: Color; +pub trait Resolver { + type Interpreter: Interpreter; /// Resolve a call (with the target code address). #[allow(clippy::type_complexity)] @@ -24,53 +21,39 @@ pub trait Resolver { &self, code_address: H160, input: Vec, - is_static: bool, state: S, - gasometer: G, handler: &mut H, - ) -> Result< - InvokerControl, (ExitResult, (S, G, Vec))>, - ExitError, - >; + ) -> Result))>, ExitError>; /// Resolve a create (with the init code). #[allow(clippy::type_complexity)] fn resolve_create( &self, init_code: Vec, - is_static: bool, state: S, - gasometer: G, handler: &mut H, - ) -> Result< - InvokerControl, (ExitResult, (S, G, Vec))>, - ExitError, - >; + ) -> Result))>, ExitError>; } /// A set of precompiles. -pub trait PrecompileSet { +pub trait PrecompileSet { /// Attempt to execute the precompile at the given `code_address`. Returns /// `None` if it's not a precompile. fn execute( &self, code_address: H160, input: &[u8], - is_static: bool, state: &mut S, - gasometer: &mut G, handler: &mut H, ) -> Option<(ExitResult, Vec)>; } -impl PrecompileSet for () { +impl PrecompileSet for () { fn execute( &self, _code_address: H160, _input: &[u8], - _is_static: bool, _state: &mut S, - _gasometer: &mut G, _handler: &mut H, ) -> Option<(ExitResult, Vec)> { None @@ -79,64 +62,54 @@ impl PrecompileSet for () { /// The standard code resolver where the color is an [Etable]. This is usually /// what you need. -pub struct EtableResolver<'config, 'precompile, 'etable, S, H, Pre, Tr, F> { +pub struct EtableResolver<'config, 'precompile, 'etable, S, H, Pre, Tr, ES> { config: &'config Config, - etable: &'etable Etable, + etable: &'etable ES, precompiles: &'precompile Pre, + _marker: PhantomData<(S, H, Tr)>, } -impl<'config, 'precompile, 'etable, S, H, Pre, Tr, F> - EtableResolver<'config, 'precompile, 'etable, S, H, Pre, Tr, F> +impl<'config, 'precompile, 'etable, S, H, Pre, Tr, ES> + EtableResolver<'config, 'precompile, 'etable, S, H, Pre, Tr, ES> { - /// Create a new [Etable] code resolver. pub fn new( config: &'config Config, precompiles: &'precompile Pre, - etable: &'etable Etable, + etable: &'etable ES, ) -> Self { Self { config, precompiles, etable, + _marker: PhantomData, } } } -impl<'config, 'precompile, 'etable, S, G, H, Pre, Tr, F> Resolver - for EtableResolver<'config, 'precompile, 'etable, S, H, Pre, Tr, F> +impl<'config, 'precompile, 'etable, S, H, Pre, Tr, ES> Resolver + for EtableResolver<'config, 'precompile, 'etable, S, H, Pre, Tr, ES> where S: AsRef + AsMut, - G: Gasometer + TransactGasometer<'config, S>, - F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, H: RuntimeBackend, - Pre: PrecompileSet, + Pre: PrecompileSet, + ES: EtableSet, { - type Color = &'etable Etable; + type Interpreter = EtableInterpreter<'etable, S, H, Tr, ES>; + /// Resolve a call (with the target code address). + #[allow(clippy::type_complexity)] fn resolve_call( &self, code_address: H160, input: Vec, - is_static: bool, mut state: S, - mut gasometer: G, handler: &mut H, - ) -> Result< - InvokerControl< - ColoredMachine>, - (ExitResult, (S, G, Vec)), - >, - ExitError, - > { - if let Some((r, retval)) = self.precompiles.execute( - code_address, - &input, - is_static, - &mut state, - &mut gasometer, - handler, - ) { - return Ok(InvokerControl::DirectExit((r, (state, gasometer, retval)))); + ) -> Result))>, ExitError> { + if let Some((r, retval)) = + self.precompiles + .execute(code_address, &input, &mut state, handler) + { + return Ok(InvokerControl::DirectExit((r, (state, retval)))); } let code = handler.code(code_address); @@ -149,31 +122,19 @@ where state, ); - let mut ret = InvokerControl::Enter(ColoredMachine { - machine, - gasometer, - is_static, - color: self.etable, - }); - routines::maybe_analyse_code(&mut ret); + let ret = InvokerControl::Enter(EtableInterpreter::new(machine, self.etable)); Ok(ret) } + /// Resolve a create (with the init code). + #[allow(clippy::type_complexity)] fn resolve_create( &self, init_code: Vec, - is_static: bool, state: S, - gasometer: G, _handler: &mut H, - ) -> Result< - InvokerControl< - ColoredMachine>, - (ExitResult, (S, G, Vec)), - >, - ExitError, - > { + ) -> Result))>, ExitError> { let machine = Machine::new( Rc::new(init_code), Rc::new(Vec::new()), @@ -182,13 +143,7 @@ where state, ); - let mut ret = InvokerControl::Enter(ColoredMachine { - machine, - gasometer, - is_static, - color: self.etable, - }); - routines::maybe_analyse_code(&mut ret); + let ret = InvokerControl::Enter(EtableInterpreter::new(machine, self.etable)); Ok(ret) } diff --git a/src/standard/invoker/routines.rs b/src/standard/invoker/routines.rs index c3b7763d5..cac2b7e0f 100644 --- a/src/standard/invoker/routines.rs +++ b/src/standard/invoker/routines.rs @@ -1,39 +1,26 @@ -use super::{CallTrapData, CreateTrapData, Resolver, SubstackInvoke, TransactGasometer}; +use super::{CallTrapData, CreateTrapData, InvokerState, Resolver, SubstackInvoke}; use crate::standard::Config; use crate::{ - ColoredMachine, ExitError, ExitException, ExitResult, Gasometer as GasometerT, InvokerControl, - MergeStrategy, Opcode, RuntimeBackend, RuntimeEnvironment, RuntimeState, StaticGasometer, - TransactionalBackend, Transfer, + ExitError, ExitException, ExitResult, InvokerControl, MergeStrategy, Opcode, RuntimeBackend, + RuntimeEnvironment, RuntimeState, TransactionalBackend, Transfer, }; use alloc::vec::Vec; use primitive_types::{H160, U256}; -#[allow(clippy::type_complexity)] -pub fn maybe_analyse_code<'config, S: AsRef, G: TransactGasometer<'config, S>, C>( - result: &mut InvokerControl, (ExitResult, (S, G, Vec))>, -) { - if let InvokerControl::Enter(machine) = result { - machine.gasometer.analyse_code(machine.machine.code()) - } -} - #[allow(clippy::too_many_arguments, clippy::type_complexity)] -pub fn make_enter_call_machine( +pub fn make_enter_call_machine( _config: &Config, resolver: &R, code_address: H160, input: Vec, - is_static: bool, transfer: Option, state: S, - gasometer: G, handler: &mut H, -) -> Result, (ExitResult, (S, G, Vec))>, ExitError> +) -> Result))>, ExitError> where S: AsRef, - G: GasometerT, H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, - R: Resolver, + R: Resolver, { handler.mark_hot(state.as_ref().context.address, None); @@ -41,26 +28,23 @@ where handler.transfer(transfer)?; } - resolver.resolve_call(code_address, input, is_static, state, gasometer, handler) + resolver.resolve_call(code_address, input, state, handler) } #[allow(clippy::type_complexity, clippy::too_many_arguments)] -pub fn make_enter_create_machine( +pub fn make_enter_create_machine( config: &Config, resolver: &R, caller: H160, init_code: Vec, - is_static: bool, transfer: Transfer, state: S, - gasometer: G, handler: &mut H, -) -> Result, (ExitResult, (S, G, Vec))>, ExitError> +) -> Result))>, ExitError> where S: AsRef, - G: GasometerT, H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, - R: Resolver, + R: Resolver, { if let Some(limit) = config.max_initcode_size { if init_code.len() > limit { @@ -85,31 +69,28 @@ where handler.reset_storage(state.as_ref().context.address); - resolver.resolve_create(init_code, is_static, state, gasometer, handler) + resolver.resolve_create(init_code, state, handler) } #[allow(clippy::type_complexity, clippy::too_many_arguments)] -pub fn enter_call_substack<'config, S, G, H, R, Tr>( - config: &'config Config, +pub fn enter_call_substack( + config: &Config, resolver: &R, trap_data: CallTrapData, code_address: H160, - is_static: bool, state: S, - gasometer: G, handler: &mut H, ) -> Result< ( SubstackInvoke, - InvokerControl, (ExitResult, (S, G, Vec))>, + InvokerControl))>, ), ExitError, > where S: AsRef, - G: GasometerT + TransactGasometer<'config, S>, H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, - R: Resolver, + R: Resolver, { handler.push_substate(); @@ -119,10 +100,8 @@ where resolver, code_address, trap_data.input.clone(), - is_static, trap_data.transfer.clone(), state, - gasometer, handler, )?; @@ -139,31 +118,28 @@ where } #[allow(clippy::type_complexity, clippy::too_many_arguments)] -pub fn enter_create_substack<'config, S, G, H, R, Tr>( - config: &'config Config, +pub fn enter_create_substack( + config: &Config, resolver: &R, code: Vec, trap_data: CreateTrapData, - is_static: bool, state: S, - gasometer: G, handler: &mut H, ) -> Result< ( SubstackInvoke, - InvokerControl, (ExitResult, (S, G, Vec))>, + InvokerControl))>, ), ExitError, > where S: AsRef, - G: GasometerT + TransactGasometer<'config, S>, H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, - R: Resolver, + R: Resolver, { handler.push_substate(); - let work = || -> Result<(SubstackInvoke, InvokerControl, (ExitResult, (S, G, Vec))>), ExitError> { + let work = || -> Result<(SubstackInvoke, InvokerControl))>), ExitError> { let CreateTrapData { scheme, value, @@ -180,7 +156,7 @@ where }; let machine = make_enter_create_machine( - config, resolver, caller, code, is_static, transfer, state, gasometer, handler, + config, resolver, caller, code, transfer, state, handler, )?; Ok(( @@ -208,15 +184,15 @@ fn check_first_byte(config: &Config, code: &[u8]) -> Result<(), ExitError> { Ok(()) } -pub fn deploy_create_code( +pub fn deploy_create_code<'config, S, H>( config: &Config, address: H160, - retbuf: &Vec, - gasometer: &mut G, + retbuf: Vec, + state: &mut S, handler: &mut H, ) -> Result<(), ExitError> where - G: GasometerT, + S: InvokerState<'config>, H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, { check_first_byte(config, &retbuf[..])?; @@ -227,9 +203,9 @@ where } } - StaticGasometer::record_codedeposit(gasometer, retbuf.len())?; + state.record_codedeposit(retbuf.len())?; - handler.set_code(address, retbuf.clone())?; + handler.set_code(address, retbuf)?; Ok(()) } diff --git a/src/standard/invoker/state.rs b/src/standard/invoker/state.rs new file mode 100644 index 000000000..eef276a28 --- /dev/null +++ b/src/standard/invoker/state.rs @@ -0,0 +1,35 @@ +use crate::{standard::Config, ExitError, GasState, MergeStrategy, RuntimeState}; +use alloc::vec::Vec; +use primitive_types::{H160, H256, U256}; + +pub trait InvokerState<'config>: GasState + Sized { + fn new_transact_call( + runtime: RuntimeState, + gas_limit: U256, + data: &[u8], + access_list: &[(H160, Vec)], + config: &'config Config, + ) -> Result; + fn new_transact_create( + runtime: RuntimeState, + gas_limit: U256, + code: &[u8], + access_list: &[(H160, Vec)], + config: &'config Config, + ) -> Result; + + fn substate( + &mut self, + runtime: RuntimeState, + gas_limit: U256, + is_static: bool, + call_has_value: bool, + ) -> Result; + fn merge(&mut self, substate: Self, strategy: MergeStrategy); + + fn record_codedeposit(&mut self, len: usize) -> Result<(), ExitError>; + + fn is_static(&self) -> bool; + fn effective_gas(&self) -> U256; + fn config(&self) -> &Config; +} diff --git a/src/standard/mod.rs b/src/standard/mod.rs index bf712929a..556cdaadc 100644 --- a/src/standard/mod.rs +++ b/src/standard/mod.rs @@ -9,52 +9,125 @@ mod gasometer; mod invoker; pub use self::config::Config; -pub use self::gasometer::{Gasometer, TransactGasometer}; -pub use self::invoker::{EtableResolver, Invoker, PrecompileSet, Resolver, TransactArgs}; +pub use self::gasometer::{eval as eval_gasometer, GasometerState}; +pub use self::invoker::{ + EtableResolver, Invoker, InvokerState, PrecompileSet, Resolver, TransactArgs, +}; -/// Standard EVM machine, where the runtime state is [crate::RuntimeState]. -pub type Machine = crate::Machine; +use crate::{ExitError, GasState, MergeStrategy, RuntimeState}; +use alloc::vec::Vec; +use primitive_types::{H160, H256, U256}; + +/// Standard machine. +pub type Machine<'config> = crate::Machine>; /// Standard Etable opcode handle function. -pub type Efn = crate::Efn; +pub type Efn<'config, H> = crate::Efn, H, crate::Opcode>; /// Standard Etable. -pub type Etable> = crate::Etable; - -/// Standard colored machine, combining an interpreter machine, a gasometer, and the standard -/// "color" -- an etable. -pub type ColoredMachine<'etable, G, H, F = Efn> = - crate::ColoredMachine>; - -/// Simply [Invoker] with common generics fixed, using standard [Gasometer] and standard trap -/// [crate::Opcode]. -pub type SimpleInvoker<'config, 'resolver, H, R> = - Invoker<'config, 'resolver, crate::RuntimeState, Gasometer<'config>, H, R, crate::Opcode>; - -/// A runtime state that can be merged across call stack substate layers. -pub trait MergeableRuntimeState: - AsRef + AsMut -{ - /// Derive a new substate from the substate runtime. - fn substate(&self, runtime: crate::RuntimeState, parent: &M) -> Self; - /// Merge a substate into the current runtime state, using the given - /// strategy. - fn merge(&mut self, substate: Self, strategy: crate::MergeStrategy); - /// Create a new top-layer runtime state with a call transaction. - fn new_transact_call(runtime: crate::RuntimeState) -> Self; - /// Create a new top-layer runtime state with a create transaction. - fn new_transact_create(runtime: crate::RuntimeState) -> Self; -} - -impl MergeableRuntimeState for crate::RuntimeState { - fn substate(&self, runtime: crate::RuntimeState, _parent: &M) -> Self { - runtime - } - fn merge(&mut self, _substate: Self, _strategy: crate::MergeStrategy) {} - fn new_transact_call(runtime: crate::RuntimeState) -> Self { - runtime - } - fn new_transact_create(runtime: crate::RuntimeState) -> Self { - runtime +pub type Etable<'config, H, F = Efn<'config, H>> = + crate::Etable, H, crate::Opcode, F>; + +pub trait GasMutState: GasState { + fn record_gas(&mut self, gas: U256) -> Result<(), ExitError>; +} + +pub struct State<'config> { + pub runtime: RuntimeState, + pub gasometer: GasometerState<'config>, +} + +impl<'config> AsRef for State<'config> { + fn as_ref(&self) -> &RuntimeState { + &self.runtime + } +} + +impl<'config> AsMut for State<'config> { + fn as_mut(&mut self) -> &mut RuntimeState { + &mut self.runtime + } +} + +impl<'config> AsRef> for State<'config> { + fn as_ref(&self) -> &GasometerState<'config> { + &self.gasometer + } +} + +impl<'config> AsMut> for State<'config> { + fn as_mut(&mut self) -> &mut GasometerState<'config> { + &mut self.gasometer + } +} + +impl<'config> GasState for State<'config> { + fn gas(&self) -> U256 { + self.gasometer.gas() + } +} + +impl<'config> GasMutState for State<'config> { + fn record_gas(&mut self, gas: U256) -> Result<(), ExitError> { + self.gasometer.record_gas(gas) + } +} + +impl<'config> InvokerState<'config> for State<'config> { + fn new_transact_call( + runtime: RuntimeState, + gas_limit: U256, + data: &[u8], + access_list: &[(H160, Vec)], + config: &'config Config, + ) -> Result { + Ok(Self { + runtime, + gasometer: GasometerState::new_transact_call(gas_limit, data, access_list, config)?, + }) + } + fn new_transact_create( + runtime: RuntimeState, + gas_limit: U256, + code: &[u8], + access_list: &[(H160, Vec)], + config: &'config Config, + ) -> Result { + Ok(Self { + runtime, + gasometer: GasometerState::new_transact_create(gas_limit, code, access_list, config)?, + }) + } + + fn substate( + &mut self, + runtime: RuntimeState, + gas_limit: U256, + is_static: bool, + call_has_value: bool, + ) -> Result { + Ok(Self { + runtime, + gasometer: self + .gasometer + .submeter(gas_limit, is_static, call_has_value)?, + }) + } + fn merge(&mut self, substate: Self, strategy: MergeStrategy) { + self.gasometer.merge(substate.gasometer, strategy) + } + + fn record_codedeposit(&mut self, len: usize) -> Result<(), ExitError> { + self.gasometer.record_codedeposit(len) + } + + fn is_static(&self) -> bool { + self.gasometer.is_static + } + fn effective_gas(&self) -> U256 { + self.gasometer.effective_gas() + } + fn config(&self) -> &Config { + self.gasometer.config } } diff --git a/tracer/src/standard.rs b/tracer/src/standard.rs index ff9687ebc..1177cf0f7 100644 --- a/tracer/src/standard.rs +++ b/tracer/src/standard.rs @@ -1,11 +1,11 @@ -use evm::standard::Machine; -use evm::{Opcode, RuntimeState}; +use evm::standard::{Machine, State}; +use evm::Opcode; pub trait EvalTracer { fn on_eval(&mut self, machine: &Machine, handle: &H, opcode: Opcode, position: usize); } -impl> crate::EvalTracer for T { +impl<'config, H, T: EvalTracer> crate::EvalTracer, H> for T { fn on_eval(&mut self, machine: &Machine, handle: &H, opcode: Opcode, position: usize) { EvalTracer::::on_eval(self, machine, handle, opcode, position) }