diff --git a/Cargo.toml b/Cargo.toml index 652c1f3e..30cc805a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,15 +25,15 @@ alloy-sol-types = "0.7.2" alloy-primitives = "0.7.2" alloy-rpc-types = { git = "https://github.com/alloy-rs/alloy", rev = "f1d7085" } alloy-rpc-types-trace = { git = "https://github.com/alloy-rs/alloy", rev = "f1d7085" } -revm = { version = "8.0", default-features = false, features = ["std"] } +revm = { version = "9.0", default-features = false, features = ["std"] } anstyle = "1.0" colorchoice = "1.0" -thiserror = { version = "1" } +thiserror = "1.0" # serde serde = { version = "1", optional = true, features = ["derive"] } -serde_json = { version = "1" } +serde_json = "1.0" # js-tracer boa_engine = { version = "0.18", optional = true } diff --git a/src/access_list.rs b/src/access_list.rs index 52c08da4..a572bcd1 100644 --- a/src/access_list.rs +++ b/src/access_list.rs @@ -66,7 +66,7 @@ where match interp.current_opcode() { opcode::SLOAD | opcode::SSTORE => { if let Ok(slot) = interp.stack().peek(0) { - let cur_contract = interp.contract.address; + let cur_contract = interp.contract.target_address; self.access_list .entry(cur_contract) .or_default() diff --git a/src/opcode.rs b/src/opcode.rs index f9fa03c9..81be1261 100644 --- a/src/opcode.rs +++ b/src/opcode.rs @@ -69,19 +69,10 @@ where } } - fn step_end(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { + fn step_end(&mut self, interp: &mut Interpreter, _context: &mut EvmContext) { // update gas usage for the last opcode if let Some((opcode, gas_remaining)) = self.last_opcode_gas_remaining.take() { - let gas_table = - revm::interpreter::instructions::opcode::spec_opcode_gas(context.spec_id()); - let opcode_gas_info = gas_table[opcode.get() as usize]; - - let mut gas_cost = opcode_gas_info.get_gas() as u64; - // if gas cost is 0 then this is dynamic gas and we need to use the tracked gas - if gas_cost == 0 { - gas_cost = gas_remaining.saturating_sub(interp.gas().remaining()); - } - + let gas_cost = gas_remaining.saturating_sub(interp.gas().remaining()); *self.opcode_gas.entry(opcode).or_default() += gas_cost; } } diff --git a/src/tracing/builder/parity.rs b/src/tracing/builder/parity.rs index 6e07d450..87999211 100644 --- a/src/tracing/builder/parity.rs +++ b/src/tracing/builder/parity.rs @@ -9,10 +9,7 @@ use alloy_rpc_types::TransactionInfo; use alloy_rpc_types_trace::parity::*; use revm::{ db::DatabaseRef, - interpreter::{ - opcode::{self, spec_opcode_gas}, - OpCode, - }, + interpreter::{opcode, OpCode}, primitives::{Account, ExecutionResult, ResultAndState, SpecId, KECCAK_EMPTY}, }; use std::collections::{HashSet, VecDeque}; @@ -24,21 +21,16 @@ use std::collections::{HashSet, VecDeque}; pub struct ParityTraceBuilder { /// Recorded trace nodes nodes: Vec, - /// The spec id of the EVM. - spec_id: Option, - - /// How the traces were recorded - _config: TracingInspectorConfig, } impl ParityTraceBuilder { /// Returns a new instance of the builder pub fn new( nodes: Vec, - spec_id: Option, + _spec_id: Option, _config: TracingInspectorConfig, ) -> Self { - Self { nodes, spec_id, _config } + Self { nodes } } /// Returns a list of all addresses that appeared as callers. @@ -396,16 +388,9 @@ impl ParityTraceBuilder { store: maybe_storage, }); - let cost = self - .spec_id - .and_then(|spec_id| { - spec_opcode_gas(spec_id).get(step.op.get() as usize).map(|op| op.get_gas()) - }) - .unwrap_or_default(); - VmInstruction { pc: step.pc, - cost: cost as u64, + cost: step.gas_cost, ex: maybe_execution, sub: maybe_sub_call, op: Some(step.op.to_string()), diff --git a/src/tracing/js/bindings.rs b/src/tracing/js/bindings.rs index 547b9770..d1aab506 100644 --- a/src/tracing/js/bindings.rs +++ b/src/tracing/js/bindings.rs @@ -79,15 +79,19 @@ struct GuardedNullableGc { impl GuardedNullableGc { /// Creates a garbage collectible value to the given reference. /// - /// SAFETY; the caller must ensure that the guard is dropped before the value is dropped. - fn r#ref(val: &Val) -> (Self, GcGuard<'_, Val>) { + /// # Safety + /// + /// The caller must ensure that the guard is dropped before the value is dropped. + fn new_ref(val: &Val) -> (Self, GcGuard<'_, Val>) { Self::new(Guarded::Ref(val)) } /// Creates a garbage collectible value to the given reference. /// - /// SAFETY; the caller must ensure that the guard is dropped before the value is dropped. - fn r#owned<'a>(val: Val) -> (Self, GcGuard<'a, Val>) { + /// # Safety + /// + /// The caller must ensure that the guard is dropped before the value is dropped. + fn new_owned<'a>(val: Val) -> (Self, GcGuard<'a, Val>) { Self::new(Guarded::Owned(val)) } @@ -95,13 +99,9 @@ impl GuardedNullableGc { let inner = Rc::new(RefCell::new(Some(val))); let guard = GcGuard { inner: Rc::clone(&inner) }; - // SAFETY: guard enforces that the value is removed from the refcell before it is dropped - let this = Self { - inner: unsafe { - #[allow(clippy::missing_transmute_annotations)] - std::mem::transmute(inner) - }, - }; + // SAFETY: guard enforces that the value is removed from the refcell before it is dropped. + #[allow(clippy::missing_transmute_annotations)] + let this = Self { inner: unsafe { std::mem::transmute(inner) } }; (this, guard) } @@ -111,10 +111,7 @@ impl GuardedNullableGc { where F: FnOnce(&Val) -> R, { - self.inner.borrow().as_ref().map(|val| match val { - Guarded::Ref(val) => f(val), - Guarded::Owned(val) => f(val), - }) + self.inner.borrow().as_ref().map(|guard| f(guard.as_ref())) } } @@ -131,6 +128,16 @@ enum Guarded<'a, T> { Owned(T), } +impl Guarded<'_, T> { + #[inline] + fn as_ref(&self) -> &T { + match self { + Guarded::Ref(val) => val, + Guarded::Owned(val) => val, + } + } +} + /// Guard the inner value, once this value is dropped the inner value is also removed. /// /// This type guarantees that it never outlives the wrapped value. @@ -232,7 +239,7 @@ pub(crate) struct MemoryRef(GuardedNullableGc); impl MemoryRef { /// Creates a new stack reference pub(crate) fn new(mem: &SharedMemory) -> (Self, GcGuard<'_, SharedMemory>) { - let (inner, guard) = GuardedNullableGc::r#ref(mem); + let (inner, guard) = GuardedNullableGc::new_ref(mem); (Self(inner), guard) } @@ -324,7 +331,7 @@ pub(crate) struct StateRef(GuardedNullableGc); impl StateRef { /// Creates a new stack reference pub(crate) fn new(state: &State) -> (Self, GcGuard<'_, State>) { - let (inner, guard) = GuardedNullableGc::r#ref(state); + let (inner, guard) = GuardedNullableGc::new_ref(state); (Self(inner), guard) } @@ -349,7 +356,7 @@ where { /// Creates a new stack reference fn new<'a>(db: DB) -> (Self, GcGuard<'a, DB>) { - let (inner, guard) = GuardedNullableGc::owned(db); + let (inner, guard) = GuardedNullableGc::new_owned(db); (Self(inner), guard) } } @@ -417,7 +424,7 @@ pub(crate) struct StackRef(GuardedNullableGc); impl StackRef { /// Creates a new stack reference pub(crate) fn new(stack: &Stack) -> (Self, GcGuard<'_, Stack>) { - let (inner, guard) = GuardedNullableGc::r#ref(stack); + let (inner, guard) = GuardedNullableGc::new_ref(stack); (Self(inner), guard) } @@ -790,21 +797,15 @@ impl EvmDbRef { return JsArrayBuffer::new(0, ctx); } - let res = self - .inner - .db - .0 - .with_inner(|db| db.code_by_hash_ref(code_hash).map(|code| code.bytecode)); - let code = match res { - Some(Ok(code)) => code, - _ => { - return Err(JsError::from_native(JsNativeError::error().with_message(format!( - "Failed to read code hash {code_hash:?} from database", - )))) - } + let Some(Ok(bytecode)) = self.inner.db.0.with_inner(|db| db.code_by_hash_ref(code_hash)) + else { + return Err(JsError::from_native( + JsNativeError::error() + .with_message(format!("Failed to read code hash {code_hash:?} from database")), + )); }; - to_buf(code.to_vec(), ctx) + to_buf(bytecode.bytecode().to_vec(), ctx) } fn read_state( diff --git a/src/tracing/js/mod.rs b/src/tracing/js/mod.rs index 1f3fffbf..4e8d4acc 100644 --- a/src/tracing/js/mod.rs +++ b/src/tracing/js/mod.rs @@ -257,7 +257,7 @@ impl JsInspector { to = Some(target); "CALL" } - TransactTo::Create(_) => "CREATE", + TransactTo::Create => "CREATE", } .to_string(), from: env.tx.caller, @@ -446,19 +446,19 @@ where self.register_precompiles(&context.precompiles); // determine correct `from` and `to` based on the call scheme - let (from, to) = match inputs.context.scheme { + let (from, to) = match inputs.scheme { CallScheme::DelegateCall | CallScheme::CallCode => { - (inputs.context.address, inputs.context.code_address) + (inputs.target_address, inputs.bytecode_address) } - _ => (inputs.context.caller, inputs.context.address), + _ => (inputs.caller, inputs.bytecode_address), }; - let value = inputs.transfer.value; + let value = inputs.transfer_value().unwrap_or_default(); self.push_call( to, inputs.input.clone(), value, - inputs.context.scheme.into(), + inputs.scheme.into(), from, inputs.gas_limit, ); diff --git a/src/tracing/mod.rs b/src/tracing/mod.rs index 029dede2..1f6f88d5 100644 --- a/src/tracing/mod.rs +++ b/src/tracing/mod.rs @@ -183,7 +183,7 @@ impl TracingInspector { &self, context: &EvmContext, to: &Address, - value: U256, + value: &U256, ) -> bool { if context.precompiles.contains_key(to) { // only if this is _not_ the root call @@ -357,7 +357,7 @@ impl TracingInspector { depth: context.journaled_state.depth(), pc: interp.program_counter(), op, - contract: interp.contract.address, + contract: interp.contract.target_address, stack, push_stack: None, memory_size: memory.len(), @@ -477,36 +477,36 @@ where self.gas_inspector.call(context, inputs); // determine correct `from` and `to` based on the call scheme - let (from, to) = match inputs.context.scheme { + let (from, to) = match inputs.scheme { CallScheme::DelegateCall | CallScheme::CallCode => { - (inputs.context.address, inputs.context.code_address) + (inputs.target_address, inputs.bytecode_address) } - _ => (inputs.context.caller, inputs.context.address), + _ => (inputs.caller, inputs.target_address), }; - let value = if matches!(inputs.context.scheme, CallScheme::DelegateCall) { + let value = if matches!(inputs.scheme, CallScheme::DelegateCall) { // for delegate calls we need to use the value of the top trace if let Some(parent) = self.active_trace() { parent.trace.value } else { - inputs.transfer.value + inputs.call_value() } } else { - inputs.transfer.value + inputs.call_value() }; // if calls to precompiles should be excluded, check whether this is a call to a precompile let maybe_precompile = self .config .exclude_precompile_calls - .then(|| self.is_precompile_call(context, &to, value)); + .then(|| self.is_precompile_call(context, &to, &value)); self.start_trace_on_call( context, to, inputs.input.clone(), value, - inputs.context.scheme.into(), + inputs.scheme.into(), from, inputs.gas_limit, maybe_precompile, diff --git a/src/tracing/types.rs b/src/tracing/types.rs index 41e4a918..5fb9128f 100644 --- a/src/tracing/types.rs +++ b/src/tracing/types.rs @@ -10,7 +10,7 @@ use alloy_rpc_types_trace::{ SelfdestructAction, TraceOutput, TransactionTrace, }, }; -use revm::interpreter::{opcode, CallContext, CallScheme, CreateScheme, InstructionResult, OpCode}; +use revm::interpreter::{opcode, CallScheme, CreateScheme, InstructionResult, OpCode}; use std::collections::VecDeque; /// A trace of a call. @@ -55,8 +55,6 @@ pub struct CallTrace { pub gas_limit: u64, /// The final status of the call. pub status: InstructionResult, - /// call context of the runtime - pub call_context: Option>, /// Opcode-level execution steps. pub steps: Vec, } diff --git a/src/transfer.rs b/src/transfer.rs index d0290fee..65f0545b 100644 --- a/src/transfer.rs +++ b/src/transfer.rs @@ -57,12 +57,12 @@ where return None; } - if !inputs.transfer.value.is_zero() { + if inputs.transfers_value() { self.transfers.push(TransferOperation { kind: TransferKind::Call, - from: inputs.transfer.source, - to: inputs.transfer.target, - value: inputs.transfer.value, + from: inputs.caller, + to: inputs.target_address, + value: inputs.call_value(), }); } diff --git a/tests/it/geth.rs b/tests/it/geth.rs index f006624e..336dac51 100644 --- a/tests/it/geth.rs +++ b/tests/it/geth.rs @@ -8,7 +8,6 @@ use alloy_rpc_types_trace::geth::{ }; use revm::{ db::{CacheDB, EmptyDB}, - interpreter::CreateScheme, primitives::{ BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ExecutionResult, HandlerCfg, Output, SpecId, TransactTo, TxEnv, @@ -66,7 +65,7 @@ fn test_geth_calltracer_logs() { TxEnv { caller: deployer, gas_limit: 1000000, - transact_to: TransactTo::Create(CreateScheme::Create), + transact_to: TransactTo::Create, data: code.into(), ..Default::default() }, @@ -175,7 +174,7 @@ fn test_geth_mux_tracer() { TxEnv { caller: deployer, gas_limit: 1000000, - transact_to: TransactTo::Create(CreateScheme::Create), + transact_to: TransactTo::Create, data: code.into(), ..Default::default() }, diff --git a/tests/it/parity.rs b/tests/it/parity.rs index 295808d2..66d0bab9 100644 --- a/tests/it/parity.rs +++ b/tests/it/parity.rs @@ -6,7 +6,6 @@ use alloy_rpc_types::TransactionInfo; use alloy_rpc_types_trace::parity::{Action, SelfdestructAction}; use revm::{ db::{CacheDB, EmptyDB}, - interpreter::CreateScheme, primitives::{ AccountInfo, BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ExecutionResult, HandlerCfg, Output, SpecId, TransactTo, TxEnv, @@ -51,7 +50,7 @@ fn test_parity_selfdestruct(spec_id: SpecId) { TxEnv { caller: deployer, gas_limit: 1000000, - transact_to: TransactTo::Create(CreateScheme::Create), + transact_to: TransactTo::Create, data: code.into(), value, ..Default::default() @@ -148,7 +147,7 @@ fn test_parity_constructor_selfdestruct() { TxEnv { caller: deployer, gas_limit: 1000000, - transact_to: TransactTo::Create(CreateScheme::Create), + transact_to: TransactTo::Create, data: code.into(), ..Default::default() }, diff --git a/tests/it/transfer.rs b/tests/it/transfer.rs index dfb9ac2a..6eed8ffa 100644 --- a/tests/it/transfer.rs +++ b/tests/it/transfer.rs @@ -3,7 +3,6 @@ use alloy_primitives::{hex, Address, U256}; use revm::{ db::{CacheDB, EmptyDB}, - interpreter::CreateScheme, primitives::{ BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ExecutionResult, HandlerCfg, Output, SpecId, TransactTo, TxEnv, @@ -41,7 +40,7 @@ fn test_internal_transfers() { TxEnv { caller: deployer, gas_limit: 1000000, - transact_to: TransactTo::Create(CreateScheme::Create), + transact_to: TransactTo::Create, data: code.into(), ..Default::default() }, diff --git a/tests/it/utils.rs b/tests/it/utils.rs index ca503c72..75bae73c 100644 --- a/tests/it/utils.rs +++ b/tests/it/utils.rs @@ -4,8 +4,8 @@ use revm::{ db::{CacheDB, EmptyDB}, inspector_handle_register, primitives::{ - BlockEnv, CreateScheme, EVMError, Env, EnvWithHandlerCfg, ExecutionResult, HandlerCfg, - Output, ResultAndState, SpecId, TransactTo, TxEnv, + BlockEnv, EVMError, Env, EnvWithHandlerCfg, ExecutionResult, HandlerCfg, Output, + ResultAndState, SpecId, TransactTo, TxEnv, }, Database, DatabaseCommit, GetInspector, }; @@ -46,7 +46,7 @@ impl TestEvm { inspector: I, ) -> Result> { self.env.tx.data = data; - self.env.tx.transact_to = TransactTo::Create(CreateScheme::Create); + self.env.tx.transact_to = TransactTo::Create; let (ResultAndState { result, state }, env) = self.inspect(inspector)?; self.db.commit(state);