Skip to main content

revm_handler/
frame_data.rs

1use context_interface::{cfg::GasParams, result::Output};
2use core::ops::Range;
3use interpreter::{CallOutcome, CreateOutcome, Gas, InstructionResult, InterpreterResult};
4use primitives::Address;
5
6/// Call Frame
7#[derive(Debug, Clone)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9pub struct CallFrame {
10    /// Call frame has return memory range where output will be stored.
11    pub return_memory_range: Range<usize>,
12}
13
14/// Create Frame
15#[derive(Debug, Clone)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17pub struct CreateFrame {
18    /// Create frame has a created address.
19    pub created_address: Address,
20}
21
22/// Frame Data
23///
24/// [`FrameData`] bundles different types of frames.
25#[derive(Debug, Clone)]
26#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
27pub enum FrameData {
28    /// Call frame data.
29    Call(CallFrame),
30    /// Create frame data.
31    Create(CreateFrame),
32}
33
34/// Frame Result
35#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
36#[derive(Debug, Clone)]
37pub enum FrameResult {
38    /// Call frame result.
39    Call(CallOutcome),
40    /// Create frame result.
41    Create(CreateOutcome),
42}
43
44impl FrameResult {
45    /// Creates a new call frame result for an out-of-gas error.
46    #[inline]
47    pub fn new_call_oog(
48        gas_limit: u64,
49        memory_offset: core::ops::Range<usize>,
50        reservoir: u64,
51    ) -> Self {
52        Self::Call(CallOutcome::new_oog(gas_limit, memory_offset, reservoir))
53    }
54
55    /// Creates a new create frame result for an out-of-gas error.
56    #[inline]
57    pub fn new_create_oog(gas_limit: u64, reservoir: u64) -> Self {
58        Self::Create(CreateOutcome::new_oog(gas_limit, reservoir))
59    }
60
61    /// Casts frame result to interpreter result.
62    #[inline]
63    pub fn into_interpreter_result(self) -> InterpreterResult {
64        match self {
65            FrameResult::Call(outcome) => outcome.result,
66            FrameResult::Create(outcome) => outcome.result,
67        }
68    }
69
70    /// Returns execution output.
71    #[inline]
72    pub fn output(&self) -> Output {
73        match self {
74            FrameResult::Call(outcome) => Output::Call(outcome.result.output.clone()),
75            FrameResult::Create(outcome) => {
76                Output::Create(outcome.result.output.clone(), outcome.address)
77            }
78        }
79    }
80
81    /// Returns reference to gas.
82    #[inline]
83    pub const fn gas(&self) -> &Gas {
84        match self {
85            FrameResult::Call(outcome) => &outcome.result.gas,
86            FrameResult::Create(outcome) => &outcome.result.gas,
87        }
88    }
89
90    /// Returns mutable reference to interpreter result.
91    #[inline]
92    pub const fn gas_mut(&mut self) -> &mut Gas {
93        match self {
94            FrameResult::Call(outcome) => &mut outcome.result.gas,
95            FrameResult::Create(outcome) => &mut outcome.result.gas,
96        }
97    }
98
99    /// Returns reference to interpreter result.
100    #[inline]
101    pub const fn interpreter_result(&self) -> &InterpreterResult {
102        match self {
103            FrameResult::Call(outcome) => &outcome.result,
104            FrameResult::Create(outcome) => &outcome.result,
105        }
106    }
107
108    /// Returns mutable reference to interpreter result.
109    #[inline]
110    pub const fn interpreter_result_mut(&mut self) -> &mut InterpreterResult {
111        match self {
112            FrameResult::Call(outcome) => &mut outcome.result,
113            FrameResult::Create(outcome) => &mut outcome.result,
114        }
115    }
116
117    /// Return Instruction result.
118    #[inline]
119    pub const fn instruction_result(&self) -> InstructionResult {
120        self.interpreter_result().result
121    }
122
123    /// Returns the upfront state charge (EIP-8037) to refund when the frame
124    /// did not create the account leaf it paid for, or `None` when nothing is
125    /// to be refunded.
126    ///
127    /// The charge was recorded on the caller's gas before the frame ran — by
128    /// the CALL/CREATE opcode for inner frames, or by the EIP-2780 runtime
129    /// gas phase on the transaction-level gas for the first frame — and its
130    /// decision is carried on the outcome's `charged_*` flags. A call refunds
131    /// it when it did not succeed; a create also refunds it when no contract
132    /// address was deployed (early-fail paths such as sender nonce overflow
133    /// report success with `address == None`, so the address is checked
134    /// rather than the result alone).
135    #[inline]
136    pub fn refundable_state_gas(&self, gas_params: &GasParams) -> Option<u64> {
137        match self {
138            FrameResult::Call(outcome) => (!outcome.instruction_result().is_ok()
139                && outcome.charged_new_account_state_gas)
140                .then(|| gas_params.new_account_state_gas()),
141            FrameResult::Create(outcome) => ((outcome.address.is_none()
142                || !outcome.instruction_result().is_ok())
143                && outcome.charged_create_state_gas)
144                .then(|| gas_params.create_state_gas()),
145        }
146    }
147}
148
149impl FrameData {
150    /// Creates a new create frame data.
151    pub const fn new_create(created_address: Address) -> Self {
152        Self::Create(CreateFrame { created_address })
153    }
154
155    /// Creates a new call frame data.
156    pub const fn new_call(return_memory_range: Range<usize>) -> Self {
157        Self::Call(CallFrame {
158            return_memory_range,
159        })
160    }
161
162    /// Returns true if frame is call frame.
163    pub const fn is_call(&self) -> bool {
164        matches!(self, Self::Call { .. })
165    }
166
167    /// Returns true if frame is create frame.
168    pub const fn is_create(&self) -> bool {
169        matches!(self, Self::Create { .. })
170    }
171
172    /// Returns created address if frame is create otherwise returns None.
173    pub const fn created_address(&self) -> Option<Address> {
174        match self {
175            Self::Create(create_frame) => Some(create_frame.created_address),
176            _ => None,
177        }
178    }
179}