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))]
16#![cfg_attr(not(feature = "std"), no_std)]
17
18extern crate alloc;
19
20use crate::execute::{BasicBlockBuilder, Executor};
21use alloc::{string::String, vec::Vec};
22use alloy_eips::eip4895::Withdrawals;
23use alloy_evm::{
24 block::{BlockExecutorFactory, BlockExecutorFor},
25 precompiles::PrecompilesMap,
26};
27use alloy_primitives::{Address, Bytes, B256};
28use core::{error::Error, fmt::Debug};
29use execute::{BasicBlockExecutor, BlockAssembler, BlockBuilder};
30use reth_execution_errors::BlockExecutionError;
31use reth_primitives_traits::{
32 BlockTy, HeaderTy, NodePrimitives, ReceiptTy, SealedBlock, SealedHeader, TxTy,
33};
34use revm::{database::State, primitives::hardfork::SpecId};
35
36pub mod either;
37/// EVM environment configuration.
38pub mod execute;
39
40mod aliases;
41pub use aliases::*;
42
43#[cfg(feature = "std")]
44mod engine;
45#[cfg(feature = "std")]
46pub use engine::{ConfigureEngineEvm, ConvertTx, ExecutableTxIterator, ExecutableTxTuple};
47
48#[cfg(feature = "metrics")]
49pub mod metrics;
50pub mod noop;
51#[cfg(any(test, feature = "test-utils"))]
52/// test helpers for mocking executor
53pub mod test_utils;
54
55pub use alloy_evm::{
56 block::{state_changes, system_calls, OnStateHook},
57 *,
58};
59
60/// A complete configuration of EVM for Reth.
61///
62/// This trait encapsulates complete configuration required for transaction execution and block
63/// execution/building, providing a unified interface for EVM operations.
64///
65/// # Architecture Overview
66///
67/// The EVM abstraction consists of the following layers:
68///
69/// 1. **[`Evm`] (produced by [`EvmFactory`])**: The core EVM implementation responsible for
70/// executing individual transactions and producing outputs including state changes, logs, gas
71/// usage, etc.
72///
73/// 2. **[`BlockExecutor`] (produced by [`BlockExecutorFactory`])**: A higher-level component that
74/// operates on top of [`Evm`] to execute entire blocks. This involves:
75/// - Executing all transactions in sequence
76/// - Building receipts from transaction outputs
77/// - Applying block rewards to the beneficiary
78/// - Executing system calls (e.g., EIP-4788 beacon root updates)
79/// - Managing state changes and bundle accumulation
80///
81/// 3. **[`BlockAssembler`]**: Responsible for assembling valid blocks from executed transactions.
82/// It takes the output from [`BlockExecutor`] along with execution context and produces a
83/// complete block ready for inclusion in the chain.
84///
85/// # Usage Patterns
86///
87/// The abstraction supports two primary use cases:
88///
89/// ## 1. Executing Externally Provided Blocks (e.g., during sync)
90///
91/// ```rust,ignore
92/// use reth_evm::ConfigureEvm;
93///
94/// // Execute a received block
95/// let mut executor = evm_config.executor(state_db);
96/// let output = executor.execute(&block)?;
97///
98/// // Access the execution results
99/// println!("Gas used: {}", output.result.gas_used);
100/// println!("Receipts: {:?}", output.result.receipts);
101/// ```
102///
103/// ## 2. Building New Blocks (e.g., payload building)
104///
105/// Payload building is slightly different as it doesn't have the block's header yet, but rather
106/// attributes for the block's environment, such as timestamp, fee recipient, and randomness value.
107/// The block's header will be the outcome of the block building process.
108///
109/// ```rust,ignore
110/// use reth_evm::{ConfigureEvm, NextBlockEnvAttributes};
111///
112/// // Create attributes for the next block
113/// let attributes = NextBlockEnvAttributes {
114/// timestamp: current_time + 12,
115/// suggested_fee_recipient: beneficiary_address,
116/// prev_randao: randomness_value,
117/// gas_limit: 30_000_000,
118/// withdrawals: Some(withdrawals),
119/// parent_beacon_block_root: Some(beacon_root),
120/// slot_number: None,
121/// };
122///
123/// // Build a new block on top of parent
124/// let mut builder = evm_config.builder_for_next_block(
125/// &mut state_db,
126/// &parent_header,
127/// attributes
128/// )?;
129///
130/// // Apply pre-execution changes (e.g., beacon root update)
131/// builder.apply_pre_execution_changes()?;
132///
133/// // Execute transactions
134/// for tx in pending_transactions {
135/// match builder.execute_transaction(tx) {
136/// Ok(gas_used) => {
137/// println!("Transaction executed, gas used: {}", gas_used);
138/// }
139/// Err(e) => {
140/// println!("Transaction failed: {:?}", e);
141/// }
142/// }
143/// }
144///
145/// // Finish block building and get the outcome (block)
146/// let outcome = builder.finish(state_provider, None)?;
147/// let block = outcome.block;
148/// ```
149///
150/// # Key Components
151///
152/// ## [`NextBlockEnvCtx`]
153///
154/// Contains attributes needed to configure the next block that cannot be derived from the
155/// parent block alone. This includes data typically provided by the consensus layer:
156/// - `timestamp`: Block timestamp
157/// - `suggested_fee_recipient`: Beneficiary address
158/// - `prev_randao`: Randomness value
159/// - `gas_limit`: Block gas limit
160/// - `withdrawals`: Consensus layer withdrawals
161/// - `parent_beacon_block_root`: EIP-4788 beacon root
162///
163/// ## [`BlockAssembler`]
164///
165/// Takes the execution output and produces a complete block. It receives:
166/// - Transaction execution results (receipts, gas used)
167/// - Final state root after all executions
168/// - Bundle state with all changes
169/// - Execution context and environment
170///
171/// The assembler is responsible for:
172/// - Setting the correct block header fields
173/// - Including executed transactions
174/// - Setting gas used and receipts root
175/// - Applying any chain-specific rules
176///
177/// [`ExecutionCtx`]: BlockExecutorFactory::ExecutionCtx
178/// [`NextBlockEnvCtx`]: ConfigureEvm::NextBlockEnvCtx
179/// [`BlockExecutor`]: alloy_evm::block::BlockExecutor
180#[auto_impl::auto_impl(&, Arc)]
181pub trait ConfigureEvm: Clone + Debug + Send + Sync + Unpin {
182 /// The primitives type used by the EVM.
183 type Primitives: NodePrimitives;
184
185 /// The error type that is returned by [`Self::next_evm_env`].
186 type Error: Error + Send + Sync + 'static;
187
188 /// Context required for configuring next block environment.
189 ///
190 /// Contains values that can't be derived from the parent block.
191 type NextBlockEnvCtx: Debug + Clone;
192
193 /// Configured [`BlockExecutorFactory`], contains [`EvmFactory`] internally.
194 type BlockExecutorFactory: for<'a> BlockExecutorFactory<
195 Transaction = TxTy<Self::Primitives>,
196 Receipt = ReceiptTy<Self::Primitives>,
197 ExecutionCtx<'a>: Debug + Send,
198 EvmFactory: EvmFactory<
199 Tx: TransactionEnvMut
200 + FromRecoveredTx<TxTy<Self::Primitives>>
201 + FromTxWithEncoded<TxTy<Self::Primitives>>,
202 Precompiles = PrecompilesMap,
203 Spec: Into<SpecId>,
204 >,
205 >;
206
207 /// A type that knows how to build a block.
208 type BlockAssembler: BlockAssembler<
209 Self::BlockExecutorFactory,
210 Block = BlockTy<Self::Primitives>,
211 >;
212
213 /// Returns reference to the configured [`BlockExecutorFactory`].
214 fn block_executor_factory(&self) -> &Self::BlockExecutorFactory;
215
216 /// Returns reference to the configured [`BlockAssembler`].
217 fn block_assembler(&self) -> &Self::BlockAssembler;
218
219 /// Creates a new [`EvmEnv`] for the given header.
220 fn evm_env(&self, header: &HeaderTy<Self::Primitives>) -> Result<EvmEnvFor<Self>, Self::Error>;
221
222 /// Returns the configured [`EvmEnv`] for `parent + 1` block.
223 ///
224 /// This is intended for usage in block building after the merge and requires additional
225 /// attributes that can't be derived from the parent block: attributes that are determined by
226 /// the CL, such as the timestamp, suggested fee recipient, and randomness value.
227 ///
228 /// # Example
229 ///
230 /// ```rust,ignore
231 /// let evm_env = evm_config.next_evm_env(&parent_header, &attributes)?;
232 /// // evm_env now contains:
233 /// // - Correct spec ID based on timestamp and block number
234 /// // - Block environment with next block's parameters
235 /// // - Configuration like chain ID and blob parameters
236 /// ```
237 fn next_evm_env(
238 &self,
239 parent: &HeaderTy<Self::Primitives>,
240 attributes: &Self::NextBlockEnvCtx,
241 ) -> Result<EvmEnvFor<Self>, Self::Error>;
242
243 /// Returns the configured [`BlockExecutorFactory::ExecutionCtx`] for a given block.
244 fn context_for_block<'a>(
245 &self,
246 block: &'a SealedBlock<BlockTy<Self::Primitives>>,
247 ) -> Result<ExecutionCtxFor<'a, Self>, Self::Error>;
248
249 /// Returns the configured [`BlockExecutorFactory::ExecutionCtx`] for `parent + 1`
250 /// block.
251 fn context_for_next_block(
252 &self,
253 parent: &SealedHeader<HeaderTy<Self::Primitives>>,
254 attributes: Self::NextBlockEnvCtx,
255 ) -> Result<ExecutionCtxFor<'_, Self>, Self::Error>;
256
257 /// Returns a [`EvmFactory::Tx`] from a transaction.
258 fn tx_env(&self, transaction: impl IntoTxEnv<TxEnvFor<Self>>) -> TxEnvFor<Self> {
259 transaction.into_tx_env()
260 }
261
262 /// Provides a reference to [`EvmFactory`] implementation.
263 fn evm_factory(&self) -> &EvmFactoryFor<Self> {
264 self.block_executor_factory().evm_factory()
265 }
266
267 /// Returns a config with JIT support enabled for subsequently created EVMs, if supported.
268 ///
269 /// This is one of three gates required before an EVM can execute JIT-compiled code: the binary
270 /// must be built with the `jit` feature, runtime compilation must be enabled by `--jit` or the
271 /// `reth_jit` RPC method, and this local support flag must be enabled for the config that
272 /// creates the EVM.
273 #[auto_impl(keep_default_for(&, Arc))]
274 fn with_jit_support_enabled(self, _enabled: bool) -> Self
275 where
276 Self: Sized,
277 {
278 self
279 }
280
281 /// Returns a config with local JIT support enabled for subsequently created EVMs, if supported.
282 #[auto_impl(keep_default_for(&, Arc))]
283 fn with_jit_support(self) -> Self
284 where
285 Self: Sized,
286 {
287 self.with_jit_support_enabled(true)
288 }
289
290 /// Returns the JIT backend, if supported.
291 fn jit_backend(&self) -> Option<&dyn JitBackend> {
292 None
293 }
294
295 /// Returns a new EVM with the given database configured with the given environment settings,
296 /// including the spec id and transaction environment.
297 ///
298 /// This will preserve any handler modifications
299 fn evm_with_env<DB: Database>(&self, db: DB, evm_env: EvmEnvFor<Self>) -> EvmFor<Self, DB> {
300 self.evm_factory().create_evm(db, evm_env)
301 }
302
303 /// Returns a new EVM with the given database configured with `cfg` and `block_env`
304 /// configuration derived from the given header. Relies on
305 /// [`ConfigureEvm::evm_env`].
306 ///
307 /// # Caution
308 ///
309 /// This does not initialize the tx environment.
310 fn evm_for_block<DB: Database>(
311 &self,
312 db: DB,
313 header: &HeaderTy<Self::Primitives>,
314 ) -> Result<EvmFor<Self, DB>, Self::Error> {
315 let evm_env = self.evm_env(header)?;
316 Ok(self.evm_with_env(db, evm_env))
317 }
318
319 /// Returns a new EVM with the given database configured with the given environment settings,
320 /// including the spec id.
321 ///
322 /// This will use the given external inspector as the EVM external context.
323 ///
324 /// This will preserve any handler modifications
325 fn evm_with_env_and_inspector<DB, I>(
326 &self,
327 db: DB,
328 evm_env: EvmEnvFor<Self>,
329 inspector: I,
330 ) -> EvmFor<Self, DB, I>
331 where
332 DB: Database,
333 I: InspectorFor<Self, DB>,
334 {
335 self.evm_factory().create_evm_with_inspector(db, evm_env, inspector)
336 }
337
338 /// Creates a strategy with given EVM and execution context.
339 fn create_executor<'a, DB, I>(
340 &'a self,
341 evm: EvmFor<Self, &'a mut State<DB>, I>,
342 ctx: <Self::BlockExecutorFactory as BlockExecutorFactory>::ExecutionCtx<'a>,
343 ) -> BlockExecutorForEvm<'a, Self, DB, I>
344 where
345 DB: Database,
346 I: InspectorFor<Self, &'a mut State<DB>> + 'a,
347 {
348 self.block_executor_factory().create_executor(evm, ctx)
349 }
350
351 /// Creates a strategy with a DB state borrow that can be shorter than the execution context.
352 fn create_executor_with_state<'a, 'db, DB, I>(
353 &'a self,
354 evm: EvmFor<Self, &'db mut State<DB>, I>,
355 ctx: <Self::BlockExecutorFactory as BlockExecutorFactory>::ExecutionCtx<'a>,
356 ) -> BlockExecutorFor<'a, Self::BlockExecutorFactory, &'db mut State<DB>, I>
357 where
358 DB: Database,
359 I: InspectorFor<Self, &'db mut State<DB>>,
360 {
361 self.block_executor_factory().create_executor(evm, ctx)
362 }
363
364 /// Creates a strategy for execution of a given block.
365 fn executor_for_block<'a, DB: Database>(
366 &'a self,
367 db: &'a mut State<DB>,
368 block: &'a SealedBlock<<Self::Primitives as NodePrimitives>::Block>,
369 ) -> Result<BlockExecutorForEvm<'a, Self, DB>, Self::Error> {
370 let evm = self.evm_for_block(db, block.header())?;
371 let ctx = self.context_for_block(block)?;
372 Ok(self.create_executor(evm, ctx))
373 }
374
375 /// Creates a [`BlockBuilder`]. Should be used when building a new block.
376 ///
377 /// Block builder wraps an inner [`alloy_evm::block::BlockExecutor`] and has a similar
378 /// interface. Builder collects all of the executed transactions, and once
379 /// [`BlockBuilder::finish`] is called, it invokes the configured [`BlockAssembler`] to
380 /// create a block.
381 ///
382 /// # Example
383 ///
384 /// ```rust,ignore
385 /// // Create a builder with specific EVM configuration
386 /// let evm = evm_config.evm_with_env(&mut state_db, evm_env);
387 /// let ctx = evm_config.context_for_next_block(&parent, attributes);
388 /// let builder = evm_config.create_block_builder(evm, &parent, ctx);
389 /// ```
390 fn create_block_builder<'a, DB, I>(
391 &'a self,
392 evm: EvmFor<Self, &'a mut State<DB>, I>,
393 parent: &'a SealedHeader<HeaderTy<Self::Primitives>>,
394 ctx: <Self::BlockExecutorFactory as BlockExecutorFactory>::ExecutionCtx<'a>,
395 ) -> impl BlockBuilder<Primitives = Self::Primitives, Executor = BlockExecutorForEvm<'a, Self, DB, I>>
396 where
397 DB: Database,
398 I: InspectorFor<Self, &'a mut State<DB>> + 'a,
399 {
400 BasicBlockBuilder {
401 executor: self.create_executor(evm, ctx.clone()),
402 ctx,
403 assembler: self.block_assembler(),
404 parent,
405 transactions: Vec::new(),
406 }
407 }
408
409 /// Creates a [`BlockBuilder`] for building of a new block. This is a helper to invoke
410 /// [`ConfigureEvm::create_block_builder`].
411 ///
412 /// This is the primary method for building new blocks. It combines:
413 /// 1. Creating the EVM environment for the next block
414 /// 2. Setting up the execution context from attributes
415 /// 3. Initializing the block builder with proper configuration
416 ///
417 /// # Example
418 ///
419 /// ```rust,ignore
420 /// // Build a block with specific attributes
421 /// let mut builder = evm_config.builder_for_next_block(
422 /// &mut state_db,
423 /// &parent_header,
424 /// attributes
425 /// )?;
426 ///
427 /// // Execute system calls (e.g., beacon root update)
428 /// builder.apply_pre_execution_changes()?;
429 ///
430 /// // Execute transactions
431 /// for tx in transactions {
432 /// builder.execute_transaction(tx)?;
433 /// }
434 ///
435 /// // Complete block building
436 /// let outcome = builder.finish(state_provider, None)?;
437 /// ```
438 fn builder_for_next_block<'a, DB: Database + 'a>(
439 &'a self,
440 db: &'a mut State<DB>,
441 parent: &'a SealedHeader<<Self::Primitives as NodePrimitives>::BlockHeader>,
442 attributes: Self::NextBlockEnvCtx,
443 ) -> Result<
444 impl BlockBuilder<Primitives = Self::Primitives, Executor = BlockExecutorForEvm<'a, Self, DB>>,
445 Self::Error,
446 > {
447 let evm_env = self.next_evm_env(parent, &attributes)?;
448 let evm = self.evm_with_env(db, evm_env);
449 let ctx = self.context_for_next_block(parent, attributes)?;
450 Ok(self.create_block_builder(evm, parent, ctx))
451 }
452
453 /// Returns a new [`Executor`] for executing blocks.
454 ///
455 /// The executor processes complete blocks including:
456 /// - All transactions in order
457 /// - Block rewards and fees
458 /// - Block level system calls
459 /// - State transitions
460 ///
461 /// # Example
462 ///
463 /// ```rust,ignore
464 /// // Create an executor
465 /// let mut executor = evm_config.executor(state_db);
466 ///
467 /// // Execute a single block
468 /// let output = executor.execute(&block)?;
469 ///
470 /// // Execute multiple blocks
471 /// let batch_output = executor.execute_batch(&blocks)?;
472 /// ```
473 #[auto_impl(keep_default_for(&, Arc))]
474 fn executor<DB: Database>(
475 &self,
476 db: DB,
477 ) -> impl Executor<DB, Primitives = Self::Primitives, Error = BlockExecutionError> {
478 BasicBlockExecutor::new(self, db)
479 }
480
481 /// Returns a new [`BasicBlockExecutor`].
482 #[auto_impl(keep_default_for(&, Arc))]
483 fn batch_executor<DB: Database>(
484 &self,
485 db: DB,
486 ) -> impl Executor<DB, Primitives = Self::Primitives, Error = BlockExecutionError> {
487 BasicBlockExecutor::new(self, db)
488 }
489}
490
491/// JIT backend controls exposed by an EVM configuration.
492pub trait JitBackend: Send + Sync {
493 /// Enables or disables JIT compilation.
494 fn set_enabled(&self, enabled: bool) -> Result<(), String>;
495
496 /// Pauses JIT helper execution while keeping queueing and resident compiled code available.
497 fn pause(&self);
498
499 /// Resumes background JIT work.
500 fn resume(&self);
501
502 /// Clears JIT runtime state.
503 fn clear(&self);
504}
505
506/// Represents additional attributes required to configure the next block.
507///
508/// This struct contains all the information needed to build a new block that cannot be
509/// derived from the parent block header alone. These attributes are typically provided
510/// by the consensus layer (CL) through the Engine API during payload building.
511///
512/// # Relationship with [`ConfigureEvm`] and [`BlockAssembler`]
513///
514/// The flow for building a new block involves:
515///
516/// 1. **Receive attributes** from the consensus layer containing:
517/// - Timestamp for the new block
518/// - Fee recipient (coinbase/beneficiary)
519/// - Randomness value (prevRandao)
520/// - Withdrawals to process
521/// - Parent beacon block root for EIP-4788
522///
523/// 2. **Configure EVM environment** using these attributes: ```rust,ignore let evm_env =
524/// evm_config.next_evm_env(&parent, &attributes)?; ```
525///
526/// 3. **Build the block** with transactions: ```rust,ignore let mut builder =
527/// evm_config.builder_for_next_block( &mut state, &parent, attributes )?; ```
528///
529/// 4. **Assemble the final block** using [`BlockAssembler`] which takes:
530/// - Execution results from all transactions
531/// - The attributes used during execution
532/// - Final state root after all changes
533///
534/// This design cleanly separates:
535/// - **Configuration** (what parameters to use) - handled by `NextBlockEnvAttributes`
536/// - **Execution** (running transactions) - handled by `BlockExecutor`
537/// - **Assembly** (creating the final block) - handled by `BlockAssembler`
538#[derive(Debug, Clone, PartialEq, Eq)]
539pub struct NextBlockEnvAttributes {
540 /// The timestamp of the next block.
541 pub timestamp: u64,
542 /// The suggested fee recipient for the next block.
543 pub suggested_fee_recipient: Address,
544 /// The randomness value for the next block.
545 pub prev_randao: B256,
546 /// Block gas limit.
547 pub gas_limit: u64,
548 /// The parent beacon block root.
549 pub parent_beacon_block_root: Option<B256>,
550 /// Withdrawals
551 pub withdrawals: Option<Withdrawals>,
552 /// Optional extra data.
553 pub extra_data: Bytes,
554 /// Optional slot number for post-Amsterdam payloads.
555 pub slot_number: Option<u64>,
556}