From 6f3d9f89d538896498274e1fb44ffb42f189922a Mon Sep 17 00:00:00 2001 From: Varun Doshi <61531351+varun-doshi@users.noreply.github.com> Date: Wed, 1 Jan 2025 02:12:32 +0530 Subject: [PATCH] feat: Split inspector.rs (#1958) * split inspector * fixed errors * fmt * fixed failing test * fmt * clippy fix * fmt --- bins/revme/src/cmd/evmrunner.rs | 5 +- bins/revme/src/cmd/statetest/runner.rs | 5 +- crates/inspector/src/inspector.rs | 460 +----------------- crates/inspector/src/inspector_context.rs | 297 +++++++++++ crates/inspector/src/inspector_instruction.rs | 136 ++++++ crates/inspector/src/journal.rs | 40 ++ crates/inspector/src/lib.rs | 3 + crates/optimism/src/evm.rs | 2 +- examples/block_traces/src/main.rs | 5 +- 9 files changed, 501 insertions(+), 452 deletions(-) create mode 100644 crates/inspector/src/inspector_context.rs create mode 100644 crates/inspector/src/inspector_instruction.rs create mode 100644 crates/inspector/src/journal.rs diff --git a/bins/revme/src/cmd/evmrunner.rs b/bins/revme/src/cmd/evmrunner.rs index cb7d776e8a..da4db08a61 100644 --- a/bins/revme/src/cmd/evmrunner.rs +++ b/bins/revme/src/cmd/evmrunner.rs @@ -1,6 +1,9 @@ use clap::Parser; use database::BenchmarkDB; -use inspector::{inspector_handler, inspectors::TracerEip3155, InspectorContext, InspectorMainEvm}; +use inspector::{ + inspector_context::InspectorContext, inspector_handler, inspectors::TracerEip3155, + InspectorMainEvm, +}; use revm::{ bytecode::{Bytecode, BytecodeDecodeError}, handler::EthHandler, diff --git a/bins/revme/src/cmd/statetest/runner.rs b/bins/revme/src/cmd/statetest/runner.rs index 656fb8e9d8..9c14a3a1aa 100644 --- a/bins/revme/src/cmd/statetest/runner.rs +++ b/bins/revme/src/cmd/statetest/runner.rs @@ -4,7 +4,10 @@ use super::{ }; use database::State; use indicatif::{ProgressBar, ProgressDrawTarget}; -use inspector::{inspector_handler, inspectors::TracerEip3155, InspectorContext, InspectorMainEvm}; +use inspector::{ + inspector_context::InspectorContext, inspector_handler, inspectors::TracerEip3155, + InspectorMainEvm, +}; use revm::{ bytecode::Bytecode, context::{block::BlockEnv, cfg::CfgEnv, tx::TxEnv}, diff --git a/crates/inspector/src/inspector.rs b/crates/inspector/src/inspector.rs index 7b7833789d..a9182b536d 100644 --- a/crates/inspector/src/inspector.rs +++ b/crates/inspector/src/inspector.rs @@ -1,14 +1,13 @@ +use crate::{ + inspector_context::InspectorContext, + inspector_instruction::InspectorInstructionProvider, + journal::{JournalExt, JournalExtGetter}, +}; use auto_impl::auto_impl; -use core::mem::MaybeUninit; use revm::{ - bytecode::opcode::OpCode, - context::JournaledState, context_interface::{ - block::BlockSetter, - journaled_state::{AccountLoad, Eip7702CodeLoad}, - transaction::TransactionSetter, - BlockGetter, CfgGetter, DatabaseGetter, ErrorGetter, Journal, JournalDBError, - JournalGetter, TransactionGetter, + BlockGetter, CfgGetter, ErrorGetter, Journal, JournalDBError, JournalGetter, + TransactionGetter, }, database_interface::{Database, EmptyDB}, handler::{ @@ -17,20 +16,16 @@ use revm::{ }, handler_interface::{Frame, FrameOrResultGen, PrecompileProvider}, interpreter::{ - instructions::host::{log, selfdestruct}, - interpreter::{EthInterpreter, InstructionProvider}, + interpreter::EthInterpreter, interpreter_types::{Jumps, LoopControl}, - table::{self, CustomInstruction}, + table::CustomInstruction, CallInputs, CallOutcome, CreateInputs, CreateOutcome, EOFCreateInputs, FrameInput, Host, - Instruction, InstructionResult, Interpreter, InterpreterTypes, SStoreResult, - SelfDestructResult, StateLoad, + Instruction, InstructionResult, Interpreter, InterpreterTypes, }, precompile::PrecompileErrors, - primitives::{Address, Bytes, Log, B256, U256}, - state::EvmState, - Context, Error, Evm, JournalEntry, + primitives::{Address, Log, U256}, + Context, Error, Evm, }; -use std::{rc::Rc, vec::Vec}; /// EVM [Interpreter] callbacks. #[auto_impl(&mut, Box)] @@ -186,285 +181,6 @@ impl> GetInspector -where - CTX: DatabaseGetter, -{ - pub inspector: INSP, - pub inner: CTX, - pub frame_input_stack: Vec, -} - -impl InspectorContext -where - CTX: BlockGetter - + TransactionGetter - + CfgGetter - + DatabaseGetter - + JournalGetter - + ErrorGetter - + Host - + ErrorGetter, -{ - pub fn new(inner: CTX, inspector: INSP) -> Self { - Self { - inner, - inspector, - frame_input_stack: Vec::new(), - } - } -} - -impl, DB, CTX> Host for InspectorContext -where - CTX: Host + DatabaseGetter, -{ - fn block_hash(&mut self, requested_number: u64) -> Option { - self.inner.block_hash(requested_number) - } - - fn load_account_delegated(&mut self, address: Address) -> Option { - self.inner.load_account_delegated(address) - } - - fn balance(&mut self, address: Address) -> Option> { - self.inner.balance(address) - } - - fn code(&mut self, address: Address) -> Option> { - self.inner.code(address) - } - - fn code_hash(&mut self, address: Address) -> Option> { - self.inner.code_hash(address) - } - - fn sload(&mut self, address: Address, index: U256) -> Option> { - self.inner.sload(address, index) - } - - fn sstore( - &mut self, - address: Address, - index: U256, - value: U256, - ) -> Option> { - self.inner.sstore(address, index, value) - } - - fn tload(&mut self, address: Address, index: U256) -> U256 { - self.inner.tload(address, index) - } - - fn tstore(&mut self, address: Address, index: U256, value: U256) { - self.inner.tstore(address, index, value) - } - - fn log(&mut self, log: Log) { - self.inner.log(log); - } - - fn selfdestruct( - &mut self, - address: Address, - target: Address, - ) -> Option> { - self.inner.selfdestruct(address, target) - } -} - -impl InspectorCtx for InspectorContext -where - INSP: GetInspector, - CTX: DatabaseGetter, -{ - type IT = EthInterpreter<()>; - - fn step(&mut self, interp: &mut Interpreter) { - self.inspector.get_inspector().step(interp, &mut self.inner); - } - - fn step_end(&mut self, interp: &mut Interpreter) { - self.inspector - .get_inspector() - .step_end(interp, &mut self.inner); - } - - fn initialize_interp(&mut self, interp: &mut Interpreter) { - self.inspector - .get_inspector() - .initialize_interp(interp, &mut self.inner); - } - fn inspector_log(&mut self, interp: &mut Interpreter, log: &Log) { - self.inspector - .get_inspector() - .log(interp, &mut self.inner, log); - } - - fn frame_start(&mut self, frame_input: &mut FrameInput) -> Option { - let insp = self.inspector.get_inspector(); - let context = &mut self.inner; - match frame_input { - FrameInput::Call(i) => { - if let Some(output) = insp.call(context, i) { - return Some(FrameResult::Call(output)); - } - } - FrameInput::Create(i) => { - if let Some(output) = insp.create(context, i) { - return Some(FrameResult::Create(output)); - } - } - FrameInput::EOFCreate(i) => { - if let Some(output) = insp.eofcreate(context, i) { - return Some(FrameResult::EOFCreate(output)); - } - } - } - self.frame_input_stack.push(frame_input.clone()); - None - } - - fn frame_end(&mut self, frame_output: &mut FrameResult) { - let insp = self.inspector.get_inspector(); - let context = &mut self.inner; - let frame_input = self.frame_input_stack.pop().expect("Frame pushed"); - match frame_output { - FrameResult::Call(outcome) => { - let FrameInput::Call(i) = frame_input else { - panic!("FrameInput::Call expected"); - }; - insp.call_end(context, &i, outcome); - } - FrameResult::Create(outcome) => { - let FrameInput::Create(i) = frame_input else { - panic!("FrameInput::Create expected"); - }; - insp.create_end(context, &i, outcome); - } - FrameResult::EOFCreate(outcome) => { - let FrameInput::EOFCreate(i) = frame_input else { - panic!("FrameInput::EofCreate expected"); - }; - insp.eofcreate_end(context, &i, outcome); - } - } - } - - fn inspector_selfdestruct(&mut self, contract: Address, target: Address, value: U256) { - self.inspector - .get_inspector() - .selfdestruct(contract, target, value) - } -} - -impl CfgGetter for InspectorContext -where - CTX: CfgGetter + DatabaseGetter, -{ - type Cfg = ::Cfg; - - fn cfg(&self) -> &Self::Cfg { - self.inner.cfg() - } -} - -impl JournalGetter for InspectorContext -where - CTX: JournalGetter + DatabaseGetter, - DB: Database, -{ - type Journal = ::Journal; - - fn journal(&mut self) -> &mut Self::Journal { - self.inner.journal() - } - - fn journal_ref(&self) -> &Self::Journal { - self.inner.journal_ref() - } -} - -impl DatabaseGetter for InspectorContext -where - CTX: DatabaseGetter, - DB: Database, -{ - type Database = ::Database; - - fn db(&mut self) -> &mut Self::Database { - self.inner.db() - } - - fn db_ref(&self) -> &Self::Database { - self.inner.db_ref() - } -} - -impl ErrorGetter for InspectorContext -where - CTX: ErrorGetter + DatabaseGetter, -{ - type Error = ::Error; - - fn take_error(&mut self) -> Result<(), Self::Error> { - self.inner.take_error() - } -} - -impl TransactionGetter for InspectorContext -where - CTX: TransactionGetter + DatabaseGetter, -{ - type Transaction = ::Transaction; - - fn tx(&self) -> &Self::Transaction { - self.inner.tx() - } -} - -impl TransactionSetter for InspectorContext -where - CTX: TransactionSetter + DatabaseGetter, -{ - fn set_tx(&mut self, tx: ::Transaction) { - self.inner.set_tx(tx); - } -} - -impl BlockGetter for InspectorContext -where - CTX: BlockGetter + DatabaseGetter, -{ - type Block = ::Block; - - fn block(&self) -> &Self::Block { - self.inner.block() - } -} - -impl BlockSetter for InspectorContext -where - CTX: BlockSetter + DatabaseGetter, -{ - fn set_block(&mut self, block: ::Block) { - self.inner.set_block(block); - } -} - -impl JournalExtGetter for InspectorContext -where - CTX: JournalExtGetter + DatabaseGetter, -{ - type JournalExt = ::JournalExt; - - fn journal_ext(&self) -> &Self::JournalExt { - self.inner.journal_ext() - } -} - impl + JournalExt, CHAIN> JournalExtGetter for Context { @@ -513,158 +229,6 @@ where } } -pub struct InspectorInstructionProvider { - instruction_table: Rc<[InspectorInstruction; 256]>, -} - -impl Clone for InspectorInstructionProvider -where - WIRE: InterpreterTypes, -{ - fn clone(&self) -> Self { - Self { - instruction_table: self.instruction_table.clone(), - } - } -} - -pub trait JournalExt { - fn logs(&self) -> &[Log]; - - fn last_journal(&self) -> &[JournalEntry]; - - fn evm_state(&self) -> &EvmState; - - fn evm_state_mut(&mut self) -> &mut EvmState; -} - -impl JournalExt for JournaledState { - fn logs(&self) -> &[Log] { - &self.logs - } - - fn last_journal(&self) -> &[JournalEntry] { - self.journal.last().expect("Journal is never empty") - } - - fn evm_state(&self) -> &EvmState { - &self.state - } - - fn evm_state_mut(&mut self) -> &mut EvmState { - &mut self.state - } -} - -#[auto_impl(&, &mut, Box, Arc)] -pub trait JournalExtGetter { - type JournalExt: JournalExt; - - fn journal_ext(&self) -> &Self::JournalExt; -} - -impl InstructionProvider for InspectorInstructionProvider -where - WIRE: InterpreterTypes, - HOST: Host + JournalExtGetter + JournalGetter + InspectorCtx, -{ - type WIRE = WIRE; - type Host = HOST; - - fn new(_context: &mut Self::Host) -> Self { - let main_table = table::make_instruction_table::(); - let mut table: [MaybeUninit>; 256] = - unsafe { MaybeUninit::uninit().assume_init() }; - - for (i, element) in table.iter_mut().enumerate() { - let function = InspectorInstruction { - instruction: main_table[i], - }; - *element = MaybeUninit::new(function); - } - - let mut table = unsafe { - core::mem::transmute::< - [MaybeUninit>; 256], - [InspectorInstruction; 256], - >(table) - }; - - // Inspector log wrapper - fn inspector_log( - interpreter: &mut Interpreter<::IT>, - context: &mut CTX, - prev: Instruction<::IT, CTX>, - ) { - prev(interpreter, context); - - if interpreter.control.instruction_result() == InstructionResult::Continue { - let last_log = context.journal_ext().logs().last().unwrap().clone(); - context.inspector_log(interpreter, &last_log); - } - } - - /* LOG and Selfdestruct instructions */ - table[OpCode::LOG0.as_usize()] = InspectorInstruction { - instruction: |interp, context| { - inspector_log(interp, context, log::<0, HOST>); - }, - }; - table[OpCode::LOG1.as_usize()] = InspectorInstruction { - instruction: |interp, context| { - inspector_log(interp, context, log::<1, HOST>); - }, - }; - table[OpCode::LOG2.as_usize()] = InspectorInstruction { - instruction: |interp, context| { - inspector_log(interp, context, log::<2, HOST>); - }, - }; - table[OpCode::LOG3.as_usize()] = InspectorInstruction { - instruction: |interp, context| { - inspector_log(interp, context, log::<3, HOST>); - }, - }; - table[OpCode::LOG4.as_usize()] = InspectorInstruction { - instruction: |interp, context| { - inspector_log(interp, context, log::<4, HOST>); - }, - }; - - table[OpCode::SELFDESTRUCT.as_usize()] = InspectorInstruction { - instruction: |interp, context| { - selfdestruct::(interp, context); - if interp.control.instruction_result() == InstructionResult::SelfDestruct { - match context.journal_ext().last_journal().last() { - Some(JournalEntry::AccountDestroyed { - address, - target, - had_balance, - .. - }) => { - context.inspector_selfdestruct(*address, *target, *had_balance); - } - Some(JournalEntry::BalanceTransfer { - from, to, balance, .. - }) => { - context.inspector_selfdestruct(*from, *to, *balance); - } - _ => {} - } - } - }, - }; - - Self { - instruction_table: Rc::new(table), - } - } - - fn table(&mut self) -> &[impl CustomInstruction; 256] { - self.instruction_table.as_ref() - } -} - pub struct InspectorEthFrame where CTX: Host, diff --git a/crates/inspector/src/inspector_context.rs b/crates/inspector/src/inspector_context.rs new file mode 100644 index 0000000000..66f1fa1d7b --- /dev/null +++ b/crates/inspector/src/inspector_context.rs @@ -0,0 +1,297 @@ +use revm::{ + context_interface::{ + block::BlockSetter, + journaled_state::{AccountLoad, Eip7702CodeLoad}, + transaction::TransactionSetter, + BlockGetter, CfgGetter, DatabaseGetter, ErrorGetter, JournalGetter, TransactionGetter, + }, + database_interface::Database, + handler::FrameResult, + interpreter::{ + interpreter::EthInterpreter, FrameInput, Host, Interpreter, SStoreResult, + SelfDestructResult, StateLoad, + }, + primitives::{Address, Bytes, Log, B256, U256}, +}; +use std::vec::Vec; + +use crate::{journal::JournalExtGetter, GetInspector, Inspector, InspectorCtx}; + +/// EVM context contains data that EVM needs for execution. +#[derive(Clone, Debug)] +pub struct InspectorContext +where + CTX: DatabaseGetter, +{ + pub inspector: INSP, + pub inner: CTX, + pub frame_input_stack: Vec, +} + +impl InspectorContext +where + CTX: BlockGetter + + TransactionGetter + + CfgGetter + + DatabaseGetter + + JournalGetter + + ErrorGetter + + Host + + ErrorGetter, +{ + pub fn new(inner: CTX, inspector: INSP) -> Self { + Self { + inner, + inspector, + frame_input_stack: Vec::new(), + } + } +} + +impl, DB, CTX> Host for InspectorContext +where + CTX: Host + DatabaseGetter, +{ + fn block_hash(&mut self, requested_number: u64) -> Option { + self.inner.block_hash(requested_number) + } + + fn load_account_delegated(&mut self, address: Address) -> Option { + self.inner.load_account_delegated(address) + } + + fn balance(&mut self, address: Address) -> Option> { + self.inner.balance(address) + } + + fn code(&mut self, address: Address) -> Option> { + self.inner.code(address) + } + + fn code_hash(&mut self, address: Address) -> Option> { + self.inner.code_hash(address) + } + + fn sload(&mut self, address: Address, index: U256) -> Option> { + self.inner.sload(address, index) + } + + fn sstore( + &mut self, + address: Address, + index: U256, + value: U256, + ) -> Option> { + self.inner.sstore(address, index, value) + } + + fn tload(&mut self, address: Address, index: U256) -> U256 { + self.inner.tload(address, index) + } + + fn tstore(&mut self, address: Address, index: U256, value: U256) { + self.inner.tstore(address, index, value) + } + + fn log(&mut self, log: Log) { + self.inner.log(log); + } + + fn selfdestruct( + &mut self, + address: Address, + target: Address, + ) -> Option> { + self.inner.selfdestruct(address, target) + } +} + +impl InspectorCtx for InspectorContext +where + INSP: GetInspector, + CTX: DatabaseGetter, +{ + type IT = EthInterpreter<()>; + + fn step(&mut self, interp: &mut Interpreter) { + self.inspector.get_inspector().step(interp, &mut self.inner); + } + + fn step_end(&mut self, interp: &mut Interpreter) { + self.inspector + .get_inspector() + .step_end(interp, &mut self.inner); + } + + fn initialize_interp(&mut self, interp: &mut Interpreter) { + self.inspector + .get_inspector() + .initialize_interp(interp, &mut self.inner); + } + fn inspector_log(&mut self, interp: &mut Interpreter, log: &Log) { + self.inspector + .get_inspector() + .log(interp, &mut self.inner, log); + } + + fn frame_start(&mut self, frame_input: &mut FrameInput) -> Option { + let insp = self.inspector.get_inspector(); + let context = &mut self.inner; + match frame_input { + FrameInput::Call(i) => { + if let Some(output) = insp.call(context, i) { + return Some(FrameResult::Call(output)); + } + } + FrameInput::Create(i) => { + if let Some(output) = insp.create(context, i) { + return Some(FrameResult::Create(output)); + } + } + FrameInput::EOFCreate(i) => { + if let Some(output) = insp.eofcreate(context, i) { + return Some(FrameResult::EOFCreate(output)); + } + } + } + self.frame_input_stack.push(frame_input.clone()); + None + } + + fn frame_end(&mut self, frame_output: &mut FrameResult) { + let insp = self.inspector.get_inspector(); + let context = &mut self.inner; + let frame_input = self.frame_input_stack.pop().expect("Frame pushed"); + match frame_output { + FrameResult::Call(outcome) => { + let FrameInput::Call(i) = frame_input else { + panic!("FrameInput::Call expected"); + }; + insp.call_end(context, &i, outcome); + } + FrameResult::Create(outcome) => { + let FrameInput::Create(i) = frame_input else { + panic!("FrameInput::Create expected"); + }; + insp.create_end(context, &i, outcome); + } + FrameResult::EOFCreate(outcome) => { + let FrameInput::EOFCreate(i) = frame_input else { + panic!("FrameInput::EofCreate expected"); + }; + insp.eofcreate_end(context, &i, outcome); + } + } + } + + fn inspector_selfdestruct(&mut self, contract: Address, target: Address, value: U256) { + self.inspector + .get_inspector() + .selfdestruct(contract, target, value) + } +} + +impl CfgGetter for InspectorContext +where + CTX: CfgGetter + DatabaseGetter, +{ + type Cfg = ::Cfg; + + fn cfg(&self) -> &Self::Cfg { + self.inner.cfg() + } +} + +impl JournalGetter for InspectorContext +where + CTX: JournalGetter + DatabaseGetter, + DB: Database, +{ + type Journal = ::Journal; + + fn journal(&mut self) -> &mut Self::Journal { + self.inner.journal() + } + + fn journal_ref(&self) -> &Self::Journal { + self.inner.journal_ref() + } +} + +impl DatabaseGetter for InspectorContext +where + CTX: DatabaseGetter, + DB: Database, +{ + type Database = ::Database; + + fn db(&mut self) -> &mut Self::Database { + self.inner.db() + } + + fn db_ref(&self) -> &Self::Database { + self.inner.db_ref() + } +} + +impl ErrorGetter for InspectorContext +where + CTX: ErrorGetter + DatabaseGetter, +{ + type Error = ::Error; + + fn take_error(&mut self) -> Result<(), Self::Error> { + self.inner.take_error() + } +} + +impl TransactionGetter for InspectorContext +where + CTX: TransactionGetter + DatabaseGetter, +{ + type Transaction = ::Transaction; + + fn tx(&self) -> &Self::Transaction { + self.inner.tx() + } +} + +impl TransactionSetter for InspectorContext +where + CTX: TransactionSetter + DatabaseGetter, +{ + fn set_tx(&mut self, tx: ::Transaction) { + self.inner.set_tx(tx); + } +} + +impl BlockGetter for InspectorContext +where + CTX: BlockGetter + DatabaseGetter, +{ + type Block = ::Block; + + fn block(&self) -> &Self::Block { + self.inner.block() + } +} + +impl BlockSetter for InspectorContext +where + CTX: BlockSetter + DatabaseGetter, +{ + fn set_block(&mut self, block: ::Block) { + self.inner.set_block(block); + } +} + +impl JournalExtGetter for InspectorContext +where + CTX: JournalExtGetter + DatabaseGetter, +{ + type JournalExt = ::JournalExt; + + fn journal_ext(&self) -> &Self::JournalExt { + self.inner.journal_ext() + } +} diff --git a/crates/inspector/src/inspector_instruction.rs b/crates/inspector/src/inspector_instruction.rs new file mode 100644 index 0000000000..5a00ff3171 --- /dev/null +++ b/crates/inspector/src/inspector_instruction.rs @@ -0,0 +1,136 @@ +use core::mem::MaybeUninit; +use revm::{ + bytecode::opcode::OpCode, + context_interface::JournalGetter, + interpreter::{ + instructions::host::{log, selfdestruct}, + interpreter::InstructionProvider, + interpreter_types::LoopControl, + table::{self, CustomInstruction}, + Host, Instruction, InstructionResult, Interpreter, InterpreterTypes, + }, + JournalEntry, +}; +use std::rc::Rc; + +use crate::{ + journal::{JournalExt, JournalExtGetter}, + InspectorCtx, InspectorInstruction, +}; + +pub struct InspectorInstructionProvider { + instruction_table: Rc<[InspectorInstruction; 256]>, +} + +impl Clone for InspectorInstructionProvider +where + WIRE: InterpreterTypes, +{ + fn clone(&self) -> Self { + Self { + instruction_table: self.instruction_table.clone(), + } + } +} + +impl InstructionProvider for InspectorInstructionProvider +where + WIRE: InterpreterTypes, + HOST: Host + JournalExtGetter + JournalGetter + InspectorCtx, +{ + type WIRE = WIRE; + type Host = HOST; + + fn new(_context: &mut Self::Host) -> Self { + let main_table = table::make_instruction_table::(); + let mut table: [MaybeUninit>; 256] = + unsafe { MaybeUninit::uninit().assume_init() }; + + for (i, element) in table.iter_mut().enumerate() { + let function = InspectorInstruction { + instruction: main_table[i], + }; + *element = MaybeUninit::new(function); + } + + let mut table = unsafe { + core::mem::transmute::< + [MaybeUninit>; 256], + [InspectorInstruction; 256], + >(table) + }; + + // Inspector log wrapper + fn inspector_log( + interpreter: &mut Interpreter<::IT>, + context: &mut CTX, + prev: Instruction<::IT, CTX>, + ) { + prev(interpreter, context); + + if interpreter.control.instruction_result() == InstructionResult::Continue { + let last_log = context.journal_ext().logs().last().unwrap().clone(); + context.inspector_log(interpreter, &last_log); + } + } + + /* LOG and Selfdestruct instructions */ + table[OpCode::LOG0.as_usize()] = InspectorInstruction { + instruction: |interp, context| { + inspector_log(interp, context, log::<0, HOST>); + }, + }; + table[OpCode::LOG1.as_usize()] = InspectorInstruction { + instruction: |interp, context| { + inspector_log(interp, context, log::<1, HOST>); + }, + }; + table[OpCode::LOG2.as_usize()] = InspectorInstruction { + instruction: |interp, context| { + inspector_log(interp, context, log::<2, HOST>); + }, + }; + table[OpCode::LOG3.as_usize()] = InspectorInstruction { + instruction: |interp, context| { + inspector_log(interp, context, log::<3, HOST>); + }, + }; + table[OpCode::LOG4.as_usize()] = InspectorInstruction { + instruction: |interp, context| { + inspector_log(interp, context, log::<4, HOST>); + }, + }; + + table[OpCode::SELFDESTRUCT.as_usize()] = InspectorInstruction { + instruction: |interp, context| { + selfdestruct::(interp, context); + if interp.control.instruction_result() == InstructionResult::SelfDestruct { + match context.journal_ext().last_journal().last() { + Some(JournalEntry::AccountDestroyed { + address, + target, + had_balance, + .. + }) => { + context.inspector_selfdestruct(*address, *target, *had_balance); + } + Some(JournalEntry::BalanceTransfer { + from, to, balance, .. + }) => { + context.inspector_selfdestruct(*from, *to, *balance); + } + _ => {} + } + } + }, + }; + + Self { + instruction_table: Rc::new(table), + } + } + + fn table(&mut self) -> &[impl CustomInstruction; 256] { + self.instruction_table.as_ref() + } +} diff --git a/crates/inspector/src/journal.rs b/crates/inspector/src/journal.rs new file mode 100644 index 0000000000..f15e41a16c --- /dev/null +++ b/crates/inspector/src/journal.rs @@ -0,0 +1,40 @@ +use auto_impl::auto_impl; +use revm::{ + context::JournaledState, database_interface::Database, primitives::Log, state::EvmState, + JournalEntry, +}; + +pub trait JournalExt { + fn logs(&self) -> &[Log]; + + fn last_journal(&self) -> &[JournalEntry]; + + fn evm_state(&self) -> &EvmState; + + fn evm_state_mut(&mut self) -> &mut EvmState; +} + +impl JournalExt for JournaledState { + fn logs(&self) -> &[Log] { + &self.logs + } + + fn last_journal(&self) -> &[JournalEntry] { + self.journal.last().expect("Journal is never empty") + } + + fn evm_state(&self) -> &EvmState { + &self.state + } + + fn evm_state_mut(&mut self) -> &mut EvmState { + &mut self.state + } +} + +#[auto_impl(&, &mut, Box, Arc)] +pub trait JournalExtGetter { + type JournalExt: JournalExt; + + fn journal_ext(&self) -> &Self::JournalExt; +} diff --git a/crates/inspector/src/lib.rs b/crates/inspector/src/lib.rs index 66e6f7084a..d4a4896b4b 100644 --- a/crates/inspector/src/lib.rs +++ b/crates/inspector/src/lib.rs @@ -9,6 +9,9 @@ extern crate alloc as std; mod eip3155; mod gas; mod inspector; +pub mod inspector_context; +pub mod inspector_instruction; +pub mod journal; mod noop; pub use inspector::*; diff --git a/crates/optimism/src/evm.rs b/crates/optimism/src/evm.rs index 392986cffd..d1674a7806 100644 --- a/crates/optimism/src/evm.rs +++ b/crates/optimism/src/evm.rs @@ -4,7 +4,7 @@ use crate::{ }, L1BlockInfo, OpSpec, OpTransaction, }; -use inspector::{InspectorContext, InspectorEthFrame}; +use inspector::{inspector_context::InspectorContext, InspectorEthFrame}; use revm::{ context::{block::BlockEnv, tx::TxEnv, CfgEnv, Context}, context_interface::result::{EVMError, InvalidTransaction}, diff --git a/examples/block_traces/src/main.rs b/examples/block_traces/src/main.rs index d053aa58a2..81a8854c1f 100644 --- a/examples/block_traces/src/main.rs +++ b/examples/block_traces/src/main.rs @@ -9,7 +9,10 @@ use alloy_provider::{ }; use database::{AlloyDB, CacheDB, StateBuilder}; use indicatif::ProgressBar; -use inspector::{inspectors::TracerEip3155, InspectorContext, InspectorEthFrame, InspectorMainEvm}; +use inspector::{ + inspector_context::InspectorContext, inspectors::TracerEip3155, InspectorEthFrame, + InspectorMainEvm, +}; use revm::{ database_interface::WrapDatabaseAsync, handler::{