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, eip8037, 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    /// Overrides the EIP-8037 `cost_per_state_byte` (CPSB).
71    ///
72    /// If `None`, CPSB defaults to [`primitives::eip8037::CPSB_GLAMSTERDAM`]
73    /// when EIP-8037 is enabled. If `Some`, the provided value is used
74    /// verbatim (useful for tests and replay).
75    pub cpsb_override: Option<u64>,
76    /// A hard memory limit in bytes beyond which
77    /// [OutOfGasError::Memory][context_interface::result::OutOfGasError::Memory] cannot be resized.
78    ///
79    /// In cases where the gas limit may be extraordinarily high, it is recommended to set this to
80    /// a sane value to prevent memory allocation panics.
81    ///
82    /// Defaults to `2^32 - 1` bytes per EIP-1985.
83    #[cfg(feature = "memory_limit")]
84    pub memory_limit: u64,
85    /// Skip balance checks if `true`
86    ///
87    /// Adds transaction cost to balance to ensure execution doesn't fail.
88    ///
89    /// By default, it is set to `false`.
90    #[cfg(feature = "optional_balance_check")]
91    pub disable_balance_check: bool,
92    /// There are use cases where it's allowed to provide a gas limit that's higher than a block's gas limit.
93    ///
94    /// To that end, you can disable the block gas limit validation.
95    ///
96    /// By default, it is set to `false`.
97    #[cfg(feature = "optional_block_gas_limit")]
98    pub disable_block_gas_limit: bool,
99    /// EIP-3541 rejects the creation of contracts that starts with 0xEF
100    ///
101    /// This is useful for chains that do not implement EIP-3541.
102    ///
103    /// By default, it is set to `false`.
104    #[cfg(feature = "optional_eip3541")]
105    pub disable_eip3541: bool,
106    /// EIP-3607 rejects transactions from senders with deployed code
107    ///
108    /// In development, it can be desirable to simulate calls from contracts, which this setting allows.
109    ///
110    /// By default, it is set to `false`.
111    #[cfg(feature = "optional_eip3607")]
112    pub disable_eip3607: bool,
113    /// EIP-7623 increases calldata cost.
114    ///
115    /// This EIP can be considered irrelevant in the context of an EVM-compatible L2 rollup,
116    /// if it does not make use of blobs.
117    ///
118    /// By default, it is set to `false`.
119    #[cfg(feature = "optional_eip7623")]
120    pub disable_eip7623: bool,
121    /// Disables base fee checks for EIP-1559 transactions
122    ///
123    /// This is useful for testing method calls with zero gas price.
124    ///
125    /// By default, it is set to `false`.
126    #[cfg(feature = "optional_no_base_fee")]
127    pub disable_base_fee: bool,
128    /// Disables "max fee must be less than or equal to max priority fee" check for EIP-1559 transactions.
129    /// This is useful because some chains (e.g. Arbitrum) do not enforce this check.
130    /// By default, it is set to `false`.
131    #[cfg(feature = "optional_priority_fee_check")]
132    pub disable_priority_fee_check: bool,
133    /// Disables fee charging for transactions.
134    /// This is useful when executing `eth_call` for example, on OP-chains where setting the base fee
135    /// to 0 isn't sufficient.
136    /// By default, it is set to `false`.
137    #[cfg(feature = "optional_fee_charge")]
138    pub disable_fee_charge: bool,
139    /// Enables EIP-8037 (Amsterdam) state creation gas cost increase.
140    ///
141    /// EIP-8037 introduces dual gas limits: regular gas for execution and state gas
142    /// for storage creation. State gas is tracked via a reservoir model.
143    /// It specifies concrete gas values based on `cost_per_state_byte` and adds
144    /// a hash cost for deployed bytecode.
145    ///
146    /// By default, it is set to `false`.
147    pub enable_amsterdam_eip8037: bool,
148    /// Disables EIP-7708 (ETH transfers emit logs).
149    ///
150    /// By default, it is set to `false`.
151    pub amsterdam_eip7708_disabled: bool,
152    /// Disables EIP-7708 delayed burn logging.
153    ///
154    /// When enabled, revm tracks all self-destructed addresses and emits logs for
155    /// accounts that still have remaining balance at the end of the transaction.
156    /// This can be disabled for performance reasons as it requires storing and
157    /// iterating over all self-destructed accounts. When disabled, the logging
158    /// can be done outside of revm when applying accounts to database state.
159    ///
160    /// By default, it is set to `false`.
161    pub amsterdam_eip7708_delayed_burn_disabled: bool,
162}
163
164impl CfgEnv {
165    /// Creates new `CfgEnv` with default values.
166    pub fn new() -> Self {
167        Self::default()
168    }
169}
170
171impl<SPEC> CfgEnv<SPEC> {
172    /// Returns the spec for the `CfgEnv`.
173    #[inline]
174    pub const fn spec(&self) -> &SPEC {
175        &self.spec
176    }
177
178    /// Consumes `self` and returns a new `CfgEnv` with the specified chain ID.
179    pub const fn with_chain_id(mut self, chain_id: u64) -> Self {
180        self.chain_id = chain_id;
181        self
182    }
183
184    /// Sets the gas params for the `CfgEnv`.
185    #[inline]
186    pub fn with_gas_params(mut self, gas_params: GasParams) -> Self {
187        self.set_gas_params(gas_params);
188        self
189    }
190
191    /// Sets the spec for the `CfgEnv`.
192    #[inline]
193    #[deprecated(note = "Use [`CfgEnv::set_spec_and_mainnet_gas_params`] instead")]
194    pub fn set_spec(&mut self, spec: SPEC) {
195        self.spec = spec;
196    }
197
198    /// Sets the gas params for the `CfgEnv`.
199    #[inline]
200    pub fn set_gas_params(&mut self, gas_params: GasParams) {
201        self.gas_params = gas_params;
202    }
203
204    /// Enables the transaction's chain ID check.
205    pub const fn enable_tx_chain_id_check(mut self) -> Self {
206        self.tx_chain_id_check = true;
207        self
208    }
209
210    /// Disables the transaction's chain ID check.
211    pub const fn disable_tx_chain_id_check(mut self) -> Self {
212        self.tx_chain_id_check = false;
213        self
214    }
215
216    /// Sets the spec for the `CfgEnv`.
217    #[inline]
218    #[deprecated(note = "Use [`CfgEnv::with_spec_and_mainnet_gas_params`] instead")]
219    pub fn with_spec(mut self, spec: SPEC) -> Self {
220        self.spec = spec;
221        self
222    }
223
224    /// Sets the spec for the `CfgEnv` and the gas params to the mainnet gas params.
225    ///
226    /// Automatically enables EIP-8037 for AMSTERDAM and later.
227    pub fn with_spec_and_mainnet_gas_params<OSPEC: Into<SpecId> + Clone>(
228        self,
229        spec: OSPEC,
230    ) -> CfgEnv<OSPEC> {
231        let is_amsterdam = spec.clone().into().is_enabled_in(SpecId::AMSTERDAM);
232        let enable_amsterdam_eip8037 = self.enable_amsterdam_eip8037 || is_amsterdam;
233        let mut cfg = self.with_spec_and_gas_params(spec.clone(), GasParams::new_spec(spec.into()));
234        cfg.enable_amsterdam_eip8037 = enable_amsterdam_eip8037;
235        cfg
236    }
237
238    /// Consumes `self` and returns a new `CfgEnv` with the specified spec.
239    ///
240    /// Resets the gas params override function as it is generic over SPEC.
241    pub fn with_spec_and_gas_params<OSPEC: Into<SpecId> + Clone>(
242        self,
243        spec: OSPEC,
244        gas_params: GasParams,
245    ) -> CfgEnv<OSPEC> {
246        CfgEnv {
247            chain_id: self.chain_id,
248            tx_chain_id_check: self.tx_chain_id_check,
249            limit_contract_code_size: self.limit_contract_code_size,
250            limit_contract_initcode_size: self.limit_contract_initcode_size,
251            spec,
252            disable_nonce_check: self.disable_nonce_check,
253            tx_gas_limit_cap: self.tx_gas_limit_cap,
254            cpsb_override: self.cpsb_override,
255            max_blobs_per_tx: self.max_blobs_per_tx,
256            blob_base_fee_update_fraction: self.blob_base_fee_update_fraction,
257            gas_params,
258            #[cfg(feature = "memory_limit")]
259            memory_limit: self.memory_limit,
260            #[cfg(feature = "optional_balance_check")]
261            disable_balance_check: self.disable_balance_check,
262            #[cfg(feature = "optional_block_gas_limit")]
263            disable_block_gas_limit: self.disable_block_gas_limit,
264            #[cfg(feature = "optional_eip3541")]
265            disable_eip3541: self.disable_eip3541,
266            #[cfg(feature = "optional_eip3607")]
267            disable_eip3607: self.disable_eip3607,
268            #[cfg(feature = "optional_eip7623")]
269            disable_eip7623: self.disable_eip7623,
270            #[cfg(feature = "optional_no_base_fee")]
271            disable_base_fee: self.disable_base_fee,
272            #[cfg(feature = "optional_priority_fee_check")]
273            disable_priority_fee_check: self.disable_priority_fee_check,
274            #[cfg(feature = "optional_fee_charge")]
275            disable_fee_charge: self.disable_fee_charge,
276            enable_amsterdam_eip8037: self.enable_amsterdam_eip8037,
277            amsterdam_eip7708_disabled: self.amsterdam_eip7708_disabled,
278            amsterdam_eip7708_delayed_burn_disabled: self.amsterdam_eip7708_delayed_burn_disabled,
279        }
280    }
281
282    /// Sets the blob target
283    pub const fn with_max_blobs_per_tx(mut self, max_blobs_per_tx: u64) -> Self {
284        self.set_max_blobs_per_tx(max_blobs_per_tx);
285        self
286    }
287
288    /// Sets the blob target
289    pub const fn set_max_blobs_per_tx(&mut self, max_blobs_per_tx: u64) {
290        self.max_blobs_per_tx = Some(max_blobs_per_tx);
291    }
292
293    /// Clears the blob target and max count over hardforks.
294    pub const fn clear_max_blobs_per_tx(&mut self) {
295        self.max_blobs_per_tx = None;
296    }
297
298    /// Sets the disable priority fee check flag.
299    #[cfg(feature = "optional_priority_fee_check")]
300    pub const fn with_disable_priority_fee_check(mut self, disable: bool) -> Self {
301        self.disable_priority_fee_check = disable;
302        self
303    }
304
305    /// Sets the disable fee charge flag.
306    #[cfg(feature = "optional_fee_charge")]
307    pub const fn with_disable_fee_charge(mut self, disable: bool) -> Self {
308        self.disable_fee_charge = disable;
309        self
310    }
311
312    /// Sets the disable eip7623 flag.
313    #[cfg(feature = "optional_eip7623")]
314    pub const fn with_disable_eip7623(mut self, disable: bool) -> Self {
315        self.disable_eip7623 = disable;
316        self
317    }
318
319    /// Sets the enable EIP-8037 (Amsterdam) state creation gas cost flag.
320    pub const fn with_enable_amsterdam_eip8037(mut self, enable: bool) -> Self {
321        self.enable_amsterdam_eip8037 = enable;
322        self
323    }
324}
325
326impl<SPEC: Into<SpecId> + Clone> CfgEnv<SPEC> {
327    /// Create new `CfgEnv` with default values and specified spec.
328    pub fn new_with_spec_and_gas_params(spec: SPEC, gas_params: GasParams) -> Self {
329        let is_amsterdam = spec.clone().into().is_enabled_in(SpecId::AMSTERDAM);
330        Self {
331            chain_id: 1,
332            tx_chain_id_check: true,
333            limit_contract_code_size: None,
334            limit_contract_initcode_size: None,
335            spec,
336            disable_nonce_check: false,
337            max_blobs_per_tx: None,
338            tx_gas_limit_cap: None,
339            cpsb_override: None,
340            blob_base_fee_update_fraction: None,
341            gas_params,
342            #[cfg(feature = "memory_limit")]
343            memory_limit: (1 << 32) - 1,
344            #[cfg(feature = "optional_balance_check")]
345            disable_balance_check: false,
346            #[cfg(feature = "optional_block_gas_limit")]
347            disable_block_gas_limit: false,
348            #[cfg(feature = "optional_eip3541")]
349            disable_eip3541: false,
350            #[cfg(feature = "optional_eip3607")]
351            disable_eip3607: false,
352            #[cfg(feature = "optional_eip7623")]
353            disable_eip7623: false,
354            #[cfg(feature = "optional_no_base_fee")]
355            disable_base_fee: false,
356            #[cfg(feature = "optional_priority_fee_check")]
357            disable_priority_fee_check: false,
358            #[cfg(feature = "optional_fee_charge")]
359            disable_fee_charge: false,
360            enable_amsterdam_eip8037: is_amsterdam,
361            amsterdam_eip7708_disabled: false,
362            amsterdam_eip7708_delayed_burn_disabled: false,
363        }
364    }
365
366    /// Returns the blob base fee update fraction from [CfgEnv::blob_base_fee_update_fraction].
367    ///
368    /// If this field is not set, return the default value for the spec.
369    ///
370    /// Default values for Cancun is [`primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN`]
371    /// and for Prague is [`primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE`].
372    pub fn blob_base_fee_update_fraction(&self) -> u64 {
373        self.blob_base_fee_update_fraction.unwrap_or_else(|| {
374            let spec: SpecId = self.spec.clone().into();
375            if spec.is_enabled_in(SpecId::PRAGUE) {
376                primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE
377            } else {
378                primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN
379            }
380        })
381    }
382
383    /// Create new `CfgEnv` with default values and specified spec.
384    /// It will create a new gas params based on mainnet spec.
385    ///
386    /// Internally it will call [`CfgEnv::new_with_spec_and_gas_params`] with the mainnet gas params.
387    pub fn new_with_spec(spec: SPEC) -> Self {
388        Self::new_with_spec_and_gas_params(spec.clone(), GasParams::new_spec(spec.into()))
389    }
390
391    /// Sets the gas params for the `CfgEnv` to the mainnet gas params.
392    ///
393    /// If spec gets changed, calling this function would use this spec to set the mainnetF gas params.
394    pub fn with_mainnet_gas_params(mut self) -> Self {
395        self.set_gas_params(GasParams::new_spec(self.spec.clone().into()));
396        self
397    }
398
399    /// Sets the spec for the `CfgEnv` and the gas params to the mainnet gas params.
400    ///
401    /// Automatically enables EIP-8037 for AMSTERDAM and later.
402    #[inline]
403    pub fn set_spec_and_mainnet_gas_params(&mut self, spec: SPEC) {
404        self.spec = spec.clone();
405        self.set_gas_params(GasParams::new_spec(spec.clone().into()));
406        // EIP-8037: Enable EIP-8037 for AMSTERDAM and later
407        if spec.into().is_enabled_in(SpecId::AMSTERDAM) {
408            self.enable_amsterdam_eip8037 = true;
409        }
410    }
411}
412
413impl<SPEC: Into<SpecId> + Clone> Cfg for CfgEnv<SPEC> {
414    type Spec = SPEC;
415
416    #[inline]
417    fn chain_id(&self) -> u64 {
418        self.chain_id
419    }
420
421    #[inline]
422    fn spec(&self) -> Self::Spec {
423        self.spec.clone()
424    }
425
426    #[inline]
427    fn tx_chain_id_check(&self) -> bool {
428        self.tx_chain_id_check
429    }
430
431    #[inline]
432    fn tx_gas_limit_cap(&self) -> u64 {
433        self.tx_gas_limit_cap
434            .unwrap_or(if self.spec.clone().into().is_enabled_in(SpecId::OSAKA) {
435                eip7825::TX_GAS_LIMIT_CAP
436            } else {
437                u64::MAX
438            })
439    }
440
441    #[inline]
442    fn max_blobs_per_tx(&self) -> Option<u64> {
443        self.max_blobs_per_tx
444    }
445
446    fn max_code_size(&self) -> usize {
447        self.limit_contract_code_size.unwrap_or(
448            if self.spec.clone().into().is_enabled_in(SpecId::AMSTERDAM) {
449                eip7954::MAX_CODE_SIZE
450            } else {
451                eip170::MAX_CODE_SIZE
452            },
453        )
454    }
455
456    fn max_initcode_size(&self) -> usize {
457        self.limit_contract_initcode_size
458            .or_else(|| {
459                self.limit_contract_code_size
460                    .map(|size| size.saturating_mul(2))
461            })
462            .unwrap_or(
463                if self.spec.clone().into().is_enabled_in(SpecId::AMSTERDAM) {
464                    eip7954::MAX_INITCODE_SIZE
465                } else {
466                    eip3860::MAX_INITCODE_SIZE
467                },
468            )
469    }
470
471    fn is_eip3541_disabled(&self) -> bool {
472        cfg_if::cfg_if! {
473            if #[cfg(feature = "optional_eip3541")] {
474                self.disable_eip3541
475            } else {
476                false
477            }
478        }
479    }
480
481    fn is_eip3607_disabled(&self) -> bool {
482        cfg_if::cfg_if! {
483            if #[cfg(feature = "optional_eip3607")] {
484                self.disable_eip3607
485            } else {
486                false
487            }
488        }
489    }
490
491    fn is_eip7623_disabled(&self) -> bool {
492        cfg_if::cfg_if! {
493            if #[cfg(feature = "optional_eip7623")] {
494                self.disable_eip7623
495            } else {
496                false
497            }
498        }
499    }
500
501    fn is_balance_check_disabled(&self) -> bool {
502        cfg_if::cfg_if! {
503            if #[cfg(feature = "optional_balance_check")] {
504                self.disable_balance_check
505            } else {
506                false
507            }
508        }
509    }
510
511    /// Returns `true` if the block gas limit is disabled.
512    fn is_block_gas_limit_disabled(&self) -> bool {
513        cfg_if::cfg_if! {
514            if #[cfg(feature = "optional_block_gas_limit")] {
515                self.disable_block_gas_limit
516            } else {
517                false
518            }
519        }
520    }
521
522    fn is_nonce_check_disabled(&self) -> bool {
523        self.disable_nonce_check
524    }
525
526    fn is_base_fee_check_disabled(&self) -> bool {
527        cfg_if::cfg_if! {
528            if #[cfg(feature = "optional_no_base_fee")] {
529                self.disable_base_fee
530            } else {
531                false
532            }
533        }
534    }
535
536    fn is_priority_fee_check_disabled(&self) -> bool {
537        cfg_if::cfg_if! {
538            if #[cfg(feature = "optional_priority_fee_check")] {
539                self.disable_priority_fee_check
540            } else {
541                false
542            }
543        }
544    }
545
546    fn is_fee_charge_disabled(&self) -> bool {
547        cfg_if::cfg_if! {
548            if #[cfg(feature = "optional_fee_charge")] {
549                self.disable_fee_charge
550            } else {
551                false
552            }
553        }
554    }
555
556    fn is_eip7708_disabled(&self) -> bool {
557        self.amsterdam_eip7708_disabled
558    }
559
560    fn is_eip7708_delayed_burn_disabled(&self) -> bool {
561        self.amsterdam_eip7708_delayed_burn_disabled
562    }
563
564    fn memory_limit(&self) -> u64 {
565        cfg_if::cfg_if! {
566            if #[cfg(feature = "memory_limit")] {
567                self.memory_limit
568            } else {
569                u64::MAX
570            }
571        }
572    }
573
574    #[inline]
575    fn gas_params(&self) -> &GasParams {
576        &self.gas_params
577    }
578
579    fn is_amsterdam_eip8037_enabled(&self) -> bool {
580        self.enable_amsterdam_eip8037
581    }
582
583    #[inline]
584    fn cpsb(&self) -> u64 {
585        if !self.enable_amsterdam_eip8037 {
586            return 0;
587        }
588        self.cpsb_override.unwrap_or(eip8037::CPSB_GLAMSTERDAM)
589    }
590}
591
592impl<SPEC: Default + Into<SpecId> + Clone> Default for CfgEnv<SPEC> {
593    fn default() -> Self {
594        Self::new_with_spec_and_gas_params(
595            SPEC::default(),
596            GasParams::new_spec(SPEC::default().into()),
597        )
598    }
599}
600
601#[cfg(test)]
602mod test {
603    use super::*;
604
605    #[test]
606    fn blob_max_and_target_count() {
607        let cfg: CfgEnv = Default::default();
608        assert_eq!(cfg.max_blobs_per_tx(), None);
609    }
610}