Skip to content

Commit 6859e18

Browse files
committed
feat: recursive sub calls in custom frame
1 parent 7f5a6a0 commit 6859e18

File tree

7 files changed

+171
-141
lines changed

7 files changed

+171
-141
lines changed

crates/handler/src/evm.rs

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,49 @@ pub trait EvmTr {
123123
&mut self,
124124
result: <Self::Frame as FrameTr>::FrameResult,
125125
) -> Result<Option<<Self::Frame as FrameTr>::FrameResult>, ContextDbError<Self::Context>>;
126+
127+
/// Run the execution loop.
128+
#[inline]
129+
fn run_exec_loop(
130+
&mut self,
131+
frame_init: <Self::Frame as FrameTr>::FrameInit,
132+
) -> Result<<Self::Frame as FrameTr>::FrameResult, ContextDbError<Self::Context>> {
133+
let res = self.frame_init(frame_init)?;
134+
135+
if let ItemOrResult::Result(frame_result) = res {
136+
return Ok(frame_result);
137+
}
138+
// local depth of the call stack
139+
let mut depth = 1;
140+
loop {
141+
let call_or_result = self.frame_run()?;
142+
143+
match call_or_result {
144+
ItemOrResult::Item(init) => {
145+
match self.frame_init(init)? {
146+
ItemOrResult::Item(_) => {
147+
depth += 1;
148+
}
149+
// Do not pop the frame since no new frame was created
150+
ItemOrResult::Result(result) => {
151+
if let Some(result) = self.frame_return_result(result)? {
152+
return Ok(result);
153+
}
154+
}
155+
}
156+
}
157+
ItemOrResult::Result(result) => {
158+
self.frame_stack().pop();
159+
depth -= 1;
160+
// if depth is 0, return the result
161+
if depth == 0 {
162+
return Ok(result);
163+
}
164+
self.frame_return_result(result)?;
165+
}
166+
};
167+
}
168+
}
126169
}
127170

128171
impl<CTX, INSP, I, P> EvmTr for Evm<CTX, INSP, I, P, EthFrame<EthInterpreter>>
@@ -206,11 +249,7 @@ where
206249
.interpreter
207250
.run_plain(instructions.instruction_table(), context);
208251

209-
frame.process_next_action(context, action).inspect(|i| {
210-
if i.is_result() {
211-
frame.set_finished(true);
212-
}
213-
})
252+
frame.process_next_action(context, action)
214253
}
215254

216255
/// Returns the result of the frame to the caller. Frame is popped from the frame stack.
@@ -219,9 +258,6 @@ where
219258
&mut self,
220259
result: <Self::Frame as FrameTr>::FrameResult,
221260
) -> Result<Option<<Self::Frame as FrameTr>::FrameResult>, ContextDbError<Self::Context>> {
222-
if self.frame_stack.get().is_finished() {
223-
self.frame_stack.pop();
224-
}
225261
if self.frame_stack.index().is_none() {
226262
return Ok(Some(result));
227263
}

crates/handler/src/frame.rs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,6 @@ pub struct EthFrame<IW: InterpreterTypes = EthInterpreter> {
4949
pub checkpoint: JournalCheckpoint,
5050
/// Interpreter instance for executing bytecode.
5151
pub interpreter: Interpreter<IW>,
52-
/// Whether the frame has been finished its execution.
53-
/// Frame is considered finished if it has been called and returned a result.
54-
pub is_finished: bool,
5552
}
5653

5754
impl<IT: InterpreterTypes> FrameTr for EthFrame<IT> {
@@ -80,19 +77,8 @@ impl EthFrame<EthInterpreter> {
8077
depth: 0,
8178
checkpoint: JournalCheckpoint::default(),
8279
interpreter,
83-
is_finished: false,
8480
}
8581
}
86-
87-
/// Returns true if the frame has finished execution.
88-
pub fn is_finished(&self) -> bool {
89-
self.is_finished
90-
}
91-
92-
/// Sets the finished state of the frame.
93-
pub fn set_finished(&mut self, finished: bool) {
94-
self.is_finished = finished;
95-
}
9682
}
9783

9884
/// Type alias for database errors from a context.
@@ -120,12 +106,10 @@ impl EthFrame<EthInterpreter> {
120106
depth: depth_ref,
121107
interpreter,
122108
checkpoint: checkpoint_ref,
123-
is_finished: is_finished_ref,
124109
} = self;
125110
*data_ref = data;
126111
*input_ref = input;
127112
*depth_ref = depth;
128-
*is_finished_ref = false;
129113
interpreter.clear(memory, bytecode, inputs, is_static, spec_id, gas_limit);
130114
*checkpoint_ref = checkpoint;
131115
}

crates/handler/src/handler.rs

