revm_interpreter/interpreter_action/
call_inputs.rs

1use crate::primitives::{Address, Bytes, TxEnv, TxKind, U256};
2use core::ops::Range;
3use std::boxed::Box;
4
5/// Inputs for a call.
6#[derive(Clone, Debug, PartialEq, Eq, Hash)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub struct CallInputs {
9    /// The call data of the call.
10    pub input: Bytes,
11    /// The return memory offset where the output of the call is written.
12    ///
13    /// In EOF, this range is invalid as EOF calls do not write output to memory.
14    pub return_memory_offset: Range<usize>,
15    /// The gas limit of the call.
16    pub gas_limit: u64,
17    /// The account address of bytecode that is going to be executed.
18    ///
19    /// Previously `context.code_address`.
20    pub bytecode_address: Address,
21    /// Target address, this account storage is going to be modified.
22    ///
23    /// Previously `context.address`.
24    pub target_address: Address,
25    /// This caller is invoking the call.
26    ///
27    /// Previously `context.caller`.
28    pub caller: Address,
29    /// Call value.
30    ///
31    /// NOTE: This value may not necessarily be transferred from caller to callee, see [`CallValue`].
32    ///
33    /// Previously `transfer.value` or `context.apparent_value`.
34    pub value: CallValue,
35    /// The call scheme.
36    ///
37    /// Previously `context.scheme`.
38    pub scheme: CallScheme,
39    /// Whether the call is a static call, or is initiated inside a static call.
40    pub is_static: bool,
41    /// Whether the call is initiated from EOF bytecode.
42    pub is_eof: bool,
43}
44
45impl CallInputs {
46    /// Creates new call inputs.
47    ///
48    /// Returns `None` if the transaction is not a call.
49    pub fn new(tx_env: &TxEnv, gas_limit: u64) -> Option<Self> {
50        let TxKind::Call(target_address) = tx_env.transact_to else {
51            return None;
52        };
53        Some(CallInputs {
54            input: tx_env.data.clone(),
55            gas_limit,
56            target_address,
57            bytecode_address: target_address,
58            caller: tx_env.caller,
59            value: CallValue::Transfer(tx_env.value),
60            scheme: CallScheme::Call,
61            is_static: false,
62            is_eof: false,
63            return_memory_offset: 0..0,
64        })
65    }
66
67    /// Creates new boxed call inputs.
68    ///
69    /// Returns `None` if the transaction is not a call.
70    pub fn new_boxed(tx_env: &TxEnv, gas_limit: u64) -> Option<Box<Self>> {
71        Self::new(tx_env, gas_limit).map(Box::new)
72    }
73
74    /// Returns `true` if the call will transfer a non-zero value.
75    #[inline]
76    pub fn transfers_value(&self) -> bool {
77        self.value.transfer().is_some_and(|x| x > U256::ZERO)
78    }
79
80    /// Returns the transfer value.
81    ///
82    /// This is the value that is transferred from caller to callee, see [`CallValue`].
83    #[inline]
84    pub const fn transfer_value(&self) -> Option<U256> {
85        self.value.transfer()
86    }
87
88    /// Returns the **apparent** call value.
89    ///
90    /// This value is not actually transferred, see [`CallValue`].
91    #[inline]
92    pub const fn apparent_value(&self) -> Option<U256> {
93        self.value.apparent()
94    }
95
96    /// Returns the address of the transfer source account.
97    ///
98    /// This is only meaningful if `transfers_value` is `true`.
99    #[inline]
100    pub const fn transfer_from(&self) -> Address {
101        self.caller
102    }
103
104    /// Returns the address of the transfer target account.
105    ///
106    /// This is only meaningful if `transfers_value` is `true`.
107    #[inline]
108    pub const fn transfer_to(&self) -> Address {
109        self.target_address
110    }
111
112    /// Returns the call value, regardless of the transfer value type.
113    ///
114    /// NOTE: this value may not necessarily be transferred from caller to callee, see [`CallValue`].
115    #[inline]
116    pub const fn call_value(&self) -> U256 {
117        self.value.get()
118    }
119}
120
121/// Call scheme.
122#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
123#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
124pub enum CallScheme {
125    /// `CALL`.
126    Call,
127    /// `CALLCODE`
128    CallCode,
129    /// `DELEGATECALL`
130    DelegateCall,
131    /// `STATICCALL`
132    StaticCall,
133    /// `EXTCALL`
134    ExtCall,
135    /// `EXTSTATICCALL`
136    ExtStaticCall,
137    /// `EXTDELEGATECALL`
138    ExtDelegateCall,
139}
140
141impl CallScheme {
142    /// Returns true if it is EOF EXT*CALL.
143    pub fn is_ext(&self) -> bool {
144        matches!(
145            self,
146            Self::ExtCall | Self::ExtStaticCall | Self::ExtDelegateCall
147        )
148    }
149
150    /// Returns true if it is ExtDelegateCall.
151    pub fn is_ext_delegate_call(&self) -> bool {
152        matches!(self, Self::ExtDelegateCall)
153    }
154}
155
156/// Call value.
157#[derive(Clone, Debug, PartialEq, Eq, Hash)]
158#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
159pub enum CallValue {
160    /// Concrete value, transferred from caller to callee at the end of the transaction.
161    Transfer(U256),
162    /// Apparent value, that is **not** actually transferred.
163    ///
164    /// Set when in a `DELEGATECALL` call type, and used by the `CALLVALUE` opcode.
165    Apparent(U256),
166}
167
168impl Default for CallValue {
169    #[inline]
170    fn default() -> Self {
171        CallValue::Transfer(U256::ZERO)
172    }
173}
174
175impl CallValue {
176    /// Returns the call value, regardless of the type.
177    #[inline]
178    pub const fn get(&self) -> U256 {
179        match *self {
180            Self::Transfer(value) | Self::Apparent(value) => value,
181        }
182    }
183
184    /// Returns the transferred value, if any.
185    #[inline]
186    pub const fn transfer(&self) -> Option<U256> {
187        match *self {
188            Self::Transfer(transfer) => Some(transfer),
189            Self::Apparent(_) => None,
190        }
191    }
192
193    /// Returns whether the call value will be transferred.
194    #[inline]
195    pub const fn is_transfer(&self) -> bool {
196        matches!(self, Self::Transfer(_))
197    }
198
199    /// Returns the apparent value, if any.
200    #[inline]
201    pub const fn apparent(&self) -> Option<U256> {
202        match *self {
203            Self::Transfer(_) => None,
204            Self::Apparent(apparent) => Some(apparent),
205        }
206    }
207
208    /// Returns whether the call value is apparent, and not actually transferred.
209    #[inline]
210    pub const fn is_apparent(&self) -> bool {
211        matches!(self, Self::Apparent(_))
212    }
213}