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