From 5501a9bd61c29b093ba843f6e0b961db0edd58dd Mon Sep 17 00:00:00 2001 From: rakita Date: Mon, 6 Nov 2023 15:01:33 +0100 Subject: [PATCH] clippy, docs, fmt --- Cargo.toml | 1 + README.md | 2 +- crates/interpreter/Cargo.toml | 1 - crates/interpreter/src/gas.rs | 3 - crates/interpreter/src/gas/calc.rs | 4 +- crates/interpreter/src/instruction_result.rs | 10 +- .../interpreter/src/instructions/control.rs | 8 +- crates/interpreter/src/instructions/host.rs | 145 ++++++------------ crates/interpreter/src/instructions/opcode.rs | 6 +- crates/interpreter/src/interpreter.rs | 21 +-- .../src/interpreter/shared_memory.rs | 2 +- crates/interpreter/src/interpreter/stack.rs | 2 +- crates/interpreter/src/lib.rs | 3 - crates/primitives/Cargo.toml | 1 - crates/revm/CHANGELOG.md | 2 +- crates/revm/Cargo.toml | 1 - crates/revm/src/evm_context.rs | 26 ++-- crates/revm/src/evm_impl.rs | 44 +++--- crates/revm/src/handler.rs | 2 - crates/revm/src/handler/mainnet.rs | 5 +- crates/revm/src/handler/optimism.rs | 43 +++--- crates/revm/src/inspector/customprinter.rs | 1 - crates/revm/src/inspector/eip3155.rs | 6 +- crates/revm/src/inspector/gas.rs | 2 - documentation/src/crates/interpreter.md | 4 - documentation/src/crates/precompile/blake2.md | 2 +- .../src/crates/primitives/specifications.md | 2 +- documentation/src/crates/revm.md | 4 - 28 files changed, 140 insertions(+), 213 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f76b7605fb9..fcb04eb7224 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ default-members = ["crates/revm"] [profile.release] lto = true codegen-units = 1 +debug = true [profile.ethtests] inherits = "test" diff --git a/README.md b/README.md index 0f06157bcf1..292ba3e9588 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ cargo run -p revm --features ethersdb --example fork_ref_transact * [Foundry](https://github.com/foundry-rs/foundry) is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust. * [Helios](https://github.com/a16z/helios) is a fully trustless, efficient, and portable Ethereum light client written in Rust. * [Reth](https://github.com/paradigmxyz/reth) Modular, contributor-friendly and blazing-fast implementation of the Ethereum protocol -* [Arbiter](https://github.com/primitivefinance/arbiter) is a CallStackFramework for stateful Ethereum smart-contract simulation +* [Arbiter](https://github.com/primitivefinance/arbiter) is a framework for stateful Ethereum smart-contract simulation * [Zeth](https://github.com/risc0/zeth) is an open-source ZK block prover for Ethereum built on the RISC Zero zkVM. * ... diff --git a/crates/interpreter/Cargo.toml b/crates/interpreter/Cargo.toml index 155deacb025..e0dc8e4b28e 100644 --- a/crates/interpreter/Cargo.toml +++ b/crates/interpreter/Cargo.toml @@ -32,7 +32,6 @@ dev = [ "optional_no_base_fee", ] memory_limit = ["revm-primitives/memory_limit"] -no_gas_measuring = ["revm-primitives/no_gas_measuring"] optional_balance_check = ["revm-primitives/optional_balance_check"] optional_block_gas_limit = ["revm-primitives/optional_block_gas_limit"] optional_eip3607 = ["revm-primitives/optional_eip3607"] diff --git a/crates/interpreter/src/gas.rs b/crates/interpreter/src/gas.rs index 21d633dc1f0..2d9ebd6f05c 100644 --- a/crates/interpreter/src/gas.rs +++ b/crates/interpreter/src/gas.rs @@ -88,9 +88,6 @@ impl Gas { /// Records an explicit cost. /// /// Returns `false` if the gas limit is exceeded. - /// - /// This function is called on every instruction in the interpreter if the feature - /// `no_gas_measuring` is not enabled. #[inline(always)] pub fn record_cost(&mut self, cost: u64) -> bool { let all_used_gas = self.all_used_gas.saturating_add(cost); diff --git a/crates/interpreter/src/gas/calc.rs b/crates/interpreter/src/gas/calc.rs index 118775ee9f8..98d26948aba 100644 --- a/crates/interpreter/src/gas/calc.rs +++ b/crates/interpreter/src/gas/calc.rs @@ -263,14 +263,12 @@ pub fn selfdestruct_cost(res: SelfDestructResult) -> u64 { } pub fn call_cost( - value: U256, + transfers_value: bool, is_new: bool, is_cold: bool, is_call_or_callcode: bool, is_call_or_staticcall: bool, ) -> u64 { - let transfers_value = value != U256::default(); - let call_gas = if SPEC::enabled(BERLIN) { if is_cold { COLD_ACCOUNT_ACCESS_COST diff --git a/crates/interpreter/src/instruction_result.rs b/crates/interpreter/src/instruction_result.rs index f64ab13b971..dd596e6726c 100644 --- a/crates/interpreter/src/instruction_result.rs +++ b/crates/interpreter/src/instruction_result.rs @@ -98,12 +98,10 @@ pub enum SuccessOrHalt { Revert, Halt(Halt), FatalExternalError, - /// Internal instruction. + /// Internal instruction that signals Interpreter should continue running. InternalContinue, - /// Internal call opcode. - InternalCall, - /// Internal create opcode. - InternalCreate, + /// Internal instruction that signals subcall. + InternalCallOrCreate, } impl SuccessOrHalt { @@ -152,7 +150,7 @@ impl From for SuccessOrHalt { InstructionResult::Return => Self::Success(Eval::Return), InstructionResult::SelfDestruct => Self::Success(Eval::SelfDestruct), InstructionResult::Revert => Self::Revert, - InstructionResult::CallOrCreate => Self::InternalCall, // used only in interpreter loop + InstructionResult::CallOrCreate => Self::InternalCallOrCreate, // used only in interpreter loop InstructionResult::CallTooDeep => Self::Halt(Halt::CallTooDeep), // not gonna happen for first call InstructionResult::OutOfFund => Self::Halt(Halt::OutOfFund), // Check for first call is done separately. InstructionResult::OutOfGas => Self::Halt(Halt::OutOfGas( diff --git a/crates/interpreter/src/instructions/control.rs b/crates/interpreter/src/instructions/control.rs index 087b902bcde..104c0690b5b 100644 --- a/crates/interpreter/src/instructions/control.rs +++ b/crates/interpreter/src/instructions/control.rs @@ -80,17 +80,17 @@ pub fn revert(interpreter: &mut Interpreter, _host: &mut H) return_inner(interpreter, InstructionResult::Revert); } +/// Stop opcode. This opcode halts the execution. pub fn stop(interpreter: &mut Interpreter, _host: &mut H) { - interpreter.return_data_buffer = Bytes::default(); interpreter.instruction_result = InstructionResult::Stop; } +/// Invalid opcode. This opcode halts the execution. pub fn invalid(interpreter: &mut Interpreter, _host: &mut H) { - interpreter.return_data_buffer = Bytes::default(); interpreter.instruction_result = InstructionResult::InvalidFEOpcode; } -pub fn not_found(interpreter: &mut Interpreter, _host: &mut H) { - interpreter.return_data_buffer = Bytes::default(); +/// Unknown opcode. This opcode halts the execution. +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 76c2fab1344..2ce4c9b6dfd 100644 --- a/crates/interpreter/src/instructions/host.rs +++ b/crates/interpreter/src/instructions/host.rs @@ -236,11 +236,9 @@ pub fn selfdestruct(interpreter: &mut Interpreter, host: &m interpreter.instruction_result = InstructionResult::SelfDestruct; } -#[inline(never)] -pub fn prepare_create_inputs( +pub fn create( interpreter: &mut Interpreter, host: &mut H, - create_inputs: &mut Option>, ) { check_staticcall!(interpreter); @@ -249,14 +247,11 @@ pub fn prepare_create_inputs( check!(interpreter, PETERSBURG); } - interpreter.return_data_buffer = Bytes::new(); - pop!(interpreter, value, code_offset, len); let len = as_usize_or_fail!(interpreter, len); - let code = if len == 0 { - Bytes::new() - } else { + let mut code = Bytes::new(); + if len != 0 { // EIP-3860: Limit and meter initcode if SPEC::enabled(SHANGHAI) { // Limit is set as double of max contract bytecode size @@ -275,9 +270,10 @@ pub fn prepare_create_inputs( let code_offset = as_usize_or_fail!(interpreter, code_offset); shared_memory_resize!(interpreter, code_offset, len); - Bytes::copy_from_slice(interpreter.shared_memory.slice(code_offset, len)) - }; + code = Bytes::copy_from_slice(interpreter.shared_memory.slice(code_offset, len)); + } + // EIP-1014: Skinny CREATE2 let scheme = if IS_CREATE2 { pop!(interpreter, salt); gas_or_fail!(interpreter, gas::create2_cost(len)); @@ -296,29 +292,15 @@ pub fn prepare_create_inputs( } gas!(interpreter, gas_limit); - *create_inputs = Some(Box::new(CreateInputs { - caller: interpreter.contract.address, - scheme, - value, - init_code: code, - gas_limit, - })); -} - -pub fn create( - interpreter: &mut Interpreter, - host: &mut H, -) { - let mut create_input: Option> = None; - prepare_create_inputs::(interpreter, host, &mut create_input); - - let Some(create_input) = create_input else { - return; - }; - // Call host to interact with target contract interpreter.next_action = Some(InterpreterAction::Create { - inputs: create_input, + inputs: Box::new(CreateInputs { + caller: interpreter.contract.address, + scheme, + value, + init_code: code, + gas_limit, + }), }); interpreter.instruction_result = InstructionResult::CallOrCreate; } @@ -339,17 +321,25 @@ pub fn static_call(interpreter: &mut Interpreter, host: &mu call_inner::(CallScheme::StaticCall, interpreter, host); } -#[inline(never)] -fn prepare_call_inputs( - interpreter: &mut Interpreter, +pub fn call_inner( scheme: CallScheme, + interpreter: &mut Interpreter, host: &mut H, - result_len: &mut usize, - result_offset: &mut usize, - result_call_inputs: &mut Option>, ) { + match scheme { + // EIP-7: DELEGATECALL + CallScheme::DelegateCall => check!(interpreter, HOMESTEAD), + // EIP-214: New opcode STATICCALL + CallScheme::StaticCall => check!(interpreter, BYZANTIUM), + _ => (), + } + pop!(interpreter, local_gas_limit); pop_address!(interpreter, to); + + // max gas limit is not possible in real ethereum situation. + // But for tests we would not like to fail on this. + // Gas limit for subcall is taken as min of this value and current gas limit. let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX); let value = match scheme { @@ -379,10 +369,10 @@ fn prepare_call_inputs( Bytes::new() }; - *result_len = as_usize_or_fail!(interpreter, out_len); - *result_offset = if *result_len != 0 { + let out_len = as_usize_or_fail!(interpreter, out_len); + let out_offset = if out_len != 0 { let out_offset = as_usize_or_fail!(interpreter, out_offset); - shared_memory_resize!(interpreter, out_offset, *result_len); + shared_memory_resize!(interpreter, out_offset, out_len); out_offset } else { usize::MAX //unrealistic value so we are sure it is not used @@ -412,24 +402,24 @@ fn prepare_call_inputs( }, }; - let transfer = if scheme == CallScheme::Call { - Transfer { + let transfer = match scheme { + CallScheme::Call => Transfer { source: interpreter.contract.address, target: to, value, - } - } else if scheme == CallScheme::CallCode { - Transfer { + }, + CallScheme::CallCode => Transfer { 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: interpreter.contract.address, - target: interpreter.contract.address, - value: U256::ZERO, + }, + _ => { + //this is dummy send for StaticCall and DelegateCall, it should do nothing and dont touch anything. + Transfer { + source: interpreter.contract.address, + target: interpreter.contract.address, + value: U256::ZERO, + } } }; @@ -443,7 +433,7 @@ fn prepare_call_inputs( gas!( interpreter, gas::call_cost::( - value, + value != U256::ZERO, is_new, is_cold, matches!(scheme, CallScheme::Call | CallScheme::CallCode), @@ -468,49 +458,16 @@ fn prepare_call_inputs( } let is_static = matches!(scheme, CallScheme::StaticCall) || interpreter.is_static; - *result_call_inputs = Some(Box::new(CallInputs { - contract: to, - transfer, - input, - gas_limit, - context, - is_static, - })); -} - -pub fn call_inner( - scheme: CallScheme, - interpreter: &mut Interpreter, - host: &mut H, -) { - match scheme { - // EIP-7: DELEGATECALL - CallScheme::DelegateCall => check!(interpreter, HOMESTEAD), - // EIP-214: New opcode STATICCALL - CallScheme::StaticCall => check!(interpreter, BYZANTIUM), - _ => (), - } - interpreter.return_data_buffer = Bytes::new(); - - let mut out_offset: usize = 0; - let mut out_len: usize = 0; - let mut call_input: Option> = None; - prepare_call_inputs::( - interpreter, - scheme, - host, - &mut out_len, - &mut out_offset, - &mut call_input, - ); - - let Some(call_input) = call_input else { - return; - }; - // Call host to interact with target contract interpreter.next_action = Some(InterpreterAction::SubCall { - inputs: call_input, + inputs: Box::new(CallInputs { + contract: to, + transfer, + input, + gas_limit, + context, + is_static, + }), return_memory_offset: out_offset..out_offset + out_len, }); interpreter.instruction_result = InstructionResult::CallOrCreate; diff --git a/crates/interpreter/src/instructions/opcode.rs b/crates/interpreter/src/instructions/opcode.rs index 0783a130f58..5e93c77d10c 100644 --- a/crates/interpreter/src/instructions/opcode.rs +++ b/crates/interpreter/src/instructions/opcode.rs @@ -43,8 +43,8 @@ pub enum InstructionTables<'a, H> { impl<'a, H> Clone for InstructionTables<'a, H> { fn clone(&self) -> Self { match self { - Self::Plain(arg0) => Self::Plain(arg0.clone()), - Self::Boxed(arg0) => Self::Boxed(arg0.clone()), + Self::Plain(table) => Self::Plain(table.clone()), + Self::Boxed(table) => Self::Boxed(table.clone()), } } } @@ -75,7 +75,7 @@ macro_rules! opcodes { pub fn instruction(opcode: u8) -> Instruction { match opcode { $($name => $f,)* - _ => control::not_found, + _ => control::unknown, } } }; diff --git a/crates/interpreter/src/interpreter.rs b/crates/interpreter/src/interpreter.rs index b079d506296..b152419a167 100644 --- a/crates/interpreter/src/interpreter.rs +++ b/crates/interpreter/src/interpreter.rs @@ -40,6 +40,9 @@ pub struct Interpreter { /// The gas state. pub gas: Gas, /// Shared memory. + /// + /// Note: This field is only set while running the interpreter loop. + /// Otherwise it is taken and replaced with empty shared memory. pub shared_memory: SharedMemory, /// Stack. pub stack: Stack, @@ -51,9 +54,10 @@ pub struct Interpreter { pub return_data_buffer: Bytes, /// Whether the interpreter is in "staticcall" mode, meaning no state changes can happen. pub is_static: bool, - /// Actions that interpreter should do. + /// Actions that the EVM should do. /// - /// Set inside CALL or CREATE instructions and RETURN or REVERT instructions. + /// Set inside CALL or CREATE instructions and RETURN or REVERT instructions. Additionally those instructions will set + /// InstructionResult to CallOrCreate/Return/Revert so we know the reason. pub next_action: Option, } @@ -99,8 +103,6 @@ impl Interpreter { } /// When sub create call returns we can insert output of that call into this interpreter. - /// - /// Note: SharedMemory is not available here because we are not executing sub call. pub fn insert_create_output(&mut self, result: InterpreterResult, address: Option
) { let interpreter = self; interpreter.return_data_buffer = match result.result { @@ -130,6 +132,9 @@ impl Interpreter { } /// When sub call returns we can insert output of that call into this interpreter. + /// + /// Note that shared memory is required as a input field. + /// As SharedMemory inside Interpreter is taken and replaced with empty (not valid) memory. pub fn insert_call_output( &mut self, shared_memory: &mut SharedMemory, @@ -189,11 +194,6 @@ impl Interpreter { &self.stack } - /// Returns a reference to the shared memory. - pub fn memory(&self) -> &SharedMemory { - &self.shared_memory - } - /// Returns the current program counter. #[inline] pub fn program_counter(&self) -> usize { @@ -252,10 +252,11 @@ impl Interpreter { if let Some(action) = self.next_action.take() { return action; } - // If not return action without output. this means it is Interpreter halt. + // If not, return action without output. InterpreterAction::Return { result: InterpreterResult { result: self.instruction_result, + // return empty bytecode output: Bytes::new(), gas: self.gas, }, diff --git a/crates/interpreter/src/interpreter/shared_memory.rs b/crates/interpreter/src/interpreter/shared_memory.rs index f988cf82d14..23756ba2bd3 100644 --- a/crates/interpreter/src/interpreter/shared_memory.rs +++ b/crates/interpreter/src/interpreter/shared_memory.rs @@ -28,7 +28,7 @@ pub struct SharedMemory { /// Empty shared memory. /// -/// As it does not have allocations it is usable with mem::replace operations. +/// Used as placeholder inside Interpreter when it is not running. pub const EMPTY_SHARED_MEMORY: SharedMemory = SharedMemory { buffer: Vec::new(), checkpoints: Vec::new(), diff --git a/crates/interpreter/src/interpreter/stack.rs b/crates/interpreter/src/interpreter/stack.rs index 8b2f19b7dd9..9235ad90567 100644 --- a/crates/interpreter/src/interpreter/stack.rs +++ b/crates/interpreter/src/interpreter/stack.rs @@ -231,7 +231,7 @@ impl Stack { } let n_words = (slice.len() + 31) / 32; - let new_len: usize = self.data.len() + n_words; + let new_len = self.data.len() + n_words; if new_len > STACK_LIMIT { return Err(InstructionResult::StackOverflow); } diff --git a/crates/interpreter/src/lib.rs b/crates/interpreter/src/lib.rs index 498d24f5fa9..a7ac0f248d7 100644 --- a/crates/interpreter/src/lib.rs +++ b/crates/interpreter/src/lib.rs @@ -18,9 +18,6 @@ mod instruction_result; pub mod instructions; mod interpreter; -#[cfg(feature = "no_gas_measuring")] -compile_error! {"no_gas_measuring feature is deprecated and feature is removed."} - // Reexport primary types. pub use gas::Gas; pub use host::{DummyHost, Host}; diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 7662ded708e..956f270bb79 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -68,7 +68,6 @@ dev = [ "optional_beneficiary_reward", ] memory_limit = [] -no_gas_measuring = [] optional_balance_check = [] optional_block_gas_limit = [] optional_eip3607 = [] diff --git a/crates/revm/CHANGELOG.md b/crates/revm/CHANGELOG.md index d92c7ecded8..60208fea7cd 100644 --- a/crates/revm/CHANGELOG.md +++ b/crates/revm/CHANGELOG.md @@ -106,7 +106,7 @@ Full git log: * 5cdaa97 - chore: avoid unnecessary allocations (#581) (6 weeks ago) * da26d0d - chore(deps): bump tokio from 1.29.1 to 1.31.0 (#595) (6 weeks ago) * ef57a46 - feat: State with account status (#499) (7 weeks ago) -* 1478724 - chore: move precompiles to EvmContext for inspectors (#588) (7 weeks ago) +* 1478724 - chore: move precompiles to EVMData for inspectors (#588) (7 weeks ago) * fe6c54e - fix(transient_storage): set previous value in journal (#585) (7 weeks ago) * bd84a07 - refactor: rewrite revm-test as a criterion bench (#579) (7 weeks ago) * 5734f12 - fix: AccessList with two same addresses (#578) (8 weeks ago) diff --git a/crates/revm/Cargo.toml b/crates/revm/Cargo.toml index 697de5047b7..dce2531840d 100644 --- a/crates/revm/Cargo.toml +++ b/crates/revm/Cargo.toml @@ -54,7 +54,6 @@ dev = [ "optional_beneficiary_reward", ] memory_limit = ["revm-interpreter/memory_limit"] -no_gas_measuring = ["revm-interpreter/no_gas_measuring"] optional_balance_check = ["revm-interpreter/optional_balance_check"] optional_block_gas_limit = ["revm-interpreter/optional_block_gas_limit"] optional_eip3607 = ["revm-interpreter/optional_eip3607"] diff --git a/crates/revm/src/evm_context.rs b/crates/revm/src/evm_context.rs index 58db16e8553..d0b47be6551 100644 --- a/crates/revm/src/evm_context.rs +++ b/crates/revm/src/evm_context.rs @@ -12,8 +12,8 @@ use crate::{ }, CallStackFrame, CALL_STACK_LIMIT, }; -use core::ops::Range; use alloc::boxed::Box; +use core::ops::Range; /// EVM Data contains all the data that EVM needs to execute. #[derive(Debug)] @@ -138,7 +138,7 @@ impl<'a, DB: Database> EvmContext<'a, DB> { pub fn make_create_frame( &mut self, inputs: &CreateInputs, - ) -> Result { + ) -> Result, InterpreterResult> { // Prepare crate. let gas = Gas::new(inputs.gas_limit); @@ -210,13 +210,13 @@ impl<'a, DB: Database> EvmContext<'a, DB> { inputs.value, )); - Ok(CallStackFrame { + Ok(Box::new(CallStackFrame { is_create: true, - checkpoint: checkpoint, + checkpoint, created_address: Some(created_address), subcall_return_memory_range: 0..0, interpreter: Interpreter::new(contract, gas.limit(), false), - }) + })) } /// Make call frame @@ -224,7 +224,7 @@ impl<'a, DB: Database> EvmContext<'a, DB> { &mut self, inputs: &CallInputs, return_memory_offset: Range, - ) -> Result { + ) -> Result, InterpreterResult> { let gas = Gas::new(inputs.gas_limit); let return_result = |instruction_result: InstructionResult| { @@ -273,7 +273,7 @@ impl<'a, DB: Database> EvmContext<'a, DB> { if let Some(precompile) = self.precompiles.get(&inputs.contract) { //println!("Call precompile"); - let result = self.call_precompile(precompile, &inputs, gas); + let result = self.call_precompile(precompile, inputs, gas); if matches!(result.result, return_ok!()) { self.journaled_state.checkpoint_commit(); } else { @@ -288,13 +288,13 @@ impl<'a, DB: Database> EvmContext<'a, DB> { &inputs.context, )); // Create interpreter and execute subcall and push new CallStackFrame. - Ok(CallStackFrame { + Ok(Box::new(CallStackFrame { is_create: false, - checkpoint: checkpoint, + checkpoint, created_address: None, subcall_return_memory_range: return_memory_offset, interpreter: Interpreter::new(contract, gas.limit(), inputs.is_static), - }) + })) } else { self.journaled_state.checkpoint_commit(); return_result(InstructionResult::Stop) @@ -346,7 +346,7 @@ impl<'a, DB: Database> EvmContext<'a, DB> { pub fn call_return( &mut self, interpreter_result: InterpreterResult, - frame: CallStackFrame, + frame: Box, ) -> InterpreterResult { // revert changes or not. if matches!(interpreter_result.result, return_ok!()) { @@ -354,7 +354,7 @@ impl<'a, DB: Database> EvmContext<'a, DB> { } else { self.journaled_state.checkpoint_revert(frame.checkpoint); } - return interpreter_result; + interpreter_result } /// Handles create return. @@ -362,7 +362,7 @@ impl<'a, DB: Database> EvmContext<'a, DB> { pub fn create_return( &mut self, mut interpreter_result: InterpreterResult, - frame: CallStackFrame, + frame: Box, ) -> (InterpreterResult, Address) { let address = frame.created_address.unwrap(); // if return is not ok revert and return. diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index 324f3c69e12..4e95b4f5ea6 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -16,7 +16,7 @@ use crate::{ }, CallStackFrame, EvmContext, Inspector, }; -use alloc::{sync::Arc, vec::Vec, boxed::Box}; +use alloc::{boxed::Box, sync::Arc, vec::Vec}; use auto_impl::auto_impl; use core::{fmt, marker::PhantomData, ops::Range}; @@ -161,15 +161,15 @@ impl<'a, SPEC: Spec + 'static, DB: Database> EVMImpl<'a, SPEC, DB> { } #[inline] - pub fn main_loop( + pub fn run( &mut self, instruction_table: &[FN; 256], - first_frame: CallStackFrame, + first_frame: Box, ) -> InterpreterResult where FN: Fn(&mut Interpreter, &mut Self), { - let mut call_stack: Vec = Vec::with_capacity(1026); + let mut call_stack: Vec> = Vec::with_capacity(1025); call_stack.push(first_frame); #[cfg(feature = "memory_limit")] @@ -202,6 +202,9 @@ impl<'a, SPEC: Spec + 'static, DB: Database> EVMImpl<'a, SPEC, DB> { ), InterpreterAction::Create { inputs } => self.handle_sub_create(inputs, stack_frame), InterpreterAction::Return { result } => { + // free memory context. + shared_memory.free_context(); + let child = call_stack.pop().unwrap(); let parent = call_stack.last_mut(); @@ -224,8 +227,8 @@ impl<'a, SPEC: Spec + 'static, DB: Database> EVMImpl<'a, SPEC, DB> { fn handle_frame_return( &mut self, - mut child_stack_frame: CallStackFrame, - parent_stack_frame: Option<&mut CallStackFrame>, + mut child_stack_frame: Box, + parent_stack_frame: Option<&mut Box>, shared_memory: &mut SharedMemory, mut result: InterpreterResult, ) -> Option { @@ -243,9 +246,6 @@ impl<'a, SPEC: Spec + 'static, DB: Database> EVMImpl<'a, SPEC, DB> { }; } - // free memory context. - shared_memory.free_context(); - // break from loop if this is last CallStackFrame. let Some(parent_stack_frame) = parent_stack_frame else { let result = if child_stack_frame.is_create { @@ -287,7 +287,7 @@ impl<'a, SPEC: Spec + 'static, DB: Database> EVMImpl<'a, SPEC, DB> { &mut self, mut inputs: Box, curent_stack_frame: &mut CallStackFrame, - ) -> Option { + ) -> Option> { // Call inspector if it is some. if let Some(inspector) = self.inspector.as_mut() { if let Some((result, address)) = inspector.create(&mut self.context, &mut inputs) { @@ -329,7 +329,7 @@ impl<'a, SPEC: Spec + 'static, DB: Database> EVMImpl<'a, SPEC, DB> { curent_stake_frame: &mut CallStackFrame, return_memory_offset: Range, shared_memory: &mut SharedMemory, - ) -> Option { + ) -> Option> { // Call inspector if it is some. if let Some(inspector) = self.inspector.as_mut() { if let Some((result, range)) = inspector.call(&mut self.context, &mut inputs) { @@ -487,7 +487,7 @@ impl<'a, SPEC: Spec + 'static, DB: Database> EVMImpl<'a, SPEC, DB> { caller_account.info.nonce = caller_account.info.nonce.saturating_add(1); self.context.make_call_frame( - &mut CallInputs { + &CallInputs { contract: address, transfer: Transfer { source: tx_caller, @@ -508,15 +508,13 @@ impl<'a, SPEC: Spec + 'static, DB: Database> EVMImpl<'a, SPEC, DB> { 0..0, ) } - TransactTo::Create(scheme) => { - self.context.make_create_frame::(&mut CreateInputs { - caller: tx_caller, - scheme, - value: tx_value, - init_code: tx_data, - gas_limit: transact_gas_limit, - }) - } + TransactTo::Create(scheme) => self.context.make_create_frame::(&CreateInputs { + caller: tx_caller, + scheme, + value: tx_value, + init_code: tx_data, + gas_limit: transact_gas_limit, + }), }; // Some only if it is create. let mut created_address = None; @@ -527,8 +525,8 @@ impl<'a, SPEC: Spec + 'static, DB: Database> EVMImpl<'a, SPEC, DB> { created_address = first_stack_frame.created_address; let table = self.instruction_table.clone(); match table { - InstructionTables::Plain(table) => self.main_loop(&table, first_stack_frame), - InstructionTables::Boxed(table) => self.main_loop(&table, first_stack_frame), + InstructionTables::Plain(table) => self.run(&table, first_stack_frame), + InstructionTables::Boxed(table) => self.run(&table, first_stack_frame), } } Err(interpreter_result) => interpreter_result, diff --git a/crates/revm/src/handler.rs b/crates/revm/src/handler.rs index fcf93ae1f3e..eef328bd413 100644 --- a/crates/revm/src/handler.rs +++ b/crates/revm/src/handler.rs @@ -54,8 +54,6 @@ pub struct Handler { pub calculate_gas_refund: CalculateGasRefundHandle, /// Main return handle, returns the output of the transact. pub main_return: MainReturnHandle, - /// Main first call - //pub main_first_call: MainFirstCall, /// End handle. pub end: EndHandle, } diff --git a/crates/revm/src/handler/mainnet.rs b/crates/revm/src/handler/mainnet.rs index fbec6402044..c39293391f9 100644 --- a/crates/revm/src/handler/mainnet.rs +++ b/crates/revm/src/handler/mainnet.rs @@ -143,9 +143,8 @@ pub fn main_return( SuccessOrHalt::FatalExternalError => { return Err(EVMError::Database(context.error.take().unwrap())); } - SuccessOrHalt::InternalContinue - | SuccessOrHalt::InternalCall - | SuccessOrHalt::InternalCreate => { + // Only two internal return flags. + SuccessOrHalt::InternalContinue | SuccessOrHalt::InternalCallOrCreate => { panic!("Internal return flags should remain internal {call_result:?}") } }; diff --git a/crates/revm/src/handler/optimism.rs b/crates/revm/src/handler/optimism.rs index 4b9582ff7a4..b90dc9bad09 100644 --- a/crates/revm/src/handler/optimism.rs +++ b/crates/revm/src/handler/optimism.rs @@ -95,31 +95,31 @@ pub fn reward_beneficiary( context: &mut EvmContext<'_, DB>, gas: &Gas, ) -> Result<(), EVMError> { - let is_deposit = data.env.cfg.optimism && data.env.tx.optimism.source_hash.is_some(); - let disable_coinbase_tip = data.env.cfg.optimism && is_deposit; + let is_deposit = context.env.cfg.optimism && context.env.tx.optimism.source_hash.is_some(); + let disable_coinbase_tip = context.env.cfg.optimism && is_deposit; // transfer fee to coinbase/beneficiary. if !disable_coinbase_tip { - mainnet::reward_beneficiary::(data, gas)?; + mainnet::reward_beneficiary::(context, gas)?; } - if data.env.cfg.optimism && !is_deposit { + if context.env.cfg.optimism && !is_deposit { // If the transaction is not a deposit transaction, fees are paid out // to both the Base Fee Vault as well as the L1 Fee Vault. - let Some(l1_block_info) = data.l1_block_info.clone() else { + let Some(l1_block_info) = context.l1_block_info.clone() else { panic!("[OPTIMISM] Failed to load L1 block information."); }; - let Some(enveloped_tx) = &data.env.tx.optimism.enveloped_tx else { + let Some(enveloped_tx) = &context.env.tx.optimism.enveloped_tx else { panic!("[OPTIMISM] Failed to load enveloped transaction."); }; let l1_cost = l1_block_info.calculate_tx_l1_cost::(enveloped_tx); // Send the L1 cost of the transaction to the L1 Fee Vault. - let Ok((l1_fee_vault_account, _)) = data + let Ok((l1_fee_vault_account, _)) = context .journaled_state - .load_account(optimism::L1_FEE_RECIPIENT, data.db) + .load_account(optimism::L1_FEE_RECIPIENT, context.db) else { panic!("[OPTIMISM] Failed to load L1 Fee Vault account"); }; @@ -127,14 +127,14 @@ pub fn reward_beneficiary( l1_fee_vault_account.info.balance += l1_cost; // Send the base fee of the transaction to the Base Fee Vault. - let Ok((base_fee_vault_account, _)) = data + let Ok((base_fee_vault_account, _)) = context .journaled_state - .load_account(optimism::BASE_FEE_RECIPIENT, data.db) + .load_account(optimism::BASE_FEE_RECIPIENT, context.db) else { panic!("[OPTIMISM] Failed to load Base Fee Vault account"); }; base_fee_vault_account.mark_touch(); - base_fee_vault_account.info.balance += data + base_fee_vault_account.info.balance += context .env .block .basefee @@ -151,14 +151,14 @@ pub fn main_return( output: Output, gas: &Gas, ) -> Result> { - let result = mainnet::main_return::(data, call_result, output, gas)?; + let result = mainnet::main_return::(context, call_result, output, gas)?; if result.result.is_halt() { // Post-regolith, if the transaction is a deposit transaction and it haults, // we bubble up to the global return handler. The mint value will be persisted // and the caller nonce will be incremented there. - let is_deposit = data.env.tx.optimism.source_hash.is_some(); - let optimism_regolith = data.env.cfg.optimism && SPEC::enabled(REGOLITH); + let is_deposit = context.env.tx.optimism.source_hash.is_some(); + let optimism_regolith = context.env.cfg.optimism && SPEC::enabled(REGOLITH); if is_deposit && optimism_regolith { return Err(EVMError::Transaction( InvalidTransaction::HaltedDepositPostRegolith, @@ -176,8 +176,8 @@ pub fn end_handle( ) -> Result> { evm_output.or_else(|err| { if matches!(err, EVMError::Transaction(_)) - && data.env().cfg.optimism - && data.env().tx.optimism.source_hash.is_some() + && context.env().cfg.optimism + && context.env().tx.optimism.source_hash.is_some() { // If the transaction is a deposit transaction and it failed // for any reason, the caller nonce must be bumped, and the @@ -185,13 +185,14 @@ pub fn end_handle( // also returned as a special Halt variant so that consumers can more // easily distinguish between a failed deposit and a failed // normal transaction. - let caller = data.env().tx.caller; + let caller = context.env().tx.caller; // Increment sender nonce and account balance for the mint amount. Deposits // always persist the mint amount, even if the transaction fails. let account = { let mut acc = Account::from( - data.db + context + .db .basic(caller) .unwrap_or_default() .unwrap_or_default(), @@ -200,7 +201,7 @@ pub fn end_handle( acc.info.balance = acc .info .balance - .saturating_add(U256::from(data.env().tx.optimism.mint.unwrap_or(0))); + .saturating_add(U256::from(context.env().tx.optimism.mint.unwrap_or(0))); acc.mark_touch(); acc }; @@ -210,14 +211,14 @@ pub fn end_handle( // limit of the transaction. pre-regolith, it is the gas limit // of the transaction for non system transactions and 0 for system // transactions. - let is_system_tx = data + let is_system_tx = context .env() .tx .optimism .is_system_transaction .unwrap_or(false); let gas_used = if SPEC::enabled(REGOLITH) || !is_system_tx { - data.env().tx.gas_limit + context.env().tx.gas_limit } else { 0 }; diff --git a/crates/revm/src/inspector/customprinter.rs b/crates/revm/src/inspector/customprinter.rs index 8a559473f8a..9ea86d5f9b7 100644 --- a/crates/revm/src/inspector/customprinter.rs +++ b/crates/revm/src/inspector/customprinter.rs @@ -111,7 +111,6 @@ impl Inspector for CustomPrintTracer { mod test { #[test] - #[cfg(not(feature = "no_gas_measuring"))] #[cfg(not(feature = "optimism"))] fn gas_calculation_underflow() { use crate::primitives::{address, bytes}; diff --git a/crates/revm/src/inspector/eip3155.rs b/crates/revm/src/inspector/eip3155.rs index 06970083b56..c0803282dc0 100644 --- a/crates/revm/src/inspector/eip3155.rs +++ b/crates/revm/src/inspector/eip3155.rs @@ -88,8 +88,6 @@ impl Inspector for TracerEip3155 { result: InterpreterResult, ) -> InterpreterResult { let result = self.gas_inspector.call_end(context, result); - // self.log_step(interp, data, is_static, eval); - //self.skip = true; if context.journaled_state.depth() == 0 { let log_line = json!({ //stateroot @@ -119,9 +117,7 @@ impl Inspector for TracerEip3155 { result: InterpreterResult, address: Option
, ) -> (InterpreterResult, Option
) { - let result = self.gas_inspector.create_end(context, result, address); - //self.skip = true; - result + self.gas_inspector.create_end(context, result, address) } } diff --git a/crates/revm/src/inspector/gas.rs b/crates/revm/src/inspector/gas.rs index 9c4999f9bf4..965d87e009f 100644 --- a/crates/revm/src/inspector/gas.rs +++ b/crates/revm/src/inspector/gas.rs @@ -25,7 +25,6 @@ impl GasInspector { } impl Inspector for GasInspector { - #[cfg(not(feature = "no_gas_measuring"))] fn initialize_interp( &mut self, interp: &mut crate::interpreter::Interpreter, @@ -34,7 +33,6 @@ impl Inspector for GasInspector { self.gas_remaining = interp.gas.limit(); } - #[cfg(not(feature = "no_gas_measuring"))] fn step_end( &mut self, interp: &mut crate::interpreter::Interpreter, diff --git a/documentation/src/crates/interpreter.md b/documentation/src/crates/interpreter.md index 6c91bf1cce0..1f728084af1 100644 --- a/documentation/src/crates/interpreter.md +++ b/documentation/src/crates/interpreter.md @@ -15,10 +15,6 @@ External Crates: - [alloc](https://doc.rust-lang.org/alloc/): The alloc crate is used to provide the ability to allocate memory on the heap. It's a part of Rust's standard library that can be used in environments without a full host OS. - [core](https://doc.rust-lang.org/core/): The core crate is the dependency-free foundation of the Rust standard library. It includes fundamental types, macros, and traits. -Constants: - -- `USE_GAS`: This constant determines whether gas measurement should be enabled. It's set to false if the `no_gas_measuring` feature is enabled. - Re-exports: - Several types and functions are re-exported for easier access by users of this library, such as `Gas`, `Host`, `InstructionResult`, `OpCode`, `Interpreter`, `Memory`, `Stack`, and others. This allows users to import these items directly from the library root instead of from their individual modules. - `revm_primitives`: This crate is re-exported, providing primitive types or functionality used in the EVM implementation. diff --git a/documentation/src/crates/precompile/blake2.md b/documentation/src/crates/precompile/blake2.md index 10921ec89fa..43b409cb94c 100644 --- a/documentation/src/crates/precompile/blake2.md +++ b/documentation/src/crates/precompile/blake2.md @@ -15,7 +15,7 @@ The rationale behind incorporating `Blake2b` into Ethereum's suite of precompile ## Core Components -Two primary constants provide the CallStackFramework for the precompiled contract: +Two primary constants provide the framework for the precompiled contract: `F_ROUND: u64`: This is the cost of each round of computation in gas units. Currently set to 1. `INPUT_LENGTH: usize`: This specifies the required length of the input data, 213 bytes in this case. diff --git a/documentation/src/crates/primitives/specifications.md b/documentation/src/crates/primitives/specifications.md index 82ff0e3e14c..7b3873fb02f 100644 --- a/documentation/src/crates/primitives/specifications.md +++ b/documentation/src/crates/primitives/specifications.md @@ -12,4 +12,4 @@ The `Spec` trait is used to abstract the process of checking whether a given spe The module then defines various `Spec` structs, each representing a different hard fork. These structs implement the `Spec` trait and each struct's `SPEC_ID` corresponds to the correct `SpecId` variant. -This module provides the necessary CallStackFramework to handle and interact with the different Ethereum hard forks within the EVM, making it possible to handle transactions and contracts differently depending on which hard fork rules apply. It also simplifies the process of adapting to future hard forks by creating a new `SpecId` and corresponding `Spec` struct. +This module provides the necessary framework to handle and interact with the different Ethereum hard forks within the EVM, making it possible to handle transactions and contracts differently depending on which hard fork rules apply. It also simplifies the process of adapting to future hard forks by creating a new `SpecId` and corresponding `Spec` struct. diff --git a/documentation/src/crates/revm.md b/documentation/src/crates/revm.md index d8c124fd501..adee43a5ea6 100644 --- a/documentation/src/crates/revm.md +++ b/documentation/src/crates/revm.md @@ -14,10 +14,6 @@ External Crates: - `alloc`: The alloc crate is used to provide the ability to allocate memory on the heap. It's a part of Rust's standard library that can be used in environments without a full host OS. -Constants: - -- `USE_GAS`: This constant determines whether gas measurement should be used. It's set to false if the no_gas_measuring feature is enabled. - Re-exported Crates: - `revm_precompile`: This crate is re-exported, providing the precompiled contracts used in the EVM implementation.