Skip to content

Commit 0629883

Browse files
loocaprorakita
andauthored
refactor(Inspector): Add CreateOutcome in create/create_end return (bluealloy#980)
* rename main Evm structs, introduce wip external type * tests * Split evm and external context * continue previous commit * wip inspector handle register * add few more handlers for frame and host * Add instruction handle * add instruction handler registration and Inspector wrap * Rm Spec generic, more handlers, start factory * move towards the builder, allow EVM modify * wip on EvmBuilder and modify functionality * EvmBuilder with stages wip * Add wip stages for builer * make handle register simple function, add raw instruction table, split external data from registers * wip on simple builder functions and handler registry * Examples and cleanup * fix lifetime and fmt * Add more handlers, deduct caller, validate tx agains state * All handlers counted, started on docs, some cleanup * renaming and docs * Support all Inspector functionality with Handler * Handler restructured. Documentation added * more docs on registers * integrate builder, fmt, move optimism l1block * add utility builder stage functions * add precompiles, fix bugs with journal spec * spec to generic, optimism build * fix optimism test * fuck macros * clippy and fmt * fix trace block example * ci fixes * Flatten builder stages to generic and handler stage * EvmBuilder doc and refactor fn access * ignore rust code in book * make revme compile, will refactor this in future * Rename handles to Pre/Post Execution and ExecutionLoop * fix optimism clippy * small rename * FrameData and docs * check links mdbook * comments and cleanup * comment * Add initialize interepreter to first frame * clippy * clippy2 * feat: create outcome * fix: createOutcome properties to pub and removed wrapper functions * review: fixed some review comments and added some improvement over instruction results * fix: removed unused is_revert method * review: adjusted comments, moved create_outcome to its own file * fix: no std check --------- Co-authored-by: rakita <dragan0rakita@gmail.com>
1 parent 4aa835a commit 0629883

File tree

9 files changed

+149
-38
lines changed

9 files changed

+149
-38
lines changed
+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use crate::{Gas, InstructionResult, InterpreterResult};
2+
use revm_primitives::{Address, Bytes};
3+
4+
/// Represents the outcome of a create operation in an interpreter.
5+
///
6+
/// This struct holds the result of the operation along with an optional address.
7+
/// It provides methods to determine the next action based on the result of the operation.
8+
pub struct CreateOutcome {
9+
// The result of the interpreter operation.
10+
pub result: InterpreterResult,
11+
// An optional address associated with the create operation.
12+
pub address: Option<Address>,
13+
}
14+
15+
impl CreateOutcome {
16+
/// Constructs a new `CreateOutcome`.
17+
///
18+
/// # Arguments
19+
///
20+
/// * `result` - An `InterpreterResult` representing the result of the interpreter operation.
21+
/// * `address` - An optional `Address` associated with the create operation.
22+
///
23+
/// # Returns
24+
///
25+
/// A new `CreateOutcome` instance.
26+
pub fn new(result: InterpreterResult, address: Option<Address>) -> Self {
27+
Self { result, address }
28+
}
29+
30+
/// Retrieves a reference to the `InstructionResult` from the `InterpreterResult`.
31+
///
32+
/// This method provides access to the `InstructionResult` which represents the
33+
/// outcome of the instruction execution. It encapsulates the result information
34+
/// such as whether the instruction was executed successfully, resulted in a revert,
35+
/// or encountered a fatal error.
36+
///
37+
/// # Returns
38+
///
39+
/// A reference to the `InstructionResult`.
40+
pub fn instruction_result(&self) -> &InstructionResult {
41+
&self.result.result
42+
}
43+
44+
/// Retrieves a reference to the output bytes from the `InterpreterResult`.
45+
///
46+
/// This method returns the output of the interpreted operation. The output is
47+
/// typically used when the operation successfully completes and returns data.
48+
///
49+
/// # Returns
50+
///
51+
/// A reference to the output `Bytes`.
52+
pub fn output(&self) -> &Bytes {
53+
&self.result.output
54+
}
55+
56+
/// Retrieves a reference to the `Gas` details from the `InterpreterResult`.
57+
///
58+
/// This method provides access to the gas details of the operation, which includes
59+
/// information about gas used, remaining, and refunded. It is essential for
60+
/// understanding the gas consumption of the operation.
61+
///
62+
/// # Returns
63+
///
64+
/// A reference to the `Gas` details.
65+
pub fn gas(&self) -> &Gas {
66+
&self.result.gas
67+
}
68+
}

crates/interpreter/src/interpreter.rs

+41-12
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ pub use contract::Contract;
88
pub use shared_memory::{next_multiple_of_32, SharedMemory};
99
pub use stack::{Stack, STACK_LIMIT};
1010

11+
use crate::alloc::borrow::ToOwned;
1112
use crate::{
12-
primitives::Bytes, push, push_b256, return_ok, return_revert, CallInputs, CreateInputs, Gas,
13-
Host, InstructionResult,
13+
primitives::Bytes, push, push_b256, return_ok, return_revert, CallInputs, CreateInputs,
14+
CreateOutcome, Gas, Host, InstructionResult,
1415
};
1516
use alloc::boxed::Box;
1617
use core::cmp::min;
1718
use core::ops::Range;
18-
use revm_primitives::{Address, U256};
19+
use revm_primitives::U256;
1920

2021
pub use self::shared_memory::EMPTY_SHARED_MEMORY;
2122

@@ -93,24 +94,52 @@ impl Interpreter {
9394
}
9495
}
9596

