Skip to content

Commit 773b909

Browse files
shemnonrakita
andauthored
feat: Add essential EIP-7756 tracing fields (#2023)
* Add essential EIP-7756 tracing fields Add (for eof) section and funcion depth fields, and make pc container relative instead of code section relative. * rm trace_pc and move logic to pc fn * change start of PC to start of bytes * cleanup --------- Co-authored-by: rakita <rakita@users.noreply.github.com> Co-authored-by: rakita <dragan0rakita@gmail.com>
1 parent a8f9824 commit 773b909

File tree

6 files changed

+60
-22
lines changed

6 files changed

+60
-22
lines changed

crates/bytecode/src/bytecode.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -142,22 +142,34 @@ impl Bytecode {
142142
}
143143
}
144144

145+
/// Pointer to the executable bytecode.
146+
///
147+
/// Note: EOF will return the pointer to the start of the code section.
148+
/// while legacy bytecode will point to the start of the bytes.
149+
pub fn bytecode_ptr(&self) -> *const u8 {
150+
self.bytecode().as_ptr()
151+
}
152+
145153
/// Returns bytes.
146154
#[inline]
147155
pub fn bytes(&self) -> Bytes {
156+
self.bytes_ref().clone()
157+
}
158+
159+
/// Returns bytes.
160+
#[inline]
161+
pub fn bytes_ref(&self) -> &Bytes {
148162
match self {
149-
Self::LegacyAnalyzed(analyzed) => analyzed.bytecode().clone(),
150-
_ => self.original_bytes(),
163+
Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
164+
Self::Eof(eof) => &eof.raw,
165+
Self::Eip7702(code) => code.raw(),
151166
}
152167
}
153168

154169
/// Returns bytes slice.
155170
#[inline]
156171
pub fn bytes_slice(&self) -> &[u8] {
157-
match self {
158-
Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
159-
_ => self.original_byte_slice(),
160-
}
172+
self.bytes_ref()
161173
}
162174

163175
/// Returns a reference to the original bytecode.

