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}