Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(evm, inspector): use GasInspector for Debugger #3261

Merged
merged 3 commits into from
Sep 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 21 additions & 41 deletions evm/src/executor/inspector/debugger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,34 @@ 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,
};
use std::{cell::RefCell, rc::Rc};

/// An inspector that collects debug nodes on every step of the interpreter.
#[derive(Default, Debug)]
#[derive(Debug)]
pub struct Debugger {
/// The arena of [DebugNode]s
pub arena: DebugArena,
/// The ID of the current [DebugNode].
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,

gas_inspector: Rc<RefCell<GasInspector>>,
}

impl Debugger {
pub fn new(gas_inspector: Rc<RefCell<GasInspector>>) -> Self {
Self {
arena: Default::default(),
head: Default::default(),
context: Default::default(),
gas_inspector,
}
}

/// Enters a new execution context.
pub fn enter(&mut self, depth: usize, address: Address, kind: CallKind) {
self.context = address;
Expand All @@ -63,16 +60,6 @@ impl<DB> Inspector<DB> for Debugger
where
DB: DatabaseExt,
{
fn initialize_interp(
&mut self,
interp: &mut Interpreter,
_: &mut EVMData<'_, DB>,
_: bool,
) -> Return {
self.previous_gas_block = interp.contract.first_gas_block();
Return::Continue
}

fn step(
&mut self,
interpreter: &mut Interpreter,
Expand All @@ -97,26 +84,19 @@ 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;
}
let total_gas_used = gas_used(
data.env.cfg.spec_id,
interpreter.gas.limit() - self.gas_inspector.borrow().gas_remaining(),
interpreter.gas.refunded() 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,
});

Return::Continue
Expand Down
8 changes: 6 additions & 2 deletions evm/src/executor/inspector/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
mod utils;

mod logs;

pub use logs::LogCollector;
use std::{cell::RefCell, rc::Rc};

mod access_list;
pub use access_list::AccessListTracer;
Expand All @@ -24,7 +26,7 @@ pub use cheatcodes::{Cheatcodes, CheatsConfig, DEFAULT_CREATE2_DEPLOYER};

use ethers::types::U256;

use revm::BlockEnv;
use revm::{BlockEnv, GasInspector};

mod fuzzer;
pub use fuzzer::Fuzzer;
Expand Down Expand Up @@ -72,7 +74,9 @@ impl InspectorStackConfig {
stack.tracer = Some(Tracer::default());
}
if self.debugger {
stack.debugger = Some(Debugger::default());
let gas_inspector = Rc::new(RefCell::new(GasInspector::default()));
stack.gas = Some(gas_inspector.clone());
stack.debugger = Some(Debugger::new(gas_inspector));
}
stack.fuzzer = self.fuzzer.clone();

Expand Down
19 changes: 16 additions & 3 deletions evm/src/executor/inspector/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use ethers::{
signers::LocalWallet,
types::{Address, Log, H256},
};
use revm::{CallInputs, CreateInputs, EVMData, Gas, Inspector, Interpreter, Return};
use std::collections::BTreeMap;
use revm::{CallInputs, CreateInputs, EVMData, Gas, GasInspector, Inspector, Interpreter, Return};
use std::{cell::RefCell, collections::BTreeMap, rc::Rc};

/// Helper macro to call the same method on multiple inspectors without resorting to dynamic
/// dispatch
Expand Down Expand Up @@ -45,6 +45,7 @@ pub struct InspectorStack {
pub tracer: Option<Tracer>,
pub logs: Option<LogCollector>,
pub cheatcodes: Option<Cheatcodes>,
pub gas: Option<Rc<RefCell<GasInspector>>>,
pub debugger: Option<Debugger>,
pub fuzzer: Option<Fuzzer>,
pub coverage: Option<CoverageCollector>,
Expand Down Expand Up @@ -85,6 +86,7 @@ where
call_inspectors!(
inspector,
[
&mut self.gas.as_deref().map(|gas| gas.borrow_mut()),
&mut self.debugger,
&mut self.coverage,
&mut self.tracer,
Expand Down Expand Up @@ -113,6 +115,7 @@ where
call_inspectors!(
inspector,
[
&mut self.gas.as_deref().map(|gas| gas.borrow_mut()),
&mut self.fuzzer,
&mut self.debugger,
&mut self.tracer,
Expand Down Expand Up @@ -154,7 +157,13 @@ where
) -> Return {
call_inspectors!(
inspector,
[&mut self.debugger, &mut self.tracer, &mut self.logs, &mut self.cheatcodes],
[
&mut self.gas.as_deref().map(|gas| gas.borrow_mut()),
&mut self.debugger,
&mut self.tracer,
&mut self.logs,
&mut self.cheatcodes
],
{
let status = inspector.step_end(interpreter, data, is_static, status);

Expand All @@ -177,6 +186,7 @@ where
call_inspectors!(
inspector,
[
&mut self.gas.as_deref().map(|gas| gas.borrow_mut()),
&mut self.fuzzer,
&mut self.debugger,
&mut self.tracer,
Expand Down Expand Up @@ -209,6 +219,7 @@ where
call_inspectors!(
inspector,
[
&mut self.gas.as_deref().map(|gas| gas.borrow_mut()),
&mut self.fuzzer,
&mut self.debugger,
&mut self.tracer,
Expand Down Expand Up @@ -246,6 +257,7 @@ where
call_inspectors!(
inspector,
[
&mut self.gas.as_deref().map(|gas| gas.borrow_mut()),
&mut self.debugger,
&mut self.tracer,
&mut self.coverage,
Expand Down Expand Up @@ -277,6 +289,7 @@ where
call_inspectors!(
inspector,
[
&mut self.gas.as_deref().map(|gas| gas.borrow_mut()),
&mut self.debugger,
&mut self.tracer,
&mut self.coverage,
Expand Down