Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add essential EIP-7756 tracing fields #2023

Merged
merged 4 commits into from
Jan 27, 2025
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
24 changes: 18 additions & 6 deletions crates/bytecode/src/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,22 +142,34 @@ impl Bytecode {
}
}

/// Pointer to the executable bytecode.
///
/// Note: EOF will return the pointer to the start of the code section.
/// while legacy bytecode will point to the start of the bytes.
pub fn bytecode_ptr(&self) -> *const u8 {
self.bytecode().as_ptr()
}

/// Returns bytes.
#[inline]
pub fn bytes(&self) -> Bytes {
self.bytes_ref().clone()
}

/// Returns bytes.
#[inline]
pub fn bytes_ref(&self) -> &Bytes {
match self {
Self::LegacyAnalyzed(analyzed) => analyzed.bytecode().clone(),
_ => self.original_bytes(),
Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
Self::Eof(eof) => &eof.raw,
Self::Eip7702(code) => code.raw(),
}
}

/// Returns bytes slice.
#[inline]
pub fn bytes_slice(&self) -> &[u8] {
match self {
Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
_ => self.original_byte_slice(),
}
self.bytes_ref()
}

/// Returns a reference to the original bytecode.
Expand Down
1 change: 1 addition & 0 deletions crates/bytecode/src/eof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ impl Default for Eof {
code_section: vec![1],
// One code section with a STOP byte.
code: Bytes::from_static(&[0x00]),
code_offset: 0,
container_section: vec![],
data_section: Bytes::new(),
is_data_filled: true,
Expand Down
14 changes: 6 additions & 8 deletions crates/bytecode/src/eof/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub struct EofBody {
/// Index of the last byte of each code section
pub code_section: Vec<usize>,
pub code: Bytes,
pub code_offset: usize,
pub container_section: Vec<Bytes>,
pub data_section: Bytes,
pub is_data_filled: bool,
Expand All @@ -34,7 +35,6 @@ impl EofBody {

/// Creates an EOF container from this body.
pub fn into_eof(self) -> Eof {
// TODO : Add bounds checks.
let mut prev_value = 0;
let header = EofHeader {
types_size: self.types_section.len() as u16 * 4,
Expand All @@ -59,22 +59,19 @@ impl EofBody {
let mut buffer = Vec::new();
header.encode(&mut buffer);
self.encode(&mut buffer);
Eof {
header,
body: self,
raw: buffer.into(),
}
Eof::decode(buffer.into()).expect("Failed to encode EOF")
}

/// Returns offset of the start of indexed code section.
///
/// First code section starts at 0.
pub fn eof_code_section_start(&self, idx: usize) -> Option<usize> {
// Starting code section start with 0.
let code_offset = self.code_offset;
if idx == 0 {
return Some(0);
return Some(code_offset);
}
self.code_section.get(idx - 1).cloned()
self.code_section.get(idx - 1).map(|i| i + code_offset)
}

/// Encodes this body into the given buffer.
Expand Down Expand Up @@ -118,6 +115,7 @@ impl EofBody {

// Extract code section
let start = header_len + header.types_size as usize;
body.code_offset = start;
let mut code_end = 0;
for size in header.code_sizes.iter().map(|x| *x as usize) {
code_end += size;
Expand Down
1 change: 1 addition & 0 deletions crates/handler/src/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ where

// ExtDelegateCall is not allowed to call non-EOF contracts.
if is_ext_delegate_call && !bytecode.bytes_slice().starts_with(&EOF_MAGIC_BYTES) {
context.journal().checkpoint_revert(checkpoint);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was causing the depth field to read incorrectly when this case triggered. Not sure if here was any way to leverage it. Also, EOF only.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good find! Yeah it is good fix and it is EOF only

return return_result(InstructionResult::InvalidExtDelegateCallTarget);
}

Expand Down
29 changes: 26 additions & 3 deletions crates/inspector/src/eip3155.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::{inspectors::GasInspector, Inspector};
use revm::interpreter::interpreter_types::{RuntimeFlag, SubRoutineStack};
use revm::{
bytecode::opcode::OpCode,
context::Cfg,
Expand All @@ -20,7 +21,9 @@ pub struct TracerEip3155<CTX, INTR> {
/// Print summary of the execution.
print_summary: bool,
stack: Vec<U256>,
pc: usize,
pc: u64,
section: Option<u64>,
function_depth: Option<u64>,
opcode: u8,
gas: u64,
refunded: i64,
Expand All @@ -39,6 +42,9 @@ struct Output {
// Required fields:
/// Program counter
pc: u64,
/// EOF code section
#[serde(default, skip_serializing_if = "Option::is_none")]
section: Option<u64>,
/// OpCode
op: u8,
/// Gas left before executing this operation
Expand All @@ -49,6 +55,9 @@ struct Output {
stack: Vec<String>,
/// 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,
/// Amount of **global** gas refunded
Expand Down Expand Up @@ -140,6 +149,8 @@ where
stack: Default::default(),
memory: Default::default(),
pc: 0,
section: None,
function_depth: None,
opcode: 0,
gas: 0,
refunded: 0,
Expand Down Expand Up @@ -213,7 +224,17 @@ where
} else {
None
};
self.pc = interp.bytecode.pc();
self.pc = interp.bytecode.pc() as u64;
self.section = if interp.runtime_flag.is_eof() {
Some(interp.sub_routine.routine_idx() as u64)
} else {
None
};
self.function_depth = if interp.runtime_flag.is_eof() {
Some(interp.sub_routine.len() as u64 + 1)
} else {
None
};
self.opcode = interp.bytecode.opcode();
self.mem_size = interp.memory.size();
self.gas = interp.control.gas().remaining();
Expand All @@ -228,12 +249,14 @@ where
}

let value = Output {
pc: self.pc as u64,
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(),
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(),
Expand Down
13 changes: 8 additions & 5 deletions crates/interpreter/src/interpreter/ext_bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ impl Deref for ExtBytecode {
impl ExtBytecode {
/// Create new extended bytecode and set the instruction pointer to the start of the bytecode.
pub fn new(base: Bytecode) -> Self {
let instruction_pointer = base.bytecode().as_ptr();
let instruction_pointer = base.bytecode_ptr();
Self {
base,
instruction_pointer,
Expand All @@ -40,7 +40,7 @@ impl ExtBytecode {

/// Creates new `ExtBytecode` with the given hash.
pub fn new_with_hash(base: Bytecode, hash: B256) -> Self {
let instruction_pointer = base.bytecode().as_ptr();
let instruction_pointer = base.bytecode_ptr();
Self {
base,
instruction_pointer,
Expand All @@ -66,10 +66,12 @@ impl Jumps for ExtBytecode {
fn relative_jump(&mut self, offset: isize) {
self.instruction_pointer = unsafe { self.instruction_pointer.offset(offset) };
}

#[inline]
fn absolute_jump(&mut self, offset: usize) {
self.instruction_pointer = unsafe { self.base.bytecode().as_ptr().add(offset) };
self.instruction_pointer = unsafe { self.base.bytes_ref().as_ptr().add(offset) };
}

#[inline]
fn is_valid_legacy_jump(&mut self, offset: usize) -> bool {
self.base
Expand All @@ -83,13 +85,14 @@ impl Jumps for ExtBytecode {
// SAFETY: `instruction_pointer` always point to bytecode.
unsafe { *self.instruction_pointer }
}

#[inline]
fn pc(&self) -> usize {
// SAFETY: `instruction_pointer` should be at an offset from the start of the bytecode.
// SAFETY: `instruction_pointer` should be at an offset from the start of the bytes.
// In practice this is always true unless a caller modifies the `instruction_pointer` field manually.
unsafe {
self.instruction_pointer
.offset_from(self.base.bytecode().as_ptr()) as usize
.offset_from(self.base.bytes_ref().as_ptr()) as usize
}
}
}
Expand Down
Loading