From 4dea8c421e93b59ab5bf217f5cb4d76cf56bf7e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20=C5=BBuk?= Date: Mon, 23 Sep 2024 12:15:49 +0200 Subject: [PATCH] feat: Add creation code printing in traces (#202) --- src/tracing/writer.rs | 15 +++++++++++++++ tests/it/utils.rs | 18 ++++++++++++++---- tests/it/writer.rs | 20 ++++++++++++++++---- 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/src/tracing/writer.rs b/src/tracing/writer.rs index 5ae00fbb..acdb9202 100644 --- a/src/tracing/writer.rs +++ b/src/tracing/writer.rs @@ -30,6 +30,7 @@ pub struct TraceWriter { use_colors: bool, color_cheatcodes: bool, indentation_level: u16, + write_bytecodes: bool, } impl TraceWriter { @@ -41,6 +42,7 @@ impl TraceWriter { use_colors: use_colors(ColorChoice::global()), color_cheatcodes: false, indentation_level: 0, + write_bytecodes: false, } } @@ -65,6 +67,13 @@ impl TraceWriter { self } + /// Sets whether contract creation codes and deployed codes should be written. + #[inline] + pub fn write_bytecodes(mut self, yes: bool) -> Self { + self.write_bytecodes = yes; + self + } + /// Returns a reference to the inner writer. #[inline] pub const fn writer(&self) -> &W { @@ -175,6 +184,9 @@ impl TraceWriter { "{trace_kind_style}{CALL}new{trace_kind_style:#} {label}@{address}", label = trace.decoded.label.as_deref().unwrap_or("") )?; + if self.write_bytecodes { + write!(self.writer, "({})", hex::encode(&trace.data))?; + } } else { let (func_name, inputs) = match &trace.decoded.call_data { Some(DecodedCallData { signature, args }) => { @@ -332,6 +344,9 @@ impl TraceWriter { if trace.kind.is_any_create() && trace.status.is_ok() { write!(self.writer, "{} bytes of code", trace.output.len())?; + if self.write_bytecodes { + write!(self.writer, " ({})", hex::encode(&trace.output))?; + } } else if !trace.output.is_empty() { write!(self.writer, "{}", trace.output)?; } diff --git a/tests/it/utils.rs b/tests/it/utils.rs index 9a6c1b90..1cd2db8d 100644 --- a/tests/it/utils.rs +++ b/tests/it/utils.rs @@ -113,16 +113,26 @@ where } pub fn write_traces(tracer: &TracingInspector) -> String { - write_traces_with(tracer, ColorChoice::Never) + write_traces_with(tracer, ColorChoice::Never, false) } -pub fn write_traces_with(tracer: &TracingInspector, color: ColorChoice) -> String { - let mut w = revm_inspectors::tracing::TraceWriter::new(Vec::::new()).use_colors(color); +pub fn write_traces_with_bytecodes(tracer: &TracingInspector) -> String { + write_traces_with(tracer, ColorChoice::Never, true) +} + +pub fn write_traces_with( + tracer: &TracingInspector, + color: ColorChoice, + write_bytecodes: bool, +) -> String { + let mut w = revm_inspectors::tracing::TraceWriter::new(Vec::::new()) + .use_colors(color) + .write_bytecodes(write_bytecodes); w.write_arena(tracer.traces()).expect("failed to write traces to Vec"); String::from_utf8(w.into_writer()).expect("trace writer wrote invalid UTF-8") } pub fn print_traces(tracer: &TracingInspector) { // Use `println!` so that the output is captured by the test runner. - println!("{}", write_traces_with(tracer, ColorChoice::Auto)); + println!("{}", write_traces_with(tracer, ColorChoice::Auto, false)); } diff --git a/tests/it/writer.rs b/tests/it/writer.rs index 2b0859cd..08e0c990 100644 --- a/tests/it/writer.rs +++ b/tests/it/writer.rs @@ -1,5 +1,5 @@ -use crate::utils::{write_traces, TestEvm}; -use alloy_primitives::{address, b256, bytes, hex, Address, Bytes, B256, U256}; +use crate::utils::{write_traces, write_traces_with_bytecodes, TestEvm}; +use alloy_primitives::{address, b256, bytes, hex, Address, B256, U256}; use alloy_sol_types::{sol, SolCall}; use revm_inspectors::tracing::{ types::{DecodedCallData, DecodedInternalCall, DecodedTraceStep}, @@ -11,12 +11,13 @@ use snapbox::{assert_data_eq, data::Inline, str}; fn test_trace_printing() { // solc +0.8.26 testdata/Counter.sol --via-ir --optimize --bin sol!("testdata/Counter.sol"); - static BYTECODE: Bytes = bytes!("60808060405234601557610415908161001a8239f35b5f80fdfe6080806040526004361015610012575f80fd5b5f905f3560e01c9081630aa7318514610347575080633fb5c1cb14610326578063526f6fc5146102cb57806377fa5d9e1461026e5780638381f58a14610252578063943ee48c146101a85780639db265eb1461014e578063d09de08a146101325763f267ce9e14610081575f80fd5b346101245780600319360112610124576100996103ba565b303b1561012457604051639db265eb60e01b81528190818160048183305af180156101275761010f575b50607b90547f5ae719eb0250b8686767e291df04bec55e7f45a5997e120be020424da1896d766060604051602081526009602082015268343490333937b6901960b91b6040820152a380f35b8161011991610384565b61012457805f6100c3565b80fd5b6040513d84823e3d90fd5b503461012457806003193601126101245761014b6103ba565b80f35b503461012457806003193601126101245780547f9d39c21a43a4dfcd7857f27f3399f31a24694b6cb361496355ab537d16f745ca606060405160208152600960208201526868692066726f6d203360b81b6040820152a280f35b503461024e575f36600319011261024e575f547f9d39c21a43a4dfcd7857f27f3399f31a24694b6cb361496355ab537d16f745ca606060405160208152600960208201526868692066726f6d203160b81b6040820152a2303b1561024e57604051637933e74f60e11b81525f8160048183305af1801561024357610230575b5061014b6103ba565b61023c91505f90610384565b5f80610227565b6040513d5f823e3d90fd5b5f80fd5b3461024e575f36600319011261024e5760205f54604051908152f35b3461024e575f36600319011261024e57607b5f547f5ae719eb0250b8686767e291df04bec55e7f45a5997e120be020424da1896d76606060405160208152600c60208201526b343490333937b6903637b39960a11b6040820152a3005b3461024e575f36600319011261024e575f547f9d39c21a43a4dfcd7857f27f3399f31a24694b6cb361496355ab537d16f745ca606060405160208152600c60208201526b68692066726f6d206c6f673160a01b6040820152a2005b3461024e57602036600319011261024e576004355f55602060405160018152f35b3461024e575f36600319011261024e576080905f54815260406020820152600c60408201526b068692066726f6d206c6f67360a41b6060820152a0005b90601f8019910116810190811067ffffffffffffffff8211176103a657604052565b634e487b7160e01b5f52604160045260245ffd5b5f545f1981146103cb576001015f55565b634e487b7160e01b5f52601160045260245ffdfea2646970667358221220d26cb46e1b195f4ef2e419f8dc457a622eb5066ea0a97b4ab2619d684fe597f764736f6c634300081a0033"); + static CREATION_CODE: &str = "60808060405234601557610415908161001a8239f35b5f80fdfe6080806040526004361015610012575f80fd5b5f905f3560e01c9081630aa7318514610347575080633fb5c1cb14610326578063526f6fc5146102cb57806377fa5d9e1461026e5780638381f58a14610252578063943ee48c146101a85780639db265eb1461014e578063d09de08a146101325763f267ce9e14610081575f80fd5b346101245780600319360112610124576100996103ba565b303b1561012457604051639db265eb60e01b81528190818160048183305af180156101275761010f575b50607b90547f5ae719eb0250b8686767e291df04bec55e7f45a5997e120be020424da1896d766060604051602081526009602082015268343490333937b6901960b91b6040820152a380f35b8161011991610384565b61012457805f6100c3565b80fd5b6040513d84823e3d90fd5b503461012457806003193601126101245761014b6103ba565b80f35b503461012457806003193601126101245780547f9d39c21a43a4dfcd7857f27f3399f31a24694b6cb361496355ab537d16f745ca606060405160208152600960208201526868692066726f6d203360b81b6040820152a280f35b503461024e575f36600319011261024e575f547f9d39c21a43a4dfcd7857f27f3399f31a24694b6cb361496355ab537d16f745ca606060405160208152600960208201526868692066726f6d203160b81b6040820152a2303b1561024e57604051637933e74f60e11b81525f8160048183305af1801561024357610230575b5061014b6103ba565b61023c91505f90610384565b5f80610227565b6040513d5f823e3d90fd5b5f80fd5b3461024e575f36600319011261024e5760205f54604051908152f35b3461024e575f36600319011261024e57607b5f547f5ae719eb0250b8686767e291df04bec55e7f45a5997e120be020424da1896d76606060405160208152600c60208201526b343490333937b6903637b39960a11b6040820152a3005b3461024e575f36600319011261024e575f547f9d39c21a43a4dfcd7857f27f3399f31a24694b6cb361496355ab537d16f745ca606060405160208152600c60208201526b68692066726f6d206c6f673160a01b6040820152a2005b3461024e57602036600319011261024e576004355f55602060405160018152f35b3461024e575f36600319011261024e576080905f54815260406020820152600c60408201526b068692066726f6d206c6f67360a41b6060820152a0005b90601f8019910116810190811067ffffffffffffffff8211176103a657604052565b634e487b7160e01b5f52604160045260245ffd5b5f545f1981146103cb576001015f55565b634e487b7160e01b5f52601160045260245ffdfea2646970667358221220d26cb46e1b195f4ef2e419f8dc457a622eb5066ea0a97b4ab2619d684fe597f764736f6c634300081a0033"; + static DEPLOYED_CODE: &str = "6080806040526004361015610012575f80fd5b5f905f3560e01c9081630aa7318514610347575080633fb5c1cb14610326578063526f6fc5146102cb57806377fa5d9e1461026e5780638381f58a14610252578063943ee48c146101a85780639db265eb1461014e578063d09de08a146101325763f267ce9e14610081575f80fd5b346101245780600319360112610124576100996103ba565b303b1561012457604051639db265eb60e01b81528190818160048183305af180156101275761010f575b50607b90547f5ae719eb0250b8686767e291df04bec55e7f45a5997e120be020424da1896d766060604051602081526009602082015268343490333937b6901960b91b6040820152a380f35b8161011991610384565b61012457805f6100c3565b80fd5b6040513d84823e3d90fd5b503461012457806003193601126101245761014b6103ba565b80f35b503461012457806003193601126101245780547f9d39c21a43a4dfcd7857f27f3399f31a24694b6cb361496355ab537d16f745ca606060405160208152600960208201526868692066726f6d203360b81b6040820152a280f35b503461024e575f36600319011261024e575f547f9d39c21a43a4dfcd7857f27f3399f31a24694b6cb361496355ab537d16f745ca606060405160208152600960208201526868692066726f6d203160b81b6040820152a2303b1561024e57604051637933e74f60e11b81525f8160048183305af1801561024357610230575b5061014b6103ba565b61023c91505f90610384565b5f80610227565b6040513d5f823e3d90fd5b5f80fd5b3461024e575f36600319011261024e5760205f54604051908152f35b3461024e575f36600319011261024e57607b5f547f5ae719eb0250b8686767e291df04bec55e7f45a5997e120be020424da1896d76606060405160208152600c60208201526b343490333937b6903637b39960a11b6040820152a3005b3461024e575f36600319011261024e575f547f9d39c21a43a4dfcd7857f27f3399f31a24694b6cb361496355ab537d16f745ca606060405160208152600c60208201526b68692066726f6d206c6f673160a01b6040820152a2005b3461024e57602036600319011261024e576004355f55602060405160018152f35b3461024e575f36600319011261024e576080905f54815260406020820152600c60408201526b068692066726f6d206c6f67360a41b6060820152a0005b90601f8019910116810190811067ffffffffffffffff8211176103a657604052565b634e487b7160e01b5f52604160045260245ffd5b5f545f1981146103cb576001015f55565b634e487b7160e01b5f52601160045260245ffdfea2646970667358221220d26cb46e1b195f4ef2e419f8dc457a622eb5066ea0a97b4ab2619d684fe597f764736f6c634300081a0033"; let mut evm = TestEvm::new(); let mut tracer = TracingInspector::new(TracingInspectorConfig::all().disable_steps()); - let address = evm.deploy(BYTECODE.clone(), &mut tracer).unwrap(); + let address = evm.deploy(CREATION_CODE.parse().unwrap(), &mut tracer).unwrap(); let s = write_traces(&tracer); assert_data_eq!( @@ -28,6 +29,17 @@ fn test_trace_printing() { "#]] ); + let s = write_traces_with_bytecodes(&tracer); + let raw = r#" + [209257] → new @0xBd770416a3345F91E4B34576cb804a576fa48EB1() + └─ ← [Return] 1045 bytes of code () +"# + .strip_prefix("\n") + .unwrap() + .replace("", CREATION_CODE) + .replace("", DEPLOYED_CODE); + assert_data_eq!(s, raw); + let mut index = 0; let mut call = |data: Vec, raw: Inline, decoded: Inline| {