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 pub charged_new_account_state_gas: bool,
177}
178
179impl CallInputs {
180 #[inline]
182 pub fn transfers_value(&self) -> bool {
183 self.value.transfer().is_some_and(|x| x > U256::ZERO)
184 }
185
186 #[inline]
190 pub const fn transfer_value(&self) -> Option<U256> {
191 self.value.transfer()
192 }
193
194 #[inline]
198 pub const fn apparent_value(&self) -> Option<U256> {
199 self.value.apparent()
200 }
201
202 #[inline]
206 pub const fn transfer_from(&self) -> Address {
207 self.caller
208 }
209
210 #[inline]
214 pub const fn transfer_to(&self) -> Address {
215 self.target_address
216 }
217
218 #[inline]
222 pub const fn call_value(&self) -> U256 {
223 self.value.get()
224 }
225}
226
227#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
229#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
230pub enum CallScheme {
231 Call,
233 CallCode,
235 DelegateCall,
237 StaticCall,
239}
240
241impl CallScheme {
242 pub const fn is_call(&self) -> bool {
244 matches!(self, Self::Call)
245 }
246
247 pub const fn is_call_code(&self) -> bool {
249 matches!(self, Self::CallCode)
250 }
251
252 pub const fn is_delegate_call(&self) -> bool {
254 matches!(self, Self::DelegateCall)
255 }
256
257 pub const fn is_static_call(&self) -> bool {
259 matches!(self, Self::StaticCall)
260 }
261}
262
263#[derive(Clone, Debug, PartialEq, Eq, Hash)]
265#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
266pub enum CallValue {
267 Transfer(U256),
269 Apparent(U256),
273}
274
275impl Default for CallValue {
276 #[inline]
277 fn default() -> Self {
278 CallValue::Transfer(U256::ZERO)
279 }
280}
281
282impl CallValue {
283 #[inline]
285 pub const fn get(&self) -> U256 {
286 match *self {
287 Self::Transfer(value) | Self::Apparent(value) => value,
288 }
289 }
290
291 #[inline]
293 pub const fn transfer(&self) -> Option<U256> {
294 match *self {
295 Self::Transfer(transfer) => Some(transfer),
296 Self::Apparent(_) => None,
297 }
298 }
299
300 #[inline]
302 pub const fn is_transfer(&self) -> bool {
303 matches!(self, Self::Transfer(_))
304 }
305
306 #[inline]
308 pub const fn apparent(&self) -> Option<U256> {
309 match *self {
310 Self::Transfer(_) => None,
311 Self::Apparent(apparent) => Some(apparent),
312 }
313 }
314
315 #[inline]
317 pub const fn is_apparent(&self) -> bool {
318 matches!(self, Self::Apparent(_))
319 }
320}
321
322#[cfg(test)]
323mod tests {
324 use super::*;
325 use core::cell::RefCell;
326 use std::rc::Rc;
327
328 struct TestLocalContext {
329 buffer: Rc<RefCell<Vec<u8>>>,
330 }
331
332 impl TestLocalContext {
333 fn new(data: Vec<u8>) -> Self {
334 Self {
335 buffer: Rc::new(RefCell::new(data)),
336 }
337 }
338 }
339
340 impl LocalContextTr for TestLocalContext {
341 fn shared_memory_buffer(&self) -> &Rc<RefCell<Vec<u8>>> {
342 &self.buffer
343 }
344
345 fn clear(&mut self) {
346 self.buffer.borrow_mut().clear();
347 }
348
349 fn set_precompile_error_context(&mut self, _output: String) {}
350
351 fn take_precompile_error_context(&mut self) -> Option<String> {
352 None
353 }
354
355 fn cpsb(&self) -> u64 {
356 0
357 }
358
359 fn set_cpsb(&mut self, _cpsb: u64) {}
360 }
361
362 #[test]
363 fn as_bytes_local_with_bytes_variant() {
364 let input = CallInput::Bytes(Bytes::from_static(b"hello"));
365 let local = TestLocalContext::new(vec![]);
366 let result = input.as_bytes_local(&local);
367 assert_eq!(&*result, b"hello");
368 }
369
370 #[test]
371 fn as_bytes_local_with_shared_buffer() {
372 let input = CallInput::SharedBuffer(1..4);
373 let local = TestLocalContext::new(vec![0, 1, 2, 3, 4]);
374 let result = input.as_bytes_local(&local);
375 assert_eq!(&*result, &[1, 2, 3]);
376 }
377
378 #[test]
379 fn as_bytes_local_with_out_of_range_buffer() {
380 let input = CallInput::SharedBuffer(10..20);
381 let local = TestLocalContext::new(vec![0, 1, 2]);
382 let result = input.as_bytes_local(&local);
383 assert_eq!(&*result, &[] as &[u8]);
385 }
386
387 #[test]
388 fn bytes_local_with_bytes_variant() {
389 let input = CallInput::Bytes(Bytes::from_static(b"world"));
390 let local = TestLocalContext::new(vec![]);
391 let result = input.bytes_local(&local);
392 assert_eq!(result, Bytes::from_static(b"world"));
393 }
394
395 #[test]
396 fn bytes_local_with_shared_buffer() {
397 let input = CallInput::SharedBuffer(0..3);
398 let local = TestLocalContext::new(vec![10, 20, 30, 40]);
399 let result = input.bytes_local(&local);
400 assert_eq!(result, Bytes::from(vec![10, 20, 30]));
401 }
402
403 #[test]
404 fn bytes_local_with_out_of_range_buffer() {
405 let input = CallInput::SharedBuffer(5..10);
406 let local = TestLocalContext::new(vec![0]);
407 let result = input.bytes_local(&local);
408 assert_eq!(result, Bytes::new());
409 }
410
411 #[test]
412 fn bytes_local_with_empty_range() {
413 let input = CallInput::SharedBuffer(2..2);
414 let local = TestLocalContext::new(vec![0, 1, 2, 3]);
415 let result = input.bytes_local(&local);
416 assert_eq!(result, Bytes::new());
417 }
418}