From d88016e71bd1d0a405b7ab2e49ec4d57dae2d37d Mon Sep 17 00:00:00 2001 From: rakita Date: Sat, 3 Dec 2022 19:03:47 +0100 Subject: [PATCH 1/5] feat(interpreter): Unify instraction fucntion signature --- Cargo.lock | 7 + Cargo.toml | 4 +- bins/revm-test/Cargo.toml | 1 + bins/revm-test/src/bin/analysis.rs | 1 - bins/revm-test/src/bin/snailtracer.rs | 27 +- crates/revm/src/evm.rs | 1 - crates/revm/src/evm_impl.rs | 87 ++--- crates/revm/src/instructions.rs | 310 ++++++++--------- crates/revm/src/instructions/arithmetic.rs | 132 +++----- crates/revm/src/instructions/bitwise.rs | 105 ++++-- crates/revm/src/instructions/control.rs | 80 ++--- crates/revm/src/instructions/host.rs | 377 +++++++++++---------- crates/revm/src/instructions/host_env.rs | 51 ++- crates/revm/src/instructions/macros.rs | 164 +++++---- crates/revm/src/instructions/memory.rs | 42 ++- crates/revm/src/instructions/stack.rs | 35 +- crates/revm/src/instructions/system.rs | 141 ++++---- crates/revm/src/interpreter.rs | 57 ++-- crates/revm/src/interpreter/stack.rs | 27 +- crates/revm/src/models.rs | 2 + crates/revm/src/specification.rs | 33 +- 21 files changed, 835 insertions(+), 849 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a756805ad3..c0043cbdd3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -987,6 +987,12 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "microbench" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4c44e40aee4e6fd2f4257bb91e5948ce79285aeb949129448889cf2fbf6da0b" + [[package]] name = "mime" version = "0.3.16" @@ -1523,6 +1529,7 @@ version = "0.1.0" dependencies = [ "bytes", "hex", + "microbench", "revm", ] diff --git a/Cargo.toml b/Cargo.toml index d465674fa0..93cd42a6a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ members = [ default-members = ["crates/revm"] [profile.release] -# debug = true +debug = true lto = true codegen-units = 1 @@ -17,4 +17,4 @@ inherits = "test" opt-level = 3 [patch.crates-io] -ruint = { git = "https://github.com/recmo/uint" } \ No newline at end of file +ruint = { git = "https://github.com/recmo/uint" } diff --git a/bins/revm-test/Cargo.toml b/bins/revm-test/Cargo.toml index 982acc1f90..84eafe6527 100644 --- a/bins/revm-test/Cargo.toml +++ b/bins/revm-test/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" bytes = "1.1" hex = "0.4" revm = { path = "../../crates/revm", version = "2.3.1" } +microbench = "0.5" [[bin]] name = "analysis" diff --git a/bins/revm-test/src/bin/analysis.rs b/bins/revm-test/src/bin/analysis.rs index 42e9d7c6fb..d77e4508df 100644 --- a/bins/revm-test/src/bin/analysis.rs +++ b/bins/revm-test/src/bin/analysis.rs @@ -2,7 +2,6 @@ use std::time::Instant; use bytes::Bytes; use revm::{db::BenchmarkDB, Bytecode, TransactTo}; - extern crate alloc; fn main() { diff --git a/bins/revm-test/src/bin/snailtracer.rs b/bins/revm-test/src/bin/snailtracer.rs index 421b320f90..ae2e48b4f4 100644 --- a/bins/revm-test/src/bin/snailtracer.rs +++ b/bins/revm-test/src/bin/snailtracer.rs @@ -1,4 +1,4 @@ -use std::time::Instant; +use std::time::Duration; use bytes::Bytes; use revm::{db::BenchmarkDB, Bytecode, TransactTo}; @@ -23,21 +23,16 @@ pub fn simple_example() { ); evm.env.tx.data = Bytes::from(hex::decode("30627b7c").unwrap()); - let mut elapsed = std::time::Duration::ZERO; - let mut times = Vec::new(); - for _ in 0..30 { - let timer = Instant::now(); - let (_, _) = evm.transact(); - let i = timer.elapsed(); - times.push(i); - elapsed += i; - } - println!("elapsed: {:?}", elapsed / 30); - let mut times = times[5..].to_vec(); - times.sort(); - for (i, time) in times.iter().rev().enumerate() { - println!("{i}: {time:?}"); - } + // Microbenchmark + let bench_options = microbench::Options::default().time(Duration::from_secs(3)); + + microbench::bench( + &bench_options, + "Snailtracer benchmark", + || { + let (_, _) = evm.transact(); + }, + ); } fn main() { diff --git a/crates/revm/src/evm.rs b/crates/revm/src/evm.rs index 5b864e015c..fa7c61a858 100644 --- a/crates/revm/src/evm.rs +++ b/crates/revm/src/evm.rs @@ -23,7 +23,6 @@ use revm_precompiles::Precompiles; /// want to update anything on it. It enabled `transact_ref` and `inspect_ref` functions /// * Database+DatabaseCommit allow directly committing changes of transaction. it enabled `transact_commit` /// and `inspect_commit` - #[derive(Clone)] pub struct EVM { pub env: Env, diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index 43df9c4e2e..722bf73192 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -1,5 +1,4 @@ use crate::{ - bits::{B160, B256}, common::keccak256, db::Database, gas, @@ -10,7 +9,7 @@ use crate::{ precompiles, return_ok, return_revert, AnalysisKind, CallContext, CallInputs, CallScheme, CreateInputs, CreateScheme, Env, ExecutionResult, Gas, Inspector, Log, Return, Spec, SpecId::{self, *}, - TransactOut, TransactTo, Transfer, KECCAK_EMPTY, U256, + TransactOut, TransactTo, Transfer, B160, B256, KECCAK_EMPTY, U256, }; use alloc::vec::Vec; use bytes::Bytes; @@ -167,8 +166,9 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact input: data, gas_limit, context, + is_static: false, }; - let (exit, gas, bytes) = self.call_inner::(&mut call_input); + let (exit, gas, bytes) = self.call_inner(&mut call_input); (exit, gas, TransactOut::Call(bytes)) } TransactTo::Create(scheme) => { @@ -179,7 +179,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact init_code: data, gas_limit, }; - let (exit, address, ret_gas, bytes) = self.create_inner::(&mut create_input); + let (exit, address, ret_gas, bytes) = self.create_inner(&mut create_input); (exit, ret_gas, TransactOut::Create(bytes, address)) } }; @@ -378,10 +378,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, } } - fn create_inner( - &mut self, - inputs: &mut CreateInputs, - ) -> (Return, Option, Gas, Bytes) { + fn create_inner(&mut self, inputs: &mut CreateInputs) -> (Return, Option, Gas, Bytes) { // Call inspector if INSPECT { let (ret, address, gas, out) = self.inspector.create(&mut self.data, inputs); @@ -457,7 +454,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, } // EIP-161: State trie clearing (invariant-preserving alternative) - if SPEC::enabled(SPURIOUS_DRAGON) + if GSPEC::enabled(SPURIOUS_DRAGON) && self .data .journaled_state @@ -470,7 +467,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, } // Create new interpreter and execute initcode - let contract = Contract::new::( + let contract = Contract::new::( Bytes::new(), Bytecode::new_raw(inputs.init_code.clone()), created_address, @@ -486,13 +483,13 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, ); #[cfg(not(feature = "memory_limit"))] - let mut interp = Interpreter::new::(contract, gas.limit()); + let mut interp = Interpreter::new::(contract, gas.limit(), false); - if Self::INSPECT { + if INSPECT { self.inspector - .initialize_interp(&mut interp, &mut self.data, SPEC::IS_STATIC_CALL); + .initialize_interp(&mut interp, &mut self.data, false); } - let exit_reason = interp.run::(self); + let exit_reason = interp.run::(self, INSPECT); // Host error if present on execution\ let (ret, address, gas, out) = match exit_reason { @@ -502,14 +499,14 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, let mut bytes = interp.return_value(); // EIP-3541: Reject new contract code starting with the 0xEF byte - if SPEC::enabled(LONDON) && !bytes.is_empty() && bytes.first() == Some(&0xEF) { + if GSPEC::enabled(LONDON) && !bytes.is_empty() && bytes.first() == Some(&0xEF) { self.data.journaled_state.checkpoint_revert(checkpoint); return (Return::CreateContractWithEF, ret, interp.gas, b); } // EIP-170: Contract code size limit // By default limit is 0x6000 (~25kb) - if SPEC::enabled(SPURIOUS_DRAGON) + if GSPEC::enabled(SPURIOUS_DRAGON) && bytes.len() > self.data.env.cfg.limit_contract_code_size.unwrap_or(0x6000) { self.data.journaled_state.checkpoint_revert(checkpoint); @@ -522,7 +519,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, // EIP-2 point 3: If contract creation does not have enough gas to pay for the // final gas fee for adding the contract code to the state, the contract // creation fails (i.e. goes out-of-gas) rather than leaving an empty contract. - if SPEC::enabled(HOMESTEAD) { + if GSPEC::enabled(HOMESTEAD) { self.data.journaled_state.checkpoint_revert(checkpoint); return (Return::OutOfGas, ret, interp.gas, b); } else { @@ -536,7 +533,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, let bytecode = match self.data.env.cfg.perf_analyse_created_bytecodes { AnalysisKind::Raw => Bytecode::new_raw(bytes), AnalysisKind::Check => Bytecode::new_raw(bytes).to_checked(), - AnalysisKind::Analyse => Bytecode::new_raw(bytes).to_analysed::(), + AnalysisKind::Analyse => Bytecode::new_raw(bytes).to_analysed::(), }; self.data @@ -558,12 +555,12 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, } } - fn call_inner(&mut self, inputs: &mut CallInputs) -> (Return, Gas, Bytes) { + fn call_inner(&mut self, inputs: &mut CallInputs) -> (Return, Gas, Bytes) { // Call the inspector if INSPECT { let (ret, gas, out) = self .inspector - .call(&mut self.data, inputs, SPEC::IS_STATIC_CALL); + .call(&mut self.data, inputs, inputs.is_static); if ret != Return::Continue { return self.inspector.call_end( &mut self.data, @@ -571,7 +568,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, gas, ret, out, - SPEC::IS_STATIC_CALL, + inputs.is_static, ); } } @@ -587,14 +584,14 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, // Check depth if self.data.journaled_state.depth() > interpreter::CALL_STACK_LIMIT { let (ret, gas, out) = (Return::CallTooDeep, gas, Bytes::new()); - if Self::INSPECT { + if INSPECT { return self.inspector.call_end( &mut self.data, inputs, gas, ret, out, - SPEC::IS_STATIC_CALL, + inputs.is_static, ); } else { return (ret, gas, out); @@ -619,14 +616,14 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, ) { self.data.journaled_state.checkpoint_revert(checkpoint); let (ret, gas, out) = (e, gas, Bytes::new()); - if Self::INSPECT { + if INSPECT { return self.inspector.call_end( &mut self.data, inputs, gas, ret, out, - SPEC::IS_STATIC_CALL, + inputs.is_static, ); } else { return (ret, gas, out); @@ -664,8 +661,11 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, } } else { // Create interpreter and execute subcall - let contract = - Contract::new_with_context::(inputs.input.clone(), bytecode, &inputs.context); + let contract = Contract::new_with_context::( + inputs.input.clone(), + bytecode, + &inputs.context, + ); #[cfg(feature = "memory_limit")] let mut interp = Interpreter::new_with_memory_limit::( @@ -675,14 +675,14 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, ); #[cfg(not(feature = "memory_limit"))] - let mut interp = Interpreter::new::(contract, gas.limit()); + let mut interp = Interpreter::new::(contract, gas.limit(), inputs.is_static); - if Self::INSPECT { + if INSPECT { // create is always no static call. self.inspector .initialize_interp(&mut interp, &mut self.data, false); } - let exit_reason = interp.run::(self); + let exit_reason = interp.run::(self, INSPECT); if matches!(exit_reason, return_ok!()) { self.data.journaled_state.checkpoint_commit(); } else { @@ -694,7 +694,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, if INSPECT { self.inspector - .call_end(&mut self.data, inputs, gas, ret, out, SPEC::IS_STATIC_CALL) + .call_end(&mut self.data, inputs, gas, ret, out, inputs.is_static) } else { (ret, gas, out) } @@ -704,9 +704,6 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, impl<'a, GSPEC: Spec, DB: Database + 'a, const INSPECT: bool> Host for EVMImpl<'a, GSPEC, DB, INSPECT> { - const INSPECT: bool = INSPECT; - type DB = DB; - fn step(&mut self, interp: &mut Interpreter, is_static: bool) -> Return { self.inspector.step(interp, &mut self.data, is_static) } @@ -827,15 +824,12 @@ impl<'a, GSPEC: Spec, DB: Database + 'a, const INSPECT: bool> Host .ok() } - fn create( - &mut self, - inputs: &mut CreateInputs, - ) -> (Return, Option, Gas, Bytes) { - self.create_inner::(inputs) + fn create(&mut self, inputs: &mut CreateInputs) -> (Return, Option, Gas, Bytes) { + self.create_inner(inputs) } - fn call(&mut self, inputs: &mut CallInputs) -> (Return, Gas, Bytes) { - self.call_inner::(inputs) + fn call(&mut self, inputs: &mut CallInputs) -> (Return, Gas, Bytes) { + self.call_inner(inputs) } } @@ -862,10 +856,6 @@ pub fn create2_address(caller: B160, code_hash: B256, salt: U256) -> B160 { /// EVM context host. pub trait Host { - const INSPECT: bool; - - type DB: Database; - fn step(&mut self, interp: &mut Interpreter, is_static: bool) -> Return; fn step_end(&mut self, interp: &mut Interpreter, is_static: bool, ret: Return) -> Return; @@ -895,10 +885,7 @@ pub trait Host { /// Mark an address to be deleted, with funds transferred to target. fn selfdestruct(&mut self, address: B160, target: B160) -> Option; /// Invoke a create operation. - fn create( - &mut self, - inputs: &mut CreateInputs, - ) -> (Return, Option, Gas, Bytes); + fn create(&mut self, inputs: &mut CreateInputs) -> (Return, Option, Gas, Bytes); /// Invoke a call operation. - fn call(&mut self, input: &mut CallInputs) -> (Return, Gas, Bytes); + fn call(&mut self, input: &mut CallInputs) -> (Return, Gas, Bytes); } diff --git a/crates/revm/src/instructions.rs b/crates/revm/src/instructions.rs index faaaa0fb75..a3cb11ee60 100644 --- a/crates/revm/src/instructions.rs +++ b/crates/revm/src/instructions.rs @@ -11,11 +11,9 @@ pub mod opcode; mod stack; mod system; +use crate::{interpreter::Interpreter, Host, Spec}; pub use opcode::{OpCode, OPCODE_JUMPMAP}; -use crate::{interpreter::Interpreter, CallScheme, Host, Spec, SpecId::*, U256}; -use core::ops::{BitAnd, BitOr, BitXor}; - #[macro_export] macro_rules! return_ok { () => { @@ -74,175 +72,165 @@ pub enum Return { CreateContractWithEF, } +pub fn return_stop(interpreter: &mut Interpreter, _host: &mut dyn Host) { + interpreter.instruction_result = Return::Stop; +} +pub fn return_invalid(interpreter: &mut Interpreter, _host: &mut dyn Host) { + interpreter.instruction_result = Return::InvalidOpcode; +} + +pub fn return_not_found(interpreter: &mut Interpreter, _host: &mut dyn Host) { + interpreter.instruction_result = Return::OpcodeNotFound; +} + #[inline(always)] -pub fn eval(opcode: u8, interp: &mut Interpreter, host: &mut H) -> Return { +pub fn eval(opcode: u8, interp: &mut Interpreter, host: &mut H) { match opcode { - /*12_u8..=15_u8 => Return::OpcodeNotFound, - 30_u8..=31_u8 => Return::OpcodeNotFound, - 33_u8..=47_u8 => Return::OpcodeNotFound, - 73_u8..=79_u8 => Return::OpcodeNotFound, - 92_u8..=95_u8 => Return::OpcodeNotFound, - 165_u8..=239_u8 => Return::OpcodeNotFound, - 246_u8..=249_u8 => Return::OpcodeNotFound, - 251_u8..=252_u8 => Return::OpcodeNotFound,*/ - opcode::STOP => Return::Stop, - opcode::ADD => op2_u256!(interp, wrapping_add), - opcode::MUL => op2_u256!(interp, wrapping_mul), - opcode::SUB => op2_u256!(interp, wrapping_sub), - opcode::DIV => op2_u256_fn!(interp, arithmetic::div), - opcode::SDIV => op2_u256_fn!(interp, arithmetic::sdiv), - opcode::MOD => op2_u256_fn!(interp, arithmetic::rem), - opcode::SMOD => op2_u256_fn!(interp, arithmetic::smod), - opcode::ADDMOD => op3_u256_fn!(interp, arithmetic::addmod), - opcode::MULMOD => op3_u256_fn!(interp, arithmetic::mulmod), - opcode::EXP => arithmetic::eval_exp::(interp), - opcode::SIGNEXTEND => op2_u256_fn!(interp, arithmetic::signextend), - opcode::LT => op2_u256_bool_ref!(interp, lt), - opcode::GT => op2_u256_bool_ref!(interp, gt), - opcode::SLT => op2_u256_fn!(interp, bitwise::slt), - opcode::SGT => op2_u256_fn!(interp, bitwise::sgt), - opcode::EQ => op2_u256_bool_ref!(interp, eq), - opcode::ISZERO => op1_u256_fn!(interp, bitwise::iszero), - opcode::AND => op2_u256!(interp, bitand), - opcode::OR => op2_u256!(interp, bitor), - opcode::XOR => op2_u256!(interp, bitxor), - opcode::NOT => op1_u256_fn!(interp, bitwise::not), - opcode::BYTE => op2_u256_fn!(interp, bitwise::byte), - opcode::SHL => op2_u256_fn!( - interp, - bitwise::shl, - S::enabled(CONSTANTINOPLE) // EIP-145: Bitwise shifting instructions in EVM - ), - opcode::SHR => op2_u256_fn!( - interp, - bitwise::shr, - S::enabled(CONSTANTINOPLE) // EIP-145: Bitwise shifting instructions in EVM - ), - opcode::SAR => op2_u256_fn!( - interp, - bitwise::sar, - S::enabled(CONSTANTINOPLE) // EIP-145: Bitwise shifting instructions in EVM - ), - opcode::SHA3 => system::sha3(interp), - - opcode::ADDRESS => system::address(interp), - opcode::BALANCE => host::balance::(interp, host), - opcode::SELFBALANCE => host::selfbalance::(interp, host), - opcode::CODESIZE => system::codesize(interp), - opcode::CODECOPY => system::codecopy(interp), - opcode::CALLDATALOAD => system::calldataload(interp), - opcode::CALLDATASIZE => system::calldatasize(interp), - opcode::CALLDATACOPY => system::calldatacopy(interp), - opcode::POP => stack::pop(interp), - opcode::MLOAD => memory::mload(interp), - opcode::MSTORE => memory::mstore(interp), - opcode::MSTORE8 => memory::mstore8(interp), - opcode::JUMP => control::jump(interp), - opcode::JUMPI => control::jumpi(interp), - opcode::PC => control::pc(interp), - opcode::MSIZE => memory::msize(interp), - opcode::JUMPDEST => control::jumpdest(interp), - opcode::PUSH1 => stack::push::<1>(interp), - opcode::PUSH2 => stack::push::<2>(interp), - opcode::PUSH3 => stack::push::<3>(interp), - opcode::PUSH4 => stack::push::<4>(interp), - opcode::PUSH5 => stack::push::<5>(interp), - opcode::PUSH6 => stack::push::<6>(interp), - opcode::PUSH7 => stack::push::<7>(interp), - opcode::PUSH8 => stack::push::<8>(interp), - opcode::PUSH9 => stack::push::<9>(interp), - opcode::PUSH10 => stack::push::<10>(interp), - opcode::PUSH11 => stack::push::<11>(interp), - opcode::PUSH12 => stack::push::<12>(interp), - opcode::PUSH13 => stack::push::<13>(interp), - opcode::PUSH14 => stack::push::<14>(interp), - opcode::PUSH15 => stack::push::<15>(interp), - opcode::PUSH16 => stack::push::<16>(interp), - opcode::PUSH17 => stack::push::<17>(interp), - opcode::PUSH18 => stack::push::<18>(interp), - opcode::PUSH19 => stack::push::<19>(interp), - opcode::PUSH20 => stack::push::<20>(interp), - opcode::PUSH21 => stack::push::<21>(interp), - opcode::PUSH22 => stack::push::<22>(interp), - opcode::PUSH23 => stack::push::<23>(interp), - opcode::PUSH24 => stack::push::<24>(interp), - opcode::PUSH25 => stack::push::<25>(interp), - opcode::PUSH26 => stack::push::<26>(interp), - opcode::PUSH27 => stack::push::<27>(interp), - opcode::PUSH28 => stack::push::<28>(interp), - opcode::PUSH29 => stack::push::<29>(interp), - opcode::PUSH30 => stack::push::<30>(interp), - opcode::PUSH31 => stack::push::<31>(interp), - opcode::PUSH32 => stack::push::<32>(interp), - opcode::DUP1 => stack::dup::<1>(interp), - opcode::DUP2 => stack::dup::<2>(interp), - opcode::DUP3 => stack::dup::<3>(interp), - opcode::DUP4 => stack::dup::<4>(interp), - opcode::DUP5 => stack::dup::<5>(interp), - opcode::DUP6 => stack::dup::<6>(interp), - opcode::DUP7 => stack::dup::<7>(interp), - opcode::DUP8 => stack::dup::<8>(interp), - opcode::DUP9 => stack::dup::<9>(interp), - opcode::DUP10 => stack::dup::<10>(interp), - opcode::DUP11 => stack::dup::<11>(interp), - opcode::DUP12 => stack::dup::<12>(interp), - opcode::DUP13 => stack::dup::<13>(interp), - opcode::DUP14 => stack::dup::<14>(interp), - opcode::DUP15 => stack::dup::<15>(interp), - opcode::DUP16 => stack::dup::<16>(interp), + opcode::STOP => return_stop(interp, host), + opcode::ADD => arithmetic::wrapped_add(interp, host), + opcode::MUL => arithmetic::wrapping_mul(interp, host), + opcode::SUB => arithmetic::wrapping_sub(interp, host), + opcode::DIV => arithmetic::div(interp, host), + opcode::SDIV => arithmetic::sdiv(interp, host), + opcode::MOD => arithmetic::rem(interp, host), + opcode::SMOD => arithmetic::smod(interp, host), + opcode::ADDMOD => arithmetic::addmod(interp, host), + opcode::MULMOD => arithmetic::mulmod(interp, host), + opcode::EXP => arithmetic::eval_exp::(interp, host), + opcode::SIGNEXTEND => arithmetic::signextend(interp, host), + opcode::LT => bitwise::lt(interp, host), + opcode::GT => bitwise::gt(interp, host), + opcode::SLT => bitwise::slt(interp, host), + opcode::SGT => bitwise::sgt(interp, host), + opcode::EQ => bitwise::eq(interp, host), + opcode::ISZERO => bitwise::iszero(interp, host), + opcode::AND => bitwise::bitand(interp, host), + opcode::OR => bitwise::bitor(interp, host), + opcode::XOR => bitwise::bitxor(interp, host), + opcode::NOT => bitwise::not(interp, host), + opcode::BYTE => bitwise::byte(interp, host), + opcode::SHL => bitwise::shl::(interp, host), + opcode::SHR => bitwise::shr::(interp, host), + opcode::SAR => bitwise::sar::(interp, host), + opcode::SHA3 => system::sha3(interp, host), + opcode::ADDRESS => system::address(interp, host), + opcode::BALANCE => host::balance::(interp, host), + opcode::SELFBALANCE => host::selfbalance::(interp, host), + opcode::CODESIZE => system::codesize(interp, host), + opcode::CODECOPY => system::codecopy(interp, host), + opcode::CALLDATALOAD => system::calldataload(interp, host), + opcode::CALLDATASIZE => system::calldatasize(interp, host), + opcode::CALLDATACOPY => system::calldatacopy(interp, host), + opcode::POP => stack::pop(interp, host), + opcode::MLOAD => memory::mload(interp, host), + opcode::MSTORE => memory::mstore(interp, host), + opcode::MSTORE8 => memory::mstore8(interp, host), + opcode::JUMP => control::jump(interp, host), + opcode::JUMPI => control::jumpi(interp, host), + opcode::PC => control::pc(interp, host), + opcode::MSIZE => memory::msize(interp, host), + opcode::JUMPDEST => control::jumpdest(interp, host), + opcode::PUSH1 => stack::push::<1>(interp, host), + opcode::PUSH2 => stack::push::<2>(interp, host), + opcode::PUSH3 => stack::push::<3>(interp, host), + opcode::PUSH4 => stack::push::<4>(interp, host), + opcode::PUSH5 => stack::push::<5>(interp, host), + opcode::PUSH6 => stack::push::<6>(interp, host), + opcode::PUSH7 => stack::push::<7>(interp, host), + opcode::PUSH8 => stack::push::<8>(interp, host), + opcode::PUSH9 => stack::push::<9>(interp, host), + opcode::PUSH10 => stack::push::<10>(interp, host), + opcode::PUSH11 => stack::push::<11>(interp, host), + opcode::PUSH12 => stack::push::<12>(interp, host), + opcode::PUSH13 => stack::push::<13>(interp, host), + opcode::PUSH14 => stack::push::<14>(interp, host), + opcode::PUSH15 => stack::push::<15>(interp, host), + opcode::PUSH16 => stack::push::<16>(interp, host), + opcode::PUSH17 => stack::push::<17>(interp, host), + opcode::PUSH18 => stack::push::<18>(interp, host), + opcode::PUSH19 => stack::push::<19>(interp, host), + opcode::PUSH20 => stack::push::<20>(interp, host), + opcode::PUSH21 => stack::push::<21>(interp, host), + opcode::PUSH22 => stack::push::<22>(interp, host), + opcode::PUSH23 => stack::push::<23>(interp, host), + opcode::PUSH24 => stack::push::<24>(interp, host), + opcode::PUSH25 => stack::push::<25>(interp, host), + opcode::PUSH26 => stack::push::<26>(interp, host), + opcode::PUSH27 => stack::push::<27>(interp, host), + opcode::PUSH28 => stack::push::<28>(interp, host), + opcode::PUSH29 => stack::push::<29>(interp, host), + opcode::PUSH30 => stack::push::<30>(interp, host), + opcode::PUSH31 => stack::push::<31>(interp, host), + opcode::PUSH32 => stack::push::<32>(interp, host), + opcode::DUP1 => stack::dup::<1>(interp, host), + opcode::DUP2 => stack::dup::<2>(interp, host), + opcode::DUP3 => stack::dup::<3>(interp, host), + opcode::DUP4 => stack::dup::<4>(interp, host), + opcode::DUP5 => stack::dup::<5>(interp, host), + opcode::DUP6 => stack::dup::<6>(interp, host), + opcode::DUP7 => stack::dup::<7>(interp, host), + opcode::DUP8 => stack::dup::<8>(interp, host), + opcode::DUP9 => stack::dup::<9>(interp, host), + opcode::DUP10 => stack::dup::<10>(interp, host), + opcode::DUP11 => stack::dup::<11>(interp, host), + opcode::DUP12 => stack::dup::<12>(interp, host), + opcode::DUP13 => stack::dup::<13>(interp, host), + opcode::DUP14 => stack::dup::<14>(interp, host), + opcode::DUP15 => stack::dup::<15>(interp, host), + opcode::DUP16 => stack::dup::<16>(interp, host), - opcode::SWAP1 => stack::swap::<1>(interp), - opcode::SWAP2 => stack::swap::<2>(interp), - opcode::SWAP3 => stack::swap::<3>(interp), - opcode::SWAP4 => stack::swap::<4>(interp), - opcode::SWAP5 => stack::swap::<5>(interp), - opcode::SWAP6 => stack::swap::<6>(interp), - opcode::SWAP7 => stack::swap::<7>(interp), - opcode::SWAP8 => stack::swap::<8>(interp), - opcode::SWAP9 => stack::swap::<9>(interp), - opcode::SWAP10 => stack::swap::<10>(interp), - opcode::SWAP11 => stack::swap::<11>(interp), - opcode::SWAP12 => stack::swap::<12>(interp), - opcode::SWAP13 => stack::swap::<13>(interp), - opcode::SWAP14 => stack::swap::<14>(interp), - opcode::SWAP15 => stack::swap::<15>(interp), - opcode::SWAP16 => stack::swap::<16>(interp), + opcode::SWAP1 => stack::swap::<1>(interp, host), + opcode::SWAP2 => stack::swap::<2>(interp, host), + opcode::SWAP3 => stack::swap::<3>(interp, host), + opcode::SWAP4 => stack::swap::<4>(interp, host), + opcode::SWAP5 => stack::swap::<5>(interp, host), + opcode::SWAP6 => stack::swap::<6>(interp, host), + opcode::SWAP7 => stack::swap::<7>(interp, host), + opcode::SWAP8 => stack::swap::<8>(interp, host), + opcode::SWAP9 => stack::swap::<9>(interp, host), + opcode::SWAP10 => stack::swap::<10>(interp, host), + opcode::SWAP11 => stack::swap::<11>(interp, host), + opcode::SWAP12 => stack::swap::<12>(interp, host), + opcode::SWAP13 => stack::swap::<13>(interp, host), + opcode::SWAP14 => stack::swap::<14>(interp, host), + opcode::SWAP15 => stack::swap::<15>(interp, host), + opcode::SWAP16 => stack::swap::<16>(interp, host), - opcode::RETURN => control::ret(interp), - opcode::REVERT => control::revert::(interp), - opcode::INVALID => Return::InvalidOpcode, - opcode::BASEFEE => host_env::basefee::(interp, host), + opcode::RETURN => control::ret(interp, host), + opcode::REVERT => control::revert::(interp, host), + opcode::INVALID => return_invalid(interp, host), + opcode::BASEFEE => host_env::basefee::(interp, host), opcode::ORIGIN => host_env::origin(interp, host), - opcode::CALLER => system::caller(interp), - opcode::CALLVALUE => system::callvalue(interp), + opcode::CALLER => system::caller(interp, host), + opcode::CALLVALUE => system::callvalue(interp, host), opcode::GASPRICE => host_env::gasprice(interp, host), - opcode::EXTCODESIZE => host::extcodesize::(interp, host), - opcode::EXTCODEHASH => host::extcodehash::(interp, host), - opcode::EXTCODECOPY => host::extcodecopy::(interp, host), - opcode::RETURNDATASIZE => system::returndatasize::(interp), - opcode::RETURNDATACOPY => system::returndatacopy::(interp), + opcode::EXTCODESIZE => host::extcodesize::(interp, host), + opcode::EXTCODEHASH => host::extcodehash::(interp, host), + opcode::EXTCODECOPY => host::extcodecopy::(interp, host), + opcode::RETURNDATASIZE => system::returndatasize::(interp, host), + opcode::RETURNDATACOPY => system::returndatacopy::(interp, host), opcode::BLOCKHASH => host::blockhash(interp, host), opcode::COINBASE => host_env::coinbase(interp, host), opcode::TIMESTAMP => host_env::timestamp(interp, host), opcode::NUMBER => host_env::number(interp, host), opcode::DIFFICULTY => host_env::difficulty::(interp, host), opcode::GASLIMIT => host_env::gaslimit(interp, host), - opcode::SLOAD => host::sload::(interp, host), - opcode::SSTORE => host::sstore::(interp, host), - opcode::GAS => system::gas(interp), - opcode::LOG0 => host::log::(interp, 0, host), - opcode::LOG1 => host::log::(interp, 1, host), - opcode::LOG2 => host::log::(interp, 2, host), - opcode::LOG3 => host::log::(interp, 3, host), - opcode::LOG4 => host::log::(interp, 4, host), - opcode::SELFDESTRUCT => host::selfdestruct::(interp, host), - opcode::CREATE => host::create::(interp, false, host), //check - opcode::CREATE2 => host::create::(interp, true, host), //check - opcode::CALL => host::call::(interp, CallScheme::Call, host), //check - opcode::CALLCODE => host::call::(interp, CallScheme::CallCode, host), //check - opcode::DELEGATECALL => host::call::(interp, CallScheme::DelegateCall, host), //check - opcode::STATICCALL => host::call::(interp, CallScheme::StaticCall, host), //check - opcode::CHAINID => host_env::chainid::(interp, host), - _ => Return::OpcodeNotFound, + opcode::SLOAD => host::sload::(interp, host), + opcode::SSTORE => host::sstore::(interp, host), + opcode::GAS => system::gas(interp, host), + opcode::LOG0 => host::log::<0, S>(interp, host), + opcode::LOG1 => host::log::<1, S>(interp, host), + opcode::LOG2 => host::log::<2, S>(interp, host), + opcode::LOG3 => host::log::<3, S>(interp, host), + opcode::LOG4 => host::log::<4, S>(interp, host), + opcode::SELFDESTRUCT => host::selfdestruct::(interp, host), + opcode::CREATE => host::create::(interp, host), //check + opcode::CREATE2 => host::create::(interp, host), //check + opcode::CALL => host::call::(interp, host), //check + opcode::CALLCODE => host::call_code::(interp, host), //check + opcode::DELEGATECALL => host::delegate_call::(interp, host), //check + opcode::STATICCALL => host::static_call::(interp, host), //check + opcode::CHAINID => host_env::chainid::(interp, host), + _ => return_not_found(interp, host), } } diff --git a/crates/revm/src/instructions/arithmetic.rs b/crates/revm/src/instructions/arithmetic.rs index e05bbdcee6..0d570491f0 100644 --- a/crates/revm/src/instructions/arithmetic.rs +++ b/crates/revm/src/instructions/arithmetic.rs @@ -1,45 +1,59 @@ use super::i256::{i256_div, i256_mod}; -use crate::{gas, Interpreter, Return, Spec, U256}; +use crate::{gas, Host, Interpreter, Return, Spec, U256}; -pub fn div(op1: U256, op2: U256) -> U256 { - op1.checked_div(op2).unwrap_or_default() +pub fn wrapped_add(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop_top!(interpreter, op1, op2); + *op2 = op1.wrapping_add(*op2); } -pub fn sdiv(op1: U256, op2: U256) -> U256 { - i256_div(op1, op2) +pub fn wrapping_mul(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop_top!(interpreter, op1, op2); + *op2 = op1.wrapping_mul(*op2); } -pub fn rem(op1: U256, op2: U256) -> U256 { - op1.checked_rem(op2).unwrap_or_default() +pub fn wrapping_sub(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop_top!(interpreter, op1, op2); + *op2 = op1.wrapping_sub(*op2); } -pub fn smod(op1: U256, op2: U256) -> U256 { - if op2 == U256::ZERO { - U256::ZERO - } else { - i256_mod(op1, op2) - } +pub fn div(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop_top!(interpreter, op1, op2); + *op2 = op1.checked_div(*op2).unwrap_or_default() +} + +pub fn sdiv(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop_top!(interpreter, op1, op2); + *op2 = i256_div(op1, *op2); +} + +pub fn rem(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop_top!(interpreter, op1, op2); + *op2 = op1.checked_rem(*op2).unwrap_or_default() } -pub fn addmod(op1: U256, op2: U256, op3: U256) -> U256 { - op1.add_mod(op2, op3) +pub fn smod(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop_top!(interpreter, op1, op2); + if *op2 != U256::ZERO { + *op2 = i256_mod(op1, *op2) + }; } -pub fn mulmod(op1: U256, op2: U256, op3: U256) -> U256 { - op1.mul_mod(op2, op3) +pub fn addmod(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop_top!(interpreter, op1, op2, op3); + *op3 = op1.add_mod(op2, *op3) } -pub fn exp(op1: U256, op2: U256) -> U256 { - op1.pow(op2) +pub fn mulmod(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop_top!(interpreter, op1, op2, op3); + *op3 = op1.mul_mod(op2, *op3) } -pub fn eval_exp(interp: &mut Interpreter) -> Return { +pub fn eval_exp(interp: &mut Interpreter, _host: &mut dyn Host) { pop!(interp, op1, op2); gas_or_fail!(interp, gas::exp_cost::(op2)); - let ret = exp(op1, op2); + // TODO see if we can use pop_top + let ret = op1.pow(op2); push!(interp, ret); - - Return::Continue } /// In the yellow paper `SIGNEXTEND` is defined to take two inputs, we will call them @@ -57,79 +71,13 @@ pub fn eval_exp(interp: &mut Interpreter) -> Return { /// `y | !mask` where `|` is the bitwise `OR` and `!` is bitwise negation. Similarly, if /// `b == 0` then the yellow paper says the output should start with all zeros, then end with /// bits from `b`; this is equal to `y & mask` where `&` is bitwise `AND`. - -pub fn signextend(op1: U256, op2: U256) -> U256 { +pub fn signextend(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop_top!(interpreter, op1, op2); if op1 < U256::from(32) { // `low_u32` works since op1 < 32 let bit_index = (8 * op1.as_limbs()[0] + 7) as usize; let bit = op2.bit(bit_index); let mask = (U256::from(1) << bit_index) - U256::from(1); - if bit { - op2 | !mask - } else { - op2 & mask - } - } else { - op2 - } -} - -#[cfg(test)] -mod tests { - use alloc::vec; - - use super::{signextend, U256}; - - /// Test to ensure new (optimized) `signextend` implementation is equivalent to the previous - /// implementation. - #[test] - fn test_signextend() { - let test_values = vec![ - U256::ZERO, - U256::from(1), - U256::from(8), - U256::from(10), - U256::from(65), - U256::from(100), - U256::from(128), - U256::from(11) * (U256::from(1) << 65), - U256::from(7) * (U256::from(1) << 123), - U256::MAX / U256::from(167), - U256::MAX, - ]; - for x in 0..64 { - for y in test_values.iter() { - compare_old_signextend(U256::from(x), *y); - } - } - } - - fn compare_old_signextend(x: U256, y: U256) { - let old = old_signextend(x, y); - let new = signextend(x, y); - - assert_eq!(old, new); - } - - fn old_signextend(op1: U256, op2: U256) -> U256 { - if op1 > U256::from(32) { - op2 - } else { - let mut ret = U256::ZERO; - let len = usize::try_from(op1).unwrap(); - let t: usize = 8 * (len + 1) - 1; - let t_bit_mask = U256::from(1) << t; - let t_value = (op2 & t_bit_mask) >> t; - for i in 0..256 { - let bit_mask = U256::from(1) << i; - let i_value = (op2 & bit_mask) >> i; - if i <= t { - ret = ret.overflowing_add(i_value << i).0; - } else { - ret = ret.overflowing_add(t_value << i).0; - } - } - ret - } + *op2 = if bit { *op2 | !mask } else { *op2 & mask }; } } diff --git a/crates/revm/src/instructions/bitwise.rs b/crates/revm/src/instructions/bitwise.rs index 4bca936ed2..0aaadf773b 100644 --- a/crates/revm/src/instructions/bitwise.rs +++ b/crates/revm/src/instructions/bitwise.rs @@ -1,36 +1,81 @@ use super::i256::{i256_cmp, i256_sign, two_compl, Sign}; -use crate::U256; +use crate::{Host, Interpreter, Return, Spec, SpecId::CONSTANTINOPLE, U256}; use core::cmp::Ordering; +use std::ops::{BitAnd, BitOr, BitXor}; -pub fn slt(op1: U256, op2: U256) -> U256 { - if i256_cmp(op1, op2) == Ordering::Less { +pub fn lt(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop_top!(interpreter, op1, op2); + *op2 = if op1.lt(op2) { U256::from(1) } else { U256::ZERO - } + }; } -pub fn sgt(op1: U256, op2: U256) -> U256 { - if i256_cmp(op1, op2) == Ordering::Greater { +pub fn gt(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop_top!(interpreter, op1, op2); + *op2 = if op1.gt(op2) { U256::from(1) } else { U256::ZERO - } + }; } -pub fn iszero(op1: U256) -> U256 { - if op1 == U256::ZERO { +pub fn slt(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop_top!(interpreter, op1, op2); + *op2 = if i256_cmp(op1, *op2) == Ordering::Less { U256::from(1) } else { U256::ZERO } } -pub fn not(op1: U256) -> U256 { - !op1 +pub fn sgt(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop_top!(interpreter, op1, op2); + *op2 = if i256_cmp(op1, *op2) == Ordering::Greater { + U256::from(1) + } else { + U256::ZERO + }; +} + +pub fn eq(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop_top!(interpreter, op1, op2); + *op2 = if op1.eq(op2) { + U256::from(1) + } else { + U256::ZERO + }; +} + +pub fn iszero(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop_top!(interpreter, op1); + *op1 = if *op1 == U256::ZERO { + U256::from(1) + } else { + U256::ZERO + }; +} +pub fn bitand(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop_top!(interpreter, op1, op2); + *op2 = op1.bitand(*op2); +} +pub fn bitor(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop_top!(interpreter, op1, op2); + *op2 = op1.bitor(*op2); +} +pub fn bitxor(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop_top!(interpreter, op1, op2); + *op2 = op1.bitxor(*op2); +} + +pub fn not(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop_top!(interpreter, op1); + *op1 = !*op1; } -pub fn byte(op1: U256, op2: U256) -> U256 { +pub fn byte(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop_top!(interpreter, op1, op2); let mut ret = U256::ZERO; for i in 0..256 { @@ -38,26 +83,36 @@ pub fn byte(op1: U256, op2: U256) -> U256 { let o = u128::try_from(op1).unwrap() as usize; let t = 255 - (7 - i + 8 * o); let bit_mask = U256::from(1) << t; - let value = (op2 & bit_mask) >> t; + let value = (*op2 & bit_mask) >> t; ret = ret.overflowing_add(value << i).0; } } - ret + *op2 = ret; } -pub fn shl(shift: U256, value: U256) -> U256 { - value << usize::try_from(shift).unwrap_or(256) +pub fn shl(interpreter: &mut Interpreter, _host: &mut dyn Host) { + // EIP-145: Bitwise shifting instructions in EVM + check!(interpreter, SPEC::enabled(CONSTANTINOPLE)); + pop_top!(interpreter, op1, op2); + *op2 = *op2 << usize::try_from(op1).unwrap_or(256) } -pub fn shr(shift: U256, value: U256) -> U256 { - value >> usize::try_from(shift).unwrap_or(256) +pub fn shr(interpreter: &mut Interpreter, _host: &mut dyn Host) { + // EIP-145: Bitwise shifting instructions in EVM + check!(interpreter, SPEC::enabled(CONSTANTINOPLE)); + pop_top!(interpreter, op1, op2); + *op2 = *op2 >> usize::try_from(op1).unwrap_or(256) } -pub fn sar(shift: U256, mut value: U256) -> U256 { - let value_sign = i256_sign::(&mut value); +pub fn sar(interpreter: &mut Interpreter, _host: &mut dyn Host) { + // EIP-145: Bitwise shifting instructions in EVM + check!(interpreter, SPEC::enabled(CONSTANTINOPLE)); + pop_top!(interpreter, op1, op2); - if value == U256::ZERO || shift >= U256::from(256) { + let value_sign = i256_sign::(op2); + + *op2 = if *op2 == U256::ZERO || op1 >= U256::from(256) { match value_sign { // value is 0 or >=1, pushing 0 Sign::Plus | Sign::Zero => U256::ZERO, @@ -65,16 +120,16 @@ pub fn sar(shift: U256, mut value: U256) -> U256 { Sign::Minus => two_compl(U256::from(1)), } } else { - let shift = usize::try_from(shift).unwrap(); + let shift = usize::try_from(op1).unwrap(); match value_sign { - Sign::Plus | Sign::Zero => value >> shift, + Sign::Plus | Sign::Zero => *op2 >> shift, Sign::Minus => { - let shifted = ((value.overflowing_sub(U256::from(1)).0) >> shift) + let shifted = ((op2.overflowing_sub(U256::from(1)).0) >> shift) .overflowing_add(U256::from(1)) .0; two_compl(shifted) } } - } + }; } diff --git a/crates/revm/src/instructions/control.rs b/crates/revm/src/instructions/control.rs index 1f4e206b7b..46532cccdb 100644 --- a/crates/revm/src/instructions/control.rs +++ b/crates/revm/src/instructions/control.rs @@ -1,75 +1,75 @@ -use crate::{gas, interpreter::Interpreter, Return, Spec, SpecId::*, U256}; +use crate::{gas, interpreter::Interpreter, Host, Return, Spec, SpecId::*, U256}; -pub fn jump(interp: &mut Interpreter) -> Return { +pub fn jump(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::MID); - pop!(interp, dest); - let dest = as_usize_or_fail!(dest, Return::InvalidJump); - if interp.contract.is_valid_jump(dest) { + pop!(interpreter, dest); + let dest = as_usize_or_fail!(interpreter,dest, Return::InvalidJump); + if interpreter.contract.is_valid_jump(dest) { // Safety: In analysis we are checking create our jump table and we do check above to be // sure that jump is safe to execute. - interp.instruction_pointer = unsafe { interp.contract.bytecode.as_ptr().add(dest) }; - Return::Continue + interpreter.instruction_pointer = unsafe { interpreter.contract.bytecode.as_ptr().add(dest) }; } else { - Return::InvalidJump + interpreter.instruction_result = Return::InvalidJump; } } -pub fn jumpi(interp: &mut Interpreter) -> Return { +pub fn jumpi(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::HIGH); - pop!(interp, dest, value); + pop!(interpreter, dest, value); if value != U256::ZERO { - let dest = as_usize_or_fail!(dest, Return::InvalidJump); - if interp.contract.is_valid_jump(dest) { + let dest = as_usize_or_fail!(interpreter,dest, Return::InvalidJump); + if interpreter.contract.is_valid_jump(dest) { // Safety: In analysis we are checking if jump is valid destination and // this `if` makes this unsafe block safe. - interp.instruction_pointer = unsafe { interp.contract.bytecode.as_ptr().add(dest) }; - Return::Continue + interpreter.instruction_pointer = + unsafe { interpreter.contract.bytecode.as_ptr().add(dest) }; } else { - Return::InvalidJump + interpreter.instruction_result = Return::InvalidJump } - } else { + } else if let Some(ret) = interpreter.add_next_gas_block(interpreter.program_counter() - 1) { // if we are not doing jump, add next gas block. - interp.add_next_gas_block(interp.program_counter() - 1) + interpreter.instruction_result = ret; } } -pub fn jumpdest(interp: &mut Interpreter) -> Return { - gas!(interp, gas::JUMPDEST); - interp.add_next_gas_block(interp.program_counter() - 1) +pub fn jumpdest(interpreter: &mut Interpreter, _host: &mut dyn Host) { + gas!(interpreter, gas::JUMPDEST); + if let Some(ret) = interpreter.add_next_gas_block(interpreter.program_counter() - 1) { + interpreter.instruction_result = ret; + } } -pub fn pc(interp: &mut Interpreter) -> Return { +pub fn pc(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::BASE); - push!(interp, U256::from(interp.program_counter() - 1)); - Return::Continue + push!(interpreter, U256::from(interpreter.program_counter() - 1)); } -pub fn ret(interp: &mut Interpreter) -> Return { +pub fn ret(interpreter: &mut Interpreter, _host: &mut dyn Host) { // zero gas cost gas!(interp,gas::ZERO); - pop!(interp, start, len); - let len = as_usize_or_fail!(len, Return::OutOfGas); + pop!(interpreter, start, len); + let len = as_usize_or_fail!(interpreter,len, Return::OutOfGas); if len == 0 { - interp.return_range = usize::MAX..usize::MAX; + interpreter.return_range = usize::MAX..usize::MAX; } else { - let offset = as_usize_or_fail!(start, Return::OutOfGas); - memory_resize!(interp, offset, len); - interp.return_range = offset..(offset + len); + let offset = as_usize_or_fail!(interpreter,start, Return::OutOfGas); + memory_resize!(interpreter, offset, len); + interpreter.return_range = offset..(offset + len); } - Return::Return + interpreter.instruction_result = Return::Return; } -pub fn revert(interp: &mut Interpreter) -> Return { +pub fn revert(interpreter: &mut Interpreter, _host: &mut dyn Host) { // zero gas cost gas!(interp,gas::ZERO); // EIP-140: REVERT instruction - check!(SPEC::enabled(BYZANTIUM)); - pop!(interp, start, len); - let len = as_usize_or_fail!(len, Return::OutOfGas); + check!(interpreter, SPEC::enabled(BYZANTIUM)); + pop!(interpreter, start, len); + let len = as_usize_or_fail!(interpreter,len, Return::OutOfGas); if len == 0 { - interp.return_range = usize::MAX..usize::MAX; + interpreter.return_range = usize::MAX..usize::MAX; } else { - let offset = as_usize_or_fail!(start, Return::OutOfGas); - memory_resize!(interp, offset, len); - interp.return_range = offset..(offset + len); + let offset = as_usize_or_fail!(interpreter,start, Return::OutOfGas); + memory_resize!(interpreter, offset, len); + interpreter.return_range = offset..(offset + len); } - Return::Revert + interpreter.instruction_result = Return::Revert; } diff --git a/crates/revm/src/instructions/host.rs b/crates/revm/src/instructions/host.rs index f856756af7..4b72fd4f56 100644 --- a/crates/revm/src/instructions/host.rs +++ b/crates/revm/src/instructions/host.rs @@ -11,15 +11,16 @@ use crate::{ use bytes::Bytes; use core::cmp::min; -pub fn balance(interp: &mut Interpreter, host: &mut H) -> Return { - pop_address!(interp, address); +pub fn balance(interpreter: &mut Interpreter, host: &mut dyn Host) { + pop_address!(interpreter, address); let ret = host.balance(address); if ret.is_none() { - return Return::FatalExternalError; + interpreter.instruction_result = Return::FatalExternalError; + return; } let (balance, is_cold) = ret.unwrap(); gas!( - interp, + interpreter, if SPEC::enabled(ISTANBUL) { // EIP-1884: Repricing for trie-size-dependent opcodes gas::account_access_gas::(is_cold) @@ -29,88 +30,92 @@ pub fn balance(interp: &mut Interpreter, host: &mut H) -> R 20 } ); - push!(interp, balance); - - Return::Continue + push!(interpreter, balance); } -pub fn selfbalance(interp: &mut Interpreter, host: &mut H) -> Return { +pub fn selfbalance(interpreter: &mut Interpreter, host: &mut dyn Host) { // gas!(interp, gas::LOW); // EIP-1884: Repricing for trie-size-dependent opcodes - check!(SPEC::enabled(ISTANBUL)); - let ret = host.balance(interp.contract.address); + check!(interpreter, SPEC::enabled(ISTANBUL)); + let ret = host.balance(interpreter.contract.address); if ret.is_none() { - return Return::FatalExternalError; + interpreter.instruction_result = Return::FatalExternalError; + return; } let (balance, _) = ret.unwrap(); - push!(interp, balance); - - Return::Continue + push!(interpreter, balance); } -pub fn extcodesize(interp: &mut Interpreter, host: &mut H) -> Return { - pop_address!(interp, address); +pub fn extcodesize(interpreter: &mut Interpreter, host: &mut dyn Host) { + pop_address!(interpreter, address); let ret = host.code(address); if ret.is_none() { - return Return::FatalExternalError; + interpreter.instruction_result = Return::FatalExternalError; + return; } let (code, is_cold) = ret.unwrap(); if SPEC::enabled(BERLIN) && is_cold { // WARM_STORAGE_READ_COST is already calculated in gas block - gas!(interp, COLD_ACCOUNT_ACCESS_COST - WARM_STORAGE_READ_COST); + gas!( + interpreter, + COLD_ACCOUNT_ACCESS_COST - WARM_STORAGE_READ_COST + ); } - push!(interp, U256::from(code.len())); - - Return::Continue + push!(interpreter, U256::from(code.len())); } -pub fn extcodehash(interp: &mut Interpreter, host: &mut H) -> Return { - check!(SPEC::enabled(CONSTANTINOPLE)); // EIP-1052: EXTCODEHASH opcode - pop_address!(interp, address); +pub fn extcodehash(interpreter: &mut Interpreter, host: &mut dyn Host) { + check!(interpreter, SPEC::enabled(CONSTANTINOPLE)); // EIP-1052: EXTCODEHASH opcode + pop_address!(interpreter, address); let ret = host.code_hash(address); if ret.is_none() { - return Return::FatalExternalError; + interpreter.instruction_result = Return::FatalExternalError; + return; } let (code_hash, is_cold) = ret.unwrap(); if SPEC::enabled(BERLIN) && is_cold { // WARM_STORAGE_READ_COST is already calculated in gas block - gas!(interp, COLD_ACCOUNT_ACCESS_COST - WARM_STORAGE_READ_COST); + gas!( + interpreter, + COLD_ACCOUNT_ACCESS_COST - WARM_STORAGE_READ_COST + ); } - push_b256!(interp, code_hash); - - Return::Continue + push_b256!(interpreter, code_hash); } -pub fn extcodecopy(interp: &mut Interpreter, host: &mut H) -> Return { - pop_address!(interp, address); - pop!(interp, memory_offset, code_offset, len_u256); +pub fn extcodecopy(interpreter: &mut Interpreter, host: &mut dyn Host) { + pop_address!(interpreter, address); + pop!(interpreter, memory_offset, code_offset, len_u256); let ret = host.code(address); if ret.is_none() { - return Return::FatalExternalError; + interpreter.instruction_result = Return::FatalExternalError; + return; } let (code, is_cold) = ret.unwrap(); - let len = as_usize_or_fail!(len_u256, Return::OutOfGas); - gas_or_fail!(interp, gas::extcodecopy_cost::(len as u64, is_cold)); + let len = as_usize_or_fail!(interpreter, len_u256, Return::OutOfGas); + gas_or_fail!( + interpreter, + gas::extcodecopy_cost::(len as u64, is_cold) + ); if len == 0 { - return Return::Continue; + return; } - let memory_offset = as_usize_or_fail!(memory_offset, Return::OutOfGas); + let memory_offset = as_usize_or_fail!(interpreter, memory_offset, Return::OutOfGas); let code_offset = min(as_usize_saturated!(code_offset), code.len()); - memory_resize!(interp, memory_offset, len); + memory_resize!(interpreter, memory_offset, len); // Safety: set_data is unsafe function and memory_resize ensures us that it is safe to call it - interp + interpreter .memory .set_data(memory_offset, code_offset, len, code.bytes()); - Return::Continue } -pub fn blockhash(interp: &mut Interpreter, host: &mut H) -> Return { +pub fn blockhash(interpreter: &mut Interpreter, host: &mut dyn Host) { // gas!(interp, gas::BLOCKHASH); - pop_top!(interp, number); + pop_top!(interpreter, number); if let Some(diff) = host.env().block.number.checked_sub(*number) { let diff = as_usize_saturated!(diff); @@ -118,210 +123,235 @@ pub fn blockhash(interp: &mut Interpreter, host: &mut H) -> Return { if diff <= 256 && diff != 0 { let ret = host.block_hash(*number); if ret.is_none() { - return Return::FatalExternalError; + interpreter.instruction_result = Return::FatalExternalError; + return; } *number = U256::from_be_bytes(*ret.unwrap()); - return Return::Continue; + return } } *number = U256::ZERO; - Return::Continue } -pub fn sload(interp: &mut Interpreter, host: &mut H) -> Return { - pop!(interp, index); +pub fn sload(interpreter: &mut Interpreter, host: &mut dyn Host) { + pop!(interpreter, index); - let ret = host.sload(interp.contract.address, index); + let ret = host.sload(interpreter.contract.address, index); if ret.is_none() { - return Return::FatalExternalError; + interpreter.instruction_result = Return::FatalExternalError; + return; } let (value, is_cold) = ret.unwrap(); - gas!(interp, gas::sload_cost::(is_cold)); - push!(interp, value); - Return::Continue + gas!(interpreter, gas::sload_cost::(is_cold)); + push!(interpreter, value); } -pub fn sstore(interp: &mut Interpreter, host: &mut H) -> Return { - check!(!SPEC::IS_STATIC_CALL); +pub fn sstore(interpreter: &mut Interpreter, host: &mut dyn Host) { + check!(interpreter, !interpreter.is_static); - pop!(interp, index, value); - let ret = host.sstore(interp.contract.address, index, value); + pop!(interpreter, index, value); + let ret = host.sstore(interpreter.contract.address, index, value); if ret.is_none() { - return Return::FatalExternalError; + interpreter.instruction_result = Return::FatalExternalError; + return; } let (original, old, new, is_cold) = ret.unwrap(); - gas_or_fail!(interp, { - let remaining_gas = interp.gas.remaining(); + gas_or_fail!(interpreter, { + let remaining_gas = interpreter.gas.remaining(); gas::sstore_cost::(original, old, new, remaining_gas, is_cold) }); - refund!(interp, gas::sstore_refund::(original, old, new)); - interp.add_next_gas_block(interp.program_counter() - 1) + refund!(interpreter, gas::sstore_refund::(original, old, new)); + if let Some(ret) = interpreter.add_next_gas_block(interpreter.program_counter() - 1) { + interpreter.instruction_result = ret; + } } -pub fn log(interp: &mut Interpreter, n: u8, host: &mut H) -> Return { - check!(!SPEC::IS_STATIC_CALL); +pub fn log(interpreter: &mut Interpreter, host: &mut dyn Host) { + check!(interpreter, !interpreter.is_static); - pop!(interp, offset, len); - let len = as_usize_or_fail!(len, Return::OutOfGas); - gas_or_fail!(interp, gas::log_cost(n, len as u64)); + pop!(interpreter, offset, len); + let len = as_usize_or_fail!(interpreter, len, Return::OutOfGas); + gas_or_fail!(interpreter, gas::log_cost(N, len as u64)); let data = if len == 0 { Bytes::new() } else { - let offset = as_usize_or_fail!(offset, Return::OutOfGas); - memory_resize!(interp, offset, len); - Bytes::copy_from_slice(interp.memory.get_slice(offset, len)) + let offset = as_usize_or_fail!(interpreter, offset, Return::OutOfGas); + memory_resize!(interpreter, offset, len); + Bytes::copy_from_slice(interpreter.memory.get_slice(offset, len)) }; - let n = n as usize; - if interp.stack.len() < n { - return Return::StackUnderflow; + let n = N as usize; + if interpreter.stack.len() < n { + interpreter.instruction_result = Return::StackUnderflow; + return; } let mut topics = Vec::with_capacity(n); for _ in 0..(n) { // Safety: stack bounds already checked few lines above - topics.push(B256(unsafe { interp.stack.pop_unsafe().to_be_bytes() })); + topics.push(B256(unsafe { interpreter.stack.pop_unsafe().to_be_bytes() })); } - host.log(interp.contract.address, topics, data); - Return::Continue + host.log(interpreter.contract.address, topics, data); } -pub fn selfdestruct(interp: &mut Interpreter, host: &mut H) -> Return { - check!(!SPEC::IS_STATIC_CALL); - pop_address!(interp, target); +pub fn selfdestruct(interpreter: &mut Interpreter, host: &mut dyn Host) { + check!(interpreter, !interpreter.is_static); + pop_address!(interpreter, target); - let res = host.selfdestruct(interp.contract.address, target); + let res = host.selfdestruct(interpreter.contract.address, target); if res.is_none() { - return Return::FatalExternalError; + interpreter.instruction_result = Return::FatalExternalError; + return; } let res = res.unwrap(); // EIP-3529: Reduction in refunds if !SPEC::enabled(LONDON) && !res.previously_destroyed { - refund!(interp, gas::SELFDESTRUCT) + refund!(interpreter, gas::SELFDESTRUCT) } - gas!(interp, gas::selfdestruct_cost::(res)); + gas!(interpreter, gas::selfdestruct_cost::(res)); - Return::SelfDestruct + interpreter.instruction_result = Return::SelfDestruct; } -pub fn create( - interp: &mut Interpreter, - is_create2: bool, - host: &mut H, -) -> Return { - check!(!SPEC::IS_STATIC_CALL); - if is_create2 { +pub fn create( + interpreter: &mut Interpreter, + host: &mut dyn Host, +) { + check!(interpreter, !interpreter.is_static); + if IS_CREATE2 { // EIP-1014: Skinny CREATE2 - check!(SPEC::enabled(PETERSBURG)); + check!(interpreter, SPEC::enabled(PETERSBURG)); } - interp.return_data_buffer = Bytes::new(); + interpreter.return_data_buffer = Bytes::new(); - pop!(interp, value, code_offset, len); - let len = as_usize_or_fail!(len, Return::OutOfGas); + pop!(interpreter, value, code_offset, len); + let len = as_usize_or_fail!(interpreter, len, Return::OutOfGas); let code = if len == 0 { Bytes::new() } else { - let code_offset = as_usize_or_fail!(code_offset, Return::OutOfGas); - memory_resize!(interp, code_offset, len); - Bytes::copy_from_slice(interp.memory.get_slice(code_offset, len)) + let code_offset = as_usize_or_fail!(interpreter, code_offset, Return::OutOfGas); + memory_resize!(interpreter, code_offset, len); + Bytes::copy_from_slice(interpreter.memory.get_slice(code_offset, len)) }; - let scheme = if is_create2 { - pop!(interp, salt); - gas_or_fail!(interp, gas::create2_cost(len)); + let scheme = if IS_CREATE2 { + pop!(interpreter, salt); + gas_or_fail!(interpreter, gas::create2_cost(len)); CreateScheme::Create2 { salt } } else { - gas!(interp, gas::CREATE); + gas!(interpreter, gas::CREATE); CreateScheme::Create }; - let mut gas_limit = interp.gas().remaining(); + let mut gas_limit = interpreter.gas().remaining(); // EIP-150: Gas cost changes for IO-heavy operations if SPEC::enabled(TANGERINE) { // take remaining gas and deduce l64 part of it. gas_limit -= gas_limit / 64 } - gas!(interp, gas_limit); + gas!(interpreter, gas_limit); let mut create_input = CreateInputs { - caller: interp.contract.address, + caller: interpreter.contract.address, scheme, value, init_code: code, gas_limit, }; - let (return_reason, address, gas, return_data) = host.create::(&mut create_input); - interp.return_data_buffer = return_data; + let (return_reason, address, gas, return_data) = host.create(&mut create_input); + interpreter.return_data_buffer = return_data; match return_reason { return_ok!() => { - push_b256!(interp, address.unwrap_or_default().into()); - interp.gas.erase_cost(gas.remaining()); - interp.gas.record_refund(gas.refunded()); + push_b256!(interpreter, address.unwrap_or_default().into()); + interpreter.gas.erase_cost(gas.remaining()); + interpreter.gas.record_refund(gas.refunded()); } return_revert!() => { - push_b256!(interp, B256::zero()); - interp.gas.erase_cost(gas.remaining()); + push_b256!(interpreter, B256::zero()); + interpreter.gas.erase_cost(gas.remaining()); + } + Return::FatalExternalError => { + interpreter.instruction_result = Return::FatalExternalError; + return; } - Return::FatalExternalError => return Return::FatalExternalError, _ => { - push_b256!(interp, B256::zero()); + push_b256!(interpreter, B256::zero()); } } - interp.add_next_gas_block(interp.program_counter() - 1) + if let Some(ret) = interpreter.add_next_gas_block(interpreter.program_counter() - 1) { + interpreter.instruction_result = ret; + } +} + +pub fn call(interpreter: &mut Interpreter, host: &mut dyn Host) { + call_inner::(interpreter, CallScheme::Call, host); +} + +pub fn call_code(interpreter: &mut Interpreter, host: &mut dyn Host) { + call_inner::(interpreter, CallScheme::CallCode, host); +} + +pub fn delegate_call(interpreter: &mut Interpreter, host: &mut dyn Host) { + call_inner::(interpreter, CallScheme::DelegateCall, host); } -pub fn call( - interp: &mut Interpreter, +pub fn static_call(interpreter: &mut Interpreter, host: &mut dyn Host) { + call_inner::(interpreter, CallScheme::StaticCall, host); +} + +pub fn call_inner( + interpreter: &mut Interpreter, scheme: CallScheme, - host: &mut H, -) -> Return { + host: &mut dyn Host, +) { match scheme { - CallScheme::DelegateCall => check!(SPEC::enabled(HOMESTEAD)), // EIP-7: DELEGATECALL - CallScheme::StaticCall => check!(SPEC::enabled(BYZANTIUM)), // EIP-214: New opcode STATICCALL + CallScheme::DelegateCall => check!(interpreter, SPEC::enabled(HOMESTEAD)), // EIP-7: DELEGATECALL + CallScheme::StaticCall => check!(interpreter, SPEC::enabled(BYZANTIUM)), // EIP-214: New opcode STATICCALL _ => (), } - interp.return_data_buffer = Bytes::new(); + interpreter.return_data_buffer = Bytes::new(); - pop!(interp, local_gas_limit); - pop_address!(interp, to); + pop!(interpreter, local_gas_limit); + pop_address!(interpreter, to); let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX); let value = match scheme { CallScheme::CallCode => { - pop!(interp, value); + pop!(interpreter, value); value } CallScheme::Call => { - pop!(interp, value); - if SPEC::IS_STATIC_CALL && value != U256::ZERO { - return Return::CallNotAllowedInsideStatic; + pop!(interpreter, value); + if interpreter.is_static && value != U256::ZERO { + interpreter.instruction_result = Return::CallNotAllowedInsideStatic; + return; } value } CallScheme::DelegateCall | CallScheme::StaticCall => U256::ZERO, }; - pop!(interp, in_offset, in_len, out_offset, out_len); + pop!(interpreter, in_offset, in_len, out_offset, out_len); - let in_len = as_usize_or_fail!(in_len, Return::OutOfGas); + let in_len = as_usize_or_fail!(interpreter, in_len, Return::OutOfGas); let input = if in_len != 0 { - let in_offset = as_usize_or_fail!(in_offset, Return::OutOfGas); - memory_resize!(interp, in_offset, in_len); - Bytes::copy_from_slice(interp.memory.get_slice(in_offset, in_len)) + let in_offset = as_usize_or_fail!(interpreter, in_offset, Return::OutOfGas); + memory_resize!(interpreter, in_offset, in_len); + Bytes::copy_from_slice(interpreter.memory.get_slice(in_offset, in_len)) } else { Bytes::new() }; - let out_len = as_usize_or_fail!(out_len, Return::OutOfGas); + let out_len = as_usize_or_fail!(interpreter, out_len, Return::OutOfGas); let out_offset = if out_len != 0 { - let out_offset = as_usize_or_fail!(out_offset, Return::OutOfGas); - memory_resize!(interp, out_offset, out_len); + let out_offset = as_usize_or_fail!(interpreter, out_offset, Return::OutOfGas); + memory_resize!(interpreter, out_offset, out_len); out_offset } else { usize::MAX //unrealistic value so we are sure it is not used @@ -330,44 +360,44 @@ pub fn call( let context = match scheme { CallScheme::Call | CallScheme::StaticCall => CallContext { address: to, - caller: interp.contract.address, + caller: interpreter.contract.address, code_address: to, apparent_value: value, scheme, }, CallScheme::CallCode => CallContext { - address: interp.contract.address, - caller: interp.contract.address, + address: interpreter.contract.address, + caller: interpreter.contract.address, code_address: to, apparent_value: value, scheme, }, CallScheme::DelegateCall => CallContext { - address: interp.contract.address, - caller: interp.contract.caller, + address: interpreter.contract.address, + caller: interpreter.contract.caller, code_address: to, - apparent_value: interp.contract.value, + apparent_value: interpreter.contract.value, scheme, }, }; let transfer = if scheme == CallScheme::Call { Transfer { - source: interp.contract.address, + source: interpreter.contract.address, target: to, value, } } else if scheme == CallScheme::CallCode { Transfer { - source: interp.contract.address, - target: interp.contract.address, + source: interpreter.contract.address, + target: interpreter.contract.address, value, } } else { //this is dummy send for StaticCall and DelegateCall, it should do nothing and dont touch anything. Transfer { - source: interp.contract.address, - target: interp.contract.address, + source: interpreter.contract.address, + target: interpreter.contract.address, value: U256::ZERO, } }; @@ -375,13 +405,14 @@ pub fn call( // load account and calculate gas cost. let res = host.load_account(to); if res.is_none() { - return Return::FatalExternalError; + interpreter.instruction_result = Return::FatalExternalError; + return; } let (is_cold, exist) = res.unwrap(); let is_new = !exist; gas!( - interp, + interpreter, gas::call_cost::( value, is_new, @@ -394,19 +425,19 @@ pub fn call( // take l64 part of gas_limit let mut gas_limit = if SPEC::enabled(TANGERINE) { //EIP-150: Gas cost changes for IO-heavy operations - let gas = interp.gas().remaining(); + let gas = interpreter.gas().remaining(); min(gas - gas / 64, local_gas_limit) } else { local_gas_limit }; - gas!(interp, gas_limit); + gas!(interpreter, gas_limit); // add call stipend if there is value to be transferred. if matches!(scheme, CallScheme::Call | CallScheme::CallCode) && transfer.value != U256::ZERO { gas_limit = gas_limit.saturating_add(gas::CALL_STIPEND); } - let is_static = matches!(scheme, CallScheme::StaticCall); + let is_static = matches!(scheme, CallScheme::StaticCall) || interpreter.is_static; let mut call_input = CallInputs { contract: to, @@ -414,38 +445,42 @@ pub fn call( input, gas_limit, context, + is_static, }; - // CALL CONTRACT, with static or ordinary spec. - let (reason, gas, return_data) = if is_static { - host.call::(&mut call_input) - } else { - host.call::(&mut call_input) - }; - interp.return_data_buffer = return_data; - let target_len = min(out_len, interp.return_data_buffer.len()); + // Call host to interuct with target contract + let (reason, gas, return_data) = host.call(&mut call_input); + + interpreter.return_data_buffer = return_data; + + let target_len = min(out_len, interpreter.return_data_buffer.len()); match reason { return_ok!() => { // return unspend gas. - interp.gas.erase_cost(gas.remaining()); - interp.gas.record_refund(gas.refunded()); - interp + interpreter.gas.erase_cost(gas.remaining()); + interpreter.gas.record_refund(gas.refunded()); + interpreter .memory - .set(out_offset, &interp.return_data_buffer[..target_len]); - push!(interp, U256::from(1)); + .set(out_offset, &interpreter.return_data_buffer[..target_len]); + push!(interpreter, U256::from(1)); } return_revert!() => { - interp.gas.erase_cost(gas.remaining()); - interp + interpreter.gas.erase_cost(gas.remaining()); + interpreter .memory - .set(out_offset, &interp.return_data_buffer[..target_len]); - push!(interp, U256::ZERO); + .set(out_offset, &interpreter.return_data_buffer[..target_len]); + push!(interpreter, U256::ZERO); + } + Return::FatalExternalError => { + interpreter.instruction_result = Return::FatalExternalError; + return; } - Return::FatalExternalError => return Return::FatalExternalError, _ => { - push!(interp, U256::ZERO); + push!(interpreter, U256::ZERO); } } - interp.add_next_gas_block(interp.program_counter() - 1) + if let Some(ret) = interpreter.add_next_gas_block(interpreter.program_counter() - 1) { + interpreter.instruction_result = ret; + } } diff --git a/crates/revm/src/instructions/host_env.rs b/crates/revm/src/instructions/host_env.rs index 0acccb7d06..6374b359ea 100644 --- a/crates/revm/src/instructions/host_env.rs +++ b/crates/revm/src/instructions/host_env.rs @@ -1,63 +1,54 @@ use crate::{interpreter::Interpreter, Host, Return, Spec, SpecId::*}; -pub fn chainid(interp: &mut Interpreter, host: &mut H) -> Return { +pub fn chainid(interpreter: &mut Interpreter, host: &mut dyn Host) { // gas!(interp, gas::BASE); // EIP-1344: ChainID opcode - check!(SPEC::enabled(ISTANBUL)); - push!(interp, host.env().cfg.chain_id); - Return::Continue + check!(interpreter, SPEC::enabled(ISTANBUL)); + push!(interpreter, host.env().cfg.chain_id); } -pub fn coinbase(interp: &mut Interpreter, host: &mut H) -> Return { +pub fn coinbase(interpreter: &mut Interpreter, host: &mut dyn Host) { // gas!(interp, gas::BASE); - push_b256!(interp, host.env().block.coinbase.into()); - Return::Continue + push_b256!(interpreter, host.env().block.coinbase.into()); } -pub fn timestamp(interp: &mut Interpreter, host: &mut H) -> Return { +pub fn timestamp(interpreter: &mut Interpreter, host: &mut dyn Host) { // gas!(interp, gas::BASE); - push!(interp, host.env().block.timestamp); - Return::Continue + push!(interpreter, host.env().block.timestamp); } -pub fn number(interp: &mut Interpreter, host: &mut H) -> Return { +pub fn number(interpreter: &mut Interpreter, host: &mut dyn Host) { // gas!(interp, gas::BASE); - push!(interp, host.env().block.number); - Return::Continue + push!(interpreter, host.env().block.number); } -pub fn difficulty(interp: &mut Interpreter, host: &mut H) -> Return { +pub fn difficulty(interpreter: &mut Interpreter, host: &mut H) { // gas!(interp, gas::BASE); if SPEC::enabled(MERGE) { - push_b256!(interp, host.env().block.prevrandao.unwrap()); + push_b256!(interpreter, host.env().block.prevrandao.unwrap()); } else { - push!(interp, host.env().block.difficulty); + push!(interpreter, host.env().block.difficulty); } - Return::Continue } -pub fn gaslimit(interp: &mut Interpreter, host: &mut H) -> Return { +pub fn gaslimit(interpreter: &mut Interpreter, host: &mut dyn Host) { // gas!(interp, gas::BASE); - push!(interp, host.env().block.gas_limit); - Return::Continue + push!(interpreter, host.env().block.gas_limit); } -pub fn gasprice(interp: &mut Interpreter, host: &mut H) -> Return { +pub fn gasprice(interpreter: &mut Interpreter, host: &mut dyn Host) { // gas!(interp, gas::BASE); - push!(interp, host.env().effective_gas_price()); - Return::Continue + push!(interpreter, host.env().effective_gas_price()); } -pub fn basefee(interp: &mut Interpreter, host: &mut H) -> Return { +pub fn basefee(interpreter: &mut Interpreter, host: &mut dyn Host) { // gas!(interp, gas::BASE); // EIP-3198: BASEFEE opcode - check!(SPEC::enabled(LONDON)); - push!(interp, host.env().block.basefee); - Return::Continue + check!(interpreter, SPEC::enabled(LONDON)); + push!(interpreter, host.env().block.basefee); } -pub fn origin(interp: &mut Interpreter, host: &mut H) -> Return { +pub fn origin(interpreter: &mut Interpreter, host: &mut dyn Host) { // gas!(interp, gas::BASE); - push_b256!(interp, host.env().tx.caller.into()); - Return::Continue + push_b256!(interpreter, host.env().tx.caller.into()); } diff --git a/crates/revm/src/instructions/macros.rs b/crates/revm/src/instructions/macros.rs index 43d043721f..b7410821cb 100644 --- a/crates/revm/src/instructions/macros.rs +++ b/crates/revm/src/instructions/macros.rs @@ -1,9 +1,10 @@ pub use crate::Return; macro_rules! check { - ($expresion:expr) => { + ($interp:expr, $expresion:expr) => { if !$expresion { - return Return::NotActivated; + $interp.instruction_result = Return::NotActivated; + return; } }; } @@ -12,7 +13,8 @@ macro_rules! gas { ($interp:expr, $gas:expr) => { if crate::USE_GAS { if !$interp.gas.record_cost(($gas)) { - return Return::OutOfGas; + $interp.instruction_result = Return::OutOfGas; + return; } } }; @@ -31,7 +33,10 @@ macro_rules! gas_or_fail { if crate::USE_GAS { match $gas { Some(gas_used) => gas!($interp, gas_used), - None => return Return::OutOfGas, + None => { + $interp.instruction_result = Return::OutOfGas; + return; + } } } }; @@ -46,20 +51,23 @@ macro_rules! memory_resize { { #[cfg(feature = "memory_limit")] if new_size > ($interp.memory_limit as usize) { - return Return::OutOfGas; + $interp.instruction_result = Return::OutOfGas; + return; } if new_size > $interp.memory.len() { if crate::USE_GAS { let num_bytes = new_size / 32; if !$interp.gas.record_memory(crate::gas::memory_gas(num_bytes)) { - return Return::OutOfGas; + $interp.instruction_result = Return::OutOfGas; + return; } } $interp.memory.resize(new_size); } } else { - return Return::OutOfGas; + $interp.instruction_result = Return::OutOfGas; + return; } }}; } @@ -67,7 +75,8 @@ macro_rules! memory_resize { macro_rules! pop_address { ( $interp:expr, $x1:ident) => { if $interp.stack.len() < 1 { - return Return::StackUnderflow; + $interp.instruction_result = Return::StackUnderflow; + return; } // Safety: Length is checked above. let $x1: B160 = B160( @@ -78,7 +87,8 @@ macro_rules! pop_address { }; ( $interp:expr, $x1:ident, $x2:ident) => { if $interp.stack.len() < 2 { - return Return::StackUnderflow; + $interp.instruction_result = Return::StackUnderflow; + return; } let mut temp = H256::zero(); @@ -98,21 +108,24 @@ macro_rules! pop_address { macro_rules! pop { ( $interp:expr, $x1:ident) => { if $interp.stack.len() < 1 { - return Return::StackUnderflow; + $interp.instruction_result = Return::StackUnderflow; + return; } // Safety: Length is checked above. let $x1 = unsafe { $interp.stack.pop_unsafe() }; }; ( $interp:expr, $x1:ident, $x2:ident) => { if $interp.stack.len() < 2 { - return Return::StackUnderflow; + $interp.instruction_result = Return::StackUnderflow; + return; } // Safety: Length is checked above. let ($x1, $x2) = unsafe { $interp.stack.pop2_unsafe() }; }; ( $interp:expr, $x1:ident, $x2:ident, $x3:ident) => { if $interp.stack.len() < 3 { - return Return::StackUnderflow; + $interp.instruction_result = Return::StackUnderflow; + return; } // Safety: Length is checked above. let ($x1, $x2, $x3) = unsafe { $interp.stack.pop3_unsafe() }; @@ -120,7 +133,8 @@ macro_rules! pop { ( $interp:expr, $x1:ident, $x2:ident, $x3:ident, $x4:ident) => { if $interp.stack.len() < 4 { - return Return::StackUnderflow; + $interp.instruction_result = Return::StackUnderflow; + return; } // Safety: Length is checked above. let ($x1, $x2, $x3, $x4) = unsafe { $interp.stack.pop4_unsafe() }; @@ -130,21 +144,24 @@ macro_rules! pop { macro_rules! pop_top { ( $interp:expr, $x1:ident) => { if $interp.stack.len() < 1 { - return Return::StackUnderflow; + $interp.instruction_result = Return::StackUnderflow; + return; } // Safety: Length is checked above. let $x1 = unsafe { $interp.stack.top_unsafe() }; }; ( $interp:expr, $x1:ident, $x2:ident) => { if $interp.stack.len() < 2 { - return Return::StackUnderflow; + $interp.instruction_result = Return::StackUnderflow; + return; } // Safety: Length is checked above. let ($x1, $x2) = unsafe { $interp.stack.pop_top_unsafe() }; }; ( $interp:expr, $x1:ident, $x2:ident, $x3:ident) => { if $interp.stack.len() < 3 { - return Return::StackUnderflow; + $interp.instruction_result = Return::StackUnderflow; + return; } // Safety: Length is checked above. let ($x1, $x2, $x3) = unsafe { $interp.stack.pop2_top_unsafe() }; @@ -156,7 +173,10 @@ macro_rules! push_b256 { $( match $interp.stack.push_b256($x) { Ok(()) => (), - Err(e) => return e, + Err(e) => { + $interp.instruction_result = e; + return + }, } )* ) @@ -167,87 +187,57 @@ macro_rules! push { $( match $interp.stack.push($x) { Ok(()) => (), - Err(e) => return e, + Err(e) => { $interp.instruction_result = e; + return + } , } )* ) } -macro_rules! op1_u256_fn { - ( $interp:expr, $op:path ) => {{ - // gas!($interp, $gas); - pop_top!($interp, op1); - *op1 = $op(*op1); - - Return::Continue - }}; -} - -macro_rules! op2_u256_bool_ref { - ( $interp:expr, $op:ident) => {{ - // gas!($interp, $gas); - pop_top!($interp, op1, op2); - let ret = op1.$op(&op2); - *op2 = if ret { U256::from(1) } else { U256::ZERO }; - - Return::Continue - }}; -} - -macro_rules! op2_u256 { - ( $interp:expr, $op:ident) => {{ - // gas!($interp, $gas); - pop_top!($interp, op1, op2); - *op2 = op1.$op(*op2); - Return::Continue - }}; -} - -macro_rules! op2_u256_fn { - ( $interp:expr, $op:path ) => {{ - // gas!($interp, $gas); - - pop_top!($interp, op1, op2); - *op2 = $op(op1, *op2); - - Return::Continue - }}; - ( $interp:expr, $op:path, $enabled:expr) => {{ - check!(($enabled)); - op2_u256_fn!($interp, $op) - }}; -} - -macro_rules! op3_u256_fn { - ( $interp:expr, $op:path) => {{ - // gas!($interp, $gas); - - pop_top!($interp, op1, op2, op3); - *op3 = $op(op1, op2, *op3); - - Return::Continue - }}; - ( $interp:expr, $op:path, $spec:ident :: $enabled:ident) => {{ - check!($spec::$enabled); - op3_u256_fn!($interp, $op) - }}; -} +// macro_rules! as_usize_saturated { +// ( $v:expr ) => { +// $v.saturating_to::() +// }; +// } + +// macro_rules! as_usize_or_fail { +// ( $interp:expr, $v:expr ) => {{ +// as_usize_or_fail!($interp, $v, Return::OutOfGas) +// }}; + +// ( $interp:expr, $v:expr, $reason:expr ) => { +// match $v[0] == 0 { +// Ok(value) => value, +// Err(_) => { +// $interp.instruction_result = $reason; +// return; +// } +// } +// }; +// } macro_rules! as_usize_saturated { - ( $v:expr ) => { - $v.saturating_to::() - }; + ( $v:expr ) => {{ + if $v.as_limbs()[1] != 0 || $v.as_limbs()[2] != 0 || $v.as_limbs()[3] != 0 { + usize::MAX + } else { + $v.as_limbs()[0] as usize + } + }}; } macro_rules! as_usize_or_fail { - ( $v:expr ) => {{ - as_usize_or_fail!($v, Return::OutOfGas) + ( $interp:expr, $v:expr ) => {{ + as_usize_or_fail!($interp, $v, Return::OutOfGas) }}; - ( $v:expr, $reason:expr ) => { - match usize::try_from($v) { - Ok(value) => value, - Err(_) => return $reason, + ( $interp:expr, $v:expr, $reason:expr ) => {{ + if $v.as_limbs()[1] != 0 || $v.as_limbs()[2] != 0 || $v.as_limbs()[3] != 0 { + $interp.instruction_result = $reason; + return; } - }; + + $v.as_limbs()[0] as usize + }}; } diff --git a/crates/revm/src/instructions/memory.rs b/crates/revm/src/instructions/memory.rs index 79541c406b..06a482f6f6 100644 --- a/crates/revm/src/instructions/memory.rs +++ b/crates/revm/src/instructions/memory.rs @@ -1,41 +1,37 @@ -use crate::{interpreter::Interpreter, Return, U256}; +use crate::{interpreter::Interpreter, Host, Return, U256}; -pub fn mload(interp: &mut Interpreter) -> Return { +pub fn mload(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::VERYLOW); - pop!(interp, index); - let index = as_usize_or_fail!(index, Return::OutOfGas); - memory_resize!(interp, index, 32); + pop!(interpreter, index); + let index = as_usize_or_fail!(interpreter, index, Return::OutOfGas); + memory_resize!(interpreter, index, 32); push!( - interp, + interpreter, U256::from_be_bytes::<{ U256::BYTES }>( - interp.memory.get_slice(index, 32).try_into().unwrap() + interpreter.memory.get_slice(index, 32).try_into().unwrap() ) ); - Return::Continue } -pub fn mstore(interp: &mut Interpreter) -> Return { +pub fn mstore(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::VERYLOW); - pop!(interp, index, value); - let index = as_usize_or_fail!(index, Return::OutOfGas); - memory_resize!(interp, index, 32); - interp.memory.set_u256(index, value); - Return::Continue + pop!(interpreter, index, value); + let index = as_usize_or_fail!(interpreter, index, Return::OutOfGas); + memory_resize!(interpreter, index, 32); + interpreter.memory.set_u256(index, value); } -pub fn mstore8(interp: &mut Interpreter) -> Return { +pub fn mstore8(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::VERYLOW); - pop!(interp, index, value); - let index = as_usize_or_fail!(index, Return::OutOfGas); - memory_resize!(interp, index, 1); + pop!(interpreter, index, value); + let index = as_usize_or_fail!(interpreter, index, Return::OutOfGas); + memory_resize!(interpreter, index, 1); let value = value.as_le_bytes()[0]; // Safety: we resized our memory two lines above. - unsafe { interp.memory.set_byte(index, value) } - Return::Continue + unsafe { interpreter.memory.set_byte(index, value) } } -pub fn msize(interp: &mut Interpreter) -> Return { +pub fn msize(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::BASE); - push!(interp, U256::from(interp.memory.effective_len())); - Return::Continue + push!(interpreter, U256::from(interpreter.memory.effective_len())); } diff --git a/crates/revm/src/instructions/stack.rs b/crates/revm/src/instructions/stack.rs index 8cb771718a..228e822c9d 100644 --- a/crates/revm/src/instructions/stack.rs +++ b/crates/revm/src/instructions/stack.rs @@ -1,28 +1,37 @@ -use crate::{interpreter::Interpreter, Return}; +use crate::{interpreter::Interpreter, Host}; -pub fn pop(interp: &mut Interpreter) -> Return { +pub fn pop(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::BASE); - interp.stack.reduce_one() + if let Some(ret) = interpreter.stack.reduce_one() { + interpreter.instruction_result = ret; + } } -pub fn push(interp: &mut Interpreter) -> Return { +pub fn push(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::VERYLOW); - let start = interp.instruction_pointer; + let start = interpreter.instruction_pointer; // Safety: In Analysis we appended needed bytes for bytecode so that we are safe to just add without // checking if it is out of bound. This makes both of our unsafes block safe to do. - let ret = interp + if let Some(ret) = interpreter .stack - .push_slice::(unsafe { core::slice::from_raw_parts(start, N) }); - interp.instruction_pointer = unsafe { interp.instruction_pointer.add(N) }; - ret + .push_slice::(unsafe { core::slice::from_raw_parts(start, N) }) + { + interpreter.instruction_result = ret; + return; + } + interpreter.instruction_pointer = unsafe { interpreter.instruction_pointer.add(N) }; } -pub fn dup(interp: &mut Interpreter) -> Return { +pub fn dup(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::VERYLOW); - interp.stack.dup::() + if let Some(ret) = interpreter.stack.dup::() { + interpreter.instruction_result = ret; + } } -pub fn swap(interp: &mut Interpreter) -> Return { +pub fn swap(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::VERYLOW); - interp.stack.swap::() + if let Some(ret) = interpreter.stack.swap::() { + interpreter.instruction_result = ret; + } } diff --git a/crates/revm/src/instructions/system.rs b/crates/revm/src/instructions/system.rs index 22f40dd691..6ad58b8846 100644 --- a/crates/revm/src/instructions/system.rs +++ b/crates/revm/src/instructions/system.rs @@ -1,144 +1,139 @@ use crate::{ - bits::B256, common::keccak256, gas, interpreter::Interpreter, Return, Spec, SpecId::*, - KECCAK_EMPTY, U256, + B256, U256, common::keccak256, gas, interpreter::Interpreter, Host, Return, Spec, SpecId::*, KECCAK_EMPTY, }; use std::cmp::min; -pub fn sha3(interp: &mut Interpreter) -> Return { - pop!(interp, from, len); - let len = as_usize_or_fail!(len, Return::OutOfGas); - gas_or_fail!(interp, gas::sha3_cost(len as u64)); +pub fn sha3(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop!(interpreter, from, len); + let len = as_usize_or_fail!(interpreter, len, Return::OutOfGas); + gas_or_fail!(interpreter, gas::sha3_cost(len as u64)); let hash = if len == 0 { KECCAK_EMPTY } else { - let from = as_usize_or_fail!(from, Return::OutOfGas); - memory_resize!(interp, from, len); - keccak256(interp.memory.get_slice(from, len)) + let from = as_usize_or_fail!(interpreter, from, Return::OutOfGas); + memory_resize!(interpreter, from, len); + keccak256(interpreter.memory.get_slice(from, len)) }; - push_b256!(interp, hash); - Return::Continue + push_b256!(interpreter, hash); } -pub fn address(interp: &mut Interpreter) -> Return { +pub fn address(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::BASE); - push_b256!(interp, B256::from(interp.contract.address)); - Return::Continue + push_b256!(interpreter, B256::from(interpreter.contract.address)); } -pub fn caller(interp: &mut Interpreter) -> Return { +pub fn caller(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::BASE); - push_b256!(interp, B256::from(interp.contract.caller)); - Return::Continue + push_b256!(interpreter, B256::from(interpreter.contract.caller)); + } -pub fn codesize(interp: &mut Interpreter) -> Return { +pub fn codesize(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::BASE); - push!(interp, U256::from(interp.contract.bytecode.len())); - Return::Continue + push!(interpreter, U256::from(interpreter.contract.bytecode.len())); } -pub fn codecopy(interp: &mut Interpreter) -> Return { - pop!(interp, memory_offset, code_offset, len); - let len = as_usize_or_fail!(len, Return::OutOfGas); - gas_or_fail!(interp, gas::verylowcopy_cost(len as u64)); +pub fn codecopy(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop!(interpreter, memory_offset, code_offset, len); + let len = as_usize_or_fail!(interpreter, len, Return::OutOfGas); + gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64)); if len == 0 { - return Return::Continue; + return; } - let memory_offset = as_usize_or_fail!(memory_offset, Return::OutOfGas); + let memory_offset = as_usize_or_fail!(interpreter, memory_offset, Return::OutOfGas); let code_offset = as_usize_saturated!(code_offset); - memory_resize!(interp, memory_offset, len); + memory_resize!(interpreter, memory_offset, len); // Safety: set_data is unsafe function and memory_resize ensures us that it is safe to call it - interp.memory.set_data( + interpreter.memory.set_data( memory_offset, code_offset, len, - interp.contract.bytecode.original_bytecode_slice(), + interpreter.contract.bytecode.original_bytecode_slice(), ); - Return::Continue } -pub fn calldataload(interp: &mut Interpreter) -> Return { +pub fn calldataload(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::VERYLOW); - pop!(interp, index); + pop!(interpreter, index); let index = as_usize_saturated!(index); - let load = if index < interp.contract.input.len() { - let have_bytes = min(interp.contract.input.len() - index, 32); - let mut bytes = [0u8; U256::BYTES]; - bytes[..have_bytes].copy_from_slice(&interp.contract.input[index..index + have_bytes]); + let load = if index < interpreter.contract.input.len() { + let have_bytes = min(interpreter.contract.input.len() - index, 32); + let mut bytes = [0u8; 32]; + bytes[..have_bytes].copy_from_slice(&interpreter.contract.input[index..index + have_bytes]); B256(bytes) } else { B256::zero() }; - push_b256!(interp, load); - Return::Continue + push_b256!(interpreter, load); } -pub fn calldatasize(interp: &mut Interpreter) -> Return { +pub fn calldatasize(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::BASE); - push!(interp, U256::from(interp.contract.input.len())); - Return::Continue + push!(interpreter, U256::from(interpreter.contract.input.len())); } -pub fn callvalue(interp: &mut Interpreter) -> Return { +pub fn callvalue(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::BASE); - push!(interp, interp.contract.value); - Return::Continue + push!(interpreter, interpreter.contract.value); } -pub fn calldatacopy(interp: &mut Interpreter) -> Return { - pop!(interp, memory_offset, data_offset, len); - let len = as_usize_or_fail!(len, Return::OutOfGas); - gas_or_fail!(interp, gas::verylowcopy_cost(len as u64)); +pub fn calldatacopy(interpreter: &mut Interpreter, _host: &mut dyn Host) { + pop!(interpreter, memory_offset, data_offset, len); + let len = as_usize_or_fail!(interpreter, len, Return::OutOfGas); + gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64)); if len == 0 { - return Return::Continue; + return; } - let memory_offset = as_usize_or_fail!(memory_offset, Return::OutOfGas); + let memory_offset = as_usize_or_fail!(interpreter, memory_offset, Return::OutOfGas); let data_offset = as_usize_saturated!(data_offset); - memory_resize!(interp, memory_offset, len); + memory_resize!(interpreter, memory_offset, len); // Safety: set_data is unsafe function and memory_resize ensures us that it is safe to call it - interp + interpreter .memory - .set_data(memory_offset, data_offset, len, &interp.contract.input); - Return::Continue + .set_data(memory_offset, data_offset, len, &interpreter.contract.input); } -pub fn returndatasize(interp: &mut Interpreter) -> Return { +pub fn returndatasize(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::BASE); // EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY - check!(SPEC::enabled(BYZANTIUM)); - push!(interp, U256::from(interp.return_data_buffer.len())); - Return::Continue + check!(interpreter, SPEC::enabled(BYZANTIUM)); + push!( + interpreter, + U256::from(interpreter.return_data_buffer.len()) + ); } -pub fn returndatacopy(interp: &mut Interpreter) -> Return { +pub fn returndatacopy(interpreter: &mut Interpreter, _host: &mut dyn Host) { // EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY - check!(SPEC::enabled(BYZANTIUM)); - pop!(interp, memory_offset, offset, len); - let len = as_usize_or_fail!(len, Return::OutOfGas); - gas_or_fail!(interp, gas::verylowcopy_cost(len as u64)); + check!(interpreter, SPEC::enabled(BYZANTIUM)); + pop!(interpreter, memory_offset, offset, len); + let len = as_usize_or_fail!(interpreter,len, Return::OutOfGas); + gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64)); let data_offset = as_usize_saturated!(offset); let (data_end, overflow) = data_offset.overflowing_add(len); - if overflow || data_end > interp.return_data_buffer.len() { - return Return::OutOfOffset; + if overflow || data_end > interpreter.return_data_buffer.len() { + interpreter.instruction_result = Return::OutOfOffset; + return; } if len != 0 { - let memory_offset = as_usize_or_fail!(memory_offset, Return::OutOfGas); - memory_resize!(interp, memory_offset, len); - interp.memory.set( + let memory_offset = as_usize_or_fail!(interpreter,memory_offset, Return::OutOfGas); + memory_resize!(interpreter, memory_offset, len); + interpreter.memory.set( memory_offset, - &interp.return_data_buffer[data_offset..data_end], + &interpreter.return_data_buffer[data_offset..data_end], ); } - Return::Continue } -pub fn gas(interp: &mut Interpreter) -> Return { +pub fn gas(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::BASE); - push!(interp, U256::from(interp.gas.remaining())); - interp.add_next_gas_block(interp.program_counter() - 1) + push!(interpreter, U256::from(interpreter.gas.remaining())); + if let Some(ret) = interpreter.add_next_gas_block(interpreter.program_counter() - 1) { + interpreter.instruction_result = ret; + } } diff --git a/crates/revm/src/interpreter.rs b/crates/revm/src/interpreter.rs index 9e83e94beb..520a616800 100644 --- a/crates/revm/src/interpreter.rs +++ b/crates/revm/src/interpreter.rs @@ -10,7 +10,7 @@ pub use stack::Stack; use crate::{ instructions::{eval, Return}, - Gas, Host, Spec, USE_GAS, + Gas, Host, USE_GAS,Spec }; use bytes::Bytes; use core::ops::Range; @@ -33,6 +33,10 @@ pub struct Interpreter { pub return_data_buffer: Bytes, /// Return value. pub return_range: Range, + /// Return is main control flag, it tell us if we should continue interpreter or break from it + pub instruction_result: Return, + /// Is interpreter call static. + pub is_static: bool, /// Memory limit. See [`crate::CfgEnv`]. #[cfg(feature = "memory_limit")] pub memory_limit: u64, @@ -43,7 +47,8 @@ impl Interpreter { unsafe { *self.instruction_pointer } } #[cfg(not(feature = "memory_limit"))] - pub fn new(contract: Contract, gas_limit: u64) -> Self { + pub fn new(contract: Contract, gas_limit: u64,is_static:bool) -> Self { + Self { instruction_pointer: contract.bytecode.as_ptr(), return_range: Range::default(), @@ -51,6 +56,8 @@ impl Interpreter { stack: Stack::new(), return_data_buffer: Bytes::new(), contract, + instruction_result: Return::Continue, + is_static, gas: Gas::new(gas_limit), } } @@ -86,14 +93,15 @@ impl Interpreter { &self.stack } - pub fn add_next_gas_block(&mut self, pc: usize) -> Return { + #[inline(always)] + pub fn add_next_gas_block(&mut self, pc: usize) -> Option { if USE_GAS { let gas_block = self.contract.gas_block(pc); if !self.gas.record_cost(gas_block) { - return Return::OutOfGas; + return Some(Return::OutOfGas); } } - Return::Continue + None } /// Return a reference of the program counter. @@ -106,36 +114,43 @@ impl Interpreter { } /// loop steps until we are finished with execution - pub fn run(&mut self, host: &mut H) -> Return { + pub fn run(&mut self, host: &mut H, inspect: bool) -> Return { //let timer = std::time::Instant::now(); - let mut ret = Return::Continue; // add first gas_block if USE_GAS && !self.gas.record_cost(self.contract.first_gas_block()) { return Return::OutOfGas; } - while ret == Return::Continue { - // step - if H::INSPECT { - let ret = host.step(self, SPEC::IS_STATIC_CALL); + if inspect { + while self.instruction_result == Return::Continue { + // step + let ret = host.step(self, self.is_static); if ret != Return::Continue { return ret; } - } - let opcode = unsafe { *self.instruction_pointer }; - // Safety: In analysis we are doing padding of bytecode so that we are sure that last. - // byte instruction is STOP so we are safe to just increment program_counter bcs on last instruction - // it will do noop and just stop execution of this contract - self.instruction_pointer = unsafe { self.instruction_pointer.offset(1) }; - ret = eval::(opcode, self, host); + let opcode = unsafe { *self.instruction_pointer }; + // Safety: In analysis we are doing padding of bytecode so that we are sure that last. + // byte instruction is STOP so we are safe to just increment program_counter bcs on last instruction + // it will do noop and just stop execution of this contract + self.instruction_pointer = unsafe { self.instruction_pointer.offset(1) }; + eval::(opcode, self, host); - if H::INSPECT { - let ret = host.step_end(self, SPEC::IS_STATIC_CALL, ret); + let ret = host.step_end(self, self.is_static, self.instruction_result); if ret != Return::Continue { return ret; } } + } else { + while self.instruction_result == Return::Continue { + // step. + let opcode = unsafe { *self.instruction_pointer }; + // Safety: In analysis we are doing padding of bytecode so that we are sure that last. + // byte instruction is STOP so we are safe to just increment program_counter bcs on last instruction + // it will do noop and just stop execution of this contract + self.instruction_pointer = unsafe { self.instruction_pointer.offset(1) }; + eval::(opcode, self, host); + } } - ret + self.instruction_result } /// Copy and get the return value of the interp, if any. diff --git a/crates/revm/src/interpreter/stack.rs b/crates/revm/src/interpreter/stack.rs index 3717cfd3fe..9c44483554 100644 --- a/crates/revm/src/interpreter/stack.rs +++ b/crates/revm/src/interpreter/stack.rs @@ -60,15 +60,16 @@ impl Stack { &self.data } - pub fn reduce_one(&mut self) -> Return { + #[inline(always)] + pub fn reduce_one(&mut self) -> Option { let len = self.data.len(); if len < 1 { - return Return::StackUnderflow; + return Some(Return::StackUnderflow); } unsafe { self.data.set_len(len - 1); } - Return::Continue + None } #[inline] @@ -212,27 +213,27 @@ impl Stack { } #[inline(always)] - pub fn dup(&mut self) -> Return { + pub fn dup(&mut self) -> Option { let len = self.data.len(); if len < N { - Return::StackUnderflow + Some(Return::StackUnderflow) } else if len + 1 > STACK_LIMIT { - Return::StackOverflow + Some(Return::StackOverflow) } else { // Safety: check for out of bounds is done above and it makes this safe to do. unsafe { *self.data.get_unchecked_mut(len) = *self.data.get_unchecked(len - N); self.data.set_len(len + 1); } - Return::Continue + None } } #[inline(always)] - pub fn swap(&mut self) -> Return { + pub fn swap(&mut self) -> Option { let len = self.data.len(); if len <= N { - return Return::StackUnderflow; + return Some(Return::StackUnderflow); } // Safety: length is checked before so we are okay to switch bytes in unsafe way. unsafe { @@ -240,15 +241,15 @@ impl Stack { let pb: *mut U256 = self.data.get_unchecked_mut(len - 1 - N); core::ptr::swap(pa, pb); } - Return::Continue + None } /// push slice onto memory it is expected to be max 32 bytes and be contains inside B256 #[inline(always)] - pub fn push_slice(&mut self, slice: &[u8]) -> Return { + pub fn push_slice(&mut self, slice: &[u8]) -> Option { let new_len = self.data.len() + 1; if new_len > STACK_LIMIT { - return Return::StackOverflow; + return Some(Return::StackOverflow); } let slot; @@ -293,7 +294,7 @@ impl Stack { } } } - Return::Continue + None } #[inline] diff --git a/crates/revm/src/models.rs b/crates/revm/src/models.rs index dc91c63a1d..5816cdcca1 100644 --- a/crates/revm/src/models.rs +++ b/crates/revm/src/models.rs @@ -89,6 +89,8 @@ pub struct CallInputs { pub gas_limit: u64, /// The context of the call. pub context: CallContext, + /// Is static call + pub is_static: bool, } #[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))] diff --git a/crates/revm/src/specification.rs b/crates/revm/src/specification.rs index 0ddc87776e..2e21dc669c 100644 --- a/crates/revm/src/specification.rs +++ b/crates/revm/src/specification.rs @@ -78,54 +78,27 @@ impl SpecId { } } -pub(crate) trait NotStaticSpec {} - pub trait Spec: Sized { - /// little bit of magic. We can have child version of Spec that contains static flag enabled - type STATIC: Spec; - #[inline(always)] fn enabled(spec_id: SpecId) -> bool { Self::SPEC_ID as u8 >= spec_id as u8 } const SPEC_ID: SpecId; - /// static flag used in STATIC type; - const IS_STATIC_CALL: bool; - - const ASSUME_PRECOMPILE_HAS_BALANCE: bool; } pub(crate) mod spec_impl { - use super::{NotStaticSpec, Spec}; macro_rules! spec { ($spec_id:tt) => { #[allow(non_snake_case)] pub mod $spec_id { - use super::{NotStaticSpec, Spec}; - use crate::SpecId; - - pub struct SpecInner< - const STATIC_CALL: bool, - const ASSUME_PRECOMPILE_HAS_BALANCE: bool, - >; + use crate::{Spec, SpecId}; - pub type SpecImpl = SpecInner; - pub type SpecStaticImpl = SpecInner; - - impl NotStaticSpec for SpecImpl {} - - impl Spec - for SpecInner - { - type STATIC = SpecInner; + pub struct SpecImpl {} + impl Spec for SpecImpl { //specification id const SPEC_ID: SpecId = SpecId::$spec_id; - - const IS_STATIC_CALL: bool = IS_STATIC_CALL; - - const ASSUME_PRECOMPILE_HAS_BALANCE: bool = ASSUME_PRECOMPILE_HAS_BALANCE; } } }; From c019de9b2e99ca826b0498b04b59915431cfbd80 Mon Sep 17 00:00:00 2001 From: rakita Date: Sun, 4 Dec 2022 13:22:13 +0100 Subject: [PATCH 2/5] rm ruint patch --- Cargo.lock | 8 +++++--- Cargo.toml | 5 +---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c0043cbdd3..59cc3068cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1623,11 +1623,12 @@ dependencies = [ [[package]] name = "ruint" version = "1.7.0" -source = "git+https://github.com/recmo/uint#da0489b40dd06a5141be37bfdba2dab8fc836a41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ad3a104dc8c3867f653b0fec89c65e00b0ceb752718ad282177a7e0f33257ac" dependencies = [ "bn-rs", "derive_more", - "primitive-types 0.12.1", + "primitive-types 0.11.1", "rlp", "ruint-macro", "rustc_version", @@ -1638,7 +1639,8 @@ dependencies = [ [[package]] name = "ruint-macro" version = "1.0.2" -source = "git+https://github.com/recmo/uint#da0489b40dd06a5141be37bfdba2dab8fc836a41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62cc5760263ea229d367e7dff3c0cbf09e4797a125bd87059a6c095804f3b2d1" [[package]] name = "rustc-hex" diff --git a/Cargo.toml b/Cargo.toml index 93cd42a6a4..e9d0e48cfd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,4 @@ codegen-units = 1 [profile.ethtests] inherits = "test" -opt-level = 3 - -[patch.crates-io] -ruint = { git = "https://github.com/recmo/uint" } +opt-level = 3 \ No newline at end of file From fb8073dfa06ba2c4087b79493f696de9d99be1de Mon Sep 17 00:00:00 2001 From: rakita Date: Sun, 4 Dec 2022 14:37:34 +0100 Subject: [PATCH 3/5] cleanup, nits, fix build --- bins/revm-test/src/bin/snailtracer.rs | 10 ++----- crates/revm/src/db/web3db.rs | 1 + crates/revm/src/evm_impl.rs | 40 +++++++++++++++---------- crates/revm/src/instructions/bitwise.rs | 6 ++-- crates/revm/src/instructions/control.rs | 15 +++++----- crates/revm/src/instructions/host.rs | 6 ++-- crates/revm/src/instructions/macros.rs | 34 ++++++--------------- crates/revm/src/instructions/system.rs | 8 ++--- crates/revm/src/interpreter.rs | 8 +++-- crates/revm_precompiles/src/modexp.rs | 9 +++--- 10 files changed, 66 insertions(+), 71 deletions(-) diff --git a/bins/revm-test/src/bin/snailtracer.rs b/bins/revm-test/src/bin/snailtracer.rs index ae2e48b4f4..bf1a9aa8f1 100644 --- a/bins/revm-test/src/bin/snailtracer.rs +++ b/bins/revm-test/src/bin/snailtracer.rs @@ -26,13 +26,9 @@ pub fn simple_example() { // Microbenchmark let bench_options = microbench::Options::default().time(Duration::from_secs(3)); - microbench::bench( - &bench_options, - "Snailtracer benchmark", - || { - let (_, _) = evm.transact(); - }, - ); + microbench::bench(&bench_options, "Snailtracer benchmark", || { + let (_, _) = evm.transact(); + }); } fn main() { diff --git a/crates/revm/src/db/web3db.rs b/crates/revm/src/db/web3db.rs index bc1ad1f2e9..eb75597893 100644 --- a/crates/revm/src/db/web3db.rs +++ b/crates/revm/src/db/web3db.rs @@ -98,6 +98,7 @@ impl Database for Web3DB { } fn block_hash(&mut self, number: U256) -> Result { + // saturate usize if number > U256::from(u64::MAX) { return Ok(KECCAK_EMPTY); } diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index 722bf73192..0887194733 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -476,32 +476,33 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, ); #[cfg(feature = "memory_limit")] - let mut interp = Interpreter::new_with_memory_limit::( + let mut interpreter = Interpreter::new_with_memory_limit::( contract, gas.limit(), + false, self.data.env.cfg.memory_limit, ); #[cfg(not(feature = "memory_limit"))] - let mut interp = Interpreter::new::(contract, gas.limit(), false); + let mut interpreter = Interpreter::new::(contract, gas.limit(), false); if INSPECT { self.inspector - .initialize_interp(&mut interp, &mut self.data, false); + .initialize_interp(&mut interpreter, &mut self.data, false); } - let exit_reason = interp.run::(self, INSPECT); + let exit_reason = interpreter.run::(self, INSPECT); // Host error if present on execution\ let (ret, address, gas, out) = match exit_reason { return_ok!() => { let b = Bytes::new(); // if ok, check contract creation limit and calculate gas deduction on output len. - let mut bytes = interp.return_value(); + let mut bytes = interpreter.return_value(); // EIP-3541: Reject new contract code starting with the 0xEF byte if GSPEC::enabled(LONDON) && !bytes.is_empty() && bytes.first() == Some(&0xEF) { self.data.journaled_state.checkpoint_revert(checkpoint); - return (Return::CreateContractWithEF, ret, interp.gas, b); + return (Return::CreateContractWithEF, ret, interpreter.gas, b); } // EIP-170: Contract code size limit @@ -510,18 +511,18 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, && bytes.len() > self.data.env.cfg.limit_contract_code_size.unwrap_or(0x6000) { self.data.journaled_state.checkpoint_revert(checkpoint); - return (Return::CreateContractLimit, ret, interp.gas, b); + return (Return::CreateContractLimit, ret, interpreter.gas, b); } if crate::USE_GAS { let gas_for_code = bytes.len() as u64 * crate::gas::CODEDEPOSIT; - if !interp.gas.record_cost(gas_for_code) { + if !interpreter.gas.record_cost(gas_for_code) { // record code deposit gas cost and check if we are out of gas. // EIP-2 point 3: If contract creation does not have enough gas to pay for the // final gas fee for adding the contract code to the state, the contract // creation fails (i.e. goes out-of-gas) rather than leaving an empty contract. if GSPEC::enabled(HOMESTEAD) { self.data.journaled_state.checkpoint_revert(checkpoint); - return (Return::OutOfGas, ret, interp.gas, b); + return (Return::OutOfGas, ret, interpreter.gas, b); } else { bytes = Bytes::new(); } @@ -539,11 +540,16 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, self.data .journaled_state .set_code(created_address, bytecode); - (Return::Continue, ret, interp.gas, b) + (Return::Continue, ret, interpreter.gas, b) } _ => { self.data.journaled_state.checkpoint_revert(checkpoint); - (exit_reason, ret, interp.gas, interp.return_value()) + ( + exit_reason, + ret, + interpreter.gas, + interpreter.return_value(), + ) } }; @@ -668,28 +674,30 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, ); #[cfg(feature = "memory_limit")] - let mut interp = Interpreter::new_with_memory_limit::( + let mut interpreter = Interpreter::new_with_memory_limit::( contract, gas.limit(), + inputs.is_static, self.data.env.cfg.memory_limit, ); #[cfg(not(feature = "memory_limit"))] - let mut interp = Interpreter::new::(contract, gas.limit(), inputs.is_static); + let mut interpreter = + Interpreter::new::(contract, gas.limit(), inputs.is_static); if INSPECT { // create is always no static call. self.inspector - .initialize_interp(&mut interp, &mut self.data, false); + .initialize_interp(&mut interpreter, &mut self.data, false); } - let exit_reason = interp.run::(self, INSPECT); + let exit_reason = interpreter.run::(self, INSPECT); if matches!(exit_reason, return_ok!()) { self.data.journaled_state.checkpoint_commit(); } else { self.data.journaled_state.checkpoint_revert(checkpoint); } - (exit_reason, interp.gas, interp.return_value()) + (exit_reason, interpreter.gas, interpreter.return_value()) }; if INSPECT { diff --git a/crates/revm/src/instructions/bitwise.rs b/crates/revm/src/instructions/bitwise.rs index 0aaadf773b..6a15426934 100644 --- a/crates/revm/src/instructions/bitwise.rs +++ b/crates/revm/src/instructions/bitwise.rs @@ -80,7 +80,7 @@ pub fn byte(interpreter: &mut Interpreter, _host: &mut dyn Host) { for i in 0..256 { if i < 8 && op1 < U256::from(32) { - let o = u128::try_from(op1).unwrap() as usize; + let o = as_usize_saturated!(op1); let t = 255 - (7 - i + 8 * o); let bit_mask = U256::from(1) << t; let value = (*op2 & bit_mask) >> t; @@ -95,14 +95,14 @@ pub fn shl(interpreter: &mut Interpreter, _host: &mut dyn Host) { // EIP-145: Bitwise shifting instructions in EVM check!(interpreter, SPEC::enabled(CONSTANTINOPLE)); pop_top!(interpreter, op1, op2); - *op2 = *op2 << usize::try_from(op1).unwrap_or(256) + *op2 <<= as_usize_saturated!(op1); } pub fn shr(interpreter: &mut Interpreter, _host: &mut dyn Host) { // EIP-145: Bitwise shifting instructions in EVM check!(interpreter, SPEC::enabled(CONSTANTINOPLE)); pop_top!(interpreter, op1, op2); - *op2 = *op2 >> usize::try_from(op1).unwrap_or(256) + *op2 >>= as_usize_saturated!(op1); } pub fn sar(interpreter: &mut Interpreter, _host: &mut dyn Host) { diff --git a/crates/revm/src/instructions/control.rs b/crates/revm/src/instructions/control.rs index 46532cccdb..0682dc9dc6 100644 --- a/crates/revm/src/instructions/control.rs +++ b/crates/revm/src/instructions/control.rs @@ -3,11 +3,12 @@ use crate::{gas, interpreter::Interpreter, Host, Return, Spec, SpecId::*, U256}; pub fn jump(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::MID); pop!(interpreter, dest); - let dest = as_usize_or_fail!(interpreter,dest, Return::InvalidJump); + let dest = as_usize_or_fail!(interpreter, dest, Return::InvalidJump); if interpreter.contract.is_valid_jump(dest) { // Safety: In analysis we are checking create our jump table and we do check above to be // sure that jump is safe to execute. - interpreter.instruction_pointer = unsafe { interpreter.contract.bytecode.as_ptr().add(dest) }; + interpreter.instruction_pointer = + unsafe { interpreter.contract.bytecode.as_ptr().add(dest) }; } else { interpreter.instruction_result = Return::InvalidJump; } @@ -17,7 +18,7 @@ pub fn jumpi(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::HIGH); pop!(interpreter, dest, value); if value != U256::ZERO { - let dest = as_usize_or_fail!(interpreter,dest, Return::InvalidJump); + let dest = as_usize_or_fail!(interpreter, dest, Return::InvalidJump); if interpreter.contract.is_valid_jump(dest) { // Safety: In analysis we are checking if jump is valid destination and // this `if` makes this unsafe block safe. @@ -47,11 +48,11 @@ pub fn pc(interpreter: &mut Interpreter, _host: &mut dyn Host) { pub fn ret(interpreter: &mut Interpreter, _host: &mut dyn Host) { // zero gas cost gas!(interp,gas::ZERO); pop!(interpreter, start, len); - let len = as_usize_or_fail!(interpreter,len, Return::OutOfGas); + let len = as_usize_or_fail!(interpreter, len, Return::OutOfGas); if len == 0 { interpreter.return_range = usize::MAX..usize::MAX; } else { - let offset = as_usize_or_fail!(interpreter,start, Return::OutOfGas); + let offset = as_usize_or_fail!(interpreter, start, Return::OutOfGas); memory_resize!(interpreter, offset, len); interpreter.return_range = offset..(offset + len); } @@ -63,11 +64,11 @@ pub fn revert(interpreter: &mut Interpreter, _host: &mut dyn Host) { // EIP-140: REVERT instruction check!(interpreter, SPEC::enabled(BYZANTIUM)); pop!(interpreter, start, len); - let len = as_usize_or_fail!(interpreter,len, Return::OutOfGas); + let len = as_usize_or_fail!(interpreter, len, Return::OutOfGas); if len == 0 { interpreter.return_range = usize::MAX..usize::MAX; } else { - let offset = as_usize_or_fail!(interpreter,start, Return::OutOfGas); + let offset = as_usize_or_fail!(interpreter, start, Return::OutOfGas); memory_resize!(interpreter, offset, len); interpreter.return_range = offset..(offset + len); } diff --git a/crates/revm/src/instructions/host.rs b/crates/revm/src/instructions/host.rs index 4b72fd4f56..23ec05e778 100644 --- a/crates/revm/src/instructions/host.rs +++ b/crates/revm/src/instructions/host.rs @@ -127,7 +127,7 @@ pub fn blockhash(interpreter: &mut Interpreter, host: &mut dyn Host) { return; } *number = U256::from_be_bytes(*ret.unwrap()); - return + return; } } *number = U256::ZERO; @@ -188,7 +188,9 @@ pub fn log(interpreter: &mut Interpreter, host: &mut dy let mut topics = Vec::with_capacity(n); for _ in 0..(n) { // Safety: stack bounds already checked few lines above - topics.push(B256(unsafe { interpreter.stack.pop_unsafe().to_be_bytes() })); + topics.push(B256(unsafe { + interpreter.stack.pop_unsafe().to_be_bytes() + })); } host.log(interpreter.contract.address, topics, data); diff --git a/crates/revm/src/instructions/macros.rs b/crates/revm/src/instructions/macros.rs index b7410821cb..6b7d30dbf3 100644 --- a/crates/revm/src/instructions/macros.rs +++ b/crates/revm/src/instructions/macros.rs @@ -195,38 +195,22 @@ macro_rules! push { ) } -// macro_rules! as_usize_saturated { -// ( $v:expr ) => { -// $v.saturating_to::() -// }; -// } - -// macro_rules! as_usize_or_fail { -// ( $interp:expr, $v:expr ) => {{ -// as_usize_or_fail!($interp, $v, Return::OutOfGas) -// }}; - -// ( $interp:expr, $v:expr, $reason:expr ) => { -// match $v[0] == 0 { -// Ok(value) => value, -// Err(_) => { -// $interp.instruction_result = $reason; -// return; -// } -// } -// }; -// } - -macro_rules! as_usize_saturated { +macro_rules! as_u64_saturated { ( $v:expr ) => {{ if $v.as_limbs()[1] != 0 || $v.as_limbs()[2] != 0 || $v.as_limbs()[3] != 0 { - usize::MAX + u64::MAX } else { - $v.as_limbs()[0] as usize + $v.as_limbs()[0] } }}; } +macro_rules! as_usize_saturated { + ( $v:expr ) => {{ + as_u64_saturated!($v) as usize + }}; +} + macro_rules! as_usize_or_fail { ( $interp:expr, $v:expr ) => {{ as_usize_or_fail!($interp, $v, Return::OutOfGas) diff --git a/crates/revm/src/instructions/system.rs b/crates/revm/src/instructions/system.rs index 6ad58b8846..088dfb535f 100644 --- a/crates/revm/src/instructions/system.rs +++ b/crates/revm/src/instructions/system.rs @@ -1,5 +1,6 @@ use crate::{ - B256, U256, common::keccak256, gas, interpreter::Interpreter, Host, Return, Spec, SpecId::*, KECCAK_EMPTY, + common::keccak256, gas, interpreter::Interpreter, Host, Return, Spec, SpecId::*, B256, + KECCAK_EMPTY, U256, }; use std::cmp::min; @@ -26,7 +27,6 @@ pub fn address(interpreter: &mut Interpreter, _host: &mut dyn Host) { pub fn caller(interpreter: &mut Interpreter, _host: &mut dyn Host) { // gas!(interp, gas::BASE); push_b256!(interpreter, B256::from(interpreter.contract.caller)); - } pub fn codesize(interpreter: &mut Interpreter, _host: &mut dyn Host) { @@ -112,7 +112,7 @@ pub fn returndatacopy(interpreter: &mut Interpreter, _host: &mut dyn // EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY check!(interpreter, SPEC::enabled(BYZANTIUM)); pop!(interpreter, memory_offset, offset, len); - let len = as_usize_or_fail!(interpreter,len, Return::OutOfGas); + let len = as_usize_or_fail!(interpreter, len, Return::OutOfGas); gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64)); let data_offset = as_usize_saturated!(offset); let (data_end, overflow) = data_offset.overflowing_add(len); @@ -121,7 +121,7 @@ pub fn returndatacopy(interpreter: &mut Interpreter, _host: &mut dyn return; } if len != 0 { - let memory_offset = as_usize_or_fail!(interpreter,memory_offset, Return::OutOfGas); + let memory_offset = as_usize_or_fail!(interpreter, memory_offset, Return::OutOfGas); memory_resize!(interpreter, memory_offset, len); interpreter.memory.set( memory_offset, diff --git a/crates/revm/src/interpreter.rs b/crates/revm/src/interpreter.rs index 520a616800..b8d2310770 100644 --- a/crates/revm/src/interpreter.rs +++ b/crates/revm/src/interpreter.rs @@ -10,7 +10,7 @@ pub use stack::Stack; use crate::{ instructions::{eval, Return}, - Gas, Host, USE_GAS,Spec + Gas, Host, Spec, USE_GAS, }; use bytes::Bytes; use core::ops::Range; @@ -47,8 +47,7 @@ impl Interpreter { unsafe { *self.instruction_pointer } } #[cfg(not(feature = "memory_limit"))] - pub fn new(contract: Contract, gas_limit: u64,is_static:bool) -> Self { - + pub fn new(contract: Contract, gas_limit: u64, is_static: bool) -> Self { Self { instruction_pointer: contract.bytecode.as_ptr(), return_range: Range::default(), @@ -66,6 +65,7 @@ impl Interpreter { pub fn new_with_memory_limit( contract: Contract, gas_limit: u64, + is_static: bool, memory_limit: u64, ) -> Self { Self { @@ -75,6 +75,8 @@ impl Interpreter { stack: Stack::new(), return_data_buffer: Bytes::new(), contract, + instruction_result: Return::Continue, + is_static, gas: Gas::new(gas_limit), memory_limit, } diff --git a/crates/revm_precompiles/src/modexp.rs b/crates/revm_precompiles/src/modexp.rs index 0f68126f83..53231fc117 100644 --- a/crates/revm_precompiles/src/modexp.rs +++ b/crates/revm_precompiles/src/modexp.rs @@ -162,10 +162,10 @@ fn byzantium_gas_calc(base_len: u64, exp_len: u64, mod_len: u64, exp_highp: &Big // mul * iter_count bounded by 2^195 < 2^256 (no overflow) let gas = (mul * iter_count) / U256::from(20); - if gas.bit_len() > 64 { + if gas.as_limbs()[1] != 0 || gas.as_limbs()[2] != 0 || gas.as_limbs()[3] != 0 { u64::MAX } else { - u128::try_from(gas).unwrap() as u64 + gas.as_limbs()[0] } } @@ -185,10 +185,11 @@ fn berlin_gas_calc(base_length: u64, exp_length: u64, mod_length: u64, exp_highp let multiplication_complexity = calculate_multiplication_complexity(base_length, mod_length); let iteration_count = calculate_iteration_count(exp_length, exp_highp); let gas = (multiplication_complexity * U256::from(iteration_count)) / U256::from(3); - if gas > U256::from(u64::MAX) { + + if gas.as_limbs()[1] != 0 || gas.as_limbs()[2] != 0 || gas.as_limbs()[3] != 0 { u64::MAX } else { - max(200, u128::try_from(gas).unwrap() as u64) + max(200, gas.as_limbs()[0]) } } From a971b07b2cf4fc48f79cbeeefbf4c6f06fed2f8e Mon Sep 17 00:00:00 2001 From: rakita Date: Sun, 4 Dec 2022 15:15:11 +0100 Subject: [PATCH 4/5] cargo update and clippy --- Cargo.lock | 38 +++++++++++++++++++------------------- crates/revm/src/bits.rs | 2 +- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 59cc3068cc..90068fab00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -952,9 +952,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.137" +version = "0.2.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" +checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" [[package]] name = "lock_api" @@ -1156,9 +1156,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.42" +version = "0.10.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13" +checksum = "020433887e44c27ff16365eaa2d380547a94544ad509aff6eb5b6e3e0b27b376" dependencies = [ "bitflags", "cfg-if", @@ -1188,9 +1188,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.77" +version = "0.9.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03b84c3b2d099b81f0953422b4d4ad58761589d0229b5506356afca05a3670a" +checksum = "07d5c8cb6e57b3a3612064d7b18b117912b4ce70955c2504d4b741c9e244b132" dependencies = [ "autocfg", "cc", @@ -1237,9 +1237,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" +checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" dependencies = [ "cfg-if", "libc", @@ -1628,7 +1628,7 @@ checksum = "0ad3a104dc8c3867f653b0fec89c65e00b0ceb752718ad282177a7e0f33257ac" dependencies = [ "bn-rs", "derive_more", - "primitive-types 0.11.1", + "primitive-types 0.12.1", "rlp", "ruint-macro", "rustc_version", @@ -1768,18 +1768,18 @@ checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" [[package]] name = "serde" -version = "1.0.147" +version = "1.0.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.147" +version = "1.0.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c" dependencies = [ "proc-macro2", "quote", @@ -1976,9 +1976,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.103" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" dependencies = [ "proc-macro2", "quote", @@ -2090,9 +2090,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.8.0" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" dependencies = [ "proc-macro2", "quote", @@ -2194,9 +2194,9 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "uint" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a45526d29728d135c2900b0d30573fe3ee79fceb12ef534c7bb30e810a91b601" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" dependencies = [ "byteorder", "crunchy", diff --git a/crates/revm/src/bits.rs b/crates/revm/src/bits.rs index 8672a93ddc..717c55415e 100644 --- a/crates/revm/src/bits.rs +++ b/crates/revm/src/bits.rs @@ -148,7 +148,7 @@ mod serialize { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match *self { Self::InvalidHex { character, index } => { - write!(fmt, "invalid hex character: {}, at {}", character, index) + write!(fmt, "invalid hex character: {character}, at {index}") } } } From e01f8723a8b5ec6689ed5bd2dd8f858a1833e735 Mon Sep 17 00:00:00 2001 From: rakita Date: Sun, 4 Dec 2022 15:21:34 +0100 Subject: [PATCH 5/5] clippy --- bins/revme/src/statetest/runner.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bins/revme/src/statetest/runner.rs b/bins/revme/src/statetest/runner.rs index 09cf5eff81..b28554edac 100644 --- a/bins/revme/src/statetest/runner.rs +++ b/bins/revme/src/statetest/runner.rs @@ -277,8 +277,7 @@ pub fn execute_test_suit(path: &Path, elapsed: &Arc>) -> Result< let db = evm.db().unwrap(); println!("{path:?} UNIT_TEST:{name}\n"); println!( - "failed reason: {:?} {:?} UNIT_TEST:{}\n gas:{:?} ({:?} refunded)", - exit_reason, path, name, gas_used, gas_refunded, + "failed reason: {exit_reason:?} {path:?} UNIT_TEST:{name}\n gas:{gas_used:?} ({gas_refunded:?} refunded)", ); println!("\nApplied state:{db:?}\n"); println!("\nStateroot: {state_root:?}\n");