From 854e9a7331c16628b0765fc239ab49c7c5e74702 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Fri, 29 Mar 2024 03:17:06 +0100 Subject: [PATCH] feat(interpreter): test Host object-safety, allow `dyn Host` in instructions --- crates/interpreter/src/host.rs | 13 +++++++ .../src/instructions/arithmetic.rs | 22 ++++++------ .../interpreter/src/instructions/bitwise.rs | 28 +++++++-------- .../interpreter/src/instructions/control.rs | 18 +++++----- crates/interpreter/src/instructions/host.rs | 34 +++++++++---------- .../src/instructions/host/call_helpers.rs | 2 +- .../interpreter/src/instructions/host_env.rs | 22 ++++++------ crates/interpreter/src/instructions/memory.rs | 10 +++--- crates/interpreter/src/instructions/opcode.rs | 19 ++++++----- crates/interpreter/src/instructions/stack.rs | 10 +++--- crates/interpreter/src/instructions/system.rs | 24 ++++++------- crates/interpreter/src/interpreter.rs | 26 ++++++++++++-- crates/revm/src/inspector/handler_register.rs | 19 +++++------ 13 files changed, 140 insertions(+), 107 deletions(-) diff --git a/crates/interpreter/src/host.rs b/crates/interpreter/src/host.rs index fff18bb848..6caecee479 100644 --- a/crates/interpreter/src/host.rs +++ b/crates/interpreter/src/host.rs @@ -65,3 +65,16 @@ pub struct SStoreResult { /// Is storage slot loaded from database pub is_cold: bool, } + +#[cfg(test)] +mod tests { + use super::*; + + fn assert_host() {} + + #[test] + fn object_safety() { + assert_host::(); + assert_host::(); + } +} diff --git a/crates/interpreter/src/instructions/arithmetic.rs b/crates/interpreter/src/instructions/arithmetic.rs index e982ccd471..7363e91782 100644 --- a/crates/interpreter/src/instructions/arithmetic.rs +++ b/crates/interpreter/src/instructions/arithmetic.rs @@ -5,25 +5,25 @@ use crate::{ Host, Interpreter, }; -pub fn wrapping_add(interpreter: &mut Interpreter, _host: &mut H) { +pub fn wrapping_add(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::VERYLOW); pop_top!(interpreter, op1, op2); *op2 = op1.wrapping_add(*op2); } -pub fn wrapping_mul(interpreter: &mut Interpreter, _host: &mut H) { +pub fn wrapping_mul(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::LOW); pop_top!(interpreter, op1, op2); *op2 = op1.wrapping_mul(*op2); } -pub fn wrapping_sub(interpreter: &mut Interpreter, _host: &mut H) { +pub fn wrapping_sub(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::VERYLOW); pop_top!(interpreter, op1, op2); *op2 = op1.wrapping_sub(*op2); } -pub fn div(interpreter: &mut Interpreter, _host: &mut H) { +pub fn div(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::LOW); pop_top!(interpreter, op1, op2); if *op2 != U256::ZERO { @@ -31,13 +31,13 @@ pub fn div(interpreter: &mut Interpreter, _host: &mut H) { } } -pub fn sdiv(interpreter: &mut Interpreter, _host: &mut H) { +pub fn sdiv(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::LOW); pop_top!(interpreter, op1, op2); *op2 = i256_div(op1, *op2); } -pub fn rem(interpreter: &mut Interpreter, _host: &mut H) { +pub fn rem(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::LOW); pop_top!(interpreter, op1, op2); if *op2 != U256::ZERO { @@ -45,7 +45,7 @@ pub fn rem(interpreter: &mut Interpreter, _host: &mut H) { } } -pub fn smod(interpreter: &mut Interpreter, _host: &mut H) { +pub fn smod(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::LOW); pop_top!(interpreter, op1, op2); if *op2 != U256::ZERO { @@ -53,19 +53,19 @@ pub fn smod(interpreter: &mut Interpreter, _host: &mut H) { } } -pub fn addmod(interpreter: &mut Interpreter, _host: &mut H) { +pub fn addmod(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::MID); pop_top!(interpreter, op1, op2, op3); *op3 = op1.add_mod(op2, *op3) } -pub fn mulmod(interpreter: &mut Interpreter, _host: &mut H) { +pub fn mulmod(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::MID); pop_top!(interpreter, op1, op2, op3); *op3 = op1.mul_mod(op2, *op3) } -pub fn exp(interpreter: &mut Interpreter, _host: &mut H) { +pub fn exp(interpreter: &mut Interpreter, _host: &mut H) { pop_top!(interpreter, op1, op2); gas_or_fail!(interpreter, gas::exp_cost::(*op2)); *op2 = op1.pow(*op2); @@ -86,7 +86,7 @@ pub fn exp(interpreter: &mut Interpreter, _host: &mut H) { /// `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(interpreter: &mut Interpreter, _host: &mut H) { +pub fn signextend(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::LOW); pop_top!(interpreter, ext, x); // For 31 we also don't need to do anything. diff --git a/crates/interpreter/src/instructions/bitwise.rs b/crates/interpreter/src/instructions/bitwise.rs index 3f49dc57eb..3ec1681751 100644 --- a/crates/interpreter/src/instructions/bitwise.rs +++ b/crates/interpreter/src/instructions/bitwise.rs @@ -6,67 +6,67 @@ use crate::{ }; use core::cmp::Ordering; -pub fn lt(interpreter: &mut Interpreter, _host: &mut H) { +pub fn lt(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::VERYLOW); pop_top!(interpreter, op1, op2); *op2 = U256::from(op1 < *op2); } -pub fn gt(interpreter: &mut Interpreter, _host: &mut H) { +pub fn gt(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::VERYLOW); pop_top!(interpreter, op1, op2); *op2 = U256::from(op1 > *op2); } -pub fn slt(interpreter: &mut Interpreter, _host: &mut H) { +pub fn slt(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::VERYLOW); pop_top!(interpreter, op1, op2); *op2 = U256::from(i256_cmp(&op1, op2) == Ordering::Less); } -pub fn sgt(interpreter: &mut Interpreter, _host: &mut H) { +pub fn sgt(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::VERYLOW); pop_top!(interpreter, op1, op2); *op2 = U256::from(i256_cmp(&op1, op2) == Ordering::Greater); } -pub fn eq(interpreter: &mut Interpreter, _host: &mut H) { +pub fn eq(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::VERYLOW); pop_top!(interpreter, op1, op2); *op2 = U256::from(op1 == *op2); } -pub fn iszero(interpreter: &mut Interpreter, _host: &mut H) { +pub fn iszero(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::VERYLOW); pop_top!(interpreter, op1); *op1 = U256::from(*op1 == U256::ZERO); } -pub fn bitand(interpreter: &mut Interpreter, _host: &mut H) { +pub fn bitand(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::VERYLOW); pop_top!(interpreter, op1, op2); *op2 = op1 & *op2; } -pub fn bitor(interpreter: &mut Interpreter, _host: &mut H) { +pub fn bitor(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::VERYLOW); pop_top!(interpreter, op1, op2); *op2 = op1 | *op2; } -pub fn bitxor(interpreter: &mut Interpreter, _host: &mut H) { +pub fn bitxor(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::VERYLOW); pop_top!(interpreter, op1, op2); *op2 = op1 ^ *op2; } -pub fn not(interpreter: &mut Interpreter, _host: &mut H) { +pub fn not(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::VERYLOW); pop_top!(interpreter, op1); *op1 = !*op1; } -pub fn byte(interpreter: &mut Interpreter, _host: &mut H) { +pub fn byte(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::VERYLOW); pop_top!(interpreter, op1, op2); @@ -80,7 +80,7 @@ pub fn byte(interpreter: &mut Interpreter, _host: &mut H) { } /// EIP-145: Bitwise shifting instructions in EVM -pub fn shl(interpreter: &mut Interpreter, _host: &mut H) { +pub fn shl(interpreter: &mut Interpreter, _host: &mut H) { check!(interpreter, CONSTANTINOPLE); gas!(interpreter, gas::VERYLOW); pop_top!(interpreter, op1, op2); @@ -88,7 +88,7 @@ pub fn shl(interpreter: &mut Interpreter, _host: &mut H) { } /// EIP-145: Bitwise shifting instructions in EVM -pub fn shr(interpreter: &mut Interpreter, _host: &mut H) { +pub fn shr(interpreter: &mut Interpreter, _host: &mut H) { check!(interpreter, CONSTANTINOPLE); gas!(interpreter, gas::VERYLOW); pop_top!(interpreter, op1, op2); @@ -96,7 +96,7 @@ pub fn shr(interpreter: &mut Interpreter, _host: &mut H) { } /// EIP-145: Bitwise shifting instructions in EVM -pub fn sar(interpreter: &mut Interpreter, _host: &mut H) { +pub fn sar(interpreter: &mut Interpreter, _host: &mut H) { check!(interpreter, CONSTANTINOPLE); gas!(interpreter, gas::VERYLOW); pop_top!(interpreter, op1, op2); diff --git a/crates/interpreter/src/instructions/control.rs b/crates/interpreter/src/instructions/control.rs index 61a132e940..26333b77a7 100644 --- a/crates/interpreter/src/instructions/control.rs +++ b/crates/interpreter/src/instructions/control.rs @@ -4,13 +4,13 @@ use crate::{ Host, InstructionResult, Interpreter, InterpreterResult, }; -pub fn jump(interpreter: &mut Interpreter, _host: &mut H) { +pub fn jump(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::MID); pop!(interpreter, dest); jump_inner(interpreter, dest); } -pub fn jumpi(interpreter: &mut Interpreter, _host: &mut H) { +pub fn jumpi(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::HIGH); pop!(interpreter, dest, value); if value != U256::ZERO { @@ -29,11 +29,11 @@ fn jump_inner(interpreter: &mut Interpreter, dest: U256) { interpreter.instruction_pointer = unsafe { interpreter.contract.bytecode.as_ptr().add(dest) }; } -pub fn jumpdest(interpreter: &mut Interpreter, _host: &mut H) { +pub fn jumpdest(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::JUMPDEST); } -pub fn pc(interpreter: &mut Interpreter, _host: &mut H) { +pub fn pc(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::BASE); // - 1 because we have already advanced the instruction pointer in `Interpreter::step` push!(interpreter, U256::from(interpreter.program_counter() - 1)); @@ -63,27 +63,27 @@ fn return_inner(interpreter: &mut Interpreter, instruction_result: InstructionRe }; } -pub fn ret(interpreter: &mut Interpreter, _host: &mut H) { +pub fn ret(interpreter: &mut Interpreter, _host: &mut H) { return_inner(interpreter, InstructionResult::Return); } /// EIP-140: REVERT instruction -pub fn revert(interpreter: &mut Interpreter, _host: &mut H) { +pub fn revert(interpreter: &mut Interpreter, _host: &mut H) { check!(interpreter, BYZANTIUM); return_inner(interpreter, InstructionResult::Revert); } /// Stop opcode. This opcode halts the execution. -pub fn stop(interpreter: &mut Interpreter, _host: &mut H) { +pub fn stop(interpreter: &mut Interpreter, _host: &mut H) { interpreter.instruction_result = InstructionResult::Stop; } /// Invalid opcode. This opcode halts the execution. -pub fn invalid(interpreter: &mut Interpreter, _host: &mut H) { +pub fn invalid(interpreter: &mut Interpreter, _host: &mut H) { interpreter.instruction_result = InstructionResult::InvalidFEOpcode; } /// Unknown opcode. This opcode halts the execution. -pub fn unknown(interpreter: &mut Interpreter, _host: &mut H) { +pub fn unknown(interpreter: &mut Interpreter, _host: &mut H) { interpreter.instruction_result = InstructionResult::OpcodeNotFound; } diff --git a/crates/interpreter/src/instructions/host.rs b/crates/interpreter/src/instructions/host.rs index 7357adf4f3..b19d0dfc01 100644 --- a/crates/interpreter/src/instructions/host.rs +++ b/crates/interpreter/src/instructions/host.rs @@ -13,7 +13,7 @@ use core::cmp::min; use revm_primitives::BLOCK_HASH_HISTORY; use std::{boxed::Box, vec::Vec}; -pub fn balance(interpreter: &mut Interpreter, host: &mut H) { +pub fn balance(interpreter: &mut Interpreter, host: &mut H) { pop_address!(interpreter, address); let Some((balance, is_cold)) = host.balance(address) else { interpreter.instruction_result = InstructionResult::FatalExternalError; @@ -34,7 +34,7 @@ pub fn balance(interpreter: &mut Interpreter, host: &mut H) } /// EIP-1884: Repricing for trie-size-dependent opcodes -pub fn selfbalance(interpreter: &mut Interpreter, host: &mut H) { +pub fn selfbalance(interpreter: &mut Interpreter, host: &mut H) { check!(interpreter, ISTANBUL); gas!(interpreter, gas::LOW); let Some((balance, _)) = host.balance(interpreter.contract.address) else { @@ -44,7 +44,7 @@ pub fn selfbalance(interpreter: &mut Interpreter, host: &mu push!(interpreter, balance); } -pub fn extcodesize(interpreter: &mut Interpreter, host: &mut H) { +pub fn extcodesize(interpreter: &mut Interpreter, host: &mut H) { pop_address!(interpreter, address); let Some((code, is_cold)) = host.code(address) else { interpreter.instruction_result = InstructionResult::FatalExternalError; @@ -69,7 +69,7 @@ pub fn extcodesize(interpreter: &mut Interpreter, host: &mu } /// EIP-1052: EXTCODEHASH opcode -pub fn extcodehash(interpreter: &mut Interpreter, host: &mut H) { +pub fn extcodehash(interpreter: &mut Interpreter, host: &mut H) { check!(interpreter, CONSTANTINOPLE); pop_address!(interpreter, address); let Some((code_hash, is_cold)) = host.code_hash(address) else { @@ -93,7 +93,7 @@ pub fn extcodehash(interpreter: &mut Interpreter, host: &mu push_b256!(interpreter, code_hash); } -pub fn extcodecopy(interpreter: &mut Interpreter, host: &mut H) { +pub fn extcodecopy(interpreter: &mut Interpreter, host: &mut H) { pop_address!(interpreter, address); pop!(interpreter, memory_offset, code_offset, len_u256); @@ -120,7 +120,7 @@ pub fn extcodecopy(interpreter: &mut Interpreter, host: &mu .set_data(memory_offset, code_offset, len, code.bytes()); } -pub fn blockhash(interpreter: &mut Interpreter, host: &mut H) { +pub fn blockhash(interpreter: &mut Interpreter, host: &mut H) { gas!(interpreter, gas::BLOCKHASH); pop_top!(interpreter, number); @@ -139,7 +139,7 @@ pub fn blockhash(interpreter: &mut Interpreter, host: &mut H) { *number = U256::ZERO; } -pub fn sload(interpreter: &mut Interpreter, host: &mut H) { +pub fn sload(interpreter: &mut Interpreter, host: &mut H) { pop!(interpreter, index); let Some((value, is_cold)) = host.sload(interpreter.contract.address, index) else { @@ -150,7 +150,7 @@ pub fn sload(interpreter: &mut Interpreter, host: &mut H) { push!(interpreter, value); } -pub fn sstore(interpreter: &mut Interpreter, host: &mut H) { +pub fn sstore(interpreter: &mut Interpreter, host: &mut H) { check_staticcall!(interpreter); pop!(interpreter, index, value); @@ -173,7 +173,7 @@ pub fn sstore(interpreter: &mut Interpreter, host: &mut H) /// EIP-1153: Transient storage opcodes /// Store value to transient storage -pub fn tstore(interpreter: &mut Interpreter, host: &mut H) { +pub fn tstore(interpreter: &mut Interpreter, host: &mut H) { check!(interpreter, CANCUN); check_staticcall!(interpreter); gas!(interpreter, gas::WARM_STORAGE_READ_COST); @@ -185,7 +185,7 @@ pub fn tstore(interpreter: &mut Interpreter, host: &mut H) /// EIP-1153: Transient storage opcodes /// Load value from transient storage -pub fn tload(interpreter: &mut Interpreter, host: &mut H) { +pub fn tload(interpreter: &mut Interpreter, host: &mut H) { check!(interpreter, CANCUN); gas!(interpreter, gas::WARM_STORAGE_READ_COST); @@ -194,7 +194,7 @@ pub fn tload(interpreter: &mut Interpreter, host: &mut H) { *index = host.tload(interpreter.contract.address, *index); } -pub fn log(interpreter: &mut Interpreter, host: &mut H) { +pub fn log(interpreter: &mut Interpreter, host: &mut H) { check_staticcall!(interpreter); pop!(interpreter, offset, len); @@ -227,7 +227,7 @@ pub fn log(interpreter: &mut Interpreter, host: &mut H) host.log(log); } -pub fn selfdestruct(interpreter: &mut Interpreter, host: &mut H) { +pub fn selfdestruct(interpreter: &mut Interpreter, host: &mut H) { check_staticcall!(interpreter); pop_address!(interpreter, target); @@ -245,7 +245,7 @@ pub fn selfdestruct(interpreter: &mut Interpreter, host: &m interpreter.instruction_result = InstructionResult::SelfDestruct; } -pub fn create( +pub fn create( interpreter: &mut Interpreter, host: &mut H, ) { @@ -314,7 +314,7 @@ pub fn create( interpreter.instruction_result = InstructionResult::CallOrCreate; } -pub fn call(interpreter: &mut Interpreter, host: &mut H) { +pub fn call(interpreter: &mut Interpreter, host: &mut H) { pop!(interpreter, local_gas_limit); pop_address!(interpreter, to); // max gas limit is not possible in real ethereum situation. @@ -374,7 +374,7 @@ pub fn call(interpreter: &mut Interpreter, host: &mut H) { interpreter.instruction_result = InstructionResult::CallOrCreate; } -pub fn call_code(interpreter: &mut Interpreter, host: &mut H) { +pub fn call_code(interpreter: &mut Interpreter, host: &mut H) { pop!(interpreter, local_gas_limit); pop_address!(interpreter, to); // max gas limit is not possible in real ethereum situation. @@ -429,7 +429,7 @@ pub fn call_code(interpreter: &mut Interpreter, host: &mut interpreter.instruction_result = InstructionResult::CallOrCreate; } -pub fn delegate_call(interpreter: &mut Interpreter, host: &mut H) { +pub fn delegate_call(interpreter: &mut Interpreter, host: &mut H) { check!(interpreter, HOMESTEAD); pop!(interpreter, local_gas_limit); pop_address!(interpreter, to); @@ -475,7 +475,7 @@ pub fn delegate_call(interpreter: &mut Interpreter, host: & interpreter.instruction_result = InstructionResult::CallOrCreate; } -pub fn static_call(interpreter: &mut Interpreter, host: &mut H) { +pub fn static_call(interpreter: &mut Interpreter, host: &mut H) { check!(interpreter, BYZANTIUM); pop!(interpreter, local_gas_limit); pop_address!(interpreter, to); diff --git a/crates/interpreter/src/instructions/host/call_helpers.rs b/crates/interpreter/src/instructions/host/call_helpers.rs index 3156c9a75b..05a7a20334 100644 --- a/crates/interpreter/src/instructions/host/call_helpers.rs +++ b/crates/interpreter/src/instructions/host/call_helpers.rs @@ -34,7 +34,7 @@ pub fn get_memory_input_and_out_ranges( } #[inline] -pub fn calc_call_gas( +pub fn calc_call_gas( interpreter: &mut Interpreter, host: &mut H, to: Address, diff --git a/crates/interpreter/src/instructions/host_env.rs b/crates/interpreter/src/instructions/host_env.rs index 230bb39b37..1b0c399559 100644 --- a/crates/interpreter/src/instructions/host_env.rs +++ b/crates/interpreter/src/instructions/host_env.rs @@ -5,28 +5,28 @@ use crate::{ }; /// EIP-1344: ChainID opcode -pub fn chainid(interpreter: &mut Interpreter, host: &mut H) { +pub fn chainid(interpreter: &mut Interpreter, host: &mut H) { check!(interpreter, ISTANBUL); gas!(interpreter, gas::BASE); push!(interpreter, U256::from(host.env().cfg.chain_id)); } -pub fn coinbase(interpreter: &mut Interpreter, host: &mut H) { +pub fn coinbase(interpreter: &mut Interpreter, host: &mut H) { gas!(interpreter, gas::BASE); push_b256!(interpreter, host.env().block.coinbase.into_word()); } -pub fn timestamp(interpreter: &mut Interpreter, host: &mut H) { +pub fn timestamp(interpreter: &mut Interpreter, host: &mut H) { gas!(interpreter, gas::BASE); push!(interpreter, host.env().block.timestamp); } -pub fn number(interpreter: &mut Interpreter, host: &mut H) { +pub fn number(interpreter: &mut Interpreter, host: &mut H) { gas!(interpreter, gas::BASE); push!(interpreter, host.env().block.number); } -pub fn difficulty(interpreter: &mut Interpreter, host: &mut H) { +pub fn difficulty(interpreter: &mut Interpreter, host: &mut H) { gas!(interpreter, gas::BASE); if SPEC::enabled(MERGE) { push_b256!(interpreter, host.env().block.prevrandao.unwrap()); @@ -35,30 +35,30 @@ pub fn difficulty(interpreter: &mut Interpreter, host: &mut } } -pub fn gaslimit(interpreter: &mut Interpreter, host: &mut H) { +pub fn gaslimit(interpreter: &mut Interpreter, host: &mut H) { gas!(interpreter, gas::BASE); push!(interpreter, host.env().block.gas_limit); } -pub fn gasprice(interpreter: &mut Interpreter, host: &mut H) { +pub fn gasprice(interpreter: &mut Interpreter, host: &mut H) { gas!(interpreter, gas::BASE); push!(interpreter, host.env().effective_gas_price()); } /// EIP-3198: BASEFEE opcode -pub fn basefee(interpreter: &mut Interpreter, host: &mut H) { +pub fn basefee(interpreter: &mut Interpreter, host: &mut H) { check!(interpreter, LONDON); gas!(interpreter, gas::BASE); push!(interpreter, host.env().block.basefee); } -pub fn origin(interpreter: &mut Interpreter, host: &mut H) { +pub fn origin(interpreter: &mut Interpreter, host: &mut H) { gas!(interpreter, gas::BASE); push_b256!(interpreter, host.env().tx.caller.into_word()); } // EIP-4844: Shard Blob Transactions -pub fn blob_hash(interpreter: &mut Interpreter, host: &mut H) { +pub fn blob_hash(interpreter: &mut Interpreter, host: &mut H) { check!(interpreter, CANCUN); gas!(interpreter, gas::VERYLOW); pop_top!(interpreter, index); @@ -70,7 +70,7 @@ pub fn blob_hash(interpreter: &mut Interpreter, host: &mut } /// EIP-7516: BLOBBASEFEE opcode -pub fn blob_basefee(interpreter: &mut Interpreter, host: &mut H) { +pub fn blob_basefee(interpreter: &mut Interpreter, host: &mut H) { check!(interpreter, CANCUN); gas!(interpreter, gas::BASE); push!( diff --git a/crates/interpreter/src/instructions/memory.rs b/crates/interpreter/src/instructions/memory.rs index 264c4c61c7..6ee2d88f93 100644 --- a/crates/interpreter/src/instructions/memory.rs +++ b/crates/interpreter/src/instructions/memory.rs @@ -5,7 +5,7 @@ use crate::{ }; use core::cmp::max; -pub fn mload(interpreter: &mut Interpreter, _host: &mut H) { +pub fn mload(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::VERYLOW); pop!(interpreter, index); let index = as_usize_or_fail!(interpreter, index); @@ -13,7 +13,7 @@ pub fn mload(interpreter: &mut Interpreter, _host: &mut H) { push!(interpreter, interpreter.shared_memory.get_u256(index)); } -pub fn mstore(interpreter: &mut Interpreter, _host: &mut H) { +pub fn mstore(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::VERYLOW); pop!(interpreter, index, value); let index = as_usize_or_fail!(interpreter, index); @@ -21,7 +21,7 @@ pub fn mstore(interpreter: &mut Interpreter, _host: &mut H) { interpreter.shared_memory.set_u256(index, value); } -pub fn mstore8(interpreter: &mut Interpreter, _host: &mut H) { +pub fn mstore8(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::VERYLOW); pop!(interpreter, index, value); let index = as_usize_or_fail!(interpreter, index); @@ -29,13 +29,13 @@ pub fn mstore8(interpreter: &mut Interpreter, _host: &mut H) { interpreter.shared_memory.set_byte(index, value.byte(0)) } -pub fn msize(interpreter: &mut Interpreter, _host: &mut H) { +pub fn msize(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::BASE); push!(interpreter, U256::from(interpreter.shared_memory.len())); } // EIP-5656: MCOPY - Memory copying instruction -pub fn mcopy(interpreter: &mut Interpreter, _host: &mut H) { +pub fn mcopy(interpreter: &mut Interpreter, _host: &mut H) { check!(interpreter, CANCUN); pop!(interpreter, dst, src, len); diff --git a/crates/interpreter/src/instructions/opcode.rs b/crates/interpreter/src/instructions/opcode.rs index 687637b4bc..b6f23307c2 100644 --- a/crates/interpreter/src/instructions/opcode.rs +++ b/crates/interpreter/src/instructions/opcode.rs @@ -28,12 +28,12 @@ pub type BoxedInstructionTable<'a, H> = [BoxedInstruction<'a, H>; 256]; /// Note that `Plain` variant gives us 10-20% faster Interpreter execution. /// /// Boxed variant can be used to wrap plain function pointer with closure. -pub enum InstructionTables<'a, H> { +pub enum InstructionTables<'a, H: ?Sized> { Plain(InstructionTable), Boxed(BoxedInstructionTable<'a, H>), } -impl InstructionTables<'_, H> { +impl InstructionTables<'_, H> { /// Creates a plain instruction table for the given spec. #[inline] pub const fn new_plain() -> Self { @@ -41,7 +41,7 @@ impl InstructionTables<'_, H> { } } -impl<'a, H: Host + 'a> InstructionTables<'a, H> { +impl<'a, H: Host + ?Sized + 'a> InstructionTables<'a, H> { /// Inserts a boxed instruction into the table with the specified index. /// /// This will convert the table into the [BoxedInstructionTable] variant if it is currently a @@ -93,13 +93,14 @@ impl<'a, H: Host + 'a> InstructionTables<'a, H> { /// Make instruction table. #[inline] -pub const fn make_instruction_table() -> InstructionTable { +pub const fn make_instruction_table() -> InstructionTable { // Force const-eval of the table creation, making this function trivial. // TODO: Replace this with a `const {}` block once it is stable. - struct ConstTable { - _phantom: core::marker::PhantomData<(H, SPEC)>, + struct ConstTable { + _host: core::marker::PhantomData, + _spec: core::marker::PhantomData, } - impl ConstTable { + impl ConstTable { const NEW: InstructionTable = { let mut tables: InstructionTable = [control::unknown; 256]; let mut i = 0; @@ -120,7 +121,7 @@ pub fn make_boxed_instruction_table<'a, H, SPEC, FN>( mut outer: FN, ) -> BoxedInstructionTable<'a, H> where - H: Host, + H: Host + ?Sized, SPEC: Spec + 'a, FN: FnMut(Instruction) -> BoxedInstruction<'a, H>, { @@ -154,7 +155,7 @@ macro_rules! opcodes { }; /// Returns the instruction function for the given opcode and spec. - pub const fn instruction(opcode: u8) -> Instruction { + pub const fn instruction(opcode: u8) -> Instruction { match opcode { $($name => $f,)* _ => control::unknown, diff --git a/crates/interpreter/src/instructions/stack.rs b/crates/interpreter/src/instructions/stack.rs index 14d9e35238..5267687591 100644 --- a/crates/interpreter/src/instructions/stack.rs +++ b/crates/interpreter/src/instructions/stack.rs @@ -4,7 +4,7 @@ use crate::{ Host, Interpreter, }; -pub fn pop(interpreter: &mut Interpreter, _host: &mut H) { +pub fn pop(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::BASE); if let Err(result) = interpreter.stack.pop() { interpreter.instruction_result = result; @@ -14,7 +14,7 @@ pub fn pop(interpreter: &mut Interpreter, _host: &mut H) { /// EIP-3855: PUSH0 instruction /// /// Introduce a new instruction which pushes the constant value 0 onto the stack. -pub fn push0(interpreter: &mut Interpreter, _host: &mut H) { +pub fn push0(interpreter: &mut Interpreter, _host: &mut H) { check!(interpreter, SHANGHAI); gas!(interpreter, gas::BASE); if let Err(result) = interpreter.stack.push(U256::ZERO) { @@ -22,7 +22,7 @@ pub fn push0(interpreter: &mut Interpreter, _host: &mut H) } } -pub fn push(interpreter: &mut Interpreter, _host: &mut H) { +pub fn push(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::VERYLOW); // SAFETY: In analysis we append trailing bytes to the bytecode so that this is safe to do // without bounds checking. @@ -37,14 +37,14 @@ pub fn push(interpreter: &mut Interpreter, _host: &mut interpreter.instruction_pointer = unsafe { ip.add(N) }; } -pub fn dup(interpreter: &mut Interpreter, _host: &mut H) { +pub fn dup(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::VERYLOW); if let Err(result) = interpreter.stack.dup::() { interpreter.instruction_result = result; } } -pub fn swap(interpreter: &mut Interpreter, _host: &mut H) { +pub fn swap(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::VERYLOW); if let Err(result) = interpreter.stack.swap::() { interpreter.instruction_result = result; diff --git a/crates/interpreter/src/instructions/system.rs b/crates/interpreter/src/instructions/system.rs index 55109d8004..be81fb3116 100644 --- a/crates/interpreter/src/instructions/system.rs +++ b/crates/interpreter/src/instructions/system.rs @@ -4,7 +4,7 @@ use crate::{ Host, InstructionResult, Interpreter, }; -pub fn keccak256(interpreter: &mut Interpreter, _host: &mut H) { +pub fn keccak256(interpreter: &mut Interpreter, _host: &mut H) { pop!(interpreter, from, len); let len = as_usize_or_fail!(interpreter, len); gas_or_fail!(interpreter, gas::keccak256_cost(len as u64)); @@ -19,22 +19,22 @@ pub fn keccak256(interpreter: &mut Interpreter, _host: &mut H) { push_b256!(interpreter, hash); } -pub fn address(interpreter: &mut Interpreter, _host: &mut H) { +pub fn address(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::BASE); push_b256!(interpreter, interpreter.contract.address.into_word()); } -pub fn caller(interpreter: &mut Interpreter, _host: &mut H) { +pub fn caller(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::BASE); push_b256!(interpreter, interpreter.contract.caller.into_word()); } -pub fn codesize(interpreter: &mut Interpreter, _host: &mut H) { +pub fn codesize(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::BASE); push!(interpreter, U256::from(interpreter.contract.bytecode.len())); } -pub fn codecopy(interpreter: &mut Interpreter, _host: &mut H) { +pub fn codecopy(interpreter: &mut Interpreter, _host: &mut H) { pop!(interpreter, memory_offset, code_offset, len); let len = as_usize_or_fail!(interpreter, len); gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64)); @@ -54,7 +54,7 @@ pub fn codecopy(interpreter: &mut Interpreter, _host: &mut H) { ); } -pub fn calldataload(interpreter: &mut Interpreter, _host: &mut H) { +pub fn calldataload(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::VERYLOW); pop!(interpreter, index); let index = as_usize_saturated!(index); @@ -70,17 +70,17 @@ pub fn calldataload(interpreter: &mut Interpreter, _host: &mut H) { push_b256!(interpreter, load); } -pub fn calldatasize(interpreter: &mut Interpreter, _host: &mut H) { +pub fn calldatasize(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::BASE); push!(interpreter, U256::from(interpreter.contract.input.len())); } -pub fn callvalue(interpreter: &mut Interpreter, _host: &mut H) { +pub fn callvalue(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::BASE); push!(interpreter, interpreter.contract.value); } -pub fn calldatacopy(interpreter: &mut Interpreter, _host: &mut H) { +pub fn calldatacopy(interpreter: &mut Interpreter, _host: &mut H) { pop!(interpreter, memory_offset, data_offset, len); let len = as_usize_or_fail!(interpreter, len); gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64)); @@ -101,7 +101,7 @@ pub fn calldatacopy(interpreter: &mut Interpreter, _host: &mut H) { } /// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY -pub fn returndatasize(interpreter: &mut Interpreter, _host: &mut H) { +pub fn returndatasize(interpreter: &mut Interpreter, _host: &mut H) { check!(interpreter, BYZANTIUM); gas!(interpreter, gas::BASE); push!( @@ -111,7 +111,7 @@ pub fn returndatasize(interpreter: &mut Interpreter, _host: } /// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY -pub fn returndatacopy(interpreter: &mut Interpreter, _host: &mut H) { +pub fn returndatacopy(interpreter: &mut Interpreter, _host: &mut H) { check!(interpreter, BYZANTIUM); pop!(interpreter, memory_offset, offset, len); let len = as_usize_or_fail!(interpreter, len); @@ -132,7 +132,7 @@ pub fn returndatacopy(interpreter: &mut Interpreter, _host: } } -pub fn gas(interpreter: &mut Interpreter, _host: &mut H) { +pub fn gas(interpreter: &mut Interpreter, _host: &mut H) { gas!(interpreter, gas::BASE); push!(interpreter, U256::from(interpreter.gas.remaining())); } diff --git a/crates/interpreter/src/interpreter.rs b/crates/interpreter/src/interpreter.rs index 2a1e99a377..4ee51db756 100644 --- a/crates/interpreter/src/interpreter.rs +++ b/crates/interpreter/src/interpreter.rs @@ -283,7 +283,7 @@ impl Interpreter { /// /// Internally it will increment instruction pointer by one. #[inline(always)] - fn step(&mut self, instruction_table: &[FN; 256], host: &mut H) + fn step(&mut self, instruction_table: &[FN; 256], host: &mut H) where FN: Fn(&mut Interpreter, &mut H), { @@ -305,7 +305,7 @@ impl Interpreter { } /// Executes the interpreter until it returns or stops. - pub fn run( + pub fn run( &mut self, shared_memory: SharedMemory, instruction_table: &[FN; 256], @@ -356,3 +356,25 @@ impl InterpreterResult { self.result.is_error() } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{opcode::InstructionTable, DummyHost}; + use revm_primitives::CancunSpec; + + #[test] + fn object_safety() { + let mut interp = Interpreter::new(Contract::default(), u64::MAX, false); + + let mut host = crate::DummyHost::default(); + let table: InstructionTable = + crate::opcode::make_instruction_table::(); + let _ = interp.run(EMPTY_SHARED_MEMORY, &table, &mut host); + + let host: &mut dyn Host = &mut host as &mut dyn Host; + let table: InstructionTable = + crate::opcode::make_instruction_table::(); + let _ = interp.run(EMPTY_SHARED_MEMORY, &table, host); + } +} diff --git a/crates/revm/src/inspector/handler_register.rs b/crates/revm/src/inspector/handler_register.rs index 0598c4f829..42cfb03910 100644 --- a/crates/revm/src/inspector/handler_register.rs +++ b/crates/revm/src/inspector/handler_register.rs @@ -260,26 +260,23 @@ pub fn inspector_instruction< #[cfg(test)] mod tests { - use super::*; use crate::{ db::EmptyDB, inspectors::NoOpInspector, - interpreter::{opcode::*, CallInputs, CreateInputs, Interpreter}, + interpreter::{opcode::*, CallInputs, CallOutcome, CreateInputs, CreateOutcome}, primitives::BerlinSpec, - Database, Evm, EvmContext, Inspector, + EvmContext, }; - use revm_interpreter::{CallOutcome, CreateOutcome}; - + // Test that this pattern builds. #[test] fn test_make_boxed_instruction_table() { - // test that this pattern builds. - let inst: InstructionTable> = - make_instruction_table::, BerlinSpec>(); - let _test: BoxedInstructionTable<'_, Evm<'_, _, _>> = - make_boxed_instruction_table::<'_, Evm<'_, NoOpInspector, EmptyDB>, BerlinSpec, _>( - inst, + type MyEvm<'a> = Evm<'a, NoOpInspector, EmptyDB>; + let table: InstructionTable> = make_instruction_table::, BerlinSpec>(); + let _boxed_table: BoxedInstructionTable<'_, MyEvm<'_>> = + make_boxed_instruction_table::<'_, MyEvm<'_>, BerlinSpec, _>( + table, inspector_instruction, ); }