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
7 changes: 3 additions & 4 deletions bins/revme/src/cmd/statetest/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ pub fn execute_test_suite(

let timer = Instant::now();
let res = ctx.inspect_commit_previous(
TracerEip3155::new(Box::new(stderr())).without_summary(),
TracerEip3155::buffered(stderr()).without_summary(),
);
*elapsed.lock().unwrap() += timer.elapsed();

Expand Down Expand Up @@ -497,9 +497,8 @@ pub fn execute_test_suite(
.with_tx(&tx)
.with_cfg(&cfg);

let _ = ctx.inspect_commit_previous(
TracerEip3155::new(Box::new(stderr())).without_summary(),
);
let _ = ctx
.inspect_commit_previous(TracerEip3155::buffered(stderr()).without_summary());

println!("\nExecution result: {exec_result:#?}");
println!("\nExpected exception: {:?}", test.expect_exception);
Expand Down
139 changes: 74 additions & 65 deletions crates/inspector/src/eip3155.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub struct TracerEip3155<CTX, INTR> {
// The CUT MUST output a `json` object for EACH operation.
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct Output {
struct Output<'a> {
// Required fields:
/// Program counter
pc: u64,
Expand All @@ -48,22 +48,26 @@ struct Output {
/// OpCode
op: u8,
/// Gas left before executing this operation
gas: String,
#[serde(serialize_with = "serde_hex_u64")]
gas: u64,
/// Gas cost of this operation
gas_cost: String,
#[serde(serialize_with = "serde_hex_u64")]
gas_cost: u64,
/// Array of all values on the stack
stack: Vec<String>,
stack: &'a [U256],
/// Depth of the call stack
depth: u64,
/// Depth of the EOF function call stack
#[serde(default, skip_serializing_if = "Option::is_none")]
function_depth: Option<u64>,
/// Data returned by the function call
return_data: String,
return_data: &'static str,
/// Amount of **global** gas refunded
refund: String,
#[serde(serialize_with = "serde_hex_u64")]
refund: u64,
/// Size of memory array
mem_size: String,
#[serde(serialize_with = "serde_hex_u64")]
mem_size: u64,

// Optional fields:
/// Name of the operation
Expand Down Expand Up @@ -93,7 +97,8 @@ struct Summary {
/// Return values of the function
output: String,
/// All gas used by the transaction
gas_used: String,
#[serde(serialize_with = "serde_hex_u64")]
gas_used: u64,
/// Bool whether transaction was executed successfully
pass: bool,

Expand All @@ -111,35 +116,13 @@ where
CTX: CfgGetter + TransactionGetter,
INTR:,
{
/// Sets the writer to use for the output.
pub fn set_writer(&mut self, writer: Box<dyn Write>) {
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::new();
stack.clear();
*pc = 0;
*opcode = 0;
*gas = 0;
*refunded = 0;
*mem_size = 0;
*skip = false;
/// Creates a new EIP-3155 tracer with the given output writer, by first wrapping it in a
/// [`BufWriter`](std::io::BufWriter).
pub fn buffered(output: impl Write + 'static) -> Self {
Self::new(Box::new(std::io::BufWriter::new(output)))
}

/// Creates a new EIP-3155 tracer with the given output writer.
pub fn new(output: Box<dyn Write>) -> Self {
Self {
output,
Expand All @@ -160,6 +143,11 @@ where
}
}

/// Sets the writer to use for the output.
pub fn set_writer(&mut self, writer: Box<dyn Write>) {
self.output = writer;
}

/// Don't include a summary at the end of the trace
pub fn without_summary(mut self) -> Self {
self.print_summary = false;
Expand All @@ -172,10 +160,29 @@ where
self
}

fn write_value(&mut self, value: &impl serde::Serialize) -> std::io::Result<()> {
serde_json::to_writer(&mut *self.output, value)?;
self.output.write_all(b"\n")?;
self.output.flush()
/// 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::new();
stack.clear();
*pc = 0;
*opcode = 0;
*gas = 0;
*refunded = 0;
*mem_size = 0;
*skip = false;
}

fn print_summary(&mut self, result: &InterpreterResult, context: &mut CTX) {
Expand All @@ -185,23 +192,27 @@ where
let value = Summary {
state_root: B256::ZERO.to_string(),
output: result.output.to_string(),
gas_used: hex_number(gas_limit - self.gas_inspector.gas_remaining()),
gas_used: gas_limit - self.gas_inspector.gas_remaining(),
pass: result.is_ok(),
time: None,
fork: Some(spec.to_string()),
};
let _ = self.write_value(&value);
}
}

fn write_value(&mut self, value: &impl serde::Serialize) -> std::io::Result<()> {
write_value(&mut *self.output, value)
}
}

pub trait CloneStack {
fn clone_from(&self) -> Vec<U256>;
fn clone_into(&self, stack: &mut Vec<U256>);
}

impl CloneStack for Stack {
fn clone_from(&self) -> Vec<U256> {
self.data().to_vec()
fn clone_into(&self, stack: &mut Vec<U256>) {
stack.extend_from_slice(self.data());
}
}

Expand All @@ -216,10 +227,11 @@ where

fn step(&mut self, interp: &mut Interpreter<INTR>, _: &mut CTX) {
self.gas_inspector.step(interp.control.gas());
self.stack = interp.stack.clone_from();
self.stack.clear();
interp.stack.clone_into(&mut self.stack);
self.memory = if self.include_memory {
Some(hex::encode_prefixed(
interp.memory.slice(0..usize::MAX).as_ref(),
interp.memory.slice(0..interp.memory.size()).as_ref(),
))
} else {
None
Expand Down Expand Up @@ -252,14 +264,14 @@ where
pc: self.pc,
section: self.section,
op: self.opcode,
gas: hex_number(self.gas),
gas_cost: hex_number(self.gas_inspector.last_gas_cost()),
stack: self.stack.iter().map(hex_number_u256).collect(),
gas: self.gas,
gas_cost: self.gas_inspector.last_gas_cost(),
stack: &self.stack,
depth: context.journal().depth() as u64,
function_depth: self.function_depth,
return_data: "0x".to_string(),
refund: hex_number(self.refunded as u64),
mem_size: self.mem_size.to_string(),
return_data: "0x",
refund: self.refunded as u64,
mem_size: self.mem_size as u64,

op_name: OpCode::new(self.opcode).map(|i| i.as_str()),
error: if !interp.control.instruction_result().is_ok() {
Expand All @@ -271,15 +283,15 @@ where
storage: None,
return_stack: None,
};
let _ = self.write_value(&value);
let _ = write_value(&mut self.output, &value);
}

fn call_end(&mut self, context: &mut CTX, _: &CallInputs, outcome: &mut CallOutcome) {
self.gas_inspector.call_end(outcome);

if context.journal().depth() == 0 {
self.print_summary(&outcome.result, context);
// Clear the state if we are at the top level
// Clear the state if we are at the top level.
self.clear();
}
}
Expand All @@ -289,23 +301,20 @@ where

if context.journal().depth() == 0 {
self.print_summary(&outcome.result, context);

// Clear the state if we are at the top level
// Clear the state if we are at the top level.
self.clear();
}
}
}

fn hex_number(uint: u64) -> String {
format!("0x{uint:x}")
fn write_value(
output: &mut dyn std::io::Write,
value: &impl serde::Serialize,
) -> std::io::Result<()> {
serde_json::to_writer(&mut *output, value)?;
output.write_all(b"\n")
}

fn hex_number_u256(b: &U256) -> String {
let s = hex::encode(b.to_be_bytes::<32>());
let s = s.trim_start_matches('0');
if s.is_empty() {
"0x0".to_string()
} else {
format!("0x{s}")
}
fn serde_hex_u64<S: serde::Serializer>(n: &u64, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&format!("{:#x}", *n))
}
Loading