Skip to content
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
5 changes: 4 additions & 1 deletion book/src/inspector.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ pub trait Inspector<CTX, INTR: InterpreterTypes> {
fn create_end(&mut self, context: &mut CTX, inputs: &CreateInputs, outcome: &mut CreateOutcome) {}

// Event tracing
fn log(&mut self, interp: &mut Interpreter<INTR>, context: &mut CTX, log: Log) {}
fn log(&mut self, context: &mut CTX, log: Log) {}
fn log_full(&mut self, interp: &mut Interpreter<INTR>, context &mut CTX, log: Log) {
self.log(context, log)
}
fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {}
}
```
Expand Down
9 changes: 6 additions & 3 deletions crates/context/interface/src/journaled_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ pub trait JournalTr {
/// Logs the log in Journal state.
fn log(&mut self, log: Log);

/// Take logs from journal.
fn take_logs(&mut self) -> Vec<Log>;

/// Returns the logs from journal.
fn logs(&self) -> &[Log];

/// Marks the account for selfdestruction and transfers all the balance to the target.
fn selfdestruct(
&mut self,
Expand Down Expand Up @@ -274,9 +280,6 @@ pub trait JournalTr {
/// Returns the depth of the journal.
fn depth(&self) -> usize;

/// Take logs from journal.
fn take_logs(&mut self) -> Vec<Log>;

/// Commit current transaction journal and returns transaction logs.
fn commit_tx(&mut self);

Expand Down
15 changes: 10 additions & 5 deletions crates/context/src/journal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,16 @@ impl<DB: Database, ENTRY: JournalEntryTr> JournalTr for Journal<DB, ENTRY> {
self.inner.log(log)
}

#[inline]
fn logs(&self) -> &[Log] {
&self.inner.logs
}

#[inline]
fn take_logs(&mut self) -> Vec<Log> {
self.inner.take_logs()
}

fn selfdestruct(
&mut self,
address: Address,
Expand Down Expand Up @@ -306,11 +316,6 @@ impl<DB: Database, ENTRY: JournalEntryTr> JournalTr for Journal<DB, ENTRY> {
.create_account_checkpoint(caller, address, balance, spec_id)
}

#[inline]
fn take_logs(&mut self) -> Vec<Log> {
self.inner.take_logs()
}

#[inline]
fn commit_tx(&mut self) {
self.inner.commit_tx()
Expand Down
6 changes: 3 additions & 3 deletions crates/ee-tests/src/op_revm_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use revm::{
handler::system_call::SYSTEM_ADDRESS,
interpreter::{
gas::{calculate_initial_tx_gas, InitialAndFloorGas},
Interpreter, InterpreterTypes,
InterpreterTypes,
},
precompile::{bls12_381_const, bls12_381_utils, bn254, secp256r1, u64_to_address},
primitives::{bytes, eip7825, Address, Bytes, Log, TxKind, U256},
Expand Down Expand Up @@ -1045,8 +1045,8 @@ struct LogInspector {
}

impl<CTX, INTR: InterpreterTypes> Inspector<CTX, INTR> for LogInspector {
fn log(&mut self, _interp: &mut Interpreter<INTR>, _context: &mut CTX, log: Log) {
self.logs.push(log)
fn log(&mut self, _context: &mut CTX, log: Log) {
self.logs.push(log);
}
}

Expand Down
11 changes: 9 additions & 2 deletions crates/handler/src/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ use primitives::{
};
use primitives::{keccak256, Address, Bytes, U256};
use state::Bytecode;
use std::borrow::ToOwned;
use std::boxed::Box;
use std::{borrow::ToOwned, boxed::Box, vec::Vec};

/// Frame implementation for Ethereum.
#[derive_where(Clone, Debug; IW,
Expand Down Expand Up @@ -155,6 +154,8 @@ impl EthFrame<EthInterpreter> {
output: Bytes::new(),
},
memory_offset: inputs.return_memory_offset.clone(),
was_precompile_called: false,
precompile_call_logs: Vec::new(),
})))
};

Expand Down Expand Up @@ -190,14 +191,20 @@ impl EthFrame<EthInterpreter> {
let gas_limit = inputs.gas_limit;

if let Some(result) = precompiles.run(ctx, &inputs).map_err(ERROR::from_string)? {
let mut logs = Vec::new();
if result.result.is_ok() {
ctx.journal_mut().checkpoint_commit();
} else {
// clone logs that precompile created, only possible with custom precompiles.
// checkpoint.log_i will be always correct.
logs = ctx.journal_mut().logs()[checkpoint.log_i..].to_vec();
ctx.journal_mut().checkpoint_revert(checkpoint);
}
return Ok(ItemOrResult::Result(FrameResult::Call(CallOutcome {
result,
memory_offset: inputs.return_memory_offset.clone(),
was_precompile_called: true,
precompile_call_logs: logs,
})));
}

Expand Down
9 changes: 2 additions & 7 deletions crates/inspector/src/count_inspector.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! CountInspector - Inspector that counts all opcodes that were called.
use crate::inspector::Inspector;
use interpreter::{interpreter_types::Jumps, InterpreterTypes};
use primitives::HashMap;
use primitives::{HashMap, Log};

/// Inspector that counts all opcodes that were called during execution.
#[derive(Clone, Debug, Default)]
Expand Down Expand Up @@ -133,12 +133,7 @@ impl<CTX, INTR: InterpreterTypes> Inspector<CTX, INTR> for CountInspector {
self.step_end_count += 1;
}

fn log(
&mut self,
_interp: &mut interpreter::Interpreter<INTR>,
_context: &mut CTX,
_log: primitives::Log,
) {
fn log(&mut self, _context: &mut CTX, _log: Log) {
self.log_count += 1;
}

Expand Down
14 changes: 11 additions & 3 deletions crates/inspector/src/either.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,18 @@ where
}

#[inline]
fn log(&mut self, interp: &mut Interpreter<INTR>, context: &mut CTX, log: Log) {
fn log(&mut self, context: &mut CTX, log: Log) {
match self {
Either::Left(inspector) => inspector.log(interp, context, log),
Either::Right(inspector) => inspector.log(interp, context, log),
Either::Left(inspector) => inspector.log(context, log),
Either::Right(inspector) => inspector.log(context, log),
}
}

#[inline]
fn log_full(&mut self, interp: &mut Interpreter<INTR>, context: &mut CTX, log: Log) {
match self {
Either::Left(inspector) => inspector.log_full(interp, context, log),
Either::Right(inspector) => inspector.log_full(interp, context, log),
}
}

Expand Down
4 changes: 2 additions & 2 deletions crates/inspector/src/handler.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{Inspector, InspectorEvmTr, JournalExt};
use context::{result::ExecutionResult, ContextTr, JournalEntry, Transaction};
use context::{result::ExecutionResult, ContextTr, JournalEntry, JournalTr, Transaction};
use handler::{evm::FrameTr, EvmTr, FrameResult, Handler, ItemOrResult};
use interpreter::{
instructions::InstructionTable,
Expand Down Expand Up @@ -260,7 +260,7 @@ fn inspect_log<CTX, IT>(
}

let log = context.journal_mut().logs().last().unwrap().clone();
inspector.log(interpreter, context, log);
inspector.log(context, log);
}

#[inline(never)]
Expand Down
34 changes: 20 additions & 14 deletions crates/inspector/src/inspector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,23 @@ pub trait Inspector<CTX, INTR: InterpreterTypes = EthInterpreter> {
let _ = context;
}

/// Called when a log is emitted.
/// Called when a log is emitted, called on every new log.
/// If there is a needs for Interpreter context, use [`Inspector::log_full`] instead.
#[inline]
fn log(&mut self, interp: &mut Interpreter<INTR>, context: &mut CTX, log: Log) {
let _ = interp;
fn log(&mut self, context: &mut CTX, log: Log) {
let _ = context;
let _ = log;
}

/// Called when a log is emitted with the interpreter context.
///
/// This will not happen only if custom precompiles where logs will be
/// gethered after precompile call.
fn log_full(&mut self, interpreter: &mut Interpreter<INTR>, context: &mut CTX, log: Log) {
let _ = interpreter;
self.log(context, log);
}

/// Called whenever a call to a contract is about to start.
///
/// Returning `CallOutcome` will override the result of the call.
Expand Down Expand Up @@ -133,9 +142,14 @@ where
self.1.step_end(interp, context);
}

fn log(&mut self, interp: &mut Interpreter<INTR>, context: &mut CTX, log: Log) {
self.0.log(interp, context, log.clone());
self.1.log(interp, context, log);
fn log(&mut self, context: &mut CTX, log: Log) {
self.0.log(context, log.clone());
self.1.log(context, log);
}

fn log_full(&mut self, interp: &mut Interpreter<INTR>, context: &mut CTX, log: Log) {
self.0.log_full(interp, context, log.clone());
self.1.log_full(interp, context, log);
}

fn call(&mut self, context: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {
Expand Down Expand Up @@ -174,9 +188,6 @@ where
/// Extends the journal with additional methods that are used by the inspector.
#[auto_impl(&mut, Box)]
pub trait JournalExt {
/// Get all logs from the journal.
fn logs(&self) -> &[Log];

/// Get the journal entries that are created from last checkpoint.
/// new checkpoint is created when sub call is made.
fn journal(&self) -> &[JournalEntry];
Expand All @@ -189,11 +200,6 @@ pub trait JournalExt {
}

impl<DB: Database> JournalExt for Journal<DB> {
#[inline]
fn logs(&self) -> &[Log] {
&self.logs
}

#[inline]
fn journal(&self) -> &[JournalEntry] {
&self.journal
Expand Down
2 changes: 1 addition & 1 deletion crates/inspector/src/inspector_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ mod tests {
}
}

fn log(&mut self, _interp: &mut Interpreter<INTR>, _ctx: &mut CTX, log: Log) {
fn log(&mut self, _ctx: &mut CTX, log: Log) {
self.events.push(InspectorEvent::Log(log));
}

Expand Down
21 changes: 19 additions & 2 deletions crates/inspector/src/traits.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use context::{ContextTr, FrameStack};
use context::{ContextTr, FrameStack, JournalTr};
use handler::{
evm::{ContextDbError, FrameInitResult, FrameTr},
instructions::InstructionProvider,
EthFrame, EvmTr, FrameInitOrResult, FrameResult, ItemOrResult,
};
use interpreter::{interpreter::EthInterpreter, interpreter_action::FrameInit, InterpreterTypes};
use interpreter::{
interpreter::EthInterpreter, interpreter_action::FrameInit, CallOutcome, InterpreterTypes,
};

use crate::{
handler::{frame_end, frame_start},
Expand Down Expand Up @@ -104,8 +106,23 @@ pub trait InspectorEvmTr:
}

let frame_input = frame_init.frame_input.clone();
let logs_i = ctx.journal().logs().len();
if let ItemOrResult::Result(mut output) = self.frame_init(frame_init)? {
let (ctx, inspector) = self.ctx_inspector();
// for precompiles send logs to inspector.
if let FrameResult::Call(CallOutcome {
was_precompile_called,
precompile_call_logs,
..
}) = &mut output
{
if *was_precompile_called {
let logs = ctx.journal_mut().logs()[logs_i..].to_vec();
for log in logs.iter().chain(precompile_call_logs.iter()).cloned() {
inspector.log(ctx, log);
}
}
}
frame_end(ctx, inspector, &frame_input, &mut output);
return Ok(ItemOrResult::Result(output));
}
Expand Down
11 changes: 10 additions & 1 deletion crates/interpreter/src/interpreter_action/call_outcome.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{Gas, InstructionResult, InterpreterResult};
use core::ops::Range;
use primitives::Bytes;
use primitives::{Bytes, Log};
use std::vec::Vec;

/// Represents the outcome of a call operation in a virtual machine.
///
Expand All @@ -18,6 +19,12 @@ pub struct CallOutcome {
pub result: InterpreterResult,
/// The range in memory where the output data is located
pub memory_offset: Range<usize>,
/// Flag to indicate if the call is precompile call.
/// Used by inspector so it can copy the logs for Inspector::logs call.
pub was_precompile_called: bool,
/// Precompile call logs. Needs as revert/halt would delete them from Journal.
/// So they can't be accessed by inspector.
pub precompile_call_logs: Vec<Log>,
}

impl CallOutcome {
Expand All @@ -33,6 +40,8 @@ impl CallOutcome {
Self {
result,
memory_offset,
was_precompile_called: false,
precompile_call_logs: Vec::new(),
}
}

Expand Down
8 changes: 4 additions & 4 deletions crates/op-revm/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1279,14 +1279,14 @@ mod tests {
assert_eq!(
handler.execution_result(
&mut evm,
FrameResult::Call(CallOutcome {
result: InterpreterResult {
FrameResult::Call(CallOutcome::new(
InterpreterResult {
result: InstructionResult::OutOfGas,
output: Default::default(),
gas: Default::default(),
},
memory_offset: Default::default(),
})
Default::default()
))
),
Err(EVMError::Transaction(
OpTransactionError::HaltedDepositPostRegolith
Expand Down
8 changes: 4 additions & 4 deletions examples/cheatcode_inspector/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ impl JournalTr for Backend {
self.journaled_state.log(log)
}

fn logs(&self) -> &[Log] {
self.journaled_state.logs()
}

fn selfdestruct(
&mut self,
address: Address,
Expand Down Expand Up @@ -314,10 +318,6 @@ impl JournalTr for Backend {
}

impl JournalExt for Backend {
fn logs(&self) -> &[Log] {
self.journaled_state.logs()
}

fn journal(&self) -> &[JournalEntry] {
self.journaled_state.journal()
}
Expand Down
Loading
Loading