96-
/// When sub create call returns we can insert output of that call into this interpreter.
97-
pub fn insert_create_output(&mut self, result: InterpreterResult, address: Option<Address>) {
98-
self.return_data_buffer = match result.result {
97+
/// Inserts the output of a `create` call into the interpreter.
98+
///
99+
/// This function is used after a `create` call has been executed. It processes the outcome
100+
/// of that call and updates the state of the interpreter accordingly.
101+
///
102+
/// # Arguments
103+
///
104+
/// * `create_outcome` - A `CreateOutcome` struct containing the results of the `create` call.
105+
///
106+
/// # Behavior
107+
///
108+
/// The function updates the `return_data_buffer` with the data from `create_outcome`.
109+
/// Depending on the `InstructionResult` indicated by `create_outcome`, it performs one of the following:
110+
///
111+
/// - `Ok`: Pushes the address from `create_outcome` to the stack, updates gas costs, and records any gas refunds.
112+
/// - `Revert`: Pushes `U256::ZERO` to the stack and updates gas costs.
113+
/// - `FatalExternalError`: Sets the `instruction_result` to `InstructionResult::FatalExternalError`.
114+
/// - `Default`: Pushes `U256::ZERO` to the stack.
115+
///
116+
/// # Side Effects
117+
///
118+
/// - Updates `return_data_buffer` with the data from `create_outcome`.
119+
/// - Modifies the stack by pushing values depending on the `InstructionResult`.
120+
/// - Updates gas costs and records refunds in the interpreter's `gas` field.
121+
/// - May alter `instruction_result` in case of external errors.
122+
pub fn insert_create_outcome(&mut self, create_outcome: CreateOutcome) {
123+
let instruction_result = create_outcome.instruction_result();
124+
125+
self.return_data_buffer = if instruction_result.is_revert() {
99126
// Save data to return data buffer if the create reverted
100-
return_revert!() => result.output,
127+
create_outcome.output().to_owned()
128+
} else {
101129
// Otherwise clear it
102-
_ => Bytes::new(),
130+
Bytes::new()
103131
};
104132

105-
match result.result {
133+
match instruction_result {
106134
return_ok!() => {
135+
let address = create_outcome.address;
107136
push_b256!(self, address.unwrap_or_default().into_word());
108-
self.gas.erase_cost(result.gas.remaining());
109-
self.gas.record_refund(result.gas.refunded());
137+
self.gas.erase_cost(create_outcome.gas().remaining());
138+
self.gas.record_refund(create_outcome.gas().refunded());
110139
}
111140
return_revert!() => {
112141
push!(self, U256::ZERO);
113-
self.gas.erase_cost(result.gas.remaining());
142+
self.gas.erase_cost(create_outcome.gas().remaining());
114143
}
115144
InstructionResult::FatalExternalError => {
116145
self.instruction_result = InstructionResult::FatalExternalError;

crates/interpreter/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ extern crate alloc;
1212
#[macro_use]
1313
mod macros;
1414

15+
mod create_outcome;
1516
pub mod gas;
1617
mod host;
1718
mod inner_models;
@@ -20,6 +21,7 @@ pub mod instructions;
2021
mod interpreter;
2122

2223
// Reexport primary types.
24+
pub use create_outcome::CreateOutcome;
2325
pub use gas::Gas;
2426
pub use host::{DummyHost, Host};
2527
pub use inner_models::*;

crates/revm/src/handler/mainnet/execution_loop.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{
22
db::Database,
33
interpreter::{
4-
return_ok, return_revert, CallInputs, CreateInputs, Gas, InstructionResult,
4+
return_ok, return_revert, CallInputs, CreateInputs, CreateOutcome, Gas, InstructionResult,
55
InterpreterResult, SharedMemory,
66
},
77
primitives::{Env, Spec, TransactTo},
@@ -92,9 +92,10 @@ pub fn frame_return<SPEC: Spec, EXT, DB: Database>(
9292
let Some(parent_stack_frame) = parent_stack_frame else {
9393
return Some(result);
9494
};
95+
let create_outcome = CreateOutcome::new(result, Some(created_address));
9596
parent_stack_frame
9697
.interpreter
97-
.insert_create_output(result, Some(created_address))
98+
.insert_create_outcome(create_outcome)
9899
}
99100
FrameData::Call {
100101
return_memory_range,
@@ -151,10 +152,11 @@ pub fn sub_create<SPEC: Spec, EXT, DB: Database>(
151152
match context.evm.make_create_frame(SPEC::SPEC_ID, &inputs) {
152153
FrameOrResult::Frame(new_frame) => Some(new_frame),
153154
FrameOrResult::Result(result) => {
155+
let create_outcome = CreateOutcome::new(result, None);
154156
// insert result of the failed creation of create CallStackFrame.
155157
curent_stack_frame
156158
.interpreter
157-
.insert_create_output(result, None);
159+
.insert_create_outcome(create_outcome);
158160
None
159161
}
160162
}

crates/revm/src/inspector.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ mod noop;
1818
// Exports.
1919

2020
pub use handler_register::{inspector_handle_register, inspector_instruction, GetInspector};
21-
use revm_interpreter::InterpreterResult;
21+
use revm_interpreter::{CreateOutcome, InterpreterResult};
2222
/// [Inspector] implementations.
2323
pub mod inspectors {
2424
#[cfg(feature = "std")]
@@ -109,7 +109,7 @@ pub trait Inspector<DB: Database> {
109109
&mut self,
110110
context: &mut EvmContext<DB>,
111111
inputs: &mut CreateInputs,
112-
) -> Option<(InterpreterResult, Option<Address>)> {
112+
) -> Option<CreateOutcome> {
113113
let _ = context;
114114
let _ = inputs;
115115
None
@@ -125,9 +125,9 @@ pub trait Inspector<DB: Database> {
125125
context: &mut EvmContext<DB>,
126126
result: InterpreterResult,
127127
address: Option<Address>,
128-
) -> (InterpreterResult, Option<Address>) {
128+
) -> CreateOutcome {
129129
let _ = context;
130-
(result, address)
130+
CreateOutcome::new(result, address)
131131
}
132132

133133
/// Called when a contract has been self-destructed with funds transferred to target.

crates/revm/src/inspector/customprinter.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! It is a great tool if some debugging is needed.
33
44
use core::ops::Range;
5+
use revm_interpreter::CreateOutcome;
56

67
use crate::{
78
inspectors::GasInspector,
@@ -73,7 +74,7 @@ impl<DB: Database> Inspector<DB> for CustomPrintTracer {
7374
context: &mut EvmContext<DB>,
7475
result: InterpreterResult,
7576
address: Option<Address>,
76-
) -> (InterpreterResult, Option<Address>) {
77+
) -> CreateOutcome {
7778
self.gas_inspector.create_end(context, result, address)
7879
}
7980

@@ -97,7 +98,7 @@ impl<DB: Database> Inspector<DB> for CustomPrintTracer {
9798
&mut self,
9899
_context: &mut EvmContext<DB>,
99100
inputs: &mut CreateInputs,
100-
) -> Option<(InterpreterResult, Option<Address>)> {
101+
) -> Option<CreateOutcome> {
101102
println!(
102103
"CREATE CALL: caller:{:?}, scheme:{:?}, value:{:?}, init_code:{:?}, gas:{:?}",
103104
inputs.caller, inputs.scheme, inputs.value, inputs.init_code, inputs.gas_limit

crates/revm/src/inspector/eip3155.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::{
55
EvmContext, GetInspector, Inspector,
66
};
77
use core::ops::Range;
8+
use revm_interpreter::CreateOutcome;
89
use serde_json::json;
910
use std::io::Write;
1011

@@ -118,7 +119,7 @@ impl<DB: Database> Inspector<DB> for TracerEip3155 {
118119
&mut self,
119120
_context: &mut EvmContext<DB>,
120121
_inputs: &mut CreateInputs,
121-
) -> Option<(InterpreterResult, Option<Address>)> {
122+
) -> Option<CreateOutcome> {
122123
None
123124
}
124125

@@ -127,7 +128,7 @@ impl<DB: Database> Inspector<DB> for TracerEip3155 {
127128
context: &mut EvmContext<DB>,
128129
result: InterpreterResult,
129130
address: Option<Address>,
130-
) -> (InterpreterResult, Option<Address>) {
131+
) -> CreateOutcome {
131132
self.gas_inspector.create_end(context, result, address)
132133
}
133134
}

crates/revm/src/inspector/gas.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! GasIspector. Helper Inspector to calculate gas for others.
22
3+
use revm_interpreter::CreateOutcome;
4+
35
use crate::{
46
interpreter::InterpreterResult,
57
primitives::{db::Database, Address},
@@ -59,13 +61,15 @@ impl<DB: Database> Inspector<DB> for GasInspector {
5961
_context: &mut EvmContext<DB>,
6062
result: InterpreterResult,
6163
address: Option<Address>,
62-
) -> (InterpreterResult, Option<Address>) {
63-
(result, address)
64+
) -> CreateOutcome {
65+
CreateOutcome::new(result, address)
6466
}
6567
}
6668

6769
#[cfg(test)]
6870
mod tests {
71+
use revm_interpreter::CreateOutcome;
72+
6973
use crate::{
7074
inspector::GetInspector,
7175
inspectors::GasInspector,
@@ -128,7 +132,7 @@ mod tests {
128132
&mut self,
129133
context: &mut EvmContext<DB>,
130134
call: &mut CreateInputs,
131-
) -> Option<(InterpreterResult, Option<Address>)> {
135+
) -> Option<CreateOutcome> {
132136
self.gas_inspector.create(context, call);
133137
None
134138
}
@@ -138,7 +142,7 @@ mod tests {
138142
context: &mut EvmContext<DB>,
139143
result: InterpreterResult,
140144
address: Option<Address>,
141-
) -> (InterpreterResult, Option<Address>) {
145+
) -> CreateOutcome {
142146
self.gas_inspector.create_end(context, result, address)
143147
}
144148
}

0 commit comments

Comments
 (0)