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, eip7954, 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-7954) 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-7954) 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    /// Enables EIP-8037 (Amsterdam) state creation gas cost increase.
134    ///
135    /// EIP-8037 introduces dual gas limits: regular gas for execution and state gas
136    /// for storage creation. State gas is tracked via a reservoir model.
137    /// It specifies concrete gas values based on `cost_per_state_byte` and adds
138    /// a hash cost for deployed bytecode.
139    ///
140    /// By default, it is set to `false`.
141    pub enable_amsterdam_eip8037: bool,
142    /// Disables EIP-7708 (ETH transfers emit logs).
143    ///
144    /// By default, it is set to `false`.
145    pub amsterdam_eip7708_disabled: bool,
146    /// Disables EIP-7708 delayed burn logging.
147    ///
148    /// When enabled, revm tracks all self-destructed addresses and emits logs for
149    /// accounts that still have remaining balance at the end of the transaction.
150    /// This can be disabled for performance reasons as it requires storing and
151    /// iterating over all self-destructed accounts. When disabled, the logging
152    /// can be done outside of revm when applying accounts to database state.
153    ///
154    /// By default, it is set to `false`.
155    pub amsterdam_eip7708_delayed_burn_disabled: bool,
156}
157
158impl CfgEnv {
159    /// Creates new `CfgEnv` with default values.
160    pub fn new() -> Self {
161        Self::default()
162    }
163}
164
165impl<SPEC> CfgEnv<SPEC> {
166    /// Returns the spec for the `CfgEnv`.
167    #[inline]
168    pub fn spec(&self) -> &SPEC {
169        &self.spec
170    }
171
172    /// Consumes `self` and returns a new `CfgEnv` with the specified chain ID.
173    pub fn with_chain_id(mut self, chain_id: u64) -> Self {
174        self.chain_id = chain_id;
175        self
176    }
177
178    /// Sets the gas params for the `CfgEnv`.
179    #[inline]
180    pub fn with_gas_params(mut self, gas_params: GasParams) -> Self {
181        self.set_gas_params(gas_params);
182        self
183    }
184
185    /// Sets the spec for the `CfgEnv`.
186    #[inline]
187    #[deprecated(note = "Use [`CfgEnv::set_spec_and_mainnet_gas_params`] instead")]
188    pub fn set_spec(&mut self, spec: SPEC) {
189        self.spec = spec;
190    }
191
192    /// Sets the gas params for the `CfgEnv`.
193    #[inline]
194    pub fn set_gas_params(&mut self, gas_params: GasParams) {
195        self.gas_params = gas_params;
196    }
197
198    /// Enables the transaction's chain ID check.
199    pub fn enable_tx_chain_id_check(mut self) -> Self {
200        self.tx_chain_id_check = true;
201        self
202    }
203
204    /// Disables the transaction's chain ID check.
205    pub fn disable_tx_chain_id_check(mut self) -> Self {
206        self.tx_chain_id_check = false;
207        self
208    }
209
210    /// Sets the spec for the `CfgEnv`.
211    #[inline]
212    #[deprecated(note = "Use [`CfgEnv::with_spec_and_mainnet_gas_params`] instead")]
213    pub fn with_spec(mut self, spec: SPEC) -> Self {
214        self.spec = spec;
215        self
216    }
217
218    /// Sets the spec for the `CfgEnv` and the gas params to the mainnet gas params.
219    ///
220    /// Automatically enables EIP-8037 for AMSTERDAM and later.
221    pub fn with_spec_and_mainnet_gas_params<OSPEC: Into<SpecId> + Clone>(
222        self,
223        spec: OSPEC,
224    ) -> CfgEnv<OSPEC> {
225        let is_amsterdam = spec.clone().into().is_enabled_in(SpecId::AMSTERDAM);
226        let enable_amsterdam_eip8037 = self.enable_amsterdam_eip8037 || is_amsterdam;
227        let mut cfg = self.with_spec_and_gas_params(spec.clone(), GasParams::new_spec(spec.into()));
228        cfg.enable_amsterdam_eip8037 = enable_amsterdam_eip8037;
229        cfg
230    }
231
232    /// Consumes `self` and returns a new `CfgEnv` with the specified spec.
233    ///
234    /// Resets the gas params override function as it is generic over SPEC.
235    pub fn with_spec_and_gas_params<OSPEC: Into<SpecId> + Clone>(
236        self,
237        spec: OSPEC,
238        gas_params: GasParams,
239    ) -> CfgEnv<OSPEC> {
240        CfgEnv {
241            chain_id: self.chain_id,
242            tx_chain_id_check: self.tx_chain_id_check,
243            limit_contract_code_size: self.limit_contract_code_size,
244            limit_contract_initcode_size: self.limit_contract_initcode_size,
245            spec,
246            disable_nonce_check: self.disable_nonce_check,
247            tx_gas_limit_cap: self.tx_gas_limit_cap,
248            max_blobs_per_tx: self.max_blobs_per_tx,
249            blob_base_fee_update_fraction: self.blob_base_fee_update_fraction,
250            gas_params,
251            #[cfg(feature = "memory_limit")]
252            memory_limit: self.memory_limit,
253            #[cfg(feature = "optional_balance_check")]
254            disable_balance_check: self.disable_balance_check,
255            #[cfg(feature = "optional_block_gas_limit")]
256            disable_block_gas_limit: self.disable_block_gas_limit,
257            #[cfg(feature = "optional_eip3541")]
258            disable_eip3541: self.disable_eip3541,
259            #[cfg(feature = "optional_eip3607")]
260            disable_eip3607: self.disable_eip3607,
261            #[cfg(feature = "optional_eip7623")]
262            disable_eip7623: self.disable_eip7623,
263            #[cfg(feature = "optional_no_base_fee")]
264            disable_base_fee: self.disable_base_fee,
265            #[cfg(feature = "optional_priority_fee_check")]
266            disable_priority_fee_check: self.disable_priority_fee_check,
267            #[cfg(feature = "optional_fee_charge")]
268            disable_fee_charge: self.disable_fee_charge,
269            enable_amsterdam_eip8037: self.enable_amsterdam_eip8037,
270            amsterdam_eip7708_disabled: self.amsterdam_eip7708_disabled,
271            amsterdam_eip7708_delayed_burn_disabled: self.amsterdam_eip7708_delayed_burn_disabled,
272        }
273    }
274
275    /// Sets the blob target
276    pub fn with_max_blobs_per_tx(mut self, max_blobs_per_tx: u64) -> Self {
277        self.set_max_blobs_per_tx(max_blobs_per_tx);
278        self
279    }
280
281    /// Sets the blob target
282    pub fn set_max_blobs_per_tx(&mut self, max_blobs_per_tx: u64) {
283        self.max_blobs_per_tx = Some(max_blobs_per_tx);
284    }
285
286    /// Clears the blob target and max count over hardforks.
287    pub fn clear_max_blobs_per_tx(&mut self) {
288        self.max_blobs_per_tx = None;
289    }
290
291    /// Sets the disable priority fee check flag.
292    #[cfg(feature = "optional_priority_fee_check")]
293    pub fn with_disable_priority_fee_check(mut self, disable: bool) -> Self {
294        self.disable_priority_fee_check = disable;
295        self
296    }
297
298    /// Sets the disable fee charge flag.
299    #[cfg(feature = "optional_fee_charge")]
300    pub fn with_disable_fee_charge(mut self, disable: bool) -> Self {
301        self.disable_fee_charge = disable;
302        self
303    }
304
305    /// Sets the disable eip7623 flag.
306    #[cfg(feature = "optional_eip7623")]
307    pub fn with_disable_eip7623(mut self, disable: bool) -> Self {
308        self.disable_eip7623 = disable;
309        self
310    }
311
312    /// Sets the enable EIP-8037 (Amsterdam) state creation gas cost flag.
313    pub fn with_enable_amsterdam_eip8037(mut self, enable: bool) -> Self {
314        self.enable_amsterdam_eip8037 = enable;
315        self
316    }
317}
318
319impl<SPEC: Into<SpecId> + Clone> CfgEnv<SPEC> {
320    /// Create new `CfgEnv` with default values and specified spec.
321    pub fn new_with_spec_and_gas_params(spec: SPEC, gas_params: GasParams) -> Self {
322        let is_amsterdam = spec.clone().into().is_enabled_in(SpecId::AMSTERDAM);
323        Self {
324            chain_id: 1,
325            tx_chain_id_check: true,
326            limit_contract_code_size: None,
327            limit_contract_initcode_size: None,
328            spec,
329            disable_nonce_check: false,
330            max_blobs_per_tx: None,
331            tx_gas_limit_cap: None,
332            blob_base_fee_update_fraction: None,
333            gas_params,
334            #[cfg(feature = "memory_limit")]
335            memory_limit: (1 << 32) - 1,
336            #[cfg(feature = "optional_balance_check")]
337            disable_balance_check: false,
338            #[cfg(feature = "optional_block_gas_limit")]
339            disable_block_gas_limit: false,
340            #[cfg(feature = "optional_eip3541")]
341            disable_eip3541: false,
342            #[cfg(feature = "optional_eip3607")]
343            disable_eip3607: false,
344            #[cfg(feature = "optional_eip7623")]
345            disable_eip7623: false,
346            #[cfg(feature = "optional_no_base_fee")]
347            disable_base_fee: false,
348            #[cfg(feature = "optional_priority_fee_check")]
349            disable_priority_fee_check: false,
350            #[cfg(feature = "optional_fee_charge")]
351            disable_fee_charge: false,
352            enable_amsterdam_eip8037: is_amsterdam,
353            amsterdam_eip7708_disabled: false,
354            amsterdam_eip7708_delayed_burn_disabled: false,
355        }
356    }
357
358    /// Returns the blob base fee update fraction from [CfgEnv::blob_base_fee_update_fraction].
359    ///
360    /// If this field is not set, return the default value for the spec.
361    ///
362    /// Default values for Cancun is [`primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN`]
363    /// and for Prague is [`primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE`].
364    pub fn blob_base_fee_update_fraction(&mut self) -> u64 {
365        self.blob_base_fee_update_fraction.unwrap_or_else(|| {
366            let spec: SpecId = self.spec.clone().into();
367            if spec.is_enabled_in(SpecId::PRAGUE) {
368                primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE
369            } else {
370                primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN
371            }
372        })
373    }
374
375    /// Create new `CfgEnv` with default values and specified spec.
376    /// It will create a new gas params based on mainnet spec.
377    ///
378    /// Internally it will call [`CfgEnv::new_with_spec_and_gas_params`] with the mainnet gas params.
379    pub fn new_with_spec(spec: SPEC) -> Self {
380        Self::new_with_spec_and_gas_params(spec.clone(), GasParams::new_spec(spec.into()))
381    }
382
383    /// Sets the gas params for the `CfgEnv` to the mainnet gas params.
384    ///
385    /// If spec gets changed, calling this function would use this spec to set the mainnetF gas params.
386    pub fn with_mainnet_gas_params(mut self) -> Self {
387        self.set_gas_params(GasParams::new_spec(self.spec.clone().into()));
388        self
389    }
390
391    /// Sets the spec for the `CfgEnv` and the gas params to the mainnet gas params.
392    ///
393    /// Automatically enables EIP-8037 for AMSTERDAM and later.
394    #[inline]
395    pub fn set_spec_and_mainnet_gas_params(&mut self, spec: SPEC) {
396        self.spec = spec.clone();
397        self.set_gas_params(GasParams::new_spec(spec.clone().into()));
398        // EIP-8037: Enable EIP-8037 for AMSTERDAM and later
399        if spec.into().is_enabled_in(SpecId::AMSTERDAM) {
400            self.enable_amsterdam_eip8037 = true;
401        }
402    }
403}
404
405impl<SPEC: Into<SpecId> + Clone> Cfg for CfgEnv<SPEC> {
406    type Spec = SPEC;
407
408    #[inline]
409    fn chain_id(&self) -> u64 {
410        self.chain_id
411    }
412
413    #[inline]
414    fn spec(&self) -> Self::Spec {
415        self.spec.clone()
416    }
417
418    #[inline]
419    fn tx_chain_id_check(&self) -> bool {
420        self.tx_chain_id_check
421    }
422
423    #[inline]
424    fn tx_gas_limit_cap(&self) -> u64 {
425        self.tx_gas_limit_cap
426            .unwrap_or(if self.spec.clone().into().is_enabled_in(SpecId::OSAKA) {
427                eip7825::TX_GAS_LIMIT_CAP
428            } else {
429                u64::MAX
430            })
431    }
432
433    #[inline]
434    fn max_blobs_per_tx(&self) -> Option<u64> {
435        self.max_blobs_per_tx
436    }
437
438    fn max_code_size(&self) -> usize {
439        self.limit_contract_code_size.unwrap_or(
440            if self.spec.clone().into().is_enabled_in(SpecId::AMSTERDAM) {
441                eip7954::MAX_CODE_SIZE
442            } else {
443                eip170::MAX_CODE_SIZE
444            },
445        )
446    }
447
448    fn max_initcode_size(&self) -> usize {
449        self.limit_contract_initcode_size
450            .or_else(|| {
451                self.limit_contract_code_size
452                    .map(|size| size.saturating_mul(2))
453            })
454            .unwrap_or(
455                if self.spec.clone().into().is_enabled_in(SpecId::AMSTERDAM) {
456                    eip7954::MAX_INITCODE_SIZE
457                } else {
458                    eip3860::MAX_INITCODE_SIZE
459                },
460            )
461    }
462
463    fn is_eip3541_disabled(&self) -> bool {
464        cfg_if::cfg_if! {
465            if #[cfg(feature = "optional_eip3541")] {
466                self.disable_eip3541
467            } else {
468                false
469            }
470        }
471    }
472
473    fn is_eip3607_disabled(&self) -> bool {
474        cfg_if::cfg_if! {
475            if #[cfg(feature = "optional_eip3607")] {
476                self.disable_eip3607
477            } else {
478                false
479            }
480        }
481    }
482
483    fn is_eip7623_disabled(&self) -> bool {
484        cfg_if::cfg_if! {
485            if #[cfg(feature = "optional_eip7623")] {
486                self.disable_eip7623
487            } else {
488                false
489            }
490        }
491    }
492
493    fn is_balance_check_disabled(&self) -> bool {
494        cfg_if::cfg_if! {
495            if #[cfg(feature = "optional_balance_check")] {
496                self.disable_balance_check
497            } else {
498                false
499            }
500        }
501    }
502
503    /// Returns `true` if the block gas limit is disabled.
504    fn is_block_gas_limit_disabled(&self) -> bool {
505        cfg_if::cfg_if! {
506            if #[cfg(feature = "optional_block_gas_limit")] {
507                self.disable_block_gas_limit
508            } else {
509                false
510            }
511        }
512    }
513
514    fn is_nonce_check_disabled(&self) -> bool {
515        self.disable_nonce_check
516    }
517
518    fn is_base_fee_check_disabled(&self) -> bool {
519        cfg_if::cfg_if! {
520            if #[cfg(feature = "optional_no_base_fee")] {
521                self.disable_base_fee
522            } else {
523                false
524            }
525        }
526    }
527
528    fn is_priority_fee_check_disabled(&self) -> bool {
529        cfg_if::cfg_if! {
530            if #[cfg(feature = "optional_priority_fee_check")] {
531                self.disable_priority_fee_check
532            } else {
533                false
534            }
535        }
536    }
537
538    fn is_fee_charge_disabled(&self) -> bool {
539        cfg_if::cfg_if! {
540            if #[cfg(feature = "optional_fee_charge")] {
541                self.disable_fee_charge
542            } else {
543                false
544            }
545        }
546    }
547
548    fn is_eip7708_disabled(&self) -> bool {
549        self.amsterdam_eip7708_disabled
550    }
551
552    fn is_eip7708_delayed_burn_disabled(&self) -> bool {
553        self.amsterdam_eip7708_delayed_burn_disabled
554    }
555
556    fn memory_limit(&self) -> u64 {
557        cfg_if::cfg_if! {
558            if #[cfg(feature = "memory_limit")] {
559                self.memory_limit
560            } else {
561                u64::MAX
562            }
563        }
564    }
565
566    #[inline]
567    fn gas_params(&self) -> &GasParams {
568        &self.gas_params
569    }
570
571    fn is_amsterdam_eip8037_enabled(&self) -> bool {
572        self.enable_amsterdam_eip8037
573    }
574}
575
576impl<SPEC: Default + Into<SpecId> + Clone> Default for CfgEnv<SPEC> {
577    fn default() -> Self {
578        Self::new_with_spec_and_gas_params(
579            SPEC::default(),
580            GasParams::new_spec(SPEC::default().into()),
581        )
582    }
583}
584
585#[cfg(test)]
586mod test {
587    use super::*;
588
589    #[test]
590    fn blob_max_and_target_count() {
591        let cfg: CfgEnv = Default::default();
592        assert_eq!(cfg.max_blobs_per_tx(), None);
593    }
594}