Skip to main content

ethrex_levm/
environment.rs

1use ethrex_common::{
2    Address, H256, U256,
3    types::{BlockHeader, ChainConfig, Fork, ForkBlobSchedule},
4};
5
6use crate::constants::{
7    BLOB_BASE_FEE_UPDATE_FRACTION, BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE, MAX_BLOB_COUNT,
8    MAX_BLOB_COUNT_ELECTRA, TARGET_BLOB_GAS_PER_BLOCK, TARGET_BLOB_GAS_PER_BLOCK_PECTRA,
9};
10use ethrex_common::seeded_hash::SeededHashMap;
11
12/// [EIP-1153]: https://eips.ethereum.org/EIPS/eip-1153#reference-implementation
13///
14/// Seeded: contracts choose these keys (see [`SeededHashMap`]).
15pub type TransientStorage = SeededHashMap<(Address, U256), U256>;
16
17#[derive(Debug, Default, Clone)]
18/// Environmental information that the execution agent must provide.
19pub struct Environment {
20    /// The sender address of the external transaction.
21    pub origin: Address,
22    /// Gas limit of the Transaction
23    pub gas_limit: u64,
24    pub config: EVMConfig,
25    pub block_number: u64,
26    /// Coinbase is the block's beneficiary - the address that receives the block rewards and fees.
27    pub coinbase: Address,
28    pub timestamp: u64,
29    pub prev_randao: Option<H256>,
30    pub difficulty: U256,
31    pub slot_number: U256,
32    pub chain_id: U256,
33    pub base_fee_per_gas: U256,
34    pub base_blob_fee_per_gas: U256,
35    pub gas_price: U256, // Effective gas price
36    pub block_excess_blob_gas: Option<u64>,
37    pub block_blob_gas_used: Option<u64>,
38    pub tx_blob_hashes: Vec<H256>,
39    pub tx_max_priority_fee_per_gas: Option<U256>,
40    pub tx_max_fee_per_gas: Option<U256>,
41    pub tx_max_fee_per_blob_gas: Option<U256>,
42    pub tx_nonce: u64,
43    pub block_gas_limit: u64,
44    pub is_privileged: bool,
45    pub fee_token: Option<Address>,
46    /// When true, skip balance deduction in `deduct_caller`. Used by the prewarmer
47    /// to avoid early reverts on insufficient balance so that warming touches more storage.
48    pub disable_balance_check: bool,
49    /// When true, skip the sender nonce-mismatch validation. Used by the simulation
50    /// RPCs (eth_call, eth_estimateGas, eth_createAccessList): call objects may omit
51    /// the nonce, and no client enforces it there. The account nonce still increments
52    /// during execution. `debug_traceCall` relies on it too (geth's
53    /// `ToMessage(_, skipNonceCheck=true)`): the synthetic call may run on top of a
54    /// mid-block state (`txIndex`) whose nonce differs from the value the caller
55    /// supplied, so enforcing the check would spuriously reject the trace.
56    pub disable_nonce_check: bool,
57    /// When true, skip the gas limits that gate a transaction's *admission* rather than
58    /// its execution: the block-level gas allowance and the EIP-7825 per-transaction cap.
59    /// Used by every simulation RPC (eth_call, eth_estimateGas, eth_createAccessList,
60    /// debug_traceCall), whose callers routinely pass a `gas` above either bound — tools
61    /// commonly pass the block gas limit — and still expect an answer, since nothing is
62    /// being submitted.
63    /// This exists so `block_gas_limit` can keep the block's real value: that field is
64    /// observable through the GASLIMIT opcode and feeds the EIP-8037 cost-per-state-byte
65    /// formula, so raising it to bypass the allowance corrupts both.
66    pub disable_gas_allowance_check: bool,
67    /// When true, skip the EIP-3607 validation that rejects a sender carrying code.
68    /// Used by every simulation RPC (eth_call, eth_estimateGas, eth_createAccessList,
69    /// debug_traceCall). EIP-3607 exists because a contract has no private key, so no
70    /// valid signature should exist for its address; a simulated call carries no
71    /// signature at all and its `from` is just an assertion by the caller, so the rule
72    /// has nothing to protect there. Enforcing it breaks the common practice of
73    /// simulating a call whose sender is a contract, such as a smart contract wallet
74    /// previewing its own transaction. Transaction admission keeps enforcing it: the
75    /// mempool rejects such a sender outright, and block execution never sets this flag.
76    pub disable_sender_eoa_check: bool,
77    /// When true, the EIP-8037 cap on the execution dimension (Amsterdam+) is lifted: the
78    /// whole gas limit is execution gas and no state-gas reservoir is funded from it, so a
79    /// simulation given more than the per-transaction execution cap can actually spend it.
80    /// Set by `eth_call` and `debug_traceCall` only, as geth does, since nothing they run is
81    /// ever submitted. `eth_estimateGas` and `eth_createAccessList` keep the cap, because
82    /// their answers must hold for a transaction that can be included. Block execution
83    /// never sets it.
84    pub disable_execution_gas_cap: bool,
85    /// When true, the tx is a pre-execution system contract call (EIP-2935, EIP-4788,
86    /// EIP-7002, EIP-7251 etc.). Skips the block-level gas-allowance check since system
87    /// calls are allowed to exceed `block_gas_limit` (their 30M cap is a separate rule).
88    pub is_system_call: bool,
89}
90
91/// This struct holds special configuration variables specific to the
92/// EVM. In most cases, at least at the time of writing (February
93/// 2025), you want to use the default blob_schedule values for the
94/// specified Fork. The "intended" way to do this is by using the `EVMConfig::canonical_values(fork: Fork)` function.
95///
96/// However, that function should NOT be used IF you want to use a
97/// custom `ForkBlobSchedule`, like it's described in [EIP-7840](https://eips.ethereum.org/EIPS/eip-7840)
98/// Values are determined by [EIP-7691](https://eips.ethereum.org/EIPS/eip-7691#specification)
99#[derive(Debug, Clone, Copy)]
100pub struct EVMConfig {
101    pub fork: Fork,
102    pub blob_schedule: ForkBlobSchedule,
103}
104
105impl EVMConfig {
106    pub fn new(fork: Fork, blob_schedule: ForkBlobSchedule) -> EVMConfig {
107        EVMConfig {
108            fork,
109            blob_schedule,
110        }
111    }
112
113    pub fn new_from_chain_config(chain_config: &ChainConfig, block_header: &BlockHeader) -> Self {
114        let fork = chain_config.fork(block_header.timestamp);
115
116        let blob_schedule = chain_config
117            .get_fork_blob_schedule(block_header.timestamp)
118            .unwrap_or_else(|| EVMConfig::canonical_values(fork));
119
120        EVMConfig::new(fork, blob_schedule)
121    }
122
123    /// This function is used for running the EF tests. If you don't
124    /// have acces to a EVMConfig (mainly in the form of a
125    /// genesis.json file) you can use this function to get the
126    /// "Default" ForkBlobSchedule for that specific Fork.
127    /// NOTE: This function could potentially be expanded to include
128    /// other types of "default"s.
129    pub fn canonical_values(fork: Fork) -> ForkBlobSchedule {
130        let max_blobs_per_block = Self::max_blobs_per_block(fork);
131        let target = Self::get_target_blob_gas_per_block_(fork);
132        let base_fee_update_fraction: u64 = Self::get_blob_base_fee_update_fraction_value(fork);
133
134        ForkBlobSchedule {
135            target,
136            max: max_blobs_per_block,
137            base_fee_update_fraction,
138        }
139    }
140
141    fn max_blobs_per_block(fork: Fork) -> u32 {
142        if fork >= Fork::Prague {
143            MAX_BLOB_COUNT_ELECTRA
144        } else {
145            MAX_BLOB_COUNT
146        }
147    }
148
149    fn get_blob_base_fee_update_fraction_value(fork: Fork) -> u64 {
150        if fork >= Fork::Prague {
151            BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE
152        } else {
153            BLOB_BASE_FEE_UPDATE_FRACTION
154        }
155    }
156
157    fn get_target_blob_gas_per_block_(fork: Fork) -> u32 {
158        if fork >= Fork::Prague {
159            TARGET_BLOB_GAS_PER_BLOCK_PECTRA
160        } else {
161            TARGET_BLOB_GAS_PER_BLOCK
162        }
163    }
164}
165
166impl Default for EVMConfig {
167    /// The default EVMConfig depends on the default Fork.
168    fn default() -> Self {
169        let fork = core::default::Default::default();
170        EVMConfig {
171            fork,
172            blob_schedule: Self::canonical_values(fork),
173        }
174    }
175}