Lines changed: 1 addition & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate::{
22
evm::FrameTr, execution, post_execution, pre_execution, validation, EvmTr, FrameResult,
3-
ItemOrResult,
43
};
54
use context::{
65
result::{ExecutionResult, FromStringError},
@@ -196,7 +195,7 @@ pub trait Handler {
196195
let first_frame_input = self.first_frame_input(evm, gas_limit)?;
197196

198197
// Run execution loop
199-
let mut frame_result = self.run_exec_loop(evm, first_frame_input)?;
198+
let mut frame_result = evm.run_exec_loop(first_frame_input)?;
200199

201200
// Handle last frame result
202201
self.last_frame_result(evm, &mut frame_result)?;
@@ -354,49 +353,6 @@ pub trait Handler {
354353
Ok(())
355354
}
356355

357-
/* FRAMES */
358-
359-
/// Executes the main frame processing loop.
360-
///
361-
/// This loop manages the frame stack, processing each frame until execution completes.
362-
/// For each iteration:
363-
/// 1. Calls the current frame
364-
/// 2. Handles the returned frame input or result
365-
/// 3. Creates new frames or propagates results as needed
366-
#[inline]
367-
fn run_exec_loop(
368-
&mut self,
369-
evm: &mut Self::Evm,
370-
first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit,
371-
) -> Result<FrameResult, Self::Error> {
372-
let res = evm.frame_init(first_frame_input)?;
373-
374-
if let ItemOrResult::Result(frame_result) = res {
375-
return Ok(frame_result);
376-
}
377-
378-
loop {
379-
let call_or_result = evm.frame_run()?;
380-
381-
let result = match call_or_result {
382-
ItemOrResult::Item(init) => {
383-
match evm.frame_init(init)? {
384-
ItemOrResult::Item(_) => {
385-
continue;
386-
}
387-
// Do not pop the frame since no new frame was created
388-
ItemOrResult::Result(result) => result,
389-
}
390-
}
391-
ItemOrResult::Result(result) => result,
392-
};
393-
394-
if let Some(result) = evm.frame_return_result(result)? {
395-
return Ok(result);
396-
}
397-
}
398-
}
399-
400356
/* POST EXECUTION */
401357

402358
/// Validates that the minimum gas floor requirements are satisfied.

crates/inspector/src/handler.rs

Lines changed: 3 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{Inspector, InspectorEvmTr, JournalExt};
22
use context::{result::ExecutionResult, ContextTr, JournalEntry, JournalTr, Transaction};
3-
use handler::{evm::FrameTr, EvmTr, FrameResult, Handler, ItemOrResult};
3+
use handler::{EvmTr, FrameResult, Handler};
44
use interpreter::{
55
instructions::InstructionTable,
66
interpreter_types::{Jumps, LoopControl},
@@ -24,7 +24,7 @@ use state::bytecode::opcode;
2424
/// * [`Handler::run`] replaced with [`InspectorHandler::inspect_run`]
2525
/// * [`Handler::run_without_catch_error`] replaced with [`InspectorHandler::inspect_run_without_catch_error`]
2626
/// * [`Handler::execution`] replaced with [`InspectorHandler::inspect_execution`]
27-
/// * [`Handler::run_exec_loop`] replaced with [`InspectorHandler::inspect_run_exec_loop`]
27+
/// * [`EvmTr::run_exec_loop`] replaced with [`InspectorEvmTr::inspect_run_exec_loop`]
2828
/// * `run_exec_loop` calls `inspect_frame_init` and `inspect_frame_run` that call inspector inside.
2929
/// * [`Handler::run_system_call`] replaced with [`InspectorHandler::inspect_run_system_call`]
3030
pub trait InspectorHandler: Handler
@@ -75,56 +75,13 @@ where
7575
let first_frame_input = self.first_frame_input(evm, gas_limit)?;
7676

7777
// Run execution loop
78-
let mut frame_result = self.inspect_run_exec_loop(evm, first_frame_input)?;
78+
let mut frame_result = evm.inspect_run_exec_loop(first_frame_input)?;
7979

8080
// Handle last frame result
8181
self.last_frame_result(evm, &mut frame_result)?;
8282
Ok(frame_result)
8383
}
8484

85-
/* FRAMES */
86-
87-
/// Run inspection on execution loop.
88-
///
89-
/// This method acts as [`Handler::run_exec_loop`] method for inspection.
90-
///
91-
/// It will call:
92-
/// * [`Inspector::call`],[`Inspector::create`] to inspect call, create and eofcreate.
93-
/// * [`Inspector::call_end`],[`Inspector::create_end`] to inspect call, create and eofcreate end.
94-
/// * [`Inspector::initialize_interp`] to inspect initialized interpreter.
95-
fn inspect_run_exec_loop(
96-
&mut self,
97-
evm: &mut Self::Evm,
98-
first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit,
99-
) -> Result<FrameResult, Self::Error> {
100-
let res = evm.inspect_frame_init(first_frame_input)?;
101-
102-
if let ItemOrResult::Result(frame_result) = res {
103-
return Ok(frame_result);
104-
}
105-
106-
loop {
107-
let call_or_result = evm.inspect_frame_run()?;
108-
109-
let result = match call_or_result {
110-
ItemOrResult::Item(init) => {
111-
match evm.inspect_frame_init(init)? {
112-
ItemOrResult::Item(_) => {
113-
continue;
114-
}
115-
// Do not pop the frame since no new frame was created
116-
ItemOrResult::Result(result) => result,
117-
}
118-
}
119-
ItemOrResult::Result(result) => result,
120-
};
121-
122-
if let Some(result) = evm.frame_return_result(result)? {
123-
return Ok(result);
124-
}
125-
}
126-
}
127-
12885
/// Run system call with inspection support.
12986
///
13087
/// This method acts as [`Handler::run_system_call`] method for inspection.

crates/inspector/src/traits.rs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,61 @@ pub trait InspectorEvmTr:
162162
// TODO When all_mut fn is added we can fetch inspector at the top of the function.s
163163
if let Some(frame) = frame.eth_frame() {
164164
frame_end(ctx, inspector, &frame.input, frame_result);
165-
frame.set_finished(true);
166165
}
167166
};
168167
result
169168
}
169+
170+
/// Run inspection on execution loop.
171+
///
172+
/// This method acts as [`EvmTr::run_exec_loop`] method for inspection.
173+
///
174+
/// It will call:
175+
/// * [`Inspector::call`],[`Inspector::create`] to inspect call, create and eofcreate.
176+
/// * [`Inspector::call_end`],[`Inspector::create_end`] to inspect call, create and eofcreate end.
177+
/// * [`Inspector::initialize_interp`] to inspect initialized interpreter.
178+
fn inspect_run_exec_loop(
179+
&mut self,
180+
frame_init: <Self::Frame as FrameTr>::FrameInit,
181+
) -> Result<<Self::Frame as FrameTr>::FrameResult, ContextDbError<Self::Context>> {
182+
let res = self.inspect_frame_init(frame_init)?;
183+
184+
if let ItemOrResult::Result(frame_result) = res {
185+
return Ok(frame_result);
186+
}
187+
188+
let mut depth = 1;
189+
loop {
190+
let call_or_result: ItemOrResult<FrameInit, FrameResult> = self.inspect_frame_run()?;
191+
192+
match call_or_result {
193+
ItemOrResult::Item(init) => {
194+
match self.inspect_frame_init(init)? {
195+
ItemOrResult::Item(_) => {
196+
depth += 1;
197+
}
198+
// Do not pop the frame since no new frame was created
199+
ItemOrResult::Result(result) => {
200+
self.frame_return_result(result)?;
201+
}
202+
}
203+
continue;
204+
}
205+
ItemOrResult::Result(result) => {
206+
self.frame_stack().pop();
207+
// local depth of the call stack
208+
depth -= 1;
209+
// if depth is 0, return the result
210+
if depth == 0 {
211+
// pop first frame
212+
self.frame_stack().pop();
213+
return Ok(result);
214+
}
215+
self.frame_return_result(result)?;
216+
}
217+
};
218+
}
219+
}
170220
}
171221

