revm_interpreter/interpreter_action/
call_inputs.rs

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