Skip to main content

revm_context/
cfg.rs

1//! This module contains [`CfgEnv`] and implements [`Cfg`] trait for it.
2pub use context_interface::Cfg;
3
4use context_interface::cfg::GasParams;
5use primitives::{eip170, eip3860, eip7825, hardfork::SpecId};
6
7/// EVM configuration
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9#[derive(Clone, Debug, Eq, PartialEq)]
10#[non_exhaustive]
11pub struct CfgEnv<SPEC = SpecId> {
12    /// Specification for EVM represent the hardfork
13    ///
14    /// [`CfgEnv::new_with_spec`] is going to set both gas params and spec.
15    ///
16    /// As GasParams is spec dependent, it is recommended to use one of following function to set both of them.
17    /// [`CfgEnv::set_spec_and_mainnet_gas_params`], [`CfgEnv::with_mainnet_gas_params`], [`CfgEnv::with_mainnet_gas_params`]
18    pub spec: SPEC,
19
20    /// Gas params for the EVM. Use [`CfgEnv::set_gas_params`] to set the gas params.
21    /// If gas_params was not set it will be set to the default gas params for the spec.
22    pub gas_params: GasParams,
23
24    /// Chain ID of the EVM. Used in CHAINID opcode and transaction's chain ID check.
25    ///
26    /// Chain ID is introduced EIP-155.
27    pub chain_id: u64,
28
29    /// Whether to check the transaction's chain ID.
30    ///
31    /// If set to `false`, the transaction's chain ID check will be skipped.
32    pub tx_chain_id_check: bool,
33
34    /// Contract code size limit override.
35    ///
36    /// If None, the limit will be determined by the SpecId (EIP-170 or EIP-7907) at runtime.
37    /// If Some, this specific limit will be used regardless of SpecId.
38    ///
39    /// Useful to increase this because of tests.
40    pub limit_contract_code_size: Option<usize>,
41    /// Contract initcode size limit override.
42    ///
43    /// If None, the limit will check if `limit_contract_code_size` is set.
44    /// If it is set, it will double it for a limit.
45    /// If it is not set, the limit will be determined by the SpecId (EIP-170 or EIP-7907) at runtime.
46    ///
47    /// Useful to increase this because of tests.
48    pub limit_contract_initcode_size: Option<usize>,
49    /// Skips the nonce validation against the account's nonce
50    pub disable_nonce_check: bool,
51    /// Blob max count. EIP-7840 Add blob schedule to EL config files.
52    ///
53    /// If this config is not set, the check for max blobs will be skipped.
54    pub max_blobs_per_tx: Option<u64>,
55    /// Blob base fee update fraction. EIP-4844 Blob base fee update fraction.
56    ///
57    /// If this config is not set, the blob base fee update fraction will be set to the default value.
58    /// See also [CfgEnv::blob_base_fee_update_fraction].
59    ///
60    /// Default values for Cancun is [`primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN`]
61    /// and for Prague is [`primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE`].
62    pub blob_base_fee_update_fraction: Option<u64>,
63    /// Configures the gas limit cap for the transaction.
64    ///
65    /// If `None`, default value defined by spec will be used.
66    ///
67    /// Introduced in Osaka in [EIP-7825: Transaction Gas Limit Cap](https://eips.ethereum.org/EIPS/eip-7825)
68    /// with initials cap of 30M.
69    pub tx_gas_limit_cap: Option<u64>,
70    /// A hard memory limit in bytes beyond which
71    /// [OutOfGasError::Memory][context_interface::result::OutOfGasError::Memory] cannot be resized.
72    ///
73    /// In cases where the gas limit may be extraordinarily high, it is recommended to set this to
74    /// a sane value to prevent memory allocation panics.
75    ///
76    /// Defaults to `2^32 - 1` bytes per EIP-1985.
77    #[cfg(feature = "memory_limit")]
78    pub memory_limit: u64,
79    /// Skip balance checks if `true`
80    ///
81    /// Adds transaction cost to balance to ensure execution doesn't fail.
82    ///
83    /// By default, it is set to `false`.
84    #[cfg(feature = "optional_balance_check")]
85    pub disable_balance_check: bool,
86    /// There are use cases where it's allowed to provide a gas limit that's higher than a block's gas limit.
87    ///
88    /// To that end, you can disable the block gas limit validation.
89    ///
90    /// By default, it is set to `false`.
91    #[cfg(feature = "optional_block_gas_limit")]
92    pub disable_block_gas_limit: bool,
93    /// EIP-3541 rejects the creation of contracts that starts with 0xEF
94    ///
95    /// This is useful for chains that do not implement EIP-3541.
96    ///
97    /// By default, it is set to `false`.
98    #[cfg(feature = "optional_eip3541")]
99    pub disable_eip3541: bool,
100    /// EIP-3607 rejects transactions from senders with deployed code
101    ///
102    /// In development, it can be desirable to simulate calls from contracts, which this setting allows.
103    ///
104    /// By default, it is set to `false`.
105    #[cfg(feature = "optional_eip3607")]
106    pub disable_eip3607: bool,
107    /// EIP-7623 increases calldata cost.
108    ///
109    /// This EIP can be considered irrelevant in the context of an EVM-compatible L2 rollup,
110    /// if it does not make use of blobs.
111    ///
112    /// By default, it is set to `false`.
113    #[cfg(feature = "optional_eip7623")]
114    pub disable_eip7623: bool,
115    /// Disables base fee checks for EIP-1559 transactions
116    ///
117    /// This is useful for testing method calls with zero gas price.
118    ///
119    /// By default, it is set to `false`.
120    #[cfg(feature = "optional_no_base_fee")]
121    pub disable_base_fee: bool,
122    /// Disables "max fee must be less than or equal to max priority fee" check for EIP-1559 transactions.
123    /// This is useful because some chains (e.g. Arbitrum) do not enforce this check.
124    /// By default, it is set to `false`.
125    #[cfg(feature = "optional_priority_fee_check")]
126    pub disable_priority_fee_check: bool,
127    /// Disables fee charging for transactions.
128    /// This is useful when executing `eth_call` for example, on OP-chains where setting the base fee
129    /// to 0 isn't sufficient.
130    /// By default, it is set to `false`.
131    #[cfg(feature = "optional_fee_charge")]
132    pub disable_fee_charge: bool,
133    /// Disables EIP-7708 (ETH transfers emit logs).
134    ///
135    /// By default, it is set to `false`.
136    pub amsterdam_eip7708_disabled: bool,
137    /// Disables EIP-7708 delayed burn logging.
138    ///
139    /// When enabled, revm tracks all self-destructed addresses and emits logs for
140    /// accounts that still have remaining balance at the end of the transaction.
141    /// This can be disabled for performance reasons as it requires storing and
142    /// iterating over all self-destructed accounts. When disabled, the logging
143    /// can be done outside of revm when applying accounts to database state.
144    ///
145    /// By default, it is set to `false`.
146    pub amsterdam_eip7708_delayed_burn_disabled: bool,
147}
148
149impl CfgEnv {
150    /// Creates new `CfgEnv` with default values.
151    pub fn new() -> Self {
152        Self::default()
153    }
154}
155
156impl<SPEC> CfgEnv<SPEC> {
157    /// Create new `CfgEnv` with default values and specified spec.
158    pub fn new_with_spec_and_gas_params(spec: SPEC, gas_params: GasParams) -> Self {
159        Self {
160            chain_id: 1,
161            tx_chain_id_check: true,
162            limit_contract_code_size: None,
163            limit_contract_initcode_size: None,
164            spec,
165            disable_nonce_check: false,
166            max_blobs_per_tx: None,
167            tx_gas_limit_cap: None,
168            blob_base_fee_update_fraction: None,
169            gas_params,
170            #[cfg(feature = "memory_limit")]
171            memory_limit: (1 << 32) - 1,
172            #[cfg(feature = "optional_balance_check")]
173            disable_balance_check: false,
174            #[cfg(feature = "optional_block_gas_limit")]
175            disable_block_gas_limit: false,
176            #[cfg(feature = "optional_eip3541")]
177            disable_eip3541: false,
178            #[cfg(feature = "optional_eip3607")]
179            disable_eip3607: false,
180            #[cfg(feature = "optional_eip7623")]
181            disable_eip7623: false,
182            #[cfg(feature = "optional_no_base_fee")]
183            disable_base_fee: false,
184            #[cfg(feature = "optional_priority_fee_check")]
185            disable_priority_fee_check: false,
186            #[cfg(feature = "optional_fee_charge")]
187            disable_fee_charge: false,
188            amsterdam_eip7708_disabled: false,
189            amsterdam_eip7708_delayed_burn_disabled: false,
190        }
191    }
192
193    /// Returns the spec for the `CfgEnv`.
194    #[inline]
195    pub fn spec(&self) -> &SPEC {
196        &self.spec
197    }
198
199    /// Consumes `self` and returns a new `CfgEnv` with the specified chain ID.
200    pub fn with_chain_id(mut self, chain_id: u64) -> Self {
201        self.chain_id = chain_id;
202        self
203    }
204
205    /// Sets the gas params for the `CfgEnv`.
206    #[inline]
207    pub fn with_gas_params(mut self, gas_params: GasParams) -> Self {
208        self.set_gas_params(gas_params);
209        self
210    }
211
212    /// Sets the spec for the `CfgEnv`.
213    #[inline]
214    pub fn set_spec(&mut self, spec: SPEC) {
215        self.spec = spec;
216    }
217
218    /// Sets the gas params for the `CfgEnv`.
219    #[inline]
220    pub fn set_gas_params(&mut self, gas_params: GasParams) {
221        self.gas_params = gas_params;
222    }
223
224    /// Enables the transaction's chain ID check.
225    pub fn enable_tx_chain_id_check(mut self) -> Self {
226        self.tx_chain_id_check = true;
227        self
228    }
229
230    /// Disables the transaction's chain ID check.
231    pub fn disable_tx_chain_id_check(mut self) -> Self {
232        self.tx_chain_id_check = false;
233        self
234    }
235
236    /// Sets the spec for the `CfgEnv`.
237    #[inline]
238    #[deprecated(
239        since = "0.1.0",
240        note = "Use [`CfgEnv::with_spec_and_mainnet_gas_params`] instead"
241    )]
242    pub fn with_spec(mut self, spec: SPEC) -> Self {
243        self.spec = spec;
244        self
245    }
246
247    /// Sets the spec for the `CfgEnv` and the gas params to the mainnet gas params.
248    pub fn with_spec_and_mainnet_gas_params<OSPEC: Into<SpecId> + Clone>(
249        self,
250        spec: OSPEC,
251    ) -> CfgEnv<OSPEC> {
252        self.with_spec_and_gas_params(spec.clone(), GasParams::new_spec(spec.into()))
253    }
254
255    /// Consumes `self` and returns a new `CfgEnv` with the specified spec.
256    ///
257    /// Resets the gas params override function as it is generic over SPEC.
258    pub fn with_spec_and_gas_params<OSPEC: Into<SpecId> + Clone>(
259        self,
260        spec: OSPEC,
261        gas_params: GasParams,
262    ) -> CfgEnv<OSPEC> {
263        CfgEnv {
264            chain_id: self.chain_id,
265            tx_chain_id_check: self.tx_chain_id_check,
266            limit_contract_code_size: self.limit_contract_code_size,
267            limit_contract_initcode_size: self.limit_contract_initcode_size,
268            spec,
269            disable_nonce_check: self.disable_nonce_check,
270            tx_gas_limit_cap: self.tx_gas_limit_cap,
271            max_blobs_per_tx: self.max_blobs_per_tx,
272            blob_base_fee_update_fraction: self.blob_base_fee_update_fraction,
273            gas_params,
274            #[cfg(feature = "memory_limit")]
275            memory_limit: self.memory_limit,
276            #[cfg(feature = "optional_balance_check")]
277            disable_balance_check: self.disable_balance_check,
278            #[cfg(feature = "optional_block_gas_limit")]
279            disable_block_gas_limit: self.disable_block_gas_limit,
280            #[cfg(feature = "optional_eip3541")]
281            disable_eip3541: self.disable_eip3541,
282            #[cfg(feature = "optional_eip3607")]
283            disable_eip3607: self.disable_eip3607,
284            #[cfg(feature = "optional_eip7623")]
285            disable_eip7623: self.disable_eip7623,
286            #[cfg(feature = "optional_no_base_fee")]
287            disable_base_fee: self.disable_base_fee,
288            #[cfg(feature = "optional_priority_fee_check")]
289            disable_priority_fee_check: self.disable_priority_fee_check,
290            #[cfg(feature = "optional_fee_charge")]
291            disable_fee_charge: self.disable_fee_charge,
292            amsterdam_eip7708_disabled: self.amsterdam_eip7708_disabled,
293            amsterdam_eip7708_delayed_burn_disabled: self.amsterdam_eip7708_delayed_burn_disabled,
294        }
295    }
296
297    /// Sets the blob target
298    pub fn with_max_blobs_per_tx(mut self, max_blobs_per_tx: u64) -> Self {
299        self.set_max_blobs_per_tx(max_blobs_per_tx);
300        self
301    }
302
303    /// Sets the blob target
304    pub fn set_max_blobs_per_tx(&mut self, max_blobs_per_tx: u64) {
305        self.max_blobs_per_tx = Some(max_blobs_per_tx);
306    }
307
308    /// Clears the blob target and max count over hardforks.
309    pub fn clear_max_blobs_per_tx(&mut self) {
310        self.max_blobs_per_tx = None;
311    }
312
313    /// Sets the disable priority fee check flag.
314    #[cfg(feature = "optional_priority_fee_check")]
315    pub fn with_disable_priority_fee_check(mut self, disable: bool) -> Self {
316        self.disable_priority_fee_check = disable;
317        self
318    }
319
320    /// Sets the disable fee charge flag.
321    #[cfg(feature = "optional_fee_charge")]
322    pub fn with_disable_fee_charge(mut self, disable: bool) -> Self {
323        self.disable_fee_charge = disable;
324        self
325    }
326
327    /// Sets the disable eip7623 flag.
328    #[cfg(feature = "optional_eip7623")]
329    pub fn with_disable_eip7623(mut self, disable: bool) -> Self {
330        self.disable_eip7623 = disable;
331        self
332    }
333}
334
335impl<SPEC: Into<SpecId> + Clone> CfgEnv<SPEC> {
336    /// Returns the blob base fee update fraction from [CfgEnv::blob_base_fee_update_fraction].
337    ///
338    /// If this field is not set, return the default value for the spec.
339    ///
340    /// Default values for Cancun is [`primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN`]
341    /// and for Prague is [`primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE`].
342    pub fn blob_base_fee_update_fraction(&mut self) -> u64 {
343        self.blob_base_fee_update_fraction.unwrap_or_else(|| {
344            let spec: SpecId = self.spec.clone().into();
345            if spec.is_enabled_in(SpecId::PRAGUE) {
346                primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE
347            } else {
348                primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN
349            }
350        })
351    }
352
353    /// Create new `CfgEnv` with default values and specified spec.
354    /// It will create a new gas params based on mainnet spec.
355    ///
356    /// Internally it will call [`CfgEnv::new_with_spec_and_gas_params`] with the mainnet gas params.
357    pub fn new_with_spec(spec: SPEC) -> Self {
358        Self::new_with_spec_and_gas_params(spec.clone(), GasParams::new_spec(spec.into()))
359    }
360
361    /// Sets the gas params for the `CfgEnv` to the mainnet gas params.
362    ///
363    /// If spec gets changed, calling this function would use this spec to set the mainnetF gas params.
364    pub fn with_mainnet_gas_params(mut self) -> Self {
365        self.set_gas_params(GasParams::new_spec(self.spec.clone().into()));
366        self
367    }
368
369    /// Sets the spec for the `CfgEnv` and the gas params to the mainnet gas params.
370    #[inline]
371    pub fn set_spec_and_mainnet_gas_params(&mut self, spec: SPEC) {
372        self.set_spec(spec.clone());
373        self.set_gas_params(GasParams::new_spec(spec.into()));
374    }
375}
376
377impl<SPEC: Into<SpecId> + Clone> Cfg for CfgEnv<SPEC> {
378    type Spec = SPEC;
379
380    #[inline]
381    fn chain_id(&self) -> u64 {
382        self.chain_id
383    }
384
385    #[inline]
386    fn spec(&self) -> Self::Spec {
387        self.spec.clone()
388    }
389
390    #[inline]
391    fn tx_chain_id_check(&self) -> bool {
392        self.tx_chain_id_check
393    }
394
395    #[inline]
396    fn tx_gas_limit_cap(&self) -> u64 {
397        self.tx_gas_limit_cap
398            .unwrap_or(if self.spec.clone().into().is_enabled_in(SpecId::OSAKA) {
399                eip7825::TX_GAS_LIMIT_CAP
400            } else {
401                u64::MAX
402            })
403    }
404
405    #[inline]
406    fn max_blobs_per_tx(&self) -> Option<u64> {
407        self.max_blobs_per_tx
408    }
409
410    fn max_code_size(&self) -> usize {
411        self.limit_contract_code_size
412            .unwrap_or(eip170::MAX_CODE_SIZE)
413    }
414
415    fn max_initcode_size(&self) -> usize {
416        self.limit_contract_initcode_size
417            .or_else(|| {
418                self.limit_contract_code_size
419                    .map(|size| size.saturating_mul(2))
420            })
421            .unwrap_or(eip3860::MAX_INITCODE_SIZE)
422    }
423
424    fn is_eip3541_disabled(&self) -> bool {
425        cfg_if::cfg_if! {
426            if #[cfg(feature = "optional_eip3541")] {
427                self.disable_eip3541
428            } else {
429                false
430            }
431        }
432    }
433
434    fn is_eip3607_disabled(&self) -> bool {
435        cfg_if::cfg_if! {
436            if #[cfg(feature = "optional_eip3607")] {
437                self.disable_eip3607
438            } else {
439                false
440            }
441        }
442    }
443
444    fn is_eip7623_disabled(&self) -> bool {
445        cfg_if::cfg_if! {
446            if #[cfg(feature = "optional_eip7623")] {
447                self.disable_eip7623
448            } else {
449                false
450            }
451        }
452    }
453
454    fn is_balance_check_disabled(&self) -> bool {
455        cfg_if::cfg_if! {
456            if #[cfg(feature = "optional_balance_check")] {
457                self.disable_balance_check
458            } else {
459                false
460            }
461        }
462    }
463
464    /// Returns `true` if the block gas limit is disabled.
465    fn is_block_gas_limit_disabled(&self) -> bool {
466        cfg_if::cfg_if! {
467            if #[cfg(feature = "optional_block_gas_limit")] {
468                self.disable_block_gas_limit
469            } else {
470                false
471            }
472        }
473    }
474
475    fn is_nonce_check_disabled(&self) -> bool {
476        self.disable_nonce_check
477    }
478
479    fn is_base_fee_check_disabled(&self) -> bool {
480        cfg_if::cfg_if! {
481            if #[cfg(feature = "optional_no_base_fee")] {
482                self.disable_base_fee
483            } else {
484                false
485            }
486        }
487    }
488
489    fn is_priority_fee_check_disabled(&self) -> bool {
490        cfg_if::cfg_if! {
491            if #[cfg(feature = "optional_priority_fee_check")] {
492                self.disable_priority_fee_check
493            } else {
494                false
495            }
496        }
497    }
498
499    fn is_fee_charge_disabled(&self) -> bool {
500        cfg_if::cfg_if! {
501            if #[cfg(feature = "optional_fee_charge")] {
502                self.disable_fee_charge
503            } else {
504                false
505            }
506        }
507    }
508
509    fn is_eip7708_disabled(&self) -> bool {
510        self.amsterdam_eip7708_disabled
511    }
512
513    fn is_eip7708_delayed_burn_disabled(&self) -> bool {
514        self.amsterdam_eip7708_delayed_burn_disabled
515    }
516
517    fn memory_limit(&self) -> u64 {
518        cfg_if::cfg_if! {
519            if #[cfg(feature = "memory_limit")] {
520                self.memory_limit
521            } else {
522                u64::MAX
523            }
524        }
525    }
526
527    #[inline]
528    fn gas_params(&self) -> &GasParams {
529        &self.gas_params
530    }
531}
532
533impl<SPEC: Default + Into<SpecId>> Default for CfgEnv<SPEC> {
534    fn default() -> Self {
535        Self::new_with_spec_and_gas_params(
536            SPEC::default(),
537            GasParams::new_spec(SPEC::default().into()),
538        )
539    }
540}
541
542#[cfg(test)]
543mod test {
544    use super::*;
545
546    #[test]
547    fn blob_max_and_target_count() {
548        let cfg: CfgEnv = Default::default();
549        assert_eq!(cfg.max_blobs_per_tx(), None);
550    }
551}