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    /// Cached created address. This is computed lazily and cached to avoid
22    /// redundant keccak computations when inspectors call `created_address`.
23    #[cfg_attr(feature = "serde", serde(skip))]
24    cached_address: OnceCell<Address>,
25    /// Cached init code hash. Shared between `created_address()` (for CREATE2)
26    /// and frame initialization (for `ExtBytecode`), ensuring keccak256 of the
27    /// init code is computed at most once.
28    #[cfg_attr(feature = "serde", serde(skip))]
29    cached_init_code_hash: OnceCell<B256>,
30}
31
32impl CreateInputs {
33    /// Creates a new `CreateInputs` instance.
34    pub const fn new(
35        caller: Address,
36        scheme: CreateScheme,
37        value: U256,
38        init_code: Bytes,
39        gas_limit: u64,
40        reservoir: u64,
41    ) -> Self {
42        Self {
43            caller,
44            scheme,
45            value,
46            init_code,
47            gas_limit,
48            reservoir,
49            cached_address: OnceCell::new(),
50            cached_init_code_hash: OnceCell::new(),
51        }
52    }
53
54    /// Returns the address that this create call will create.
55    ///
56    /// The result is cached to avoid redundant keccak computations.
57    pub fn created_address(&self, nonce: u64) -> Address {
58        *self.cached_address.get_or_init(|| match self.scheme {
59            CreateScheme::Create => self.caller.create(nonce),
60            CreateScheme::Create2 { salt } => self
61                .caller
62                .create2(salt.to_be_bytes(), self.init_code_hash()),
63            CreateScheme::Custom { address } => address,
64        })
65    }
66
67    /// Returns the keccak256 hash of the init code.
68    ///
69    /// The result is cached so that `created_address()` and frame initialization
70    /// share a single hash computation.
71    pub fn init_code_hash(&self) -> B256 {
72        *self
73            .cached_init_code_hash
74            .get_or_init(|| keccak256(self.init_code.as_ref()))
75    }
76
77    /// Returns the caller address of the EVM.
78    pub const fn caller(&self) -> Address {
79        self.caller
80    }
81
82    /// Returns the create scheme of the EVM.
83    pub const fn scheme(&self) -> CreateScheme {
84        self.scheme
85    }
86
87    /// Returns the value to transfer.
88    pub const fn value(&self) -> U256 {
89        self.value
90    }
91
92    /// Returns the init code of the contract.
93    pub const fn init_code(&self) -> &Bytes {
94        &self.init_code
95    }
96
97    /// Returns the gas limit of the call.
98    pub const fn gas_limit(&self) -> u64 {
99        self.gas_limit
100    }
101
102    /// Set call
103    pub const fn set_call(&mut self, caller: Address) {
104        self.caller = caller;
105        self.cached_address = OnceCell::new();
106    }
107
108    /// Set scheme
109    pub const fn set_scheme(&mut self, scheme: CreateScheme) {
110        self.scheme = scheme;
111        self.cached_address = OnceCell::new();
112    }
113
114    /// Set value
115    pub const fn set_value(&mut self, value: U256) {
116        self.value = value;
117    }
118
119    /// Set init code
120    pub fn set_init_code(&mut self, init_code: Bytes) {
121        self.init_code = init_code;
122        self.cached_address = OnceCell::new();
123        self.cached_init_code_hash = OnceCell::new();
124    }
125
126    /// Set gas limit
127    pub const fn set_gas_limit(&mut self, gas_limit: u64) {
128        self.gas_limit = gas_limit;
129    }
130
131    /// Returns the state gas reservoir (EIP-8037).
132    pub const fn reservoir(&self) -> u64 {
133        self.reservoir
134    }
135
136    /// Set the state gas reservoir (EIP-8037).
137    pub const fn set_reservoir(&mut self, reservoir: u64) {
138        self.reservoir = reservoir;
139    }
140}