crates/bytecode/src/eof.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ impl Default for Eof {
4343
code_section: vec![1],
4444
// One code section with a STOP byte.
4545
code: Bytes::from_static(&[0x00]),
46+
code_offset: 0,
4647
container_section: vec![],
4748
data_section: Bytes::new(),
4849
is_data_filled: true,

crates/bytecode/src/eof/body.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub struct EofBody {
1515
/// Index of the last byte of each code section
1616
pub code_section: Vec<usize>,
1717
pub code: Bytes,
18+
pub code_offset: usize,
1819
pub container_section: Vec<Bytes>,
1920
pub data_section: Bytes,
2021
pub is_data_filled: bool,
@@ -34,7 +35,6 @@ impl EofBody {
3435

3536
/// Creates an EOF container from this body.
3637
pub fn into_eof(self) -> Eof {
37-
// TODO : Add bounds checks.
3838
let mut prev_value = 0;
3939
let header = EofHeader {
4040
types_size: self.types_section.len() as u16 * 4,
@@ -59,22 +59,19 @@ impl EofBody {
5959
let mut buffer = Vec::new();
6060
header.encode(&mut buffer);
6161
self.encode(&mut buffer);
62-
Eof {
63-
header,
64-
body: self,
65-
raw: buffer.into(),
66-
}
62+
Eof::decode(buffer.into()).expect("Failed to encode EOF")
6763
}
6864

6965
/// Returns offset of the start of indexed code section.
7066
///
7167
/// First code section starts at 0.
7268
pub fn eof_code_section_start(&self, idx: usize) -> Option<usize> {
7369
// Starting code section start with 0.
70+
let code_offset = self.code_offset;
7471
if idx == 0 {
75-
return Some(0);
72+
return Some(code_offset);
7673
}
77-
self.code_section.get(idx - 1).cloned()
74+
self.code_section.get(idx - 1).map(|i| i + code_offset)
7875
}
7976

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

119116
// Extract code section
120117
let start = header_len + header.types_size as usize;
118+
body.code_offset = start;
121119
let mut code_end = 0;
122120
for size in header.code_sizes.iter().map(|x| *x as usize) {
123121
code_end += size;

crates/handler/src/frame.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ where
161161

162162
// ExtDelegateCall is not allowed to call non-EOF contracts.
163163
if is_ext_delegate_call && !bytecode.bytes_slice().starts_with(&EOF_MAGIC_BYTES) {
164+
context.journal().checkpoint_revert(checkpoint);
164165
return return_result(InstructionResult::InvalidExtDelegateCallTarget);
165166
}
166167

crates/inspector/src/eip3155.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::{inspectors::GasInspector, Inspector};
2+
use revm::interpreter::interpreter_types::{RuntimeFlag, SubRoutineStack};
23
use revm::{
34
bytecode::opcode::OpCode,
45
context::Cfg,
@@ -20,7 +21,9 @@ pub struct TracerEip3155<CTX, INTR> {
2021
/// Print summary of the execution.
2122
print_summary: bool,
2223
stack: Vec<U256>,
23-
pc: usize,
24+
pc: u64,
25+
section: Option<u64>,
26+
function_depth: Option<u64>,
2427
opcode: u8,
2528
gas: u64,
2629
refunded: i64,
@@ -39,6 +42,9 @@ struct Output {
3942
// Required fields:
4043
/// Program counter
4144
pc: u64,
45+
/// EOF code section
46+
#[serde(default, skip_serializing_if = "Option::is_none")]
47+
section: Option<u64>,
4248
/// OpCode
4349
op: u8,
4450
/// Gas left before executing this operation
@@ -49,6 +55,9 @@ struct Output {
4955
stack: Vec<String>,
5056
/// Depth of the call stack
5157
depth: u64,
58+
/// Depth of the EOF function call stack
59+
#[serde(default, skip_serializing_if = "Option::is_none")]
60+
function_depth: Option<u64>,
5261
/// Data returned by the function call
5362
return_data: String,
5463
/// Amount of **global** gas refunded
@@ -140,6 +149,8 @@ where
140149
stack: Default::default(),
141150
memory: Default::default(),
142151
pc: 0,
152+
section: None,
153+
function_depth: None,
143154
opcode: 0,
144155
gas: 0,
145156
refunded: 0,
@@ -213,7 +224,17 @@ where
213224
} else {
214225
None
215226
};
216-
self.pc = interp.bytecode.pc();
227+
self.pc = interp.bytecode.pc() as u64;
228+
self.section = if interp.runtime_flag.is_eof() {
229+
Some(interp.sub_routine.routine_idx() as u64)
230+
} else {
231+
None
232+
};
233+
self.function_depth = if interp.runtime_flag.is_eof() {
234+
Some(interp.sub_routine.len() as u64 + 1)
235+
} else {
236+
None
237+
};
217238
self.opcode = interp.bytecode.opcode();
218239
self.mem_size = interp.memory.size();
219240
self.gas = interp.control.gas().remaining();
@@ -228,12 +249,14 @@ where
228249
}
229250

230251
let value = Output {
231-
pc: self.pc as u64,
252+
pc: self.pc,
253+
section: self.section,
232254
op: self.opcode,
233255
gas: hex_number(self.gas),
234256
gas_cost: hex_number(self.gas_inspector.last_gas_cost()),
235257
stack: self.stack.iter().map(hex_number_u256).collect(),
236258
depth: context.journal().depth() as u64,
259+
function_depth: self.function_depth,
237260
return_data: "0x".to_string(),
238261
refund: hex_number(self.refunded as u64),
239262
mem_size: self.mem_size.to_string(),

crates/interpreter/src/interpreter/ext_bytecode.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ impl Deref for ExtBytecode {
3030
impl ExtBytecode {
3131
/// Create new extended bytecode and set the instruction pointer to the start of the bytecode.
3232
pub fn new(base: Bytecode) -> Self {
33-
let instruction_pointer = base.bytecode().as_ptr();
33+
let instruction_pointer = base.bytecode_ptr();
3434
Self {
3535
base,
3636
instruction_pointer,
@@ -40,7 +40,7 @@ impl ExtBytecode {
4040

4141
/// Creates new `ExtBytecode` with the given hash.
4242
pub fn new_with_hash(base: Bytecode, hash: B256) -> Self {
43-
let instruction_pointer = base.bytecode().as_ptr();
43+
let instruction_pointer = base.bytecode_ptr();
4444
Self {
4545
base,
4646
instruction_pointer,
@@ -66,10 +66,12 @@ impl Jumps for ExtBytecode {
6666
fn relative_jump(&mut self, offset: isize) {
6767
self.instruction_pointer = unsafe { self.instruction_pointer.offset(offset) };
6868
}
69+
6970
#[inline]
7071
fn absolute_jump(&mut self, offset: usize) {
71-
self.instruction_pointer = unsafe { self.base.bytecode().as_ptr().add(offset) };
72+
self.instruction_pointer = unsafe { self.base.bytes_ref().as_ptr().add(offset) };
7273
}
74+
7375
#[inline]
7476
fn is_valid_legacy_jump(&mut self, offset: usize) -> bool {
7577
self.base
@@ -83,13 +85,14 @@ impl Jumps for ExtBytecode {
8385
// SAFETY: `instruction_pointer` always point to bytecode.
8486
unsafe { *self.instruction_pointer }
8587
}
88+
8689
#[inline]
8790
fn pc(&self) -> usize {
88-
// SAFETY: `instruction_pointer` should be at an offset from the start of the bytecode.
91+
// SAFETY: `instruction_pointer` should be at an offset from the start of the bytes.
8992
// In practice this is always true unless a caller modifies the `instruction_pointer` field manually.
9093
unsafe {
9194
self.instruction_pointer
92-
.offset_from(self.base.bytecode().as_ptr()) as usize
95+
.offset_from(self.base.bytes_ref().as_ptr()) as usize
9396
}
9497
}
9598
}

0 commit comments

Comments
 (0)