From 5f72aa321748aa3fc369aeb50aed5f30d9a1a96c Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Thu, 15 Sep 2022 22:06:43 +0100 Subject: [PATCH 1/7] fix(anvil, evm): gas accounting in debug_traceTransaction --- anvil/src/eth/backend/mem/inspector.rs | 12 +++++ anvil/src/eth/backend/mem/storage.rs | 2 +- evm/src/executor/inspector/tracer.rs | 64 ++++++++++++++++++++++++-- evm/src/trace/mod.rs | 4 +- 4 files changed, 74 insertions(+), 8 deletions(-) diff --git a/anvil/src/eth/backend/mem/inspector.rs b/anvil/src/eth/backend/mem/inspector.rs index 2238f93312d3..0c1463cd1f9b 100644 --- a/anvil/src/eth/backend/mem/inspector.rs +++ b/anvil/src/eth/backend/mem/inspector.rs @@ -50,6 +50,18 @@ impl Inspector { } impl revm::Inspector for Inspector { + fn initialize_interp( + &mut self, + interp: &mut Interpreter, + data: &mut EVMData<'_, DB>, + is_static: bool, + ) -> Return { + if let Some(tracer) = self.tracer.as_mut() { + tracer.initialize_interp(interp, data, is_static); + } + Return::Continue + } + fn step( &mut self, interp: &mut Interpreter, diff --git a/anvil/src/eth/backend/mem/storage.rs b/anvil/src/eth/backend/mem/storage.rs index 4672ed06849c..9cce1da68d26 100644 --- a/anvil/src/eth/backend/mem/storage.rs +++ b/anvil/src/eth/backend/mem/storage.rs @@ -295,7 +295,7 @@ impl MinedTransaction { } pub fn geth_trace(&self, opts: GethDebugTracingOptions) -> GethTrace { - self.info.traces.geth_trace(opts) + self.info.traces.geth_trace(self.receipt.gas_used(), opts) } } diff --git a/evm/src/executor/inspector/tracer.rs b/evm/src/executor/inspector/tracer.rs index 1a4bd34f305b..652493a4012c 100644 --- a/evm/src/executor/inspector/tracer.rs +++ b/evm/src/executor/inspector/tracer.rs @@ -13,8 +13,8 @@ use ethers::{ types::{Address, H256, U256}, }; use revm::{ - opcode, return_ok, CallInputs, CallScheme, CreateInputs, Database, EVMData, Gas, Inspector, - Interpreter, JournalEntry, Return, + opcode, return_ok, spec_opcode_gas, CallInputs, CallScheme, CreateInputs, Database, EVMData, + Gas, Inspector, Interpreter, JournalEntry, Return, }; /// An inspector that collects call traces. @@ -25,6 +25,15 @@ pub struct Tracer { pub trace_stack: Vec, pub traces: CallTraceArena, pub step_stack: Vec<(usize, usize)>, // (trace_idx, step_idx) + + // Cumulative gas counter starting with `Gas::limit` and decreasing after each step execution + pub gas_left: u64, + + reduced_gas_block: u64, + full_gas_block: u64, + was_return: bool, + was_jumpi: Option, + previous_gas_remaining: u64, } impl Tracer { @@ -91,6 +100,30 @@ impl Tracer { self.step_stack.push((trace_idx, trace.trace.steps.len())); let pc = interp.program_counter(); + let op = interp.contract.bytecode.bytecode()[pc]; + + // Get opcode information + let opcode_infos = spec_opcode_gas(data.env.cfg.spec_id); + let opcode_info = &opcode_infos[op as usize]; + + let gas_remaining = interp.gas.remaining() + self.full_gas_block - self.reduced_gas_block; + + if let Some(step) = trace.trace.steps.last_mut() { + step.gas_cost = self.previous_gas_remaining - gas_remaining; + self.gas_left -= step.gas_cost; + } + + self.previous_gas_remaining = gas_remaining; + + if op == opcode::JUMPI { + self.was_jumpi = Some(pc); + } else if opcode_info.is_gas_block_end() { + self.reduced_gas_block = 0; + self.full_gas_block = interp.contract.gas_block(pc); + } else { + self.reduced_gas_block += opcode_info.get_gas() as u64; + } + trace.trace.steps.push(CallTraceStep { depth: data.journaled_state.depth(), pc, @@ -98,7 +131,7 @@ impl Tracer { contract: interp.contract.address, stack: interp.stack.clone(), memory: interp.memory.clone(), - gas: interp.gas.remaining(), + gas: self.gas_left, gas_refund_counter: interp.gas.refunded() as u64, gas_cost: 0, state_diff: None, @@ -138,8 +171,16 @@ impl Tracer { _ => None, }; - // TODO: calculate spent gas as in `Debugger::step` - step.gas_cost = step.gas - interp.gas.remaining(); + if let Some(was_pc) = self.was_jumpi { + if was_pc == pc { + self.reduced_gas_block = 0; + self.full_gas_block = interp.contract.gas_block(was_pc); + } + self.was_jumpi = None; + } else if self.was_return { + self.full_gas_block = interp.contract.gas_block(pc); + self.was_return = false; + } // Error codes only if status as u8 > Return::OutOfGas as u8 { @@ -152,6 +193,17 @@ impl Inspector for Tracer where DB: Database, { + fn initialize_interp( + &mut self, + interp: &mut Interpreter, + _data: &mut EVMData<'_, DB>, + _is_static: bool, + ) -> Return { + self.gas_left = interp.gas.limit(); + self.full_gas_block = interp.contract.first_gas_block(); + Return::Continue + } + fn step( &mut self, interp: &mut Interpreter, @@ -230,6 +282,7 @@ where retdata.to_vec(), None, ); + self.was_return = true; (status, gas, retdata) } @@ -279,6 +332,7 @@ where code, address, ); + self.was_return = true; (status, address, gas, retdata) } diff --git a/evm/src/trace/mod.rs b/evm/src/trace/mod.rs index fdd5e7d4cf92..630dafc7cccf 100644 --- a/evm/src/trace/mod.rs +++ b/evm/src/trace/mod.rs @@ -89,11 +89,10 @@ impl CallTraceArena { .collect() } - pub fn geth_trace(&self, opts: GethDebugTracingOptions) -> GethTrace { + pub fn geth_trace(&self, receipt_gas_used: U256, opts: GethDebugTracingOptions) -> GethTrace { let mut storage = HashMap::>::new(); let mut trace = self.arena.iter().fold(GethTrace::default(), |mut acc, trace| { acc.failed |= !trace.trace.success; - acc.gas += trace.trace.gas_cost; acc.struct_logs.extend(trace.trace.steps.iter().map(|step| { let mut log: StructLog = step.into(); @@ -118,6 +117,7 @@ impl CallTraceArena { acc }); + trace.gas = receipt_gas_used.as_u64(); if let Some(last_trace) = self.arena.first() { trace.return_value = last_trace.trace.output.to_raw().into(); } From cc38c10875dc77d558c0caa062d00eeba661d42a Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Thu, 15 Sep 2022 22:33:04 +0100 Subject: [PATCH 2/7] checked sub for previous pc --- evm/src/executor/inspector/tracer.rs | 59 ++++++++++++++-------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/evm/src/executor/inspector/tracer.rs b/evm/src/executor/inspector/tracer.rs index 652493a4012c..8716217476e0 100644 --- a/evm/src/executor/inspector/tracer.rs +++ b/evm/src/executor/inspector/tracer.rs @@ -149,37 +149,38 @@ impl Tracer { self.step_stack.pop().expect("can't fill step without starting a step first"); let step = &mut self.traces.arena[trace_idx].trace.steps[step_idx]; - let pc = interp.program_counter() - 1; - let op = interp.contract.bytecode.bytecode()[pc]; - - let journal_entry = data - .journaled_state - .journal - .last() - // This should always work because revm initializes it as `vec![vec![]]` - .unwrap() - .last(); - - step.state_diff = match (op, journal_entry) { - ( - opcode::SLOAD | opcode::SSTORE, - Some(JournalEntry::StorageChage { address, key, .. }), - ) => { - let value = data.journaled_state.state[address].storage[key].present_value(); - Some((*key, value)) - } - _ => None, - }; + if let Some(pc) = interp.program_counter().checked_sub(1) { + let op = interp.contract.bytecode.bytecode()[pc]; - if let Some(was_pc) = self.was_jumpi { - if was_pc == pc { - self.reduced_gas_block = 0; - self.full_gas_block = interp.contract.gas_block(was_pc); + let journal_entry = data + .journaled_state + .journal + .last() + // This should always work because revm initializes it as `vec![vec![]]` + .unwrap() + .last(); + + step.state_diff = match (op, journal_entry) { + ( + opcode::SLOAD | opcode::SSTORE, + Some(JournalEntry::StorageChage { address, key, .. }), + ) => { + let value = data.journaled_state.state[address].storage[key].present_value(); + Some((*key, value)) + } + _ => None, + }; + + if let Some(was_pc) = self.was_jumpi { + if was_pc == pc { + self.reduced_gas_block = 0; + self.full_gas_block = interp.contract.gas_block(was_pc); + } + self.was_jumpi = None; + } else if self.was_return { + self.full_gas_block = interp.contract.gas_block(pc); + self.was_return = false; } - self.was_jumpi = None; - } else if self.was_return { - self.full_gas_block = interp.contract.gas_block(pc); - self.was_return = false; } // Error codes only From dc499c216d5560d84bfecb598b4bd2f7afc61f93 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Fri, 16 Sep 2022 10:58:46 +0100 Subject: [PATCH 3/7] use revm gas inspector --- Cargo.lock | 25 +---- Cargo.toml | 2 +- anvil/src/eth/backend/mem/inspector.rs | 90 +++++++++++------ evm/src/executor/inspector/stack.rs | 1 + evm/src/executor/inspector/tracer.rs | 134 +++++++------------------ 5 files changed, 106 insertions(+), 146 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3a99d7b465a3..a9eee4841b3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,7 +120,6 @@ dependencies = [ "memory-db", "parking_lot 0.12.0", "pretty_assertions", - "revm_precompiles 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde", "serde_json", "tempfile", @@ -4488,7 +4487,7 @@ dependencies = [ [[package]] name = "revm" version = "2.0.0" -source = "git+https://github.com/bluealloy/revm#1e25c99b544863d15610e9af8e623dd173397b48" +source = "git+https://github.com/shekhirin/revm?branch=gas-inspector#1eee730379d6c9b2f8a1c12364aa20875868def1" dependencies = [ "arrayref", "auto_impl 1.0.1", @@ -4497,7 +4496,7 @@ dependencies = [ "hex", "num_enum", "primitive-types", - "revm_precompiles 1.1.1 (git+https://github.com/bluealloy/revm)", + "revm_precompiles", "rlp", "serde", "sha3", @@ -4506,25 +4505,7 @@ dependencies = [ [[package]] name = "revm_precompiles" version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00e68901326fe20437526cb6d64a2898d2976383b7d222329dfce1717902da50" -dependencies = [ - "bytes", - "hashbrown 0.12.0", - "num", - "once_cell", - "primitive-types", - "ripemd", - "secp256k1", - "sha2 0.10.5", - "sha3", - "substrate-bn", -] - -[[package]] -name = "revm_precompiles" -version = "1.1.1" -source = "git+https://github.com/bluealloy/revm#1e25c99b544863d15610e9af8e623dd173397b48" +source = "git+https://github.com/shekhirin/revm?branch=gas-inspector#1eee730379d6c9b2f8a1c12364aa20875868def1" dependencies = [ "bytes", "hashbrown 0.12.0", diff --git a/Cargo.toml b/Cargo.toml index e7a4793c190e..6e04bd5182da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,5 +66,5 @@ debug = 0 [patch.crates-io] #revm = { path = "../revm/crates/revm" } -revm = { git = "https://github.com/bluealloy/revm" } +revm = { git = "https://github.com/shekhirin/revm", branch = "gas-inspector" } svm-rs = { git = "https://github.com/roynalnaruto/svm-rs" } diff --git a/anvil/src/eth/backend/mem/inspector.rs b/anvil/src/eth/backend/mem/inspector.rs index 0c1463cd1f9b..86af6e47bc98 100644 --- a/anvil/src/eth/backend/mem/inspector.rs +++ b/anvil/src/eth/backend/mem/inspector.rs @@ -7,15 +7,19 @@ use crate::{ use bytes::Bytes; use ethers::types::{Address, Log, H256}; use foundry_evm::{ + call_inspectors, decode::decode_console_logs, executor::inspector::{LogCollector, Tracer}, revm, - revm::{CallInputs, EVMData, Gas, Return}, + revm::{CallInputs, EVMData, Gas, GasInspector, Return}, }; +use parking_lot::RwLock; +use std::sync::Arc; /// The [`revm::Inspector`] used when transacting in the evm #[derive(Debug, Clone, Default)] pub struct Inspector { + pub gas: Option>>, pub tracer: Option, /// collects all `console.sol` logs pub logs: LogCollector, @@ -33,7 +37,9 @@ impl Inspector { /// Configures the `Tracer` [`revm::Inspector`] pub fn with_tracing(mut self) -> Self { - self.tracer = Some(Default::default()); + let gas_inspector = Arc::new(RwLock::new(GasInspector::default())); + self.gas = Some(gas_inspector.clone()); + self.tracer = Some(Tracer::new(gas_inspector)); self } @@ -56,9 +62,11 @@ impl revm::Inspector for Inspector { data: &mut EVMData<'_, DB>, is_static: bool, ) -> Return { - if let Some(tracer) = self.tracer.as_mut() { - tracer.initialize_interp(interp, data, is_static); - } + call_inspectors!( + inspector, + [&mut self.gas.as_ref().map(|gas| gas.write()), &mut self.tracer], + { inspector.initialize_interp(interp, data, is_static) } + ); Return::Continue } @@ -68,9 +76,13 @@ impl revm::Inspector for Inspector { data: &mut EVMData<'_, DB>, is_static: bool, ) -> Return { - if let Some(tracer) = self.tracer.as_mut() { - tracer.step(interp, data, is_static); - } + call_inspectors!( + inspector, + [&mut self.gas.as_ref().map(|gas| gas.write()), &mut self.tracer], + { + inspector.step(interp, data, is_static); + } + ); Return::Continue } @@ -81,10 +93,13 @@ impl revm::Inspector for Inspector { topics: &[H256], data: &Bytes, ) { - if let Some(tracer) = self.tracer.as_mut() { - tracer.log(evm_data, address, topics, data); - } - self.logs.log(evm_data, address, topics, data); + call_inspectors!( + inspector, + [&mut self.gas.as_ref().map(|gas| gas.write()), &mut self.tracer, Some(&mut self.logs)], + { + inspector.log(evm_data, address, topics, data); + } + ); } fn step_end( @@ -94,9 +109,13 @@ impl revm::Inspector for Inspector { is_static: bool, eval: Return, ) -> Return { - if let Some(tracer) = self.tracer.as_mut() { - tracer.step_end(interp, data, is_static, eval); - } + call_inspectors!( + inspector, + [&mut self.gas.as_ref().map(|gas| gas.write()), &mut self.tracer], + { + inspector.step_end(interp, data, is_static, eval); + } + ); eval } @@ -106,10 +125,13 @@ impl revm::Inspector for Inspector { call: &mut CallInputs, is_static: bool, ) -> (Return, Gas, Bytes) { - if let Some(tracer) = self.tracer.as_mut() { - tracer.call(data, call, is_static); - } - self.logs.call(data, call, is_static); + call_inspectors!( + inspector, + [&mut self.gas.as_ref().map(|gas| gas.write()), &mut self.tracer, Some(&mut self.logs)], + { + inspector.call(data, call, is_static); + } + ); (Return::Continue, Gas::new(call.gas_limit), Bytes::new()) } @@ -123,9 +145,13 @@ impl revm::Inspector for Inspector { out: Bytes, is_static: bool, ) -> (Return, Gas, Bytes) { - if let Some(tracer) = self.tracer.as_mut() { - tracer.call_end(data, inputs, remaining_gas, ret, out.clone(), is_static); - } + call_inspectors!( + inspector, + [&mut self.gas.as_ref().map(|gas| gas.write()), &mut self.tracer], + { + inspector.call_end(data, inputs, remaining_gas, ret, out.clone(), is_static); + } + ); (ret, remaining_gas, out) } @@ -134,9 +160,13 @@ impl revm::Inspector for Inspector { data: &mut EVMData<'_, DB>, call: &mut CreateInputs, ) -> (Return, Option
, Gas, Bytes) { - if let Some(tracer) = self.tracer.as_mut() { - tracer.create(data, call); - } + call_inspectors!( + inspector, + [&mut self.gas.as_ref().map(|gas| gas.write()), &mut self.tracer], + { + inspector.create(data, call); + } + ); (Return::Continue, None, Gas::new(call.gas_limit), Bytes::new()) } @@ -150,9 +180,13 @@ impl revm::Inspector for Inspector { gas: Gas, retdata: Bytes, ) -> (Return, Option
, Gas, Bytes) { - if let Some(tracer) = self.tracer.as_mut() { - tracer.create_end(data, inputs, status, address, gas, retdata.clone()); - } + call_inspectors!( + inspector, + [&mut self.gas.as_ref().map(|gas| gas.write()), &mut self.tracer], + { + inspector.create_end(data, inputs, status, address, gas, retdata.clone()); + } + ); (status, address, gas, retdata) } } diff --git a/evm/src/executor/inspector/stack.rs b/evm/src/executor/inspector/stack.rs index 136cf5703bac..8668eba84e7f 100644 --- a/evm/src/executor/inspector/stack.rs +++ b/evm/src/executor/inspector/stack.rs @@ -15,6 +15,7 @@ use std::collections::BTreeMap; /// Helper macro to call the same method on multiple inspectors without resorting to dynamic /// dispatch +#[macro_export] macro_rules! call_inspectors { ($id:ident, [ $($inspector:expr),+ ], $call:block) => { $({ diff --git a/evm/src/executor/inspector/tracer.rs b/evm/src/executor/inspector/tracer.rs index 8716217476e0..790d25dbeccd 100644 --- a/evm/src/executor/inspector/tracer.rs +++ b/evm/src/executor/inspector/tracer.rs @@ -12,38 +12,37 @@ use ethers::{ abi::RawLog, types::{Address, H256, U256}, }; +use parking_lot::RwLock; use revm::{ - opcode, return_ok, spec_opcode_gas, CallInputs, CallScheme, CreateInputs, Database, EVMData, - Gas, Inspector, Interpreter, JournalEntry, Return, + opcode, return_ok, CallInputs, CallScheme, CreateInputs, Database, EVMData, Gas, GasInspector, + Inspector, Interpreter, JournalEntry, Return, }; +use std::sync::Arc; /// An inspector that collects call traces. #[derive(Default, Debug, Clone)] pub struct Tracer { - pub record_steps: bool, + record_steps: bool, - pub trace_stack: Vec, pub traces: CallTraceArena, - pub step_stack: Vec<(usize, usize)>, // (trace_idx, step_idx) + trace_stack: Vec, + step_stack: Vec<(usize, usize)>, // (trace_idx, step_idx) - // Cumulative gas counter starting with `Gas::limit` and decreasing after each step execution - pub gas_left: u64, - - reduced_gas_block: u64, - full_gas_block: u64, - was_return: bool, - was_jumpi: Option, - previous_gas_remaining: u64, + gas_inspector: Arc>, } impl Tracer { + pub fn new(gas_inspector: Arc>) -> Self { + Self { gas_inspector, ..Default::default() } + } + pub fn with_steps_recording(mut self) -> Self { self.record_steps = true; self } - pub fn start_trace( + fn start_trace( &mut self, depth: usize, address: Address, @@ -67,13 +66,7 @@ impl Tracer { )); } - pub fn fill_trace( - &mut self, - status: Return, - cost: u64, - output: Vec, - address: Option
, - ) { + fn fill_trace(&mut self, status: Return, cost: u64, output: Vec, address: Option
) { let success = matches!(status, return_ok!()); let trace = &mut self.traces.arena [self.trace_stack.pop().expect("more traces were filled than started")] @@ -88,11 +81,7 @@ impl Tracer { } } - pub fn start_step( - &mut self, - interp: &mut Interpreter, - data: &mut EVMData<'_, DB>, - ) { + fn start_step(&mut self, interp: &mut Interpreter, data: &mut EVMData<'_, DB>) { let trace_idx = *self.trace_stack.last().expect("can't start step without starting a trace first"); let trace = &mut self.traces.arena[trace_idx]; @@ -100,29 +89,6 @@ impl Tracer { self.step_stack.push((trace_idx, trace.trace.steps.len())); let pc = interp.program_counter(); - let op = interp.contract.bytecode.bytecode()[pc]; - - // Get opcode information - let opcode_infos = spec_opcode_gas(data.env.cfg.spec_id); - let opcode_info = &opcode_infos[op as usize]; - - let gas_remaining = interp.gas.remaining() + self.full_gas_block - self.reduced_gas_block; - - if let Some(step) = trace.trace.steps.last_mut() { - step.gas_cost = self.previous_gas_remaining - gas_remaining; - self.gas_left -= step.gas_cost; - } - - self.previous_gas_remaining = gas_remaining; - - if op == opcode::JUMPI { - self.was_jumpi = Some(pc); - } else if opcode_info.is_gas_block_end() { - self.reduced_gas_block = 0; - self.full_gas_block = interp.contract.gas_block(pc); - } else { - self.reduced_gas_block += opcode_info.get_gas() as u64; - } trace.trace.steps.push(CallTraceStep { depth: data.journaled_state.depth(), @@ -131,7 +97,7 @@ impl Tracer { contract: interp.contract.address, stack: interp.stack.clone(), memory: interp.memory.clone(), - gas: self.gas_left, + gas: self.gas_inspector.read().gas_remaining(), gas_refund_counter: interp.gas.refunded() as u64, gas_cost: 0, state_diff: None, @@ -139,7 +105,7 @@ impl Tracer { }); } - pub fn fill_step( + fn fill_step( &mut self, interp: &mut Interpreter, data: &mut EVMData<'_, DB>, @@ -171,16 +137,7 @@ impl Tracer { _ => None, }; - if let Some(was_pc) = self.was_jumpi { - if was_pc == pc { - self.reduced_gas_block = 0; - self.full_gas_block = interp.contract.gas_block(was_pc); - } - self.was_jumpi = None; - } else if self.was_return { - self.full_gas_block = interp.contract.gas_block(pc); - self.was_return = false; - } + step.gas_cost = step.gas - self.gas_inspector.read().gas_remaining(); } // Error codes only @@ -194,17 +151,6 @@ impl Inspector for Tracer where DB: Database, { - fn initialize_interp( - &mut self, - interp: &mut Interpreter, - _data: &mut EVMData<'_, DB>, - _is_static: bool, - ) -> Return { - self.gas_left = interp.gas.limit(); - self.full_gas_block = interp.contract.first_gas_block(); - Return::Continue - } - fn step( &mut self, interp: &mut Interpreter, @@ -246,36 +192,36 @@ where fn call( &mut self, data: &mut EVMData<'_, DB>, - call: &mut CallInputs, - _: bool, + inputs: &mut CallInputs, + _is_static: bool, ) -> (Return, Gas, Bytes) { - let (from, to) = match call.context.scheme { + let (from, to) = match inputs.context.scheme { CallScheme::DelegateCall | CallScheme::CallCode => { - (call.context.address, call.context.code_address) + (inputs.context.address, inputs.context.code_address) } - _ => (call.context.caller, call.context.address), + _ => (inputs.context.caller, inputs.context.address), }; self.start_trace( data.journaled_state.depth() as usize, to, - call.input.to_vec(), - call.transfer.value, - call.context.scheme.into(), + inputs.input.to_vec(), + inputs.transfer.value, + inputs.context.scheme.into(), from, ); - (Return::Continue, Gas::new(call.gas_limit), Bytes::new()) + (Return::Continue, Gas::new(inputs.gas_limit), Bytes::new()) } fn call_end( &mut self, data: &mut EVMData<'_, DB>, - _call: &CallInputs, + _inputs: &CallInputs, gas: Gas, status: Return, retdata: Bytes, - _: bool, + _is_static: bool, ) -> (Return, Gas, Bytes) { self.fill_trace( status, @@ -283,7 +229,6 @@ where retdata.to_vec(), None, ); - self.was_return = true; (status, gas, retdata) } @@ -291,27 +236,27 @@ where fn create( &mut self, data: &mut EVMData<'_, DB>, - call: &mut CreateInputs, + inputs: &mut CreateInputs, ) -> (Return, Option
, Gas, Bytes) { // TODO: Does this increase gas cost? - let _ = data.journaled_state.load_account(call.caller, data.db); - let nonce = data.journaled_state.account(call.caller).info.nonce; + let _ = data.journaled_state.load_account(inputs.caller, data.db); + let nonce = data.journaled_state.account(inputs.caller).info.nonce; self.start_trace( data.journaled_state.depth() as usize, - get_create_address(call, nonce), - call.init_code.to_vec(), - call.value, - call.scheme.into(), - call.caller, + get_create_address(inputs, nonce), + inputs.init_code.to_vec(), + inputs.value, + inputs.scheme.into(), + inputs.caller, ); - (Return::Continue, None, Gas::new(call.gas_limit), Bytes::new()) + (Return::Continue, None, Gas::new(inputs.gas_limit), Bytes::new()) } fn create_end( &mut self, data: &mut EVMData<'_, DB>, - _: &CreateInputs, + _inputs: &CreateInputs, status: Return, address: Option
, gas: Gas, @@ -333,7 +278,6 @@ where code, address, ); - self.was_return = true; (status, address, gas, retdata) } From 8ca5e200592afcfdb6902e9e5e747383507d86f1 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Fri, 16 Sep 2022 11:01:44 +0100 Subject: [PATCH 4/7] bump ethers --- Cargo.lock | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a9eee4841b3a..569ab4d4ccae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1627,7 +1627,7 @@ dependencies = [ [[package]] name = "ethers" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#6b4007f6193ffa8a685a802eec7ff7be9431d112" +source = "git+https://github.com/gakonst/ethers-rs#78e406b2619340053d3d55d504621b6077add7b9" dependencies = [ "ethers-addressbook", "ethers-contract", @@ -1642,7 +1642,7 @@ dependencies = [ [[package]] name = "ethers-addressbook" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#6b4007f6193ffa8a685a802eec7ff7be9431d112" +source = "git+https://github.com/gakonst/ethers-rs#78e406b2619340053d3d55d504621b6077add7b9" dependencies = [ "ethers-core", "once_cell", @@ -1653,7 +1653,7 @@ dependencies = [ [[package]] name = "ethers-contract" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#6b4007f6193ffa8a685a802eec7ff7be9431d112" +source = "git+https://github.com/gakonst/ethers-rs#78e406b2619340053d3d55d504621b6077add7b9" dependencies = [ "ethers-contract-abigen", "ethers-contract-derive", @@ -1671,7 +1671,7 @@ dependencies = [ [[package]] name = "ethers-contract-abigen" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#6b4007f6193ffa8a685a802eec7ff7be9431d112" +source = "git+https://github.com/gakonst/ethers-rs#78e406b2619340053d3d55d504621b6077add7b9" dependencies = [ "Inflector", "cfg-if 1.0.0", @@ -1694,7 +1694,7 @@ dependencies = [ [[package]] name = "ethers-contract-derive" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#6b4007f6193ffa8a685a802eec7ff7be9431d112" +source = "git+https://github.com/gakonst/ethers-rs#78e406b2619340053d3d55d504621b6077add7b9" dependencies = [ "ethers-contract-abigen", "ethers-core", @@ -1708,7 +1708,7 @@ dependencies = [ [[package]] name = "ethers-core" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#6b4007f6193ffa8a685a802eec7ff7be9431d112" +source = "git+https://github.com/gakonst/ethers-rs#78e406b2619340053d3d55d504621b6077add7b9" dependencies = [ "arrayvec 0.7.2", "bytes", @@ -1739,7 +1739,7 @@ dependencies = [ [[package]] name = "ethers-etherscan" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#6b4007f6193ffa8a685a802eec7ff7be9431d112" +source = "git+https://github.com/gakonst/ethers-rs#78e406b2619340053d3d55d504621b6077add7b9" dependencies = [ "ethers-core", "getrandom 0.2.6", @@ -1755,7 +1755,7 @@ dependencies = [ [[package]] name = "ethers-middleware" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#6b4007f6193ffa8a685a802eec7ff7be9431d112" +source = "git+https://github.com/gakonst/ethers-rs#78e406b2619340053d3d55d504621b6077add7b9" dependencies = [ "async-trait", "auto_impl 0.5.0", @@ -1780,7 +1780,7 @@ dependencies = [ [[package]] name = "ethers-providers" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#6b4007f6193ffa8a685a802eec7ff7be9431d112" +source = "git+https://github.com/gakonst/ethers-rs#78e406b2619340053d3d55d504621b6077add7b9" dependencies = [ "async-trait", "auto_impl 1.0.1", @@ -1817,7 +1817,7 @@ dependencies = [ [[package]] name = "ethers-signers" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#6b4007f6193ffa8a685a802eec7ff7be9431d112" +source = "git+https://github.com/gakonst/ethers-rs#78e406b2619340053d3d55d504621b6077add7b9" dependencies = [ "async-trait", "coins-bip32", @@ -1840,7 +1840,7 @@ dependencies = [ [[package]] name = "ethers-solc" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#6b4007f6193ffa8a685a802eec7ff7be9431d112" +source = "git+https://github.com/gakonst/ethers-rs#78e406b2619340053d3d55d504621b6077add7b9" dependencies = [ "cfg-if 1.0.0", "dunce", From b019aa999baaedaa1c5d6e2d9b0098b7c268cff0 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Fri, 16 Sep 2022 17:24:55 +0100 Subject: [PATCH 5/7] bump revm --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 569ab4d4ccae..2e1df083b586 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4487,7 +4487,7 @@ dependencies = [ [[package]] name = "revm" version = "2.0.0" -source = "git+https://github.com/shekhirin/revm?branch=gas-inspector#1eee730379d6c9b2f8a1c12364aa20875868def1" +source = "git+https://github.com/shekhirin/revm?branch=gas-inspector#808fc89ab66b7d5ac484f01655fa5c5a9a09f9ee" dependencies = [ "arrayref", "auto_impl 1.0.1", @@ -4505,7 +4505,7 @@ dependencies = [ [[package]] name = "revm_precompiles" version = "1.1.1" -source = "git+https://github.com/shekhirin/revm?branch=gas-inspector#1eee730379d6c9b2f8a1c12364aa20875868def1" +source = "git+https://github.com/shekhirin/revm?branch=gas-inspector#808fc89ab66b7d5ac484f01655fa5c5a9a09f9ee" dependencies = [ "bytes", "hashbrown 0.12.0", From 9d49e39a830fdd50e76faa9638ac611fba82fa86 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Fri, 16 Sep 2022 19:08:06 +0100 Subject: [PATCH 6/7] Arc> -> Rc> for GasInspector --- anvil/src/eth/backend/mem/inspector.rs | 39 +++++++++++++++----------- evm/src/executor/inspector/tracer.rs | 20 ++++++------- 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/anvil/src/eth/backend/mem/inspector.rs b/anvil/src/eth/backend/mem/inspector.rs index 86af6e47bc98..cb45b30888a9 100644 --- a/anvil/src/eth/backend/mem/inspector.rs +++ b/anvil/src/eth/backend/mem/inspector.rs @@ -13,13 +13,12 @@ use foundry_evm::{ revm, revm::{CallInputs, EVMData, Gas, GasInspector, Return}, }; -use parking_lot::RwLock; -use std::sync::Arc; +use std::{cell::RefCell, rc::Rc}; /// The [`revm::Inspector`] used when transacting in the evm #[derive(Debug, Clone, Default)] pub struct Inspector { - pub gas: Option>>, + pub gas: Option>>, pub tracer: Option, /// collects all `console.sol` logs pub logs: LogCollector, @@ -37,19 +36,19 @@ impl Inspector { /// Configures the `Tracer` [`revm::Inspector`] pub fn with_tracing(mut self) -> Self { - let gas_inspector = Arc::new(RwLock::new(GasInspector::default())); - self.gas = Some(gas_inspector.clone()); - self.tracer = Some(Tracer::new(gas_inspector)); + self.tracer = Some(Default::default()); self } - /// Enables steps recording for `Tracer` + /// Enables steps recording for `Tracer` and attaches `GasInspector` to it /// If `Tracer` wasn't configured before, configures it automatically pub fn with_steps_tracing(mut self) -> Self { if self.tracer.is_none() { self = self.with_tracing() } - self.tracer = self.tracer.map(|tracer| tracer.with_steps_recording()); + let gas_inspector = Rc::new(RefCell::new(GasInspector::default())); + self.gas = Some(gas_inspector.clone()); + self.tracer = self.tracer.map(|tracer| tracer.with_steps_recording(gas_inspector)); self } @@ -64,7 +63,7 @@ impl revm::Inspector for Inspector { ) -> Return { call_inspectors!( inspector, - [&mut self.gas.as_ref().map(|gas| gas.write()), &mut self.tracer], + [&mut self.gas.as_deref().map(|gas| gas.borrow_mut()), &mut self.tracer], { inspector.initialize_interp(interp, data, is_static) } ); Return::Continue @@ -78,7 +77,7 @@ impl revm::Inspector for Inspector { ) -> Return { call_inspectors!( inspector, - [&mut self.gas.as_ref().map(|gas| gas.write()), &mut self.tracer], + [&mut self.gas.as_deref().map(|gas| gas.borrow_mut()), &mut self.tracer], { inspector.step(interp, data, is_static); } @@ -95,7 +94,11 @@ impl revm::Inspector for Inspector { ) { call_inspectors!( inspector, - [&mut self.gas.as_ref().map(|gas| gas.write()), &mut self.tracer, Some(&mut self.logs)], + [ + &mut self.gas.as_deref().map(|gas| gas.borrow_mut()), + &mut self.tracer, + Some(&mut self.logs) + ], { inspector.log(evm_data, address, topics, data); } @@ -111,7 +114,7 @@ impl revm::Inspector for Inspector { ) -> Return { call_inspectors!( inspector, - [&mut self.gas.as_ref().map(|gas| gas.write()), &mut self.tracer], + [&mut self.gas.as_deref().map(|gas| gas.borrow_mut()), &mut self.tracer], { inspector.step_end(interp, data, is_static, eval); } @@ -127,7 +130,11 @@ impl revm::Inspector for Inspector { ) -> (Return, Gas, Bytes) { call_inspectors!( inspector, - [&mut self.gas.as_ref().map(|gas| gas.write()), &mut self.tracer, Some(&mut self.logs)], + [ + &mut self.gas.as_deref().map(|gas| gas.borrow_mut()), + &mut self.tracer, + Some(&mut self.logs) + ], { inspector.call(data, call, is_static); } @@ -147,7 +154,7 @@ impl revm::Inspector for Inspector { ) -> (Return, Gas, Bytes) { call_inspectors!( inspector, - [&mut self.gas.as_ref().map(|gas| gas.write()), &mut self.tracer], + [&mut self.gas.as_deref().map(|gas| gas.borrow_mut()), &mut self.tracer], { inspector.call_end(data, inputs, remaining_gas, ret, out.clone(), is_static); } @@ -162,7 +169,7 @@ impl revm::Inspector for Inspector { ) -> (Return, Option
, Gas, Bytes) { call_inspectors!( inspector, - [&mut self.gas.as_ref().map(|gas| gas.write()), &mut self.tracer], + [&mut self.gas.as_deref().map(|gas| gas.borrow_mut()), &mut self.tracer], { inspector.create(data, call); } @@ -182,7 +189,7 @@ impl revm::Inspector for Inspector { ) -> (Return, Option
, Gas, Bytes) { call_inspectors!( inspector, - [&mut self.gas.as_ref().map(|gas| gas.write()), &mut self.tracer], + [&mut self.gas.as_deref().map(|gas| gas.borrow_mut()), &mut self.tracer], { inspector.create_end(data, inputs, status, address, gas, retdata.clone()); } diff --git a/evm/src/executor/inspector/tracer.rs b/evm/src/executor/inspector/tracer.rs index 790d25dbeccd..89f4604e8171 100644 --- a/evm/src/executor/inspector/tracer.rs +++ b/evm/src/executor/inspector/tracer.rs @@ -12,12 +12,11 @@ use ethers::{ abi::RawLog, types::{Address, H256, U256}, }; -use parking_lot::RwLock; use revm::{ opcode, return_ok, CallInputs, CallScheme, CreateInputs, Database, EVMData, Gas, GasInspector, Inspector, Interpreter, JournalEntry, Return, }; -use std::sync::Arc; +use std::{cell::RefCell, rc::Rc}; /// An inspector that collects call traces. #[derive(Default, Debug, Clone)] @@ -28,16 +27,17 @@ pub struct Tracer { trace_stack: Vec, step_stack: Vec<(usize, usize)>, // (trace_idx, step_idx) - gas_inspector: Arc>, + gas_inspector: Rc>, } impl Tracer { - pub fn new(gas_inspector: Arc>) -> Self { - Self { gas_inspector, ..Default::default() } - } - - pub fn with_steps_recording(mut self) -> Self { + /// Enables step recording and uses [revm::GasInspector] to report gas costs for each step. + /// + /// Gas Inspector should be called externally **before** [Tracer], this is why we need it as + /// `Rc>` here. + pub fn with_steps_recording(mut self, gas_inspector: Rc>) -> Self { self.record_steps = true; + self.gas_inspector = gas_inspector; self } @@ -97,7 +97,7 @@ impl Tracer { contract: interp.contract.address, stack: interp.stack.clone(), memory: interp.memory.clone(), - gas: self.gas_inspector.read().gas_remaining(), + gas: self.gas_inspector.borrow().gas_remaining(), gas_refund_counter: interp.gas.refunded() as u64, gas_cost: 0, state_diff: None, @@ -137,7 +137,7 @@ impl Tracer { _ => None, }; - step.gas_cost = step.gas - self.gas_inspector.read().gas_remaining(); + step.gas_cost = step.gas - self.gas_inspector.borrow().gas_remaining(); } // Error codes only From 63c5a0e0237ccc16a2be99760e6a1e290bd632b0 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Sun, 18 Sep 2022 12:11:25 +0100 Subject: [PATCH 7/7] bump revm --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ed608d874d0..04d6d4a54913 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4493,7 +4493,7 @@ dependencies = [ [[package]] name = "revm" version = "2.0.0" -source = "git+https://github.com/shekhirin/revm?branch=gas-inspector#808fc89ab66b7d5ac484f01655fa5c5a9a09f9ee" +source = "git+https://github.com/bluealloy/revm#ca14d61375cc94b216742bb016d2199c0b006b17" dependencies = [ "arrayref", "auto_impl 1.0.1", @@ -4511,7 +4511,7 @@ dependencies = [ [[package]] name = "revm_precompiles" version = "1.1.1" -source = "git+https://github.com/shekhirin/revm?branch=gas-inspector#808fc89ab66b7d5ac484f01655fa5c5a9a09f9ee" +source = "git+https://github.com/bluealloy/revm#ca14d61375cc94b216742bb016d2199c0b006b17" dependencies = [ "bytes", "hashbrown 0.12.0", diff --git a/Cargo.toml b/Cargo.toml index 6e04bd5182da..e7a4793c190e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,5 +66,5 @@ debug = 0 [patch.crates-io] #revm = { path = "../revm/crates/revm" } -revm = { git = "https://github.com/shekhirin/revm", branch = "gas-inspector" } +revm = { git = "https://github.com/bluealloy/revm" } svm-rs = { git = "https://github.com/roynalnaruto/svm-rs" }