1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
use context_interface::CreateScheme;
use core::cell::OnceCell;
use primitives::{keccak256, Address, Bytes, B256, U256};
/// Inputs for a create call
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CreateInputs {
/// Caller address of the EVM
caller: Address,
/// The create scheme
scheme: CreateScheme,
/// The value to transfer
value: U256,
/// The init code of the contract
init_code: Bytes,
/// The gas limit of the call
gas_limit: u64,
/// State gas reservoir (EIP-8037). Passed from parent frame to child frame.
reservoir: u64,
/// EIP-8037: whether the CREATE opcode charged the conditional
/// `create_state_gas` on the parent's tracker (the destination did not
/// exist at access time). Propagated onto [`crate::CreateOutcome`] so the
/// parent refunds the charge when the create fails.
charged_create_state_gas: bool,
/// Cached created address. This is computed lazily and cached to avoid
/// redundant keccak computations when inspectors call `created_address`.
#[cfg_attr(feature = "serde", serde(skip))]
cached_address: OnceCell<Address>,
/// Cached init code hash. Shared between `created_address()` (for CREATE2)
/// and frame initialization (for `ExtBytecode`), ensuring keccak256 of the
/// init code is computed at most once.
#[cfg_attr(feature = "serde", serde(skip))]
cached_init_code_hash: OnceCell<B256>,
}
impl CreateInputs {
/// Creates a new `CreateInputs` instance.
pub const fn new(
caller: Address,
scheme: CreateScheme,
value: U256,
init_code: Bytes,
gas_limit: u64,
reservoir: u64,
) -> Self {
Self {
caller,
scheme,
value,
init_code,
gas_limit,
reservoir,
charged_create_state_gas: false,
cached_address: OnceCell::new(),
cached_init_code_hash: OnceCell::new(),
}
}
/// Returns the address that this create call will create.
///
/// The result is cached to avoid redundant keccak computations.
pub fn created_address(&self, nonce: u64) -> Address {
*self.cached_address.get_or_init(|| match self.scheme {
CreateScheme::Create => self.caller.create(nonce),
CreateScheme::Create2 { salt } => self
.caller
.create2(salt.to_be_bytes(), self.init_code_hash()),
CreateScheme::Custom { address } => address,
})
}
/// Returns the keccak256 hash of the init code.
///
/// The result is cached so that `created_address()` and frame initialization
/// share a single hash computation.
pub fn init_code_hash(&self) -> B256 {
*self
.cached_init_code_hash
.get_or_init(|| keccak256(self.init_code.as_ref()))
}
/// Returns the caller address of the EVM.
pub const fn caller(&self) -> Address {
self.caller
}
/// Returns the create scheme of the EVM.
pub const fn scheme(&self) -> CreateScheme {
self.scheme
}
/// Returns the value to transfer.
pub const fn value(&self) -> U256 {
self.value
}
/// Returns the init code of the contract.
pub const fn init_code(&self) -> &Bytes {
&self.init_code
}
/// Returns the gas limit of the call.
pub const fn gas_limit(&self) -> u64 {
self.gas_limit
}
/// Set call
pub const fn set_call(&mut self, caller: Address) {
self.caller = caller;
self.cached_address = OnceCell::new();
}
/// Set scheme
pub const fn set_scheme(&mut self, scheme: CreateScheme) {
self.scheme = scheme;
self.cached_address = OnceCell::new();
}
/// Set value
pub const fn set_value(&mut self, value: U256) {
self.value = value;
}
/// Set init code
pub fn set_init_code(&mut self, init_code: Bytes) {
self.init_code = init_code;
self.cached_address = OnceCell::new();
self.cached_init_code_hash = OnceCell::new();
}
/// Set gas limit
pub const fn set_gas_limit(&mut self, gas_limit: u64) {
self.gas_limit = gas_limit;
}
/// Returns the state gas reservoir (EIP-8037).
pub const fn reservoir(&self) -> u64 {
self.reservoir
}
/// Returns whether the CREATE opcode charged the conditional
/// `create_state_gas` (EIP-8037).
pub const fn charged_create_state_gas(&self) -> bool {
self.charged_create_state_gas
}
/// Marks that the CREATE opcode charged the conditional `create_state_gas`
/// on the parent's tracker (EIP-8037).
pub const fn set_charged_create_state_gas(&mut self, charged: bool) {
self.charged_create_state_gas = charged;
}
/// Sets the state gas reservoir (EIP-8037).
pub const fn set_reservoir(&mut self, reservoir: u64) {
self.reservoir = reservoir;
}
}