Skip to main content

revm_interpreter/
interpreter_action.rs

1mod call_inputs;
2mod call_outcome;
3mod create_inputs;
4mod create_outcome;
5
6pub use call_inputs::{CallInput, CallInputs, CallScheme, CallValue};
7pub use call_outcome::CallOutcome;
8pub use create_inputs::CreateInputs;
9pub use create_outcome::CreateOutcome;
10use primitives::Bytes;
11
12use crate::{Gas, InstructionResult, InterpreterResult, SharedMemory};
13use std::boxed::Box;
14
15/// Input data for creating a new execution frame.
16#[derive(Clone, Debug, PartialEq, Eq)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18pub enum FrameInput {
19    /// No input data (empty frame)
20    Empty,
21    /// `CALL`, `CALLCODE`, `DELEGATECALL`, `STATICCALL` instruction called.
22    Call(Box<CallInputs>),
23    /// `CREATE` or `CREATE2` instruction called.
24    Create(Box<CreateInputs>),
25}
26
27/// Initialization data for creating a new execution frame.
28#[derive(Clone, Debug, PartialEq, Eq)]
29#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
30pub struct FrameInit {
31    /// depth of the next frame
32    pub depth: usize,
33    /// shared memory set to this shared context
34    pub memory: SharedMemory,
35    /// Data needed as input for Interpreter.
36    pub frame_input: FrameInput,
37}
38
39impl FrameInput {
40    /// Reduces the gas limit of the contained Call or Create inputs by `amount`.
41    /// Used to charge initial state gas from the frame's regular gas budget
42    /// when the reservoir is insufficient.
43    pub fn reduce_gas_limit(&mut self, amount: u64) {
44        match self {
45            FrameInput::Call(inputs) => {
46                inputs.gas_limit = inputs.gas_limit.saturating_sub(amount);
47            }
48            FrameInput::Create(inputs) => {
49                inputs.set_gas_limit(inputs.gas_limit().saturating_sub(amount));
50            }
51            FrameInput::Empty => {}
52        }
53    }
54
55    /// Returns the state gas reservoir (EIP-8037).
56    pub fn reservoir(&self) -> u64 {
57        match self {
58            FrameInput::Call(inputs) => inputs.reservoir,
59            FrameInput::Create(inputs) => inputs.reservoir(),
60            FrameInput::Empty => 0,
61        }
62    }
63
64    /// Sets the state gas reservoir (EIP-8037).
65    pub fn set_reservoir(&mut self, reservoir: u64) {
66        match self {
67            FrameInput::Call(inputs) => inputs.reservoir = reservoir,
68            FrameInput::Create(inputs) => inputs.set_reservoir(reservoir),
69            FrameInput::Empty => {}
70        }
71    }
72}
73
74impl AsMut<Self> for FrameInput {
75    fn as_mut(&mut self) -> &mut Self {
76        self
77    }
78}
79
80/// Actions that the interpreter can request from the host environment.
81#[derive(Clone, Debug, PartialEq, Eq)]
82#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
83pub enum InterpreterAction {
84    /// New frame
85    NewFrame(FrameInput),
86    /// Interpreter finished execution.
87    Return(InterpreterResult),
88}
89
90impl InterpreterAction {
91    /// Returns `true` if action is call.
92    #[inline]
93    pub fn is_call(&self) -> bool {
94        matches!(self, InterpreterAction::NewFrame(FrameInput::Call(..)))
95    }
96
97    /// Returns `true` if action is create.
98    #[inline]
99    pub fn is_create(&self) -> bool {
100        matches!(self, InterpreterAction::NewFrame(FrameInput::Create(..)))
101    }
102
103    /// Returns `true` if action is return.
104    #[inline]
105    pub fn is_return(&self) -> bool {
106        matches!(self, InterpreterAction::Return { .. })
107    }
108
109    /// Returns [`Gas`] if action is return.
110    #[inline]
111    pub fn gas_mut(&mut self) -> Option<&mut Gas> {
112        match self {
113            InterpreterAction::Return(result) => Some(&mut result.gas),
114            _ => None,
115        }
116    }
117
118    /// Returns [`InterpreterResult`] if action is return.
119    ///
120    /// Else it returns [None].
121    #[inline]
122    pub fn into_result_return(self) -> Option<InterpreterResult> {
123        match self {
124            InterpreterAction::Return(result) => Some(result),
125            _ => None,
126        }
127    }
128
129    /// Returns [`InstructionResult`] if action is return.
130    ///
131    /// Else it returns [None].
132    #[inline]
133    pub fn instruction_result(&self) -> Option<InstructionResult> {
134        match self {
135            InterpreterAction::Return(result) => Some(result.result),
136            _ => None,
137        }
138    }
139
140    /// Create new frame action with the given frame input.
141    #[inline]
142    pub fn new_frame(frame_input: FrameInput) -> Self {
143        Self::NewFrame(frame_input)
144    }
145
146    /// Create new halt action with the given result and gas.
147    #[inline]
148    pub fn new_halt(result: InstructionResult, gas: Gas) -> Self {
149        Self::Return(InterpreterResult::new(result, Bytes::new(), gas))
150    }
151
152    /// Create new return action with the given result, output and gas.
153    #[inline]
154    pub fn new_return(result: InstructionResult, output: Bytes, gas: Gas) -> Self {
155        Self::Return(InterpreterResult::new(result, output, gas))
156    }
157
158    /// Create new stop action.
159    #[inline]
160    pub fn new_stop() -> Self {
161        Self::Return(InterpreterResult::new(
162            InstructionResult::Stop,
163            Bytes::new(),
164            Gas::new(0),
165        ))
166    }
167}