revm_interpreter/interpreter_action/call_inputs.rs
1use crate::interpreter_types::MemoryTr;
2use context_interface::{ContextTr, LocalContextTr};
3use core::ops::Range;
4use primitives::{Address, Bytes, B256, U256};
5use state::Bytecode;
6
7/// Input enum for a call.
8///
9/// As CallInput uses shared memory buffer it can get overridden if not used directly when call happens.
10#[derive(Clone, Debug, PartialEq, Eq)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub enum CallInput {
13 /// Bytes of the call data.
14 Bytes(Bytes),
15 /// The Range points to the SharedMemory buffer. Buffer can be found in [`context_interface::LocalContextTr::shared_memory_buffer_slice`] function.
16 /// And can be accessed with `evm.ctx().local().shared_memory_buffer()`
17 ///
18 /// # Warning
19 ///
20 /// Use it with caution, CallInput shared buffer can be overridden if context from child call is returned so
21 /// recommendation is to fetch buffer at first Inspector call and clone it from [`context_interface::LocalContextTr::shared_memory_buffer_slice`] function.
22 SharedBuffer(Range<usize>),
23}
24
25impl CallInput {
26 /// Returns the length of the call input.
27 #[inline]
28 pub fn len(&self) -> usize {
29 match self {
30 Self::Bytes(bytes) => bytes.len(),
31 Self::SharedBuffer(range) => range.len(),
32 }
33 }
34
35 /// Returns `true` if the call input is empty.
36 #[inline]
37 pub fn is_empty(&self) -> bool {
38 self.len() == 0
39 }
40
41 /// Returns the bytes of the call input from the given context.
42 #[inline]
43 pub fn as_bytes<'a, CTX: ContextTr>(
44 &'a self,
45 ctx: &'a CTX,
46 ) -> impl core::ops::Deref<Target = [u8]> + 'a {
47 match self {
48 Self::Bytes(bytes) => CallInputRef::Bytes(bytes.as_ref()),
49 Self::SharedBuffer(range) => {
50 CallInputRef::SharedBuffer(ctx.local().shared_memory_buffer_slice(range.clone()))
51 }
52 }
53 }
54
55 /// Returns the bytes of the call input from the given memory.
56 #[inline]
57 pub fn as_bytes_memory<'a, M: MemoryTr>(
58 &'a self,
59 memory: &'a M,
60 ) -> impl core::ops::Deref<Target = [u8]> + 'a {
61 match self {
62 Self::Bytes(bytes) => CallInputRef::Bytes(bytes.as_ref()),
63 Self::SharedBuffer(range) => {
64 CallInputRef::SharedBuffer(Some(memory.global_slice(range.clone())))
65 }
66 }
67 }
68
69 /// Returns the bytes of the call input.
70 ///
71 /// SharedMemory buffer can be shrunked or overwritten if the child call returns the
72 /// shared memory context to its parent, the range in `CallInput::SharedBuffer` can show unexpected data.
73 ///
74 /// # Allocation
75 ///
76 /// If this `CallInput` is a `SharedBuffer`, the slice will be copied
77 /// into a fresh `Bytes` buffer, which can pose a performance penalty.
78 pub fn bytes<CTX: ContextTr>(&self, ctx: &CTX) -> Bytes {
79 match self {
80 CallInput::Bytes(bytes) => bytes.clone(),
81 CallInput::SharedBuffer(range) => ctx
82 .local()
83 .shared_memory_buffer_slice(range.clone())
84 .map(|b| Bytes::from(b.to_vec()))
85 .unwrap_or_default(),
86 }
87 }
88}
89
90impl Default for CallInput {
91 #[inline]
92 fn default() -> Self {
93 CallInput::Bytes(Bytes::new())
94 }
95}
96
97enum CallInputRef<'a> {
98 Bytes(&'a [u8]),
99 SharedBuffer(Option<core::cell::Ref<'a, [u8]>>),
100}
101
102impl core::ops::Deref for CallInputRef<'_> {
103 type Target = [u8];
104
105 #[inline]
106 fn deref(&self) -> &Self::Target {
107 match self {
108 Self::Bytes(x) => x,
109 Self::SharedBuffer(x) => x.as_deref().unwrap_or_default(),
110 }
111 }
112}
113
114/// Inputs for a call.
115#[derive(Clone, Debug, PartialEq, Eq)]
116#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
117pub struct CallInputs {
118 /// The call data of the call.
119 pub input: CallInput,
120 /// The return memory offset where the output of the call is written.
121 pub return_memory_offset: Range<usize>,
122 /// The gas limit of the call.
123 pub gas_limit: u64,
124 /// The account address of bytecode that is going to be executed.
125 ///
126 /// Previously `context.code_address`.
127 pub bytecode_address: Address,
128 /// Known bytecode and its hash.
129 /// If None, bytecode will be loaded from the account at `bytecode_address`.
130 /// If Some((hash, bytecode)), the provided bytecode and hash will be used.
131 pub known_bytecode: Option<(B256, Bytecode)>,
132 /// Target address, this account storage is going to be modified.
133 ///
134 /// Previously `context.address`.
135 pub target_address: Address,
136 /// This caller is invoking the call.
137 ///
138 /// Previously `context.caller`.
139 pub caller: Address,
140 /// Call value.
141 ///
142 /// **Note**: This value may not necessarily be transferred from caller to callee, see [`CallValue`].
143 ///
144 /// Previously `transfer.value` or `context.apparent_value`.
145 pub value: CallValue,
146 /// The call scheme.
147 ///
148 /// Previously `context.scheme`.
149 pub scheme: CallScheme,
150 /// Whether the call is a static call, or is initiated inside a static call.
151 pub is_static: bool,
152}
153
154impl CallInputs {
155 /// Returns `true` if the call will transfer a non-zero value.
156 #[inline]
157 pub fn transfers_value(&self) -> bool {
158 self.value.transfer().is_some_and(|x| x > U256::ZERO)
159 }
160
161 /// Returns the transfer value.
162 ///
163 /// This is the value that is transferred from caller to callee, see [`CallValue`].
164 #[inline]
165 pub const fn transfer_value(&self) -> Option<U256> {
166 self.value.transfer()
167 }
168
169 /// Returns the **apparent** call value.
170 ///
171 /// This value is not actually transferred, see [`CallValue`].
172 #[inline]
173 pub const fn apparent_value(&self) -> Option<U256> {
174 self.value.apparent()
175 }
176
177 /// Returns the address of the transfer source account.
178 ///
179 /// This is only meaningful if `transfers_value` is `true`.
180 #[inline]
181 pub const fn transfer_from(&self) -> Address {
182 self.caller
183 }
184
185 /// Returns the address of the transfer target account.
186 ///
187 /// This is only meaningful if `transfers_value` is `true`.
188 #[inline]
189 pub const fn transfer_to(&self) -> Address {
190 self.target_address
191 }
192
193 /// Returns the call value, regardless of the transfer value type.
194 ///
195 /// **Note**: This value may not necessarily be transferred from caller to callee, see [`CallValue`].
196 #[inline]
197 pub const fn call_value(&self) -> U256 {
198 self.value.get()
199 }
200}
201
202/// Call scheme.
203#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
204#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
205pub enum CallScheme {
206 /// `CALL`.
207 Call,
208 /// `CALLCODE`
209 CallCode,
210 /// `DELEGATECALL`
211 DelegateCall,
212 /// `STATICCALL`
213 StaticCall,
214}
215
216impl CallScheme {
217 /// Returns true if it is `CALL`.
218 pub fn is_call(&self) -> bool {
219 matches!(self, Self::Call)
220 }
221
222 /// Returns true if it is `CALLCODE`.
223 pub fn is_call_code(&self) -> bool {
224 matches!(self, Self::CallCode)
225 }
226
227 /// Returns true if it is `DELEGATECALL`.
228 pub fn is_delegate_call(&self) -> bool {
229 matches!(self, Self::DelegateCall)
230 }
231
232 /// Returns true if it is `STATICCALL`.
233 pub fn is_static_call(&self) -> bool {
234 matches!(self, Self::StaticCall)
235 }
236}
237
238/// Call value.
239#[derive(Clone, Debug, PartialEq, Eq, Hash)]
240#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
241pub enum CallValue {
242 /// Concrete value, transferred from caller to callee at the end of the transaction.
243 Transfer(U256),
244 /// Apparent value, that is **not** actually transferred.
245 ///
246 /// Set when in a `DELEGATECALL` call type, and used by the `CALLVALUE` opcode.
247 Apparent(U256),
248}
249
250impl Default for CallValue {
251 #[inline]
252 fn default() -> Self {
253 CallValue::Transfer(U256::ZERO)
254 }
255}
256
257impl CallValue {
258 /// Returns the call value, regardless of the type.
259 #[inline]
260 pub const fn get(&self) -> U256 {
261 match *self {
262 Self::Transfer(value) | Self::Apparent(value) => value,
263 }
264 }
265
266 /// Returns the transferred value, if any.
267 #[inline]
268 pub const fn transfer(&self) -> Option<U256> {
269 match *self {
270 Self::Transfer(transfer) => Some(transfer),
271 Self::Apparent(_) => None,
272 }
273 }
274
275 /// Returns whether the call value will be transferred.
276 #[inline]
277 pub const fn is_transfer(&self) -> bool {
278 matches!(self, Self::Transfer(_))
279 }
280
281 /// Returns the apparent value, if any.
282 #[inline]
283 pub const fn apparent(&self) -> Option<U256> {
284 match *self {
285 Self::Transfer(_) => None,
286 Self::Apparent(apparent) => Some(apparent),
287 }
288 }
289
290 /// Returns whether the call value is apparent, and not actually transferred.
291 #[inline]
292 pub const fn is_apparent(&self) -> bool {
293 matches!(self, Self::Apparent(_))
294 }
295}