172222
/// Trait that extends the [`FrameTr`] trait with additional functionality that is needed for inspection.

examples/my_evm/src/api.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ where
3232
type Block = <CTX as ContextTr>::Block;
3333

3434
fn set_block(&mut self, block: Self::Block) {
35-
self.0.ctx.set_block(block);
35+
self.evm.ctx.set_block(block);
3636
}
3737

3838
fn transact_one(&mut self, tx: Self::Tx) -> Result<Self::ExecutionResult, Self::Error> {
39-
self.0.ctx.set_tx(tx);
39+
self.evm.ctx.set_tx(tx);
4040
let mut handler = MyHandler::default();
4141
handler.run(self)
4242
}
@@ -75,11 +75,11 @@ where
7575
type Inspector = INSP;
7676

7777
fn set_inspector(&mut self, inspector: Self::Inspector) {
78-
self.0.inspector = inspector;
78+
self.evm.inspector = inspector;
7979
}
8080

8181
fn inspect_one_tx(&mut self, tx: Self::Tx) -> Result<Self::ExecutionResult, Self::Error> {
82-
self.0.ctx.set_tx(tx);
82+
self.evm.ctx.set_tx(tx);
8383
let mut handler = MyHandler::default();
8484
handler.inspect_run(self)
8585
}

0 commit comments

Comments
 (0)