Skip to content

Commit 76e22ba

Browse files
authored
feat: add helper methods to CallInputs (bluealloy#1345)
1 parent bcdc652 commit 76e22ba

File tree

5 files changed

+137
-44
lines changed

5 files changed

+137
-44
lines changed

crates/interpreter/src/instructions/contract.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use crate::{
1111
instructions::utility::read_u16,
1212
interpreter::Interpreter,
1313
primitives::{Address, Bytes, Eof, Spec, SpecId::*, B256, U256},
14-
CallInputs, CallScheme, CreateInputs, CreateScheme, EOFCreateInput, Host, InstructionResult,
15-
InterpreterAction, InterpreterResult, LoadAccountResult, TransferValue, MAX_INITCODE_SIZE,
14+
CallInputs, CallScheme, CallValue, CreateInputs, CreateScheme, EOFCreateInput, Host,
15+
InstructionResult, InterpreterAction, InterpreterResult, LoadAccountResult, MAX_INITCODE_SIZE,
1616
};
1717
use core::{cmp::max, ops::Range};
1818
use std::boxed::Box;
@@ -304,7 +304,7 @@ pub fn extcall<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host
304304
target_address,
305305
caller: interpreter.contract.target_address,
306306
bytecode_address: target_address,
307-
value: TransferValue::Value(value),
307+
value: CallValue::Transfer(value),
308308
scheme: CallScheme::Call,
309309
is_static: interpreter.is_static,
310310
is_eof: true,
@@ -336,7 +336,7 @@ pub fn extdcall<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, hos
336336
target_address,
337337
caller: interpreter.contract.target_address,
338338
bytecode_address: target_address,
339-
value: TransferValue::ApparentValue(interpreter.contract.call_value),
339+
value: CallValue::Apparent(interpreter.contract.call_value),
340340
// TODO(EOF) should be EofDelegateCall?
341341
scheme: CallScheme::DelegateCall,
342342
is_static: interpreter.is_static,
@@ -368,7 +368,7 @@ pub fn extscall<H: Host + ?Sized>(interpreter: &mut Interpreter, host: &mut H) {
368368
target_address,
369369
caller: interpreter.contract.target_address,
370370
bytecode_address: target_address,
371-
value: TransferValue::Value(U256::ZERO),
371+
value: CallValue::Transfer(U256::ZERO),
372372
scheme: CallScheme::Call,
373373
is_static: interpreter.is_static,
374374
is_eof: true,
@@ -494,7 +494,7 @@ pub fn call<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &
494494
target_address: to,
495495
caller: interpreter.contract.target_address,
496496
bytecode_address: to,
497-
value: TransferValue::Value(value),
497+
value: CallValue::Transfer(value),
498498
scheme: CallScheme::Call,
499499
is_static: interpreter.is_static,
500500
is_eof: false,
@@ -545,7 +545,7 @@ pub fn call_code<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, ho
545545
target_address: interpreter.contract.target_address,
546546
caller: interpreter.contract.target_address,
547547
bytecode_address: to,
548-
value: TransferValue::Value(value),
548+
value: CallValue::Transfer(value),
549549
scheme: CallScheme::CallCode,
550550
is_static: interpreter.is_static,
551551
is_eof: false,
@@ -586,7 +586,7 @@ pub fn delegate_call<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter
586586
target_address: interpreter.contract.target_address,
587587
caller: interpreter.contract.caller,
588588
bytecode_address: to,
589-
value: TransferValue::ApparentValue(interpreter.contract.call_value),
589+
value: CallValue::Apparent(interpreter.contract.call_value),
590590
scheme: CallScheme::DelegateCall,
591591
is_static: interpreter.is_static,
592592
is_eof: false,
@@ -627,7 +627,7 @@ pub fn static_call<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter,
627627
target_address: to,
628628
caller: interpreter.contract.target_address,
629629
bytecode_address: to,
630-
value: TransferValue::Value(U256::ZERO),
630+
value: CallValue::Transfer(U256::ZERO),
631631
scheme: CallScheme::StaticCall,
632632
is_static: true,
633633
is_eof: false,

crates/interpreter/src/interpreter_action.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ mod create_outcome;
55
mod eof_create_inputs;
66
mod eof_create_outcome;
77

8-
pub use call_inputs::{CallInputs, CallScheme, TransferValue};
8+
pub use call_inputs::{CallInputs, CallScheme, CallValue};
99
pub use call_outcome::CallOutcome;
1010
pub use create_inputs::{CreateInputs, CreateScheme};
1111
pub use create_outcome::CreateOutcome;

crates/interpreter/src/interpreter_action/call_inputs.rs

+120-27
Original file line numberDiff line numberDiff line change
@@ -9,65 +9,116 @@ pub struct CallInputs {
99
/// The call data of the call.
1010
pub input: Bytes,
1111
/// The return memory offset where the output of the call is written.
12-
/// For EOF this range is invalid as EOF does write output to memory.
12+
///
13+
/// In EOF, this range is invalid as EOF calls do not write output to memory.
1314
pub return_memory_offset: Range<usize>,
1415
/// The gas limit of the call.
1516
pub gas_limit: u64,
16-
/// The account address of bytecode that is going to be executed.
17+
/// The account address of bytecode that is going to be executed.
18+
///
19+
/// Previously `context.code_address`.
1720
pub bytecode_address: Address,
1821
/// Target address, this account storage is going to be modified.
22+
///
23+
/// Previously `context.address`.
1924
pub target_address: Address,
2025
/// This caller is invoking the call.
26+
///
27+
/// Previously `context.caller`.
2128
pub caller: Address,
22-
/// Value that is transferred in Ether.
29+
/// Call value.
30+
///
31+
/// NOTE: This value may not necessarily be transferred from caller to callee, see [`CallValue`].
2332
///
24-
/// If enum is [`TransferValue::Value`] balance is transferer from `caller` to the `target_address`.
33+
/// Previously `transfer.value` or `context.apparent_value`.
34+
pub value: CallValue,
35+
/// The call scheme.
2536
///
26-
/// If enum is [`TransferValue::ApparentValue`] balance transfer is **not**
27-
/// done and apparent value is used by CALLVALUE opcode. Used by delegate call.
28-
pub value: TransferValue,
29-
/// The scheme used for the call. Call, callcode, delegatecall or staticcall.
37+
/// Previously `context.scheme`.
3038
pub scheme: CallScheme,
31-
/// Whether this is a static call.
39+
/// Whether the call is initiated inside a static call.
3240
pub is_static: bool,
33-
/// Call is initiated from EOF bytecode.
41+
/// Whether the call is initiated from EOF bytecode.
3442
pub is_eof: bool,
3543
}
3644

3745
impl CallInputs {
3846
/// Creates new call inputs.
47+
///
48+
/// Returns `None` if the transaction is not a call.
3949
pub fn new(tx_env: &TxEnv, gas_limit: u64) -> Option<Self> {
4050
let TransactTo::Call(target_address) = tx_env.transact_to else {
4151
return None;
4252
};
43-
4453
Some(CallInputs {
4554
input: tx_env.data.clone(),
4655
gas_limit,
4756
target_address,
4857
bytecode_address: target_address,
4958
caller: tx_env.caller,
50-
value: TransferValue::Value(tx_env.value),
59+
value: CallValue::Transfer(tx_env.value),
5160
scheme: CallScheme::Call,
5261
is_static: false,
5362
is_eof: false,
5463
return_memory_offset: 0..0,
5564
})
5665
}
5766

58-
/// Returns boxed call inputs.
67+
/// Creates new boxed call inputs.
68+
///
69+
/// Returns `None` if the transaction is not a call.
5970
pub fn new_boxed(tx_env: &TxEnv, gas_limit: u64) -> Option<Box<Self>> {
6071
Self::new(tx_env, gas_limit).map(Box::new)
6172
}
6273

63-
/// Return call value
64-
pub fn call_value(&self) -> U256 {
65-
let (TransferValue::Value(value) | TransferValue::ApparentValue(value)) = self.value;
66-
value
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()
67118
}
68119
}
69120

70-
/// Call schemes.
121+
/// Call scheme.
71122
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
72123
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
73124
pub enum CallScheme {
@@ -81,19 +132,61 @@ pub enum CallScheme {
81132
StaticCall,
82133
}
83134

84-
/// Transfered value from caller to callee.
135+
/// Call value.
85136
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
86137
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
87-
pub enum TransferValue {
88-
/// Transfer value from caller to callee.
89-
Value(U256),
90-
/// For delegate call, the value is not transferred but
91-
/// apparent value is used for CALLVALUE opcode
92-
ApparentValue(U256),
138+
pub enum CallValue {
139+
/// Concrete value, transferred from caller to callee at the end of the transaction.
140+
Transfer(U256),
141+
/// Apparent value, that is **not** actually transferred.
142+
///
143+
/// Set when in a `DELEGATECALL` call type, and used by the `CALLVALUE` opcode.
144+
Apparent(U256),
93145
}
94146

95-
impl Default for TransferValue {
147+
impl Default for CallValue {
148+
#[inline]
96149
fn default() -> Self {
97-
TransferValue::Value(U256::ZERO)
150+
CallValue::Transfer(U256::ZERO)
151+
}
152+
}
153+
154+
impl CallValue {
155+
/// Returns the call value, regardless of the type.
156+
#[inline]
157+
pub const fn get(&self) -> U256 {
158+
match *self {
159+
Self::Transfer(value) | Self::Apparent(value) => value,
160+
}
161+
}
162+
163+
/// Returns the transferred value, if any.
164+
#[inline]
165+
pub const fn transfer(&self) -> Option<U256> {
166+
match *self {
167+
Self::Transfer(transfer) => Some(transfer),
168+
Self::Apparent(_) => None,
169+
}
170+
}
171+
172+
/// Returns whether the call value will be transferred.
173+
#[inline]
174+
pub const fn is_transfer(&self) -> bool {
175+
matches!(self, Self::Transfer(_))
176+
}
177+
178+
/// Returns the apparent value, if any.
179+
#[inline]
180+
pub const fn apparent(&self) -> Option<U256> {
181+
match *self {
182+
Self::Transfer(_) => None,
183+
Self::Apparent(apparent) => Some(apparent),
184+
}
185+
}
186+
187+
/// Returns whether the call value is apparent, and not actually transferred.
188+
#[inline]
189+
pub const fn is_apparent(&self) -> bool {
190+
matches!(self, Self::Apparent(_))
98191
}
99192
}

crates/interpreter/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ pub use interpreter::{
3838
EMPTY_SHARED_MEMORY, STACK_LIMIT,
3939
};
4040
pub use interpreter_action::{
41-
CallInputs, CallOutcome, CallScheme, CreateInputs, CreateOutcome, CreateScheme, EOFCreateInput,
42-
EOFCreateOutcome, InterpreterAction, TransferValue,
41+
CallInputs, CallOutcome, CallScheme, CallValue, CreateInputs, CreateOutcome, CreateScheme,
42+
EOFCreateInput, EOFCreateOutcome, InterpreterAction,
4343
};
4444
pub use opcode::{Instruction, OpCode, OPCODE_INFO_JUMPTABLE};
4545
pub use primitives::{MAX_CODE_SIZE, MAX_INITCODE_SIZE};

crates/revm/src/context/evm_context.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use revm_interpreter::TransferValue;
1+
use revm_interpreter::CallValue;
22

33
use super::inner_evm_context::InnerEvmContext;
44
use crate::{
@@ -175,11 +175,11 @@ impl<DB: Database> EvmContext<DB> {
175175
// Touch address. For "EIP-158 State Clear", this will erase empty accounts.
176176
match inputs.value {
177177
// if transfer value is zero, do the touch.
178-
TransferValue::Value(value) if value == U256::ZERO => {
178+
CallValue::Transfer(value) if value == U256::ZERO => {
179179
self.load_account(inputs.target_address)?;
180180
self.journaled_state.touch(&inputs.target_address);
181181
}
182-
TransferValue::Value(value) => {
182+
CallValue::Transfer(value) => {
183183
// Transfer value from caller to called account
184184
if let Some(result) = self.inner.journaled_state.transfer(
185185
&inputs.caller,
@@ -241,7 +241,7 @@ pub(crate) mod test_utils {
241241
bytecode_address: to,
242242
target_address: to,
243243
caller: MOCK_CALLER,
244-
value: TransferValue::Value(U256::ZERO),
244+
value: CallValue::Transfer(U256::ZERO),
245245
scheme: revm_interpreter::CallScheme::Call,
246246
is_eof: false,
247247
is_static: false,
@@ -344,7 +344,7 @@ mod tests {
344344
let mut evm_context = test_utils::create_empty_evm_context(Box::new(env), db);
345345
let contract = address!("dead10000000000000000000000000000001dead");
346346
let mut call_inputs = test_utils::create_mock_call_inputs(contract);
347-
call_inputs.value = TransferValue::Value(U256::from(1));
347+
call_inputs.value = CallValue::Transfer(U256::from(1));
348348
let res = evm_context.make_call_frame(&call_inputs);
349349
let Ok(FrameOrResult::Result(result)) = res else {
350350
panic!("Expected FrameOrResult::Result");

0 commit comments

Comments
 (0)