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}
134
135impl CfgEnv {
136    /// Creates new `CfgEnv` with default values.
137    pub fn new() -> Self {
138        Self::default()
139    }
140}
141
142impl<SPEC> CfgEnv<SPEC> {
143    /// Create new `CfgEnv` with default values and specified spec.
144    pub fn new_with_spec_and_gas_params(spec: SPEC, gas_params: GasParams) -> Self {
145        Self {
146            chain_id: 1,
147            tx_chain_id_check: true,
148            limit_contract_code_size: None,
149            limit_contract_initcode_size: None,
150            spec,
151            disable_nonce_check: false,
152            max_blobs_per_tx: None,
153            tx_gas_limit_cap: None,
154            blob_base_fee_update_fraction: None,
155            gas_params,
156            #[cfg(feature = "memory_limit")]
157            memory_limit: (1 << 32) - 1,
158            #[cfg(feature = "optional_balance_check")]
159            disable_balance_check: false,
160            #[cfg(feature = "optional_block_gas_limit")]
161            disable_block_gas_limit: false,
162            #[cfg(feature = "optional_eip3541")]
163            disable_eip3541: false,
164            #[cfg(feature = "optional_eip3607")]
165            disable_eip3607: false,
166            #[cfg(feature = "optional_eip7623")]
167            disable_eip7623: false,
168            #[cfg(feature = "optional_no_base_fee")]
169            disable_base_fee: false,
170            #[cfg(feature = "optional_priority_fee_check")]
171            disable_priority_fee_check: false,
172            #[cfg(feature = "optional_fee_charge")]
173            disable_fee_charge: false,
174        }
175    }
176
177    /// Returns the spec for the `CfgEnv`.
178    #[inline]
179    pub fn spec(&self) -> &SPEC {
180        &self.spec
181    }
182
183    /// Consumes `self` and returns a new `CfgEnv` with the specified chain ID.
184    pub fn with_chain_id(mut self, chain_id: u64) -> Self {
185        self.chain_id = chain_id;
186        self
187    }
188
189    /// Sets the gas params for the `CfgEnv`.
190    #[inline]
191    pub fn with_gas_params(mut self, gas_params: GasParams) -> Self {
192        self.set_gas_params(gas_params);
193        self
194    }
195
196    /// Sets the spec for the `CfgEnv`.
197    #[inline]
198    pub fn set_spec(&mut self, spec: SPEC) {
199        self.spec = spec;
200    }
201
202    /// Sets the gas params for the `CfgEnv`.
203    #[inline]
204    pub fn set_gas_params(&mut self, gas_params: GasParams) {
205        self.gas_params = gas_params;
206    }
207
208    /// Enables the transaction's chain ID check.
209    pub fn enable_tx_chain_id_check(mut self) -> Self {
210        self.tx_chain_id_check = true;
211        self
212    }
213
214    /// Disables the transaction's chain ID check.
215    pub fn disable_tx_chain_id_check(mut self) -> Self {
216        self.tx_chain_id_check = false;
217        self
218    }
219
220    /// Sets the spec for the `CfgEnv`.
221    #[inline]
222    #[deprecated(
223        since = "0.1.0",
224        note = "Use [`CfgEnv::with_spec_and_mainnet_gas_params`] instead"
225    )]
226    pub fn with_spec(mut self, spec: SPEC) -> Self {
227        self.spec = spec;
228        self
229    }
230
231    /// Sets the spec for the `CfgEnv` and the gas params to the mainnet gas params.
232    pub fn with_spec_and_mainnet_gas_params<OSPEC: Into<SpecId> + Clone>(
233        self,
234        spec: OSPEC,
235    ) -> CfgEnv<OSPEC> {
236        self.with_spec_and_gas_params(spec.clone(), GasParams::new_spec(spec.into()))
237    }
238
239    /// Consumes `self` and returns a new `CfgEnv` with the specified spec.
240    ///
241    /// Resets the gas params override function as it is generic over SPEC.
242    pub fn with_spec_and_gas_params<OSPEC: Into<SpecId> + Clone>(
243        self,
244        spec: OSPEC,
245        gas_params: GasParams,
246    ) -> CfgEnv<OSPEC> {
247        CfgEnv {
248            chain_id: self.chain_id,
249            tx_chain_id_check: self.tx_chain_id_check,
250            limit_contract_code_size: self.limit_contract_code_size,
251            limit_contract_initcode_size: self.limit_contract_initcode_size,
252            spec,
253            disable_nonce_check: self.disable_nonce_check,
254            tx_gas_limit_cap: self.tx_gas_limit_cap,
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        }
277    }
278
279    /// Sets the blob target
280    pub fn with_max_blobs_per_tx(mut self, max_blobs_per_tx: u64) -> Self {
281        self.set_max_blobs_per_tx(max_blobs_per_tx);
282        self
283    }
284
285    /// Sets the blob target
286    pub fn set_max_blobs_per_tx(&mut self, max_blobs_per_tx: u64) {
287        self.max_blobs_per_tx = Some(max_blobs_per_tx);
288    }
289
290    /// Clears the blob target and max count over hardforks.
291    pub fn clear_max_blobs_per_tx(&mut self) {
292        self.max_blobs_per_tx = None;
293    }
294
295    /// Sets the disable priority fee check flag.
296    #[cfg(feature = "optional_priority_fee_check")]
297    pub fn with_disable_priority_fee_check(mut self, disable: bool) -> Self {
298        self.disable_priority_fee_check = disable;
299        self
300    }
301
302    /// Sets the disable fee charge flag.
303    #[cfg(feature = "optional_fee_charge")]
304    pub fn with_disable_fee_charge(mut self, disable: bool) -> Self {
305        self.disable_fee_charge = disable;
306        self
307    }
308
309    /// Sets the disable eip7623 flag.
310    #[cfg(feature = "optional_eip7623")]
311    pub fn with_disable_eip7623(mut self, disable: bool) -> Self {
312        self.disable_eip7623 = disable;
313        self
314    }
315}
316
317impl<SPEC: Into<SpecId> + Clone> CfgEnv<SPEC> {
318    /// Returns the blob base fee update fraction from [CfgEnv::blob_base_fee_update_fraction].
319    ///
320    /// If this field is not set, return the default value for the spec.
321    ///
322    /// Default values for Cancun is [`primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN`]
323    /// and for Prague is [`primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE`].
324    pub fn blob_base_fee_update_fraction(&mut self) -> u64 {
325        self.blob_base_fee_update_fraction.unwrap_or_else(|| {
326            let spec: SpecId = self.spec.clone().into();
327            if spec.is_enabled_in(SpecId::PRAGUE) {
328                primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE
329            } else {
330                primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN
331            }
332        })
333    }
334
335    /// Create new `CfgEnv` with default values and specified spec.
336    /// It will create a new gas params based on mainnet spec.
337    ///
338    /// Internally it will call [`CfgEnv::new_with_spec_and_gas_params`] with the mainnet gas params.
339    pub fn new_with_spec(spec: SPEC) -> Self {
340        Self::new_with_spec_and_gas_params(spec.clone(), GasParams::new_spec(spec.into()))
341    }
342
343    /// Sets the gas params for the `CfgEnv` to the mainnet gas params.
344    ///
345    /// If spec gets changed, calling this function would use this spec to set the mainnetF gas params.
346    pub fn with_mainnet_gas_params(mut self) -> Self {
347        self.set_gas_params(GasParams::new_spec(self.spec.clone().into()));
348        self
349    }
350
351    /// Sets the spec for the `CfgEnv` and the gas params to the mainnet gas params.
352    #[inline]
353    pub fn set_spec_and_mainnet_gas_params(&mut self, spec: SPEC) {
354        self.set_spec(spec.clone());
355        self.set_gas_params(GasParams::new_spec(spec.into()));
356    }
357}
358
359impl<SPEC: Into<SpecId> + Clone> Cfg for CfgEnv<SPEC> {
360    type Spec = SPEC;
361
362    #[inline]
363    fn chain_id(&self) -> u64 {
364        self.chain_id
365    }
366
367    #[inline]
368    fn spec(&self) -> Self::Spec {
369        self.spec.clone()
370    }
371
372    #[inline]
373    fn tx_chain_id_check(&self) -> bool {
374        self.tx_chain_id_check
375    }
376
377    #[inline]
378    fn tx_gas_limit_cap(&self) -> u64 {
379        self.tx_gas_limit_cap
380            .unwrap_or(if self.spec.clone().into().is_enabled_in(SpecId::OSAKA) {
381                eip7825::TX_GAS_LIMIT_CAP
382            } else {
383                u64::MAX
384            })
385    }
386
387    #[inline]
388    fn max_blobs_per_tx(&self) -> Option<u64> {
389        self.max_blobs_per_tx
390    }
391
392    fn max_code_size(&self) -> usize {
393        self.limit_contract_code_size
394            .unwrap_or(eip170::MAX_CODE_SIZE)
395    }
396
397    fn max_initcode_size(&self) -> usize {
398        self.limit_contract_initcode_size
399            .or_else(|| {
400                self.limit_contract_code_size
401                    .map(|size| size.saturating_mul(2))
402            })
403            .unwrap_or(eip3860::MAX_INITCODE_SIZE)
404    }
405
406    fn is_eip3541_disabled(&self) -> bool {
407        cfg_if::cfg_if! {
408            if #[cfg(feature = "optional_eip3541")] {
409                self.disable_eip3541
410            } else {
411                false
412            }
413        }
414    }
415
416    fn is_eip3607_disabled(&self) -> bool {
417        cfg_if::cfg_if! {
418            if #[cfg(feature = "optional_eip3607")] {
419                self.disable_eip3607
420            } else {
421                false
422            }
423        }
424    }
425
426    fn is_eip7623_disabled(&self) -> bool {
427        cfg_if::cfg_if! {
428            if #[cfg(feature = "optional_eip7623")] {
429                self.disable_eip7623
430            } else {
431                false
432            }
433        }
434    }
435
436    fn is_balance_check_disabled(&self) -> bool {
437        cfg_if::cfg_if! {
438            if #[cfg(feature = "optional_balance_check")] {
439                self.disable_balance_check
440            } else {
441                false
442            }
443        }
444    }
445
446    /// Returns `true` if the block gas limit is disabled.
447    fn is_block_gas_limit_disabled(&self) -> bool {
448        cfg_if::cfg_if! {
449            if #[cfg(feature = "optional_block_gas_limit")] {
450                self.disable_block_gas_limit
451            } else {
452                false
453            }
454        }
455    }
456
457    fn is_nonce_check_disabled(&self) -> bool {
458        self.disable_nonce_check
459    }
460
461    fn is_base_fee_check_disabled(&self) -> bool {
462        cfg_if::cfg_if! {
463            if #[cfg(feature = "optional_no_base_fee")] {
464                self.disable_base_fee
465            } else {
466                false
467            }
468        }
469    }
470
471    fn is_priority_fee_check_disabled(&self) -> bool {
472        cfg_if::cfg_if! {
473            if #[cfg(feature = "optional_priority_fee_check")] {
474                self.disable_priority_fee_check
475            } else {
476                false
477            }
478        }
479    }
480
481    fn is_fee_charge_disabled(&self) -> bool {
482        cfg_if::cfg_if! {
483            if #[cfg(feature = "optional_fee_charge")] {
484                self.disable_fee_charge
485            } else {
486                false
487            }
488        }
489    }
490
491    fn memory_limit(&self) -> u64 {
492        cfg_if::cfg_if! {
493            if #[cfg(feature = "memory_limit")] {
494                self.memory_limit
495            } else {
496                u64::MAX
497            }
498        }
499    }
500
501    #[inline]
502    fn gas_params(&self) -> &GasParams {
503        &self.gas_params
504    }
505}
506
507impl<SPEC: Default + Into<SpecId>> Default for CfgEnv<SPEC> {
508    fn default() -> Self {
509        Self::new_with_spec_and_gas_params(
510            SPEC::default(),
511            GasParams::new_spec(SPEC::default().into()),
512        )
513    }
514}
515
516#[cfg(test)]
517mod test {
518    use super::*;
519
520    #[test]
521    fn blob_max_and_target_count() {
522        let cfg: CfgEnv = Default::default();
523        assert_eq!(cfg.max_blobs_per_tx(), None);
524    }
525}