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