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::execute::BasicBlockBuilder;
21use alloc::vec::Vec;
22use alloy_eips::{
23    eip2718::{EIP2930_TX_TYPE_ID, LEGACY_TX_TYPE_ID},
24    eip2930::AccessList,
25    eip4895::Withdrawals,
26};
27use alloy_evm::block::{BlockExecutorFactory, BlockExecutorFor};
28use alloy_primitives::{Address, B256};
29use core::{error::Error, fmt::Debug};
30use execute::{BasicBlockExecutor, BlockAssembler, BlockBuilder};
31use reth_primitives_traits::{
32    BlockTy, HeaderTy, NodePrimitives, ReceiptTy, SealedBlock, SealedHeader, TxTy,
33};
34use revm::{context::TxEnv, database::State};
35
36pub mod either;
37/// EVM environment configuration.
38pub mod execute;
39
40mod aliases;
41pub use aliases::*;
42
43#[cfg(feature = "metrics")]
44pub mod metrics;
45pub mod noop;
46#[cfg(any(test, feature = "test-utils"))]
47/// test helpers for mocking executor
48pub mod test_utils;
49
50pub use alloy_evm::{
51    block::{state_changes, system_calls, OnStateHook},
52    *,
53};
54
55pub use alloy_evm::block::state_changes as state_change;
56
57/// A complete configuration of EVM for Reth.
58///
59/// This trait encapsulates complete configuration required for transaction execution and block
60/// execution/building.
61///
62/// The EVM abstraction consists of the following layers:
63///     - [`Evm`] produced by [`EvmFactory`]: The EVM implementation responsilble for executing
64///       individual transactions and producing output for them including state changes, logs, gas
65///       usage, etc.
66///     - [`BlockExecutor`] produced by [`BlockExecutorFactory`]: Executor operates on top of
67///       [`Evm`] and is responsible for executing entire blocks. This is different from simply
68///       aggregating outputs of transactions execution as it also involves higher level state
69///       changes such as receipt building, applying block rewards, system calls, etc.
70///     - [`BlockAssembler`]: Encapsulates logic for assembling blocks. It operates on context and
71///       output of [`BlockExecutor`], and is required to know how to assemble a next block to
72///       include in the chain.
73///
74/// All of the above components need configuration environment which we are abstracting over to
75/// allow plugging EVM implementation into Reth SDK.
76///
77/// The abstraction is designed to serve 2 codepaths:
78///     1. Externally provided complete block (e.g received while syncing).
79///     2. Block building when we know parent block and some additional context obtained from
80///       payload attributes or alike.
81///
82/// First case is handled by [`ConfigureEvm::evm_env`] and [`ConfigureEvm::context_for_block`]
83/// which implement a conversion from [`NodePrimitives::Block`] to [`EvmEnv`] and [`ExecutionCtx`],
84/// and allow configuring EVM and block execution environment at a given block.
85///
86/// Second case is handled by similar [`ConfigureEvm::next_evm_env`] and
87/// [`ConfigureEvm::context_for_next_block`] which take parent [`NodePrimitives::BlockHeader`]
88/// along with [`NextBlockEnvCtx`]. [`NextBlockEnvCtx`] is very similar to payload attributes and
89/// simply contains context for next block that is generally received from a CL node (timestamp,
90/// beneficiary, withdrawals, etc.).
91///
92/// [`ExecutionCtx`]: BlockExecutorFactory::ExecutionCtx
93/// [`NextBlockEnvCtx`]: ConfigureEvm::NextBlockEnvCtx
94/// [`BlockExecutor`]: alloy_evm::block::BlockExecutor
95#[auto_impl::auto_impl(&, Arc)]
96pub trait ConfigureEvm: Clone + Debug + Send + Sync + Unpin {
97    /// The primitives type used by the EVM.
98    type Primitives: NodePrimitives;
99
100    /// The error type that is returned by [`Self::next_evm_env`].
101    type Error: Error + Send + Sync + 'static;
102
103    /// Context required for configuring next block environment.
104    ///
105    /// Contains values that can't be derived from the parent block.
106    type NextBlockEnvCtx: Debug + Clone;
107
108    /// Configured [`BlockExecutorFactory`], contains [`EvmFactory`] internally.
109    type BlockExecutorFactory: BlockExecutorFactory<
110        Transaction = TxTy<Self::Primitives>,
111        Receipt = ReceiptTy<Self::Primitives>,
112        EvmFactory: EvmFactory<
113            Tx: TransactionEnv
114                    + FromRecoveredTx<TxTy<Self::Primitives>>
115                    + FromTxWithEncoded<TxTy<Self::Primitives>>,
116            // Precompiles = PrecompilesMap,
117        >,
118    >;
119
120    /// A type that knows how to build a block.
121    type BlockAssembler: BlockAssembler<
122        Self::BlockExecutorFactory,
123        Block = BlockTy<Self::Primitives>,
124    >;
125
126    /// Returns reference to the configured [`BlockExecutorFactory`].
127    fn block_executor_factory(&self) -> &Self::BlockExecutorFactory;
128
129    /// Returns reference to the configured [`BlockAssembler`].
130    fn block_assembler(&self) -> &Self::BlockAssembler;
131
132    /// Creates a new [`EvmEnv`] for the given header.
133    fn evm_env(&self, header: &HeaderTy<Self::Primitives>) -> EvmEnvFor<Self>;
134
135    /// Returns the configured [`EvmEnv`] for `parent + 1` block.
136    ///
137    /// This is intended for usage in block building after the merge and requires additional
138    /// attributes that can't be derived from the parent block: attributes that are determined by
139    /// the CL, such as the timestamp, suggested fee recipient, and randomness value.
140    fn next_evm_env(
141        &self,
142        parent: &HeaderTy<Self::Primitives>,
143        attributes: &Self::NextBlockEnvCtx,
144    ) -> Result<EvmEnvFor<Self>, Self::Error>;
145
146    /// Returns the configured [`BlockExecutorFactory::ExecutionCtx`] for a given block.
147    fn context_for_block<'a>(
148        &self,
149        block: &'a SealedBlock<BlockTy<Self::Primitives>>,
150    ) -> ExecutionCtxFor<'a, Self>;
151
152    /// Returns the configured [`BlockExecutorFactory::ExecutionCtx`] for `parent + 1`
153    /// block.
154    fn context_for_next_block(
155        &self,
156        parent: &SealedHeader<HeaderTy<Self::Primitives>>,
157        attributes: Self::NextBlockEnvCtx,
158    ) -> ExecutionCtxFor<'_, Self>;
159
160    /// Returns a [`TxEnv`] from a transaction and [`Address`].
161    fn tx_env(&self, transaction: impl IntoTxEnv<TxEnvFor<Self>>) -> TxEnvFor<Self> {
162        transaction.into_tx_env()
163    }
164
165    /// Provides a reference to [`EvmFactory`] implementation.
166    fn evm_factory(&self) -> &EvmFactoryFor<Self> {
167        self.block_executor_factory().evm_factory()
168    }
169
170    /// Returns a new EVM with the given database configured with the given environment settings,
171    /// including the spec id and transaction environment.
172    ///
173    /// This will preserve any handler modifications
174    fn evm_with_env<DB: Database>(&self, db: DB, evm_env: EvmEnvFor<Self>) -> EvmFor<Self, DB> {
175        self.evm_factory().create_evm(db, evm_env)
176    }
177
178    /// Returns a new EVM with the given database configured with `cfg` and `block_env`
179    /// configuration derived from the given header. Relies on
180    /// [`ConfigureEvm::evm_env`].
181    ///
182    /// # Caution
183    ///
184    /// This does not initialize the tx environment.
185    fn evm_for_block<DB: Database>(
186        &self,
187        db: DB,
188        header: &HeaderTy<Self::Primitives>,
189    ) -> EvmFor<Self, DB> {
190        let evm_env = self.evm_env(header);
191        self.evm_with_env(db, evm_env)
192    }
193
194    /// Returns a new EVM with the given database configured with the given environment settings,
195    /// including the spec id.
196    ///
197    /// This will use the given external inspector as the EVM external context.
198    ///
199    /// This will preserve any handler modifications
200    fn evm_with_env_and_inspector<DB, I>(
201        &self,
202        db: DB,
203        evm_env: EvmEnvFor<Self>,
204        inspector: I,
205    ) -> EvmFor<Self, DB, I>
206    where
207        DB: Database,
208        I: InspectorFor<Self, DB>,
209    {
210        self.evm_factory().create_evm_with_inspector(db, evm_env, inspector)
211    }
212
213    /// Creates a strategy with given EVM and execution context.
214    fn create_executor<'a, DB, I>(
215        &'a self,
216        evm: EvmFor<Self, &'a mut State<DB>, I>,
217        ctx: <Self::BlockExecutorFactory as BlockExecutorFactory>::ExecutionCtx<'a>,
218    ) -> impl BlockExecutorFor<'a, Self::BlockExecutorFactory, DB, I>
219    where
220        DB: Database,
221        I: InspectorFor<Self, &'a mut State<DB>> + 'a,
222    {
223        self.block_executor_factory().create_executor(evm, ctx)
224    }
225
226    /// Creates a strategy for execution of a given block.
227    fn executor_for_block<'a, DB: Database>(
228        &'a self,
229        db: &'a mut State<DB>,
230        block: &'a SealedBlock<<Self::Primitives as NodePrimitives>::Block>,
231    ) -> impl BlockExecutorFor<'a, Self::BlockExecutorFactory, DB> {
232        let evm = self.evm_for_block(db, block.header());
233        let ctx = self.context_for_block(block);
234        self.create_executor(evm, ctx)
235    }
236
237    /// Creates a [`BlockBuilder`]. Should be used when building a new block.
238    ///
239    /// Block builder wraps an inner [`alloy_evm::block::BlockExecutor`] and has a similar
240    /// interface. Builder collects all of the executed transactions, and once
241    /// [`BlockBuilder::finish`] is called, it invokes the configured [`BlockAssembler`] to
242    /// create a block.
243    fn create_block_builder<'a, DB, I>(
244        &'a self,
245        evm: EvmFor<Self, &'a mut State<DB>, I>,
246        parent: &'a SealedHeader<HeaderTy<Self::Primitives>>,
247        ctx: <Self::BlockExecutorFactory as BlockExecutorFactory>::ExecutionCtx<'a>,
248    ) -> impl BlockBuilder<
249        Primitives = Self::Primitives,
250        Executor: BlockExecutorFor<'a, Self::BlockExecutorFactory, DB, I>,
251    >
252    where
253        DB: Database,
254        I: InspectorFor<Self, &'a mut State<DB>> + 'a,
255    {
256        BasicBlockBuilder {
257            executor: self.create_executor(evm, ctx.clone()),
258            ctx,
259            assembler: self.block_assembler(),
260            parent,
261            transactions: Vec::new(),
262        }
263    }
264
265    /// Creates a [`BlockBuilder`] for building of a new block. This is a helper to invoke
266    /// [`ConfigureEvm::create_block_builder`].
267    fn builder_for_next_block<'a, DB: Database>(
268        &'a self,
269        db: &'a mut State<DB>,
270        parent: &'a SealedHeader<<Self::Primitives as NodePrimitives>::BlockHeader>,
271        attributes: Self::NextBlockEnvCtx,
272    ) -> Result<impl BlockBuilder<Primitives = Self::Primitives>, Self::Error> {
273        let evm_env = self.next_evm_env(parent, &attributes)?;
274        let evm = self.evm_with_env(db, evm_env);
275        let ctx = self.context_for_next_block(parent, attributes);
276        Ok(self.create_block_builder(evm, parent, ctx))
277    }
278
279    /// Returns a new [`BasicBlockExecutor`].
280    #[auto_impl(keep_default_for(&, Arc))]
281    fn executor<DB: Database>(&self, db: DB) -> BasicBlockExecutor<&Self, DB> {
282        BasicBlockExecutor::new(self, db)
283    }
284
285    /// Returns a new [`BasicBlockExecutor`].
286    #[auto_impl(keep_default_for(&, Arc))]
287    fn batch_executor<DB: Database>(&self, db: DB) -> BasicBlockExecutor<&Self, DB> {
288        BasicBlockExecutor::new(self, db)
289    }
290}
291
292/// Represents additional attributes required to configure the next block.
293/// This is used to configure the next block's environment
294/// [`ConfigureEvm::next_evm_env`] and contains fields that can't be derived from the
295/// parent header alone (attributes that are determined by the CL.)
296#[derive(Debug, Clone, PartialEq, Eq)]
297pub struct NextBlockEnvAttributes {
298    /// The timestamp of the next block.
299    pub timestamp: u64,
300    /// The suggested fee recipient for the next block.
301    pub suggested_fee_recipient: Address,
302    /// The randomness value for the next block.
303    pub prev_randao: B256,
304    /// Block gas limit.
305    pub gas_limit: u64,
306    /// The parent beacon block root.
307    pub parent_beacon_block_root: Option<B256>,
308    /// Withdrawals
309    pub withdrawals: Option<Withdrawals>,
310}
311
312/// Abstraction over transaction environment.
313pub trait TransactionEnv:
314    revm::context_interface::Transaction + Debug + Clone + Send + Sync + 'static
315{
316    /// Set the gas limit.
317    fn set_gas_limit(&mut self, gas_limit: u64);
318
319    /// Set the gas limit.
320    fn with_gas_limit(mut self, gas_limit: u64) -> Self {
321        self.set_gas_limit(gas_limit);
322        self
323    }
324
325    /// Returns the configured nonce.
326    fn nonce(&self) -> u64;
327
328    /// Sets the nonce.
329    fn set_nonce(&mut self, nonce: u64);
330
331    /// Sets the nonce.
332    fn with_nonce(mut self, nonce: u64) -> Self {
333        self.set_nonce(nonce);
334        self
335    }
336
337    /// Set access list.
338    fn set_access_list(&mut self, access_list: AccessList);
339
340    /// Set access list.
341    fn with_access_list(mut self, access_list: AccessList) -> Self {
342        self.set_access_list(access_list);
343        self
344    }
345}
346
347impl TransactionEnv for TxEnv {
348    fn set_gas_limit(&mut self, gas_limit: u64) {
349        self.gas_limit = gas_limit;
350    }
351
352    fn nonce(&self) -> u64 {
353        self.nonce
354    }
355
356    fn set_nonce(&mut self, nonce: u64) {
357        self.nonce = nonce;
358    }
359
360    fn set_access_list(&mut self, access_list: AccessList) {
361        self.access_list = access_list;
362
363        if self.tx_type == LEGACY_TX_TYPE_ID {
364            // if this was previously marked as legacy tx, this must be upgraded to eip2930 with an
365            // accesslist
366            self.tx_type = EIP2930_TX_TYPE_ID;
367        }
368    }
369}
370
371#[cfg(feature = "op")]
372impl<T: TransactionEnv> TransactionEnv for op_revm::OpTransaction<T> {
373    fn set_gas_limit(&mut self, gas_limit: u64) {
374        self.base.set_gas_limit(gas_limit);
375    }
376
377    fn nonce(&self) -> u64 {
378        TransactionEnv::nonce(&self.base)
379    }
380
381    fn set_nonce(&mut self, nonce: u64) {
382        self.base.set_nonce(nonce);
383    }
384
385    fn set_access_list(&mut self, access_list: AccessList) {
386        self.base.set_access_list(access_list);
387    }
388}
389
390impl<T: TransactionEnv> TransactionEnv for seismic_revm::SeismicTransaction<T> {
391    fn set_gas_limit(&mut self, gas_limit: u64) {
392        self.base.set_gas_limit(gas_limit);
393    }
394
395    fn nonce(&self) -> u64 {
396        TransactionEnv::nonce(&self.base)
397    }
398
399    fn set_nonce(&mut self, nonce: u64) {
400        self.base.set_nonce(nonce);
401    }
402
403    fn set_access_list(&mut self, access_list: AccessList) {
404        self.base.set_access_list(access_list);
405    }
406}