Skip to main content

revm_interpreter/interpreter_action/
create_inputs.rs

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