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}