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    #[inline]
62    fn default() -> Self {
63        CallInput::SharedBuffer(0..0)
64    }
65}
66
67/// Inputs for a call.
68#[derive(Clone, Debug, PartialEq, Eq)]
69#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
70pub struct CallInputs {
71    /// The call data of the call.
72    pub input: CallInput,
73    /// The return memory offset where the output of the call is written.
74    pub return_memory_offset: Range<usize>,
75    /// The gas limit of the call.
76    pub gas_limit: u64,
77    /// The account address of bytecode that is going to be executed.
78    ///
79    /// Previously `context.code_address`.
80    pub bytecode_address: Address,
81    /// Target address, this account storage is going to be modified.
82    ///
83    /// Previously `context.address`.
84    pub target_address: Address,
85    /// This caller is invoking the call.
86    ///
87    /// Previously `context.caller`.
88    pub caller: Address,
89    /// Call value.
90    ///
91    /// **Note**: This value may not necessarily be transferred from caller to callee, see [`CallValue`].
92    ///
93    /// Previously `transfer.value` or `context.apparent_value`.
94    pub value: CallValue,
95    /// The call scheme.
96    ///
97    /// Previously `context.scheme`.
98    pub scheme: CallScheme,
99    /// Whether the call is a static call, or is initiated inside a static call.
100    pub is_static: bool,
101}
102
103impl CallInputs {
104    /// Returns `true` if the call will transfer a non-zero value.
105    #[inline]
106    pub fn transfers_value(&self) -> bool {
107        self.value.transfer().is_some_and(|x| x > U256::ZERO)
108    }
109
110    /// Returns the transfer value.
111    ///
112    /// This is the value that is transferred from caller to callee, see [`CallValue`].
113    #[inline]
114    pub const fn transfer_value(&self) -> Option<U256> {
115        self.value.transfer()
116    }
117
118    /// Returns the **apparent** call value.
119    ///
120    /// This value is not actually transferred, see [`CallValue`].
121    #[inline]
122    pub const fn apparent_value(&self) -> Option<U256> {
123        self.value.apparent()
124    }
125
126    /// Returns the address of the transfer source account.
127    ///
128    /// This is only meaningful if `transfers_value` is `true`.
129    #[inline]
130    pub const fn transfer_from(&self) -> Address {
131        self.caller
132    }
133
134    /// Returns the address of the transfer target account.
135    ///
136    /// This is only meaningful if `transfers_value` is `true`.
137    #[inline]
138    pub const fn transfer_to(&self) -> Address {
139        self.target_address
140    }
141
142    /// Returns the call value, regardless of the transfer value type.
143    ///
144    /// **Note**: This value may not necessarily be transferred from caller to callee, see [`CallValue`].
145    #[inline]
146    pub const fn call_value(&self) -> U256 {
147        self.value.get()
148    }
149}
150
151/// Call scheme.
152#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
153#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
154pub enum CallScheme {
155    /// `CALL`.
156    Call,
157    /// `CALLCODE`
158    CallCode,
159    /// `DELEGATECALL`
160    DelegateCall,
161    /// `STATICCALL`
162    StaticCall,
163}
164
165impl CallScheme {
166    /// Returns true if it is `CALL`.
167    pub fn is_call(&self) -> bool {
168        matches!(self, Self::Call)
169    }
170
171    /// Returns true if it is `CALLCODE`.
172    pub fn is_call_code(&self) -> bool {
173        matches!(self, Self::CallCode)
174    }
175
176    /// Returns true if it is `DELEGATECALL`.
177    pub fn is_delegate_call(&self) -> bool {
178        matches!(self, Self::DelegateCall)
179    }
180
181    /// Returns true if it is `STATICCALL`.
182    pub fn is_static_call(&self) -> bool {
183        matches!(self, Self::StaticCall)
184    }
185}
186
187/// Call value.
188#[derive(Clone, Debug, PartialEq, Eq, Hash)]
189#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
190pub enum CallValue {
191    /// Concrete value, transferred from caller to callee at the end of the transaction.
192    Transfer(U256),
193    /// Apparent value, that is **not** actually transferred.
194    ///
195    /// Set when in a `DELEGATECALL` call type, and used by the `CALLVALUE` opcode.
196    Apparent(U256),
197}
198
199impl Default for CallValue {
200    #[inline]
201    fn default() -> Self {
202        CallValue::Transfer(U256::ZERO)
203    }
204}
205
206impl CallValue {
207    /// Returns the call value, regardless of the type.
208    #[inline]
209    pub const fn get(&self) -> U256 {
210        match *self {
211            Self::Transfer(value) | Self::Apparent(value) => value,
212        }
213    }
214
215    /// Returns the transferred value, if any.
216    #[inline]
217    pub const fn transfer(&self) -> Option<U256> {
218        match *self {
219            Self::Transfer(transfer) => Some(transfer),
220            Self::Apparent(_) => None,
221        }
222    }
223
224    /// Returns whether the call value will be transferred.
225    #[inline]
226    pub const fn is_transfer(&self) -> bool {
227        matches!(self, Self::Transfer(_))
228    }
229
230    /// Returns the apparent value, if any.
231    #[inline]
232    pub const fn apparent(&self) -> Option<U256> {
233        match *self {
234            Self::Transfer(_) => None,
235            Self::Apparent(apparent) => Some(apparent),
236        }
237    }
238
239    /// Returns whether the call value is apparent, and not actually transferred.
240    #[inline]
241    pub const fn is_apparent(&self) -> bool {
242        matches!(self, Self::Apparent(_))
243    }
244}