revm_context/
cfg.rs

1pub use context_interface::Cfg;
2
3use primitives::{eip170::MAX_CODE_SIZE, hardfork::SpecId};
4use std::{vec, vec::Vec};
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
12    ///
13    /// `chain_id` will be compared to the transaction's Chain ID.
14    ///
15    /// Chain ID is introduced EIP-155.
16    pub chain_id: u64,
17    /// Specification for EVM represent the hardfork
18    pub spec: SPEC,
19    /// If some it will effects EIP-170: Contract code size limit.
20    ///
21    /// Useful to increase this because of tests.
22    ///
23    /// By default it is `0x6000` (~25kb).
24    pub limit_contract_code_size: Option<usize>,
25    /// Skips the nonce validation against the account's nonce
26    pub disable_nonce_check: bool,
27    /// Blob target count. EIP-7840 Add blob schedule to EL config files.
28    ///
29    /// Note : Items must be sorted by `SpecId`.
30    pub blob_target_and_max_count: Vec<(SpecId, u64, u64)>,
31    /// A hard memory limit in bytes beyond which
32    /// [OutOfGasError::Memory][context_interface::result::OutOfGasError::Memory] cannot be resized.
33    ///
34    /// In cases where the gas limit may be extraordinarily high, it is recommended to set this to
35    /// a sane value to prevent memory allocation panics.
36    ///
37    /// Defaults to `2^32 - 1` bytes per EIP-1985.
38    #[cfg(feature = "memory_limit")]
39    pub memory_limit: u64,
40    /// Skip balance checks if `true`
41    ///
42    /// Adds transaction cost to balance to ensure execution doesn't fail.
43    ///
44    /// By default, it is set to `false`.
45    #[cfg(feature = "optional_balance_check")]
46    pub disable_balance_check: bool,
47    /// There are use cases where it's allowed to provide a gas limit that's higher than a block's gas limit.
48    ///
49    /// To that end, you can disable the block gas limit validation.
50    ///
51    /// By default, it is set to `false`.
52    #[cfg(feature = "optional_block_gas_limit")]
53    pub disable_block_gas_limit: bool,
54    /// EIP-3607 rejects transactions from senders with deployed code
55    ///
56    /// In development, it can be desirable to simulate calls from contracts, which this setting allows.
57    ///
58    /// By default, it is set to `false`.
59    #[cfg(feature = "optional_eip3607")]
60    pub disable_eip3607: bool,
61    /// Disables base fee checks for EIP-1559 transactions
62    ///
63    /// This is useful for testing method calls with zero gas price.
64    ///
65    /// By default, it is set to `false`.
66    #[cfg(feature = "optional_no_base_fee")]
67    pub disable_base_fee: bool,
68}
69
70impl CfgEnv {
71    /// Creates new `CfgEnv` with default values.
72    pub fn new() -> Self {
73        Self::default()
74    }
75}
76
77impl<SPEC> CfgEnv<SPEC> {
78    pub fn new_with_spec(spec: SPEC) -> Self {
79        Self {
80            chain_id: 1,
81            limit_contract_code_size: None,
82            spec,
83            disable_nonce_check: false,
84            blob_target_and_max_count: vec![(SpecId::CANCUN, 3, 6), (SpecId::PRAGUE, 6, 9)],
85            #[cfg(feature = "memory_limit")]
86            memory_limit: (1 << 32) - 1,
87            #[cfg(feature = "optional_balance_check")]
88            disable_balance_check: false,
89            #[cfg(feature = "optional_block_gas_limit")]
90            disable_block_gas_limit: false,
91            #[cfg(feature = "optional_eip3607")]
92            disable_eip3607: false,
93            #[cfg(feature = "optional_no_base_fee")]
94            disable_base_fee: false,
95        }
96    }
97
98    pub fn with_chain_id(mut self, chain_id: u64) -> Self {
99        self.chain_id = chain_id;
100        self
101    }
102
103    pub fn with_spec<OSPEC: Into<SpecId>>(self, spec: OSPEC) -> CfgEnv<OSPEC> {
104        CfgEnv {
105            chain_id: self.chain_id,
106            limit_contract_code_size: self.limit_contract_code_size,
107            spec,
108            disable_nonce_check: self.disable_nonce_check,
109            blob_target_and_max_count: self.blob_target_and_max_count,
110            #[cfg(feature = "memory_limit")]
111            memory_limit: self.memory_limit,
112            #[cfg(feature = "optional_balance_check")]
113            disable_balance_check: self.disable_balance_check,
114            #[cfg(feature = "optional_block_gas_limit")]
115            disable_block_gas_limit: self.disable_block_gas_limit,
116            #[cfg(feature = "optional_eip3607")]
117            disable_eip3607: self.disable_eip3607,
118            #[cfg(feature = "optional_no_base_fee")]
119            disable_base_fee: self.disable_base_fee,
120        }
121    }
122
123    /// Sets the blob target and max count over hardforks.
124    pub fn with_blob_max_and_target_count(mut self, blob_params: Vec<(SpecId, u64, u64)>) -> Self {
125        self.set_blob_max_and_target_count(blob_params);
126        self
127    }
128
129    /// Sets the blob target and max count over hardforks.
130    pub fn set_blob_max_and_target_count(&mut self, mut blob_params: Vec<(SpecId, u64, u64)>) {
131        blob_params.sort_by_key(|(id, _, _)| *id);
132        self.blob_target_and_max_count = blob_params;
133    }
134}
135
136impl<SPEC: Into<SpecId> + Copy> Cfg for CfgEnv<SPEC> {
137    type Spec = SPEC;
138
139    fn chain_id(&self) -> u64 {
140        self.chain_id
141    }
142
143    fn spec(&self) -> Self::Spec {
144        self.spec
145    }
146
147    #[inline]
148    fn blob_max_count(&self, spec_id: SpecId) -> u64 {
149        self.blob_target_and_max_count
150            .iter()
151            .rev()
152            .find_map(|(id, _, max)| {
153                if spec_id as u8 >= *id as u8 {
154                    return Some(*max);
155                }
156                None
157            })
158            .unwrap_or(6)
159    }
160
161    fn max_code_size(&self) -> usize {
162        self.limit_contract_code_size.unwrap_or(MAX_CODE_SIZE)
163    }
164
165    fn is_eip3607_disabled(&self) -> bool {
166        cfg_if::cfg_if! {
167            if #[cfg(feature = "optional_eip3607")] {
168                self.disable_eip3607
169            } else {
170                false
171            }
172        }
173    }
174
175    fn is_balance_check_disabled(&self) -> bool {
176        cfg_if::cfg_if! {
177            if #[cfg(feature = "optional_balance_check")] {
178                self.disable_balance_check
179            } else {
180                false
181            }
182        }
183    }
184
185    /// Returns `true` if the block gas limit is disabled.
186    fn is_block_gas_limit_disabled(&self) -> bool {
187        cfg_if::cfg_if! {
188            if #[cfg(feature = "optional_block_gas_limit")] {
189                self.disable_block_gas_limit
190            } else {
191                false
192            }
193        }
194    }
195
196    fn is_nonce_check_disabled(&self) -> bool {
197        self.disable_nonce_check
198    }
199
200    fn is_base_fee_check_disabled(&self) -> bool {
201        cfg_if::cfg_if! {
202            if #[cfg(feature = "optional_no_base_fee")] {
203                self.disable_base_fee
204            } else {
205                false
206            }
207        }
208    }
209}
210
211impl<SPEC: Default> Default for CfgEnv<SPEC> {
212    fn default() -> Self {
213        Self::new_with_spec(SPEC::default())
214    }
215}
216
217#[cfg(test)]
218mod test {
219    use super::*;
220
221    #[test]
222    fn blob_max_and_target_count() {
223        let cfg: CfgEnv = Default::default();
224        assert_eq!(cfg.blob_max_count(SpecId::BERLIN), (6));
225        assert_eq!(cfg.blob_max_count(SpecId::CANCUN), (6));
226        assert_eq!(cfg.blob_max_count(SpecId::PRAGUE), (9));
227        assert_eq!(cfg.blob_max_count(SpecId::OSAKA), (9));
228    }
229}