Skip to content

Commit

Permalink
Arc<RwLock<_>> -> Rc<RefCell<_>> for GasInspector
Browse files Browse the repository at this point in the history
  • Loading branch information
shekhirin committed Sep 16, 2022
1 parent 05993db commit 227d4e7
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 66 deletions.
39 changes: 23 additions & 16 deletions anvil/src/eth/backend/mem/inspector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Arc<RwLock<GasInspector>>>,
pub gas: Option<Rc<RefCell<GasInspector>>>,
pub tracer: Option<Tracer>,
/// collects all `console.sol` logs
pub logs: LogCollector,
Expand All @@ -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
}
Expand All @@ -64,7 +63,7 @@ impl<DB: Database> revm::Inspector<DB> 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
Expand All @@ -78,7 +77,7 @@ impl<DB: Database> revm::Inspector<DB> 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);
}
Expand All @@ -95,7 +94,11 @@ impl<DB: Database> revm::Inspector<DB> 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);
}
Expand All @@ -111,7 +114,7 @@ impl<DB: Database> revm::Inspector<DB> 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);
}
Expand All @@ -127,7 +130,11 @@ impl<DB: Database> revm::Inspector<DB> 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);
}
Expand All @@ -147,7 +154,7 @@ impl<DB: Database> revm::Inspector<DB> 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);
}
Expand All @@ -162,7 +169,7 @@ impl<DB: Database> revm::Inspector<DB> for Inspector {
) -> (Return, Option<Address>, 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);
}
Expand All @@ -182,7 +189,7 @@ impl<DB: Database> revm::Inspector<DB> for Inspector {
) -> (Return, Option<Address>, 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());
}
Expand Down
74 changes: 34 additions & 40 deletions evm/src/executor/inspector/debugger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use crate::{
use bytes::Bytes;
use ethers::types::Address;
use revm::{
opcode, spec_opcode_gas, CallInputs, CreateInputs, EVMData, Gas, Inspector, Interpreter,
Memory, Return,
opcode, spec_opcode_gas, CallInputs, CreateInputs, EVMData, Gas, GasInspector, Inspector,
Interpreter, Memory, Return,
};

/// An inspector that collects debug nodes on every step of the interpreter.
Expand All @@ -24,21 +24,8 @@ pub struct Debugger {
pub head: usize,
/// The current execution address.
pub context: Address,
/// The amount of gas spent in the current gas block.
///
/// REVM adds gas in blocks, so we need to keep track of this separately to get accurate gas
/// numbers on an opcode level.
///
/// Gas blocks contain the gas costs of opcodes with a fixed cost. Dynamic costs are not
/// included in the gas block, and are instead added during execution of the contract.
pub current_gas_block: u64,
/// The amount of gas spent in the previous gas block.
///
/// Costs for gas blocks are accounted for when *entering* the gas block, which also means that
/// every run of the interpreter will always start with a non-zero `gas.spend()`.
///
/// For more information on gas blocks, see [current_gas_block].
pub previous_gas_block: u64,

pub gas_inspector: GasInspector,
}

impl Debugger {
Expand Down Expand Up @@ -66,19 +53,21 @@ where
fn initialize_interp(
&mut self,
interp: &mut Interpreter,
_: &mut EVMData<'_, DB>,
_: bool,
data: &mut EVMData<'_, DB>,
is_static: bool,
) -> Return {
self.previous_gas_block = interp.contract.first_gas_block();
self.gas_inspector.initialize_interp(interp, data, is_static);
Return::Continue
}

fn step(
&mut self,
interpreter: &mut Interpreter,
data: &mut EVMData<'_, DB>,
_is_static: bool,
is_static: bool,
) -> Return {
self.gas_inspector.step(interpreter, data, is_static);

let pc = interpreter.program_counter();
let op = interpreter.contract.bytecode.bytecode()[pc];

Expand All @@ -97,31 +86,34 @@ where
}
};

// Calculate the current amount of gas used
let gas = interpreter.gas();
let total_gas_spent = gas
.spend()
.saturating_sub(self.previous_gas_block)
.saturating_add(self.current_gas_block);
if opcode_info.is_gas_block_end() {
self.previous_gas_block = interpreter.contract.gas_block(pc);
self.current_gas_block = 0;
} else {
self.current_gas_block += opcode_info.get_gas() as u64;
}

self.arena.arena[self.head].steps.push(DebugStep {
pc,
stack: interpreter.stack().data().clone(),
memory: interpreter.memory.clone(),
instruction: Instruction::OpCode(op),
push_bytes,
total_gas_used: gas_used(data.env.cfg.spec_id, total_gas_spent, gas.refunded() as u64),
total_gas_used: 0,
});

Return::Continue
}

fn step_end(
&mut self,
interp: &mut Interpreter,
data: &mut EVMData<'_, DB>,
is_static: bool,
eval: Return,
) -> Return {
self.gas_inspector.step_end(interp, data, is_static, eval);

let total_gas_spent = interp.gas.limit() - self.gas_inspector.gas_remaining();
self.arena.arena[self.head].steps.last_mut().unwrap().total_gas_used =
gas_used(data.env.cfg.spec_id, total_gas_spent, interp.gas.refunded() as u64);

Return::Continue
}

fn call(
&mut self,
data: &mut EVMData<'_, DB>,
Expand All @@ -148,13 +140,14 @@ where

fn call_end(
&mut self,
_: &mut EVMData<'_, DB>,
_: &CallInputs,
data: &mut EVMData<'_, DB>,
inputs: &CallInputs,
gas: Gas,
status: Return,
retdata: Bytes,
_: bool,
is_static: bool,
) -> (Return, Gas, Bytes) {
self.gas_inspector.call_end(data, inputs, gas, status, retdata.clone(), is_static);
self.exit();

(status, gas, retdata)
Expand Down Expand Up @@ -182,13 +175,14 @@ where

fn create_end(
&mut self,
_: &mut EVMData<'_, DB>,
_: &CreateInputs,
data: &mut EVMData<'_, DB>,
inputs: &CreateInputs,
status: Return,
address: Option<Address>,
gas: Gas,
retdata: Bytes,
) -> (Return, Option<Address>, Gas, Bytes) {
self.gas_inspector.create_end(data, inputs, status, address, gas, retdata.clone());
self.exit();

(status, address, gas, retdata)
Expand Down
20 changes: 10 additions & 10 deletions evm/src/executor/inspector/tracer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -28,16 +27,17 @@ pub struct Tracer {
trace_stack: Vec<usize>,
step_stack: Vec<(usize, usize)>, // (trace_idx, step_idx)

gas_inspector: Arc<RwLock<GasInspector>>,
gas_inspector: Rc<RefCell<GasInspector>>,
}

impl Tracer {
pub fn new(gas_inspector: Arc<RwLock<GasInspector>>) -> 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<RefCell<_>>` here.
pub fn with_steps_recording(mut self, gas_inspector: Rc<RefCell<GasInspector>>) -> Self {
self.record_steps = true;
self.gas_inspector = gas_inspector;

self
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 227d4e7

Please sign in to comment.