From b1ec4eb7252e4b50be791c9ae64a445d011a60a6 Mon Sep 17 00:00:00 2001 From: Pana Date: Sun, 31 Mar 2024 18:52:35 +0800 Subject: [PATCH] fix(TracerEip3155): clear Inspector data after transaction. (#1230) * fix examples->generate_block_traces reuse TracerEip3155.gas_inspector issue * fmt code * clear the eip3155 tracer state so that it can be used in next transaction * print summary and clean state when create_end * update documentation * fix left nits --- crates/revm/src/inspector/eip3155.rs | 85 ++++++++++++++++--- crates/revm/src/inspector/handler_register.rs | 2 +- .../src/crates/interpreter/instructions.md | 4 +- documentation/src/crates/revm.md | 4 +- examples/generate_block_traces.rs | 5 +- 5 files changed, 82 insertions(+), 18 deletions(-) diff --git a/crates/revm/src/inspector/eip3155.rs b/crates/revm/src/inspector/eip3155.rs index 0a7f62ec0d..ca1f6cc574 100644 --- a/crates/revm/src/inspector/eip3155.rs +++ b/crates/revm/src/inspector/eip3155.rs @@ -1,6 +1,9 @@ use crate::{ inspectors::GasInspector, - interpreter::{opcode, CallInputs, CallOutcome, Interpreter}, + interpreter::{ + opcode, CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter, + InterpreterResult, + }, primitives::{db::Database, hex, HashMap, B256, U256}, EvmContext, Inspector, }; @@ -97,6 +100,30 @@ impl TracerEip3155 { pub fn set_writer(&mut self, writer: Box) { self.output = writer; } + + /// Resets the Tracer to its initial state of [Self::new]. + /// This makes the inspector ready to be used again. + pub fn clear(&mut self) { + let Self { + gas_inspector, + stack, + pc, + opcode, + gas, + refunded, + mem_size, + skip, + .. + } = self; + *gas_inspector = GasInspector::default(); + stack.clear(); + *pc = 0; + *opcode = 0; + *gas = 0; + *refunded = 0; + *mem_size = 0; + *skip = false; + } } impl TracerEip3155 { @@ -134,6 +161,28 @@ impl TracerEip3155 { self.output.write_all(b"\n")?; self.output.flush() } + + fn print_summary( + &mut self, + result: &InterpreterResult, + context: &mut EvmContext, + ) { + if self.print_summary { + let spec_name: &str = context.spec_id().into(); + let value = Summary { + state_root: B256::ZERO.to_string(), + output: result.output.to_string(), + gas_used: hex_number( + context.inner.env().tx.gas_limit - self.gas_inspector.gas_remaining(), + ), + pass: result.is_ok(), + + time: None, + fork: Some(spec_name.to_string()), + }; + let _ = self.write_value(&value); + } + } } impl Inspector for TracerEip3155 { @@ -194,19 +243,31 @@ impl Inspector for TracerEip3155 { outcome: CallOutcome, ) -> CallOutcome { let outcome = self.gas_inspector.call_end(context, inputs, outcome); - if self.print_summary && context.journaled_state.depth() == 0 { - let spec_name: &str = context.spec_id().into(); - let value = Summary { - state_root: B256::ZERO.to_string(), - output: outcome.result.output.to_string(), - gas_used: hex_number(inputs.gas_limit - self.gas_inspector.gas_remaining()), - pass: outcome.result.is_ok(), - time: None, - fork: Some(spec_name.to_string()), - }; - let _ = self.write_value(&value); + if context.journaled_state.depth() == 0 { + self.print_summary(&outcome.result, context); + // clear the state if we are at the top level + self.clear(); + } + + outcome + } + + fn create_end( + &mut self, + context: &mut EvmContext, + inputs: &CreateInputs, + outcome: CreateOutcome, + ) -> CreateOutcome { + let outcome = self.gas_inspector.create_end(context, inputs, outcome); + + if context.journaled_state.depth() == 0 { + self.print_summary(&outcome.result, context); + + // clear the state if we are at the top level + self.clear(); } + outcome } } diff --git a/crates/revm/src/inspector/handler_register.rs b/crates/revm/src/inspector/handler_register.rs index 0598c4f829..ba5fb8e117 100644 --- a/crates/revm/src/inspector/handler_register.rs +++ b/crates/revm/src/inspector/handler_register.rs @@ -133,7 +133,7 @@ pub fn inspector_handle_register<'a, DB: Database, EXT: GetInspector>( let call_input_stack = Rc::>>::new(RefCell::new(Vec::new())); let create_input_stack = Rc::>>::new(RefCell::new(Vec::new())); - // Create handle + // Create handler let create_input_stack_inner = create_input_stack.clone(); let old_handle = handler.execution.create.clone(); handler.execution.create = Arc::new( diff --git a/documentation/src/crates/interpreter/instructions.md b/documentation/src/crates/interpreter/instructions.md index 7835718131..84b5b8a857 100644 --- a/documentation/src/crates/interpreter/instructions.md +++ b/documentation/src/crates/interpreter/instructions.md @@ -10,6 +10,6 @@ The `Opcode` enum represents the opcodes that are available in the Ethereum Virt The `Instruction` struct represents a single instruction in the EVM. It contains the opcode, which is the operation to be performed, and a list of bytes representing the operands for the instruction. -## `execute` Function +## `step` Function -The `execute` function interprets an instruction. It uses the opcode to determine what operation to perform and then performs the operation using the operands in the instruction. \ No newline at end of file +The `step` function interprets an instruction. It uses the opcode to determine what operation to perform and then performs the operation using the operands in the instruction. \ No newline at end of file diff --git a/documentation/src/crates/revm.md b/documentation/src/crates/revm.md index ed17b8d7d5..2ad609f40a 100644 --- a/documentation/src/crates/revm.md +++ b/documentation/src/crates/revm.md @@ -4,7 +4,7 @@ The `evm` crate is focused on the implementation of Ethereum Virtual Machine (EV This crate pulls Primitives, Interpreter and Precompiles together to deliver the rust evm. The starting point for reading the documentation is [`Evm`](./revm/evm.md), that is main structure of EVM. -Then, I read about the [`EvmBuilder`](./revm/builder.md) that is used to create the `Evm` and modify it. +Then, you can read about the [`EvmBuilder`](./revm/builder.md) that is used to create the `Evm` and modify it. After, you can read about the [`Handler`](./revm/handler.md) that is used to modify the logic of the Evm, and it will tie with how Evm introspection can be done. Finally, you can read about the [`Inspector`](./revm/inspector.md), a legacy interface for inspecting execution that is now repurposed as a handler register example. @@ -34,6 +34,6 @@ Finally, you can read about the [`Inspector`](./revm/inspector.md), a legacy int - `Database`, `DatabaseCommit`, `InMemoryDB`: These types from the `db` module are re-exported for handling the database operations. - `EVM`: The `EVM` struct from the `evm` module is re-exported, serving as the main interface to the EVM implementation. -- `EvmContext`: The `EvmContext` struct from the `evm_impl` module is re-exported, providing data structures to encapsulate EVM execution data. +- `EvmContext`: The `EvmContext` struct from the `context` module is re-exported, providing data structures to encapsulate EVM execution data. - `JournalEntry`, `JournaledState`: These types from the `journaled_state` module are re-exported, providing the journaling system for the EVM state. - `inspectors`, `Inspector`: The `Inspector` trait and its implementations from the `inspector` module are re-exported for observing the EVM execution. diff --git a/examples/generate_block_traces.rs b/examples/generate_block_traces.rs index 5270bb9abd..cfd8f030c1 100644 --- a/examples/generate_block_traces.rs +++ b/examples/generate_block_traces.rs @@ -13,6 +13,7 @@ use std::io::BufWriter; use std::io::Write; use std::sync::Arc; use std::sync::Mutex; +use std::time::Instant; macro_rules! local_fill { ($left:expr, $right:expr, $fun:expr) => { @@ -100,7 +101,7 @@ async fn main() -> anyhow::Result<()> { println!("Found {txs} transactions."); let console_bar = Arc::new(ProgressBar::new(txs as u64)); - let elapsed = std::time::Duration::ZERO; + let start = Instant::now(); // Create the traces directory if it doesn't exist std::fs::create_dir_all("traces").expect("Failed to create traces directory"); @@ -176,6 +177,8 @@ async fn main() -> anyhow::Result<()> { } console_bar.finish_with_message("Finished all transactions."); + + let elapsed = start.elapsed(); println!( "Finished execution. Total CPU time: {:.6}s", elapsed.as_secs_f64()