revm_context/
cfg.rs

1//! This module contains [`CfgEnv`] and implements [`Cfg`] trait for it.
2pub use context_interface::Cfg;
3
4use primitives::{eip170::MAX_CODE_SIZE, hardfork::SpecId};
5
6/// EVM configuration
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8#[derive(Clone, Debug, Eq, PartialEq)]
9#[non_exhaustive]
10pub struct CfgEnv<SPEC = SpecId> {
11    /// Chain ID of the EVM. Used in CHAINID opcode and transaction's chain ID check.
12    ///
13    /// Chain ID is introduced EIP-155.
14    pub chain_id: u64,
15
16    /// Whether to check the transaction's chain ID.
17    ///
18    /// If set to `false`, the transaction's chain ID check will be skipped.
19    pub tx_chain_id_check: bool,
20
21    /// Specification for EVM represent the hardfork
22    pub spec: SPEC,
23    /// If some it will effects EIP-170: Contract code size limit.
24    ///
25    /// Useful to increase this because of tests.
26    ///
27    /// By default it is `0x6000` (~25kb).
28    pub limit_contract_code_size: Option<usize>,
29    /// Skips the nonce validation against the account's nonce
30    pub disable_nonce_check: bool,
31    /// Blob max count. EIP-7840 Add blob schedule to EL config files.
32    ///
33    /// If this config is not set, the check for max blobs will be skipped.
34    pub blob_max_count: Option<u64>,
35    /// Blob base fee update fraction. EIP-4844 Blob base fee update fraction.
36    ///
37    /// If this config is not set, the blob base fee update fraction will be set to the default value.
38    /// See also [CfgEnv::blob_base_fee_update_fraction].
39    ///
40    /// Default values for Cancun is [`primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN`]
41    /// and for Prague is [`primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE`].
42    pub blob_base_fee_update_fraction: Option<u64>,
43    /// A hard memory limit in bytes beyond which
44    /// [OutOfGasError::Memory][context_interface::result::OutOfGasError::Memory] cannot be resized.
45    ///
46    /// In cases where the gas limit may be extraordinarily high, it is recommended to set this to
47    /// a sane value to prevent memory allocation panics.
48    ///
49    /// Defaults to `2^32 - 1` bytes per EIP-1985.
50    #[cfg(feature = "memory_limit")]
51    pub memory_limit: u64,
52    /// Skip balance checks if `true`
53    ///
54    /// Adds transaction cost to balance to ensure execution doesn't fail.
55    ///
56    /// By default, it is set to `false`.
57    #[cfg(feature = "optional_balance_check")]
58    pub disable_balance_check: bool,
59    /// There are use cases where it's allowed to provide a gas limit that's higher than a block's gas limit.
60    ///
61    /// To that end, you can disable the block gas limit validation.
62    ///
63    /// By default, it is set to `false`.
64    #[cfg(feature = "optional_block_gas_limit")]
65    pub disable_block_gas_limit: bool,
66    /// EIP-3607 rejects transactions from senders with deployed code
67    ///
68    /// In development, it can be desirable to simulate calls from contracts, which this setting allows.
69    ///
70    /// By default, it is set to `false`.
71    #[cfg(feature = "optional_eip3607")]
72    pub disable_eip3607: bool,
73    /// Disables base fee checks for EIP-1559 transactions
74    ///
75    /// This is useful for testing method calls with zero gas price.
76    ///
77    /// By default, it is set to `false`.
78    #[cfg(feature = "optional_no_base_fee")]
79    pub disable_base_fee: bool,
80}
81
82impl CfgEnv {
83    /// Creates new `CfgEnv` with default values.
84    pub fn new() -> Self {
85        Self::default()
86    }
87}
88
89impl<SPEC: Into<SpecId> + Copy> CfgEnv<SPEC> {
90    /// Returns the blob base fee update fraction from [CfgEnv::blob_base_fee_update_fraction].
91    ///
92    /// If this field is not set, return the default value for the spec.
93    ///
94    /// Default values for Cancun is [`primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN`]
95    /// and for Prague is [`primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE`].
96    pub fn blob_base_fee_update_fraction(&mut self) -> u64 {
97        self.blob_base_fee_update_fraction.unwrap_or_else(|| {
98            let spec: SpecId = self.spec.into();
99            if spec.is_enabled_in(SpecId::PRAGUE) {
100                primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE
101            } else {
102                primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN
103            }
104        })
105    }
106}
107
108impl<SPEC> CfgEnv<SPEC> {
109    /// Create new `CfgEnv` with default values and specified spec.
110    pub fn new_with_spec(spec: SPEC) -> Self {
111        Self {
112            chain_id: 1,
113            tx_chain_id_check: false,
114            limit_contract_code_size: None,
115            spec,
116            disable_nonce_check: false,
117            blob_max_count: None,
118            blob_base_fee_update_fraction: None,
119            #[cfg(feature = "memory_limit")]
120            memory_limit: (1 << 32) - 1,
121            #[cfg(feature = "optional_balance_check")]
122            disable_balance_check: false,
123            #[cfg(feature = "optional_block_gas_limit")]
124            disable_block_gas_limit: false,
125            #[cfg(feature = "optional_eip3607")]
126            disable_eip3607: false,
127            #[cfg(feature = "optional_no_base_fee")]
128            disable_base_fee: false,
129        }
130    }
131
132    /// Consumes `self` and returns a new `CfgEnv` with the specified chain ID.
133    pub fn with_chain_id(mut self, chain_id: u64) -> Self {
134        self.chain_id = chain_id;
135        self
136    }
137
138    /// Enables the transaction's chain ID check.
139    pub fn enable_tx_chain_id_check(mut self) -> Self {
140        self.tx_chain_id_check = true;
141        self
142    }
143
144    /// Disables the transaction's chain ID check.
145    pub fn disable_tx_chain_id_check(mut self) -> Self {
146        self.tx_chain_id_check = false;
147        self
148    }
149
150    /// Consumes `self` and returns a new `CfgEnv` with the specified spec.
151    pub fn with_spec<OSPEC: Into<SpecId>>(self, spec: OSPEC) -> CfgEnv<OSPEC> {
152        CfgEnv {
153            chain_id: self.chain_id,
154            tx_chain_id_check: self.tx_chain_id_check,
155            limit_contract_code_size: self.limit_contract_code_size,
156            spec,
157            disable_nonce_check: self.disable_nonce_check,
158            blob_max_count: self.blob_max_count,
159            blob_base_fee_update_fraction: self.blob_base_fee_update_fraction,
160            #[cfg(feature = "memory_limit")]
161            memory_limit: self.memory_limit,
162            #[cfg(feature = "optional_balance_check")]
163            disable_balance_check: self.disable_balance_check,
164            #[cfg(feature = "optional_block_gas_limit")]
165            disable_block_gas_limit: self.disable_block_gas_limit,
166            #[cfg(feature = "optional_eip3607")]
167            disable_eip3607: self.disable_eip3607,
168            #[cfg(feature = "optional_no_base_fee")]
169            disable_base_fee: self.disable_base_fee,
170        }
171    }
172
173    /// Sets the blob target
174    pub fn with_blob_max_count(mut self, blob_max_count: u64) -> Self {
175        self.set_blob_max_count(blob_max_count);
176        self
177    }
178
179    /// Sets the blob target
180    pub fn set_blob_max_count(&mut self, blob_max_count: u64) {
181        self.blob_max_count = Some(blob_max_count);
182    }
183
184    /// Clears the blob target and max count over hardforks.
185    pub fn clear_blob_max_count(&mut self) {
186        self.blob_max_count = None;
187    }
188}
189
190impl<SPEC: Into<SpecId> + Copy> Cfg for CfgEnv<SPEC> {
191    type Spec = SPEC;
192
193    fn chain_id(&self) -> u64 {
194        self.chain_id
195    }
196
197    fn spec(&self) -> Self::Spec {
198        self.spec
199    }
200
201    fn tx_chain_id_check(&self) -> bool {
202        self.tx_chain_id_check
203    }
204
205    #[inline]
206    fn blob_max_count(&self) -> Option<u64> {
207        self.blob_max_count
208    }
209
210    fn max_code_size(&self) -> usize {
211        self.limit_contract_code_size.unwrap_or(MAX_CODE_SIZE)
212    }
213
214    fn is_eip3607_disabled(&self) -> bool {
215        cfg_if::cfg_if! {
216            if #[cfg(feature = "optional_eip3607")] {
217                self.disable_eip3607
218            } else {
219                false
220            }
221        }
222    }
223
224    fn is_balance_check_disabled(&self) -> bool {
225        cfg_if::cfg_if! {
226            if #[cfg(feature = "optional_balance_check")] {
227                self.disable_balance_check
228            } else {
229                false
230            }
231        }
232    }
233
234    /// Returns `true` if the block gas limit is disabled.
235    fn is_block_gas_limit_disabled(&self) -> bool {
236        cfg_if::cfg_if! {
237            if #[cfg(feature = "optional_block_gas_limit")] {
238                self.disable_block_gas_limit
239            } else {
240                false
241            }
242        }
243    }
244
245    fn is_nonce_check_disabled(&self) -> bool {
246        self.disable_nonce_check
247    }
248
249    fn is_base_fee_check_disabled(&self) -> bool {
250        cfg_if::cfg_if! {
251            if #[cfg(feature = "optional_no_base_fee")] {
252                self.disable_base_fee
253            } else {
254                false
255            }
256        }
257    }
258}
259
260impl<SPEC: Default> Default for CfgEnv<SPEC> {
261    fn default() -> Self {
262        Self::new_with_spec(SPEC::default())
263    }
264}
265
266#[cfg(test)]
267mod test {
268    use super::*;
269
270    #[test]
271    fn blob_max_and_target_count() {
272        let cfg: CfgEnv = Default::default();
273        assert_eq!(cfg.blob_max_count(), None);
274    }
275}