reth_evm/
lib.rs

1//! Traits for configuring an EVM specifics.
2//!
3//! # Revm features
4//!
5//! This crate does __not__ enforce specific revm features such as `blst` or `c-kzg`, which are
6//! critical for revm's evm internals, it is the responsibility of the implementer to ensure the
7//! proper features are selected.
8
9#![doc(
10    html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
11    html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
12    issue_tracker_base_url = "https://github.com/SeismicSystems/seismic-reth/issues/"
13)]
14#![cfg_attr(not(test), warn(unused_crate_dependencies))]
15#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
16#![cfg_attr(not(feature = "std"), no_std)]
17
18extern crate alloc;
19
20use crate::builder::RethEvmBuilder;
21use alloy_consensus::{transaction::TxSeismicElements, BlockHeader as _, TxSeismic};
22use alloy_primitives::{Address, Bytes, TxHash, B256, U256};
23use reth_enclave::{EnclaveError, SchnorrkelKeypair};
24use reth_primitives_traits::BlockHeader;
25use revm::{seismic::RngContainer, Database, Evm, GetInspector};
26use revm_primitives::{
27    BlockEnv, CfgEnvWithHandlerCfg, EVMError, EVMResultGeneric, Env, EnvWithHandlerCfg, SpecId,
28    TxEnv,
29};
30
31pub mod builder;
32pub mod either;
33pub mod execute;
34#[cfg(feature = "std")]
35pub mod metrics;
36pub mod noop;
37pub mod provider;
38pub mod state_change;
39pub mod system_calls;
40#[cfg(any(test, feature = "test-utils"))]
41/// test helpers for mocking executor
42pub mod test_utils;
43
44/// Trait for configuring the EVM for executing full blocks.
45#[auto_impl::auto_impl(&, Arc)]
46pub trait ConfigureEvm: ConfigureEvmEnv {
47    /// Associated type for the default external context that should be configured for the EVM.
48    type DefaultExternalContext<'a>;
49
50    /// Returns new EVM with the given database
51    ///
52    /// This does not automatically configure the EVM with [`ConfigureEvmEnv`] methods. It is up to
53    /// the caller to call an appropriate method to fill the transaction and block environment
54    /// before executing any transactions using the provided EVM.
55    fn evm<DB: Database>(&self, db: DB) -> Evm<'_, Self::DefaultExternalContext<'_>, DB> {
56        RethEvmBuilder::new(db, self.default_external_context()).build()
57    }
58
59    /// Returns a new EVM with the given database configured with the given environment settings,
60    /// including the spec id.
61    ///
62    /// This will preserve any handler modifications
63    fn evm_with_env<DB: Database>(
64        &self,
65        db: DB,
66        env: EnvWithHandlerCfg,
67    ) -> Evm<'_, Self::DefaultExternalContext<'_>, DB> {
68        let mut evm = self.evm(db);
69        evm.modify_spec_id(env.spec_id());
70
71        // This will change if we use our own spec id
72        if env.spec_id() == SpecId::MERCURY {
73            let keypair = match self.get_eph_rng_keypair() {
74                Ok(kp) => kp,
75                Err(err) => {
76                    panic!("Failed to get ephemeral RNG keypair: {err:?}");
77                }
78            };
79            evm.context.evm = evm.context.evm.with_rng_container(RngContainer::new(keypair));
80        }
81
82        evm.context.evm.env = env.env;
83        evm
84    }
85
86    /// Returns a new EVM with the given database configured with the given environment settings,
87    /// including the spec id.
88    ///
89    /// This will use the given external inspector as the EVM external context.
90    ///
91    /// This will preserve any handler modifications
92    fn evm_with_env_and_inspector<DB, I>(
93        &self,
94        db: DB,
95        env: EnvWithHandlerCfg,
96        inspector: I,
97    ) -> Evm<'_, I, DB>
98    where
99        DB: Database,
100        I: GetInspector<DB>,
101    {
102        let mut evm = self.evm_with_inspector(db, inspector);
103        evm.modify_spec_id(env.spec_id());
104        evm.context.evm.env = env.env;
105        evm
106    }
107
108    /// Returns a new EVM with the given inspector.
109    ///
110    /// Caution: This does not automatically configure the EVM with [`ConfigureEvmEnv`] methods. It
111    /// is up to the caller to call an appropriate method to fill the transaction and block
112    /// environment before executing any transactions using the provided EVM.
113    fn evm_with_inspector<DB, I>(&self, db: DB, inspector: I) -> Evm<'_, I, DB>
114    where
115        DB: Database,
116        I: GetInspector<DB>,
117    {
118        RethEvmBuilder::new(db, self.default_external_context()).build_with_inspector(inspector)
119    }
120
121    /// Provides the default external context.
122    fn default_external_context<'a>(&self) -> Self::DefaultExternalContext<'a>;
123}
124
125/// This represents the set of methods used to configure the EVM's environment before block
126/// execution.
127///
128/// Default trait method  implementation is done w.r.t. L1.
129#[auto_impl::auto_impl(&, Arc)]
130pub trait ConfigureEvmEnv: Send + Sync + Unpin + Clone + 'static {
131    /// The header type used by the EVM.
132    type Header: BlockHeader;
133
134    /// The transaction type.
135    type Transaction;
136
137    /// The error type that is returned by [`Self::next_cfg_and_block_env`].
138    type Error: core::error::Error + Send + Sync;
139
140    /// seismic feature encrypt the transaction
141    fn encrypt(
142        &self,
143        _data: &Bytes,
144        _seismic_elements: &TxSeismicElements,
145    ) -> EVMResultGeneric<Bytes, EnclaveError>;
146
147    /// seismic feature decrypt the transaction
148    fn decrypt(
149        &self,
150        _data: &Bytes,
151        _seismic_elements: &TxSeismicElements,
152    ) -> EVMResultGeneric<Bytes, EnclaveError>;
153
154    /// Get current eph_rng_keypair
155    fn get_eph_rng_keypair(&self) -> EVMResultGeneric<SchnorrkelKeypair, EnclaveError>;
156
157    /// seismic feature decrypt the transaction
158    fn fill_seismic_tx_env(
159        &self,
160        _tx_env: &mut TxEnv,
161        _tx: &TxSeismic,
162        _sender: Address,
163        _tx_hash: TxHash,
164    ) -> EVMResultGeneric<(), EnclaveError> {
165        Err(EVMError::Database(EnclaveError::DecryptionError))
166    }
167
168    /// Returns a [`TxEnv`] from a transaction and [`Address`].
169    fn tx_env(
170        &self,
171        transaction: &Self::Transaction,
172        signer: Address,
173    ) -> EVMResultGeneric<TxEnv, EnclaveError> {
174        let mut tx_env = TxEnv::default();
175        self.fill_tx_env(&mut tx_env, transaction, signer)?;
176        Ok(tx_env)
177    }
178
179    /// Fill transaction environment from a transaction  and the given sender address.
180    fn fill_tx_env(
181        &self,
182        tx_env: &mut TxEnv,
183        transaction: &Self::Transaction,
184        sender: Address,
185    ) -> EVMResultGeneric<(), EnclaveError>;
186
187    /// Fill transaction environment with a system contract call.
188    fn fill_tx_env_system_contract_call(
189        &self,
190        env: &mut Env,
191        caller: Address,
192        contract: Address,
193        data: Bytes,
194    );
195
196    /// Returns a [`CfgEnvWithHandlerCfg`] for the given header.
197    fn cfg_env(&self, header: &Self::Header, total_difficulty: U256) -> CfgEnvWithHandlerCfg {
198        let mut cfg = CfgEnvWithHandlerCfg::new(Default::default(), Default::default());
199        self.fill_cfg_env(&mut cfg, header, total_difficulty);
200        cfg
201    }
202
203    /// Fill [`CfgEnvWithHandlerCfg`] fields according to the chain spec and given header.
204    ///
205    /// This __must__ set the corresponding spec id in the handler cfg, based on timestamp or total
206    /// difficulty
207    fn fill_cfg_env(
208        &self,
209        cfg_env: &mut CfgEnvWithHandlerCfg,
210        header: &Self::Header,
211        total_difficulty: U256,
212    );
213
214    /// Fill [`BlockEnv`] field according to the chain spec and given header
215    fn fill_block_env(&self, block_env: &mut BlockEnv, header: &Self::Header, after_merge: bool) {
216        block_env.number = U256::from(header.number());
217        block_env.coinbase = header.beneficiary();
218        block_env.timestamp = U256::from(header.timestamp());
219        if after_merge {
220            block_env.prevrandao = header.mix_hash();
221            block_env.difficulty = U256::ZERO;
222        } else {
223            block_env.difficulty = header.difficulty();
224            block_env.prevrandao = None;
225        }
226        block_env.basefee = U256::from(header.base_fee_per_gas().unwrap_or_default());
227        block_env.gas_limit = U256::from(header.gas_limit());
228
229        // EIP-4844 excess blob gas of this block, introduced in Cancun
230        if let Some(excess_blob_gas) = header.excess_blob_gas() {
231            block_env.set_blob_excess_gas_and_price(excess_blob_gas);
232        }
233    }
234
235    /// Creates a new [`CfgEnvWithHandlerCfg`] and [`BlockEnv`] for the given header.
236    fn cfg_and_block_env(
237        &self,
238        header: &Self::Header,
239        total_difficulty: U256,
240    ) -> (CfgEnvWithHandlerCfg, BlockEnv) {
241        let mut cfg = CfgEnvWithHandlerCfg::new(Default::default(), Default::default());
242        let mut block_env = BlockEnv::default();
243        self.fill_cfg_and_block_env(&mut cfg, &mut block_env, header, total_difficulty);
244        (cfg, block_env)
245    }
246
247    /// Convenience function to call both [`fill_cfg_env`](ConfigureEvmEnv::fill_cfg_env) and
248    /// [`ConfigureEvmEnv::fill_block_env`].
249    ///
250    /// Note: Implementers should ensure that all fields are required fields are filled.
251    fn fill_cfg_and_block_env(
252        &self,
253        cfg: &mut CfgEnvWithHandlerCfg,
254        block_env: &mut BlockEnv,
255        header: &Self::Header,
256        total_difficulty: U256,
257    ) {
258        self.fill_cfg_env(cfg, header, total_difficulty);
259        let after_merge = cfg.handler_cfg.spec_id >= SpecId::MERGE;
260        self.fill_block_env(block_env, header, after_merge);
261    }
262
263    /// Returns the configured [`CfgEnvWithHandlerCfg`] and [`BlockEnv`] for `parent + 1` block.
264    ///
265    /// This is intended for usage in block building after the merge and requires additional
266    /// attributes that can't be derived from the parent block: attributes that are determined by
267    /// the CL, such as the timestamp, suggested fee recipient, and randomness value.
268    fn next_cfg_and_block_env(
269        &self,
270        parent: &Self::Header,
271        attributes: NextBlockEnvAttributes,
272    ) -> Result<(CfgEnvWithHandlerCfg, BlockEnv), Self::Error>;
273}
274
275/// Represents additional attributes required to configure the next block.
276/// This is used to configure the next block's environment
277/// [`ConfigureEvmEnv::next_cfg_and_block_env`] and contains fields that can't be derived from the
278/// parent header alone (attributes that are determined by the CL.)
279#[derive(Debug, Clone, Copy, PartialEq, Eq)]
280pub struct NextBlockEnvAttributes {
281    /// The timestamp of the next block.
282    pub timestamp: u64,
283    /// The suggested fee recipient for the next block.
284    pub suggested_fee_recipient: Address,
285    /// The randomness value for the next block.
286    pub prev_randao: B256,
287}
288
289/// Function hook that allows to modify a transaction environment.
290pub trait TxEnvOverrides {
291    /// Apply the overrides by modifying the given `TxEnv`.
292    fn apply(&mut self, env: &mut TxEnv);
293}
294
295impl<F> TxEnvOverrides for F
296where
297    F: FnMut(&mut TxEnv),
298{
299    fn apply(&mut self, env: &mut TxEnv) {
300        self(env)
301    }
302}