revm_interpreter/interpreter_action/
call_inputs.rs1use crate::interpreter_types::MemoryTr;
2use context_interface::{ContextTr, LocalContextTr};
3use core::ops::Range;
4use primitives::{Address, Bytes, B256, U256};
5use state::Bytecode;
6
7#[derive(Clone, Debug, PartialEq, Eq)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub enum CallInput {
13 Bytes(Bytes),
15 SharedBuffer(Range<usize>),
23}
24
25impl CallInput {
26 #[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 #[inline]
37 pub fn is_empty(&self) -> bool {
38 self.len() == 0
39 }
40
41 #[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 self.as_bytes_local(ctx.local())
48 }
49
50 #[inline]
52 pub fn as_bytes_local<'a, L: LocalContextTr>(
53 &'a self,
54 local: &'a L,
55 ) -> impl core::ops::Deref<Target = [u8]> + 'a {
56 match self {
57 Self::Bytes(bytes) => CallInputRef::Bytes(bytes.as_ref()),
58 Self::SharedBuffer(range) => {
59 CallInputRef::SharedBuffer(local.shared_memory_buffer_slice(range.clone()))
60 }
61 }
62 }
63
64 #[inline]
66 pub fn as_bytes_memory<'a, M: MemoryTr>(
67 &'a self,
68 memory: &'a M,
69 ) -> impl core::ops::Deref<Target = [u8]> + 'a {
70 match self {
71 Self::Bytes(bytes) => CallInputRef::Bytes(bytes.as_ref()),
72 Self::SharedBuffer(range) => {
73 CallInputRef::SharedBuffer(Some(memory.global_slice(range.clone())))
74 }
75 }
76 }
77
78 pub fn bytes<CTX: ContextTr>(&self, ctx: &CTX) -> Bytes {
88 self.bytes_local(ctx.local())
89 }
90
91 #[inline]
97 pub fn bytes_local<L: LocalContextTr>(&self, local: &L) -> Bytes {
98 match self {
99 CallInput::Bytes(bytes) => bytes.clone(),
100 CallInput::SharedBuffer(range) => local
101 .shared_memory_buffer_slice(range.clone())
102 .map(|b| Bytes::from(b.to_vec()))
103 .unwrap_or_default(),
104 }
105 }
106}
107
108impl Default for CallInput {
109 #[inline]
110 fn default() -> Self {
111 CallInput::Bytes(Bytes::new())
112 }
113}
114
115enum CallInputRef<'a> {
116 Bytes(&'a [u8]),
117 SharedBuffer(Option<core::cell::Ref<'a, [u8]>>),
118}
119
120impl core::ops::Deref for CallInputRef<'_> {
121 type Target = [u8];
122
123 #[inline]
124 fn deref(&self) -> &Self::Target {
125 match self {
126 Self::Bytes(x) => x,
127 Self::SharedBuffer(x) => x.as_deref().unwrap_or_default(),
128 }
129 }
130}
131
132#[derive(Clone, Debug, PartialEq, Eq)]
134#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
135pub struct CallInputs {
136 pub input: CallInput,
138 pub return_memory_offset: Range<usize>,
140 pub gas_limit: u64,
142 pub reservoir: u64,
144 pub bytecode_address: Address,
148 pub known_bytecode: (B256, Bytecode),
152 pub target_address: Address,
156 pub caller: Address,
160 pub value: CallValue,
166 pub scheme: CallScheme,
170 pub is_static: bool,
172}
173
174impl CallInputs {
175 #[inline]
177 pub fn transfers_value(&self) -> bool {
178 self.value.transfer().is_some_and(|x| x > U256::ZERO)
179 }
180
181 #[inline]
185 pub const fn transfer_value(&self) -> Option<U256> {
186 self.value.transfer()
187 }
188
189 #[inline]
193 pub const fn apparent_value(&self) -> Option<U256> {
194 self.value.apparent()
195 }
196
197 #[inline]
201 pub const fn transfer_from(&self) -> Address {
202 self.caller
203 }
204
205 #[inline]
209 pub const fn transfer_to(&self) -> Address {
210 self.target_address
211 }
212
213 #[inline]
217 pub const fn call_value(&self) -> U256 {
218 self.value.get()
219 }
220}
221
222#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
224#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
225pub enum CallScheme {
226 Call,
228 CallCode,
230 DelegateCall,
232 StaticCall,
234}
235
236impl CallScheme {
237 pub fn is_call(&self) -> bool {
239 matches!(self, Self::Call)
240 }
241
242 pub fn is_call_code(&self) -> bool {
244 matches!(self, Self::CallCode)
245 }
246
247 pub fn is_delegate_call(&self) -> bool {
249 matches!(self, Self::DelegateCall)
250 }
251
252 pub fn is_static_call(&self) -> bool {
254 matches!(self, Self::StaticCall)
255 }
256}
257
258#[derive(Clone, Debug, PartialEq, Eq, Hash)]
260#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
261pub enum CallValue {
262 Transfer(U256),
264 Apparent(U256),
268}
269
270impl Default for CallValue {
271 #[inline]
272 fn default() -> Self {
273 CallValue::Transfer(U256::ZERO)
274 }
275}
276
277impl CallValue {
278 #[inline]
280 pub const fn get(&self) -> U256 {
281 match *self {
282 Self::Transfer(value) | Self::Apparent(value) => value,
283 }
284 }
285
286 #[inline]
288 pub const fn transfer(&self) -> Option<U256> {
289 match *self {
290 Self::Transfer(transfer) => Some(transfer),
291 Self::Apparent(_) => None,
292 }
293 }
294
295 #[inline]
297 pub const fn is_transfer(&self) -> bool {
298 matches!(self, Self::Transfer(_))
299 }
300
301 #[inline]
303 pub const fn apparent(&self) -> Option<U256> {
304 match *self {
305 Self::Transfer(_) => None,
306 Self::Apparent(apparent) => Some(apparent),
307 }
308 }
309
310 #[inline]
312 pub const fn is_apparent(&self) -> bool {
313 matches!(self, Self::Apparent(_))
314 }
315}
316
317#[cfg(test)]
318mod tests {
319 use super::*;
320 use core::cell::RefCell;
321 use std::rc::Rc;
322
323 struct TestLocalContext {
324 buffer: Rc<RefCell<Vec<u8>>>,
325 }
326
327 impl TestLocalContext {
328 fn new(data: Vec<u8>) -> Self {
329 Self {
330 buffer: Rc::new(RefCell::new(data)),
331 }
332 }
333 }
334
335 impl LocalContextTr for TestLocalContext {
336 fn shared_memory_buffer(&self) -> &Rc<RefCell<Vec<u8>>> {
337 &self.buffer
338 }
339
340 fn clear(&mut self) {
341 self.buffer.borrow_mut().clear();
342 }
343
344 fn set_precompile_error_context(&mut self, _output: String) {}
345
346 fn take_precompile_error_context(&mut self) -> Option<String> {
347 None
348 }
349 }
350
351 #[test]
352 fn as_bytes_local_with_bytes_variant() {
353 let input = CallInput::Bytes(Bytes::from_static(b"hello"));
354 let local = TestLocalContext::new(vec![]);
355 let result = input.as_bytes_local(&local);
356 assert_eq!(&*result, b"hello");
357 }
358
359 #[test]
360 fn as_bytes_local_with_shared_buffer() {
361 let input = CallInput::SharedBuffer(1..4);
362 let local = TestLocalContext::new(vec![0, 1, 2, 3, 4]);
363 let result = input.as_bytes_local(&local);
364 assert_eq!(&*result, &[1, 2, 3]);
365 }
366
367 #[test]
368 fn as_bytes_local_with_out_of_range_buffer() {
369 let input = CallInput::SharedBuffer(10..20);
370 let local = TestLocalContext::new(vec![0, 1, 2]);
371 let result = input.as_bytes_local(&local);
372 assert_eq!(&*result, &[] as &[u8]);
374 }
375
376 #[test]
377 fn bytes_local_with_bytes_variant() {
378 let input = CallInput::Bytes(Bytes::from_static(b"world"));
379 let local = TestLocalContext::new(vec![]);
380 let result = input.bytes_local(&local);
381 assert_eq!(result, Bytes::from_static(b"world"));
382 }
383
384 #[test]
385 fn bytes_local_with_shared_buffer() {
386 let input = CallInput::SharedBuffer(0..3);
387 let local = TestLocalContext::new(vec![10, 20, 30, 40]);
388 let result = input.bytes_local(&local);
389 assert_eq!(result, Bytes::from(vec![10, 20, 30]));
390 }
391
392 #[test]
393 fn bytes_local_with_out_of_range_buffer() {
394 let input = CallInput::SharedBuffer(5..10);
395 let local = TestLocalContext::new(vec![0]);
396 let result = input.bytes_local(&local);
397 assert_eq!(result, Bytes::new());
398 }
399
400 #[test]
401 fn bytes_local_with_empty_range() {
402 let input = CallInput::SharedBuffer(2..2);
403 let local = TestLocalContext::new(vec![0, 1, 2, 3]);
404 let result = input.bytes_local(&local);
405 assert_eq!(result, Bytes::new());
406 }
407}