reth_evm/lib.rs
1//! Traits for configuring EVM specifics.
2
3#![doc(
4 html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
5 html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
6 issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
7)]
8#![cfg_attr(not(test), warn(unused_crate_dependencies))]
9#![cfg_attr(docsrs, feature(doc_cfg))]
10#![cfg_attr(not(feature = "std"), no_std)]
11
12extern crate alloc;
13
14#[cfg(feature = "std")]
15use crate::execute::{BasicBlockBuilder, BasicBlockExecutor};
16use alloc::string::String;
17use alloy_eips::eip4895::Withdrawals;
18use alloy_primitives::{Address, Bytes, B256};
19use core::{error::Error, fmt::Debug};
20use reth_primitives_traits::{
21 BlockTy, HeaderTy, NodePrimitives, ReceiptTy, SealedBlock, SealedHeader, TxTy,
22};
23
24pub use evm2::{
25 debug_unreachable,
26 evm::{Database, DynDatabase},
27};
28
29/// Cached database adapters for payload building.
30pub mod cached;
31/// Database adapters for EVM execution.
32pub mod database;
33pub mod either;
34/// EVM environment configuration.
35pub mod execute;
36/// precompile cache provider.
37#[cfg(feature = "std")]
38pub mod precompile_cache;
39
40mod aliases;
41pub use aliases::*;
42pub use execute::{
43 BlockAssembler, BlockAssemblerInput, BlockBuilder, BlockBuilderOutcome, BlockExecutionError,
44 BlockExecutionOutput, BlockExecutor, BlockExecutorFactory, BlockTransactionResult,
45 BlockValidationError, CommitChanges, Evm, ExecutableTxFor, ExecutableTxParts, Executor,
46 ExecutorTx, FromRecoveredTx, FromTxWithEncoded, GasOutput, InternalBlockExecutionError,
47 IntoTxEnv, InvalidTxError, ReceiptBuilder, ReceiptBuilderCtx, RecoveredTx, TransactionEnvMut,
48 WithTxEnv,
49};
50pub use reth_execution_types::{OnStateHook, StateUpdate};
51pub use reth_trie_common::bundle_state::BundleState;
52
53/// Transaction validation limits resolved for an EVM environment.
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub struct EvmTransactionValidationLimits {
56 /// Maximum contract creation initcode size.
57 pub max_initcode_size: usize,
58 /// Transaction gas limit cap. `0` disables the txpool-level cap check.
59 pub tx_gas_limit_cap: u64,
60}
61
62/// Transaction validation gas rules resolved for an EVM environment.
63#[derive(Debug, Clone, Copy)]
64pub struct EvmTransactionValidationGasRules {
65 /// The configured native gas schedule and enabled features.
66 pub version: evm2::Version,
67}
68
69/// Transaction validation gas resolved for a transaction.
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
71pub struct EvmTransactionValidationGas {
72 /// Transaction intrinsic gas.
73 pub intrinsic_gas: u64,
74 /// Transaction floor gas.
75 pub floor_gas: u64,
76}
77
78impl EvmTransactionValidationGasRules {
79 /// Returns the intrinsic regular gas cap, or zero when EIP-8037 is disabled.
80 pub const fn regular_gas_cap(&self) -> u64 {
81 if self.version.feature(evm2::EvmFeatures::EIP8037) {
82 self.version.tx_gas_limit_cap
83 } else {
84 0
85 }
86 }
87
88 /// Calculates validation gas with the same native rules used during execution.
89 #[expect(clippy::too_many_arguments)]
90 pub fn calculate(
91 &self,
92 caller: alloy_primitives::Address,
93 to: alloy_primitives::TxKind,
94 value: alloy_primitives::U256,
95 input: &alloy_primitives::Bytes,
96 access_list_accounts: u64,
97 access_list_storage_keys: u64,
98 authorization_list_len: u64,
99 ) -> EvmTransactionValidationGas {
100 let (mut intrinsic_gas, floor_gas) = evm2::ethereum::intrinsic_and_floor_gas(
101 &self.version,
102 caller,
103 to,
104 input,
105 access_list_accounts,
106 access_list_storage_keys,
107 value,
108 );
109 if self.version.feature(evm2::EvmFeatures::EIP7702) {
110 intrinsic_gas += authorization_list_len *
111 self.version.gas_params.get(evm2::version::GasId::TxEip7702PerEmptyAccountCost);
112 }
113 EvmTransactionValidationGas { intrinsic_gas, floor_gas }
114 }
115}
116
117/// Resolved EVM environment data needed by the EVM execution path.
118pub trait EvmEnv: Debug + Clone + Send + Sync + 'static {
119 /// Runtime EVM type family.
120 type EvmTypes: evm2::EvmTypes;
121
122 /// Returns the active EVM specification.
123 fn spec_id(&self) -> <Self::EvmTypes as evm2::EvmTypesHost>::SpecId;
124
125 /// Returns the active chain ID.
126 fn chain_id(&self) -> u64;
127
128 /// Returns the configured block environment.
129 fn block_env(&self) -> &evm2::env::BlockEnv<Self::EvmTypes>;
130
131 /// Returns the configured block environment mutably.
132 fn block_env_mut(&mut self) -> &mut evm2::env::BlockEnv<Self::EvmTypes>;
133
134 /// Returns the active EVM version.
135 fn version(&self) -> &evm2::Version;
136
137 /// Returns the active EVM version mutably.
138 fn version_mut(&mut self) -> &mut evm2::Version;
139
140 /// Returns the block base fee resolved for this environment.
141 fn block_base_fee(&self) -> u64;
142
143 /// Returns the block blob base fee resolved for this environment.
144 fn block_blob_base_fee(&self) -> u64;
145
146 /// Returns transaction validation limits active in this environment.
147 fn transaction_validation_limits(&self) -> EvmTransactionValidationLimits;
148
149 /// Returns transaction validation gas rules active in this environment.
150 fn transaction_validation_gas_rules(&self) -> EvmTransactionValidationGasRules;
151
152 /// Returns whether the block uses independent regular and state gas capacity.
153 fn uses_separate_block_gas(&self) -> bool {
154 false
155 }
156
157 /// Returns the transaction limit used to reserve regular block gas.
158 fn regular_gas_limit_cap(&self) -> u64 {
159 u64::MAX
160 }
161
162 /// Returns this environment with transaction nonce checks disabled.
163 fn with_nonce_check_disabled(self) -> Self;
164
165 /// Returns this environment with transaction balance checks disabled.
166 fn with_balance_check_disabled(self) -> Self;
167}
168
169#[cfg(feature = "std")]
170mod engine;
171#[cfg(feature = "std")]
172pub use engine::{ConfigureEngineEvm, ConvertTx, ExecutableTxIterator, ExecutableTxTuple};
173mod sender_recovery;
174pub use sender_recovery::SenderRecoveryCache;
175
176#[cfg(feature = "metrics")]
177pub mod metrics;
178pub mod noop;
179/// Helper types for execution witness generation.
180#[cfg(feature = "witness")]
181pub mod witness;
182
183/// A complete configuration of EVM for Reth.
184///
185/// This trait encapsulates complete configuration required for transaction execution and block
186/// execution/building, providing a unified interface for EVM operations.
187///
188/// # Architecture Overview
189///
190/// The EVM abstraction consists of the following layers:
191///
192/// 1. **[`Evm`] (created by [`BlockExecutorFactory::evm_with_env`])**: The core EVM implementation
193/// responsible for executing individual transactions and producing outputs including state
194/// changes, logs, gas usage, etc. The factory that configures it is
195/// [`BlockExecutorFactory::EvmFactory`].
196///
197/// 2. **[`BlockExecutor`] (created by [`BlockExecutorFactory::create_executor`])**: A higher-level
198/// component that operates on top of [`Evm`] to execute entire blocks. This involves:
199/// - Executing all transactions in sequence
200/// - Building receipts from transaction outputs
201/// - Applying block rewards to the beneficiary
202/// - Executing system calls (e.g., EIP-4788 beacon root updates)
203/// - Managing state changes and bundle accumulation
204///
205/// 3. **[`BlockAssembler`]**: Responsible for assembling valid blocks from executed transactions.
206/// It takes the output from [`BlockExecutor`] along with execution context and produces a
207/// complete block ready for inclusion in the chain.
208///
209/// # Usage Patterns
210///
211/// The abstraction supports two primary use cases:
212///
213/// ## 1. Executing Externally Provided Blocks (e.g., during sync)
214///
215/// ```rust,ignore
216/// use reth_evm::ConfigureEvm;
217///
218/// // Execute a received block
219/// let mut executor = evm_config.executor(state_db);
220/// let output = executor.execute(&block)?;
221///
222/// // Access the execution results
223/// println!("Gas used: {}", output.result.gas_used);
224/// println!("Receipts: {:?}", output.result.receipts);
225/// ```
226///
227/// ## 2. Building New Blocks (e.g., payload building)
228///
229/// Payload building is slightly different as it doesn't have the block's header yet, but rather
230/// attributes for the block's environment, such as timestamp, fee recipient, and randomness value.
231/// The block's header will be the outcome of the block building process.
232///
233/// ```rust,ignore
234/// use reth_evm::{ConfigureEvm, NextBlockEnvAttributes};
235///
236/// // Create attributes for the next block
237/// let attributes = NextBlockEnvAttributes {
238/// timestamp: current_time + 12,
239/// suggested_fee_recipient: beneficiary_address,
240/// prev_randao: randomness_value,
241/// gas_limit: 30_000_000,
242/// withdrawals: Some(withdrawals),
243/// parent_beacon_block_root: Some(beacon_root),
244/// extra_data: Bytes::new(),
245/// slot_number: None,
246/// };
247///
248/// // Build a new block on top of parent
249/// let mut builder = evm_config.builder_for_next_block(
250/// state_db,
251/// &parent_header,
252/// attributes
253/// )?;
254///
255/// // Apply pre-execution changes (e.g., beacon root update)
256/// builder.apply_pre_execution_changes()?;
257///
258/// // Execute transactions
259/// for tx in pending_transactions {
260/// match builder.execute_transaction(tx) {
261/// Ok(gas_output) => {
262/// println!("Transaction executed, gas used: {}", gas_output.tx_gas_used());
263/// }
264/// Err(e) => {
265/// println!("Transaction failed: {:?}", e);
266/// }
267/// }
268/// }
269///
270/// // Finish block building and get the outcome (block)
271/// let outcome = builder.finish(state_provider, None)?;
272/// let block = outcome.block;
273/// ```
274///
275/// # Key Components
276///
277/// ## [`NextBlockEnvCtx`]
278///
279/// Contains attributes needed to configure the next block that cannot be derived from the
280/// parent block alone. This includes data typically provided by the consensus layer:
281/// - `timestamp`: Block timestamp
282/// - `suggested_fee_recipient`: Beneficiary address
283/// - `prev_randao`: Randomness value
284/// - `gas_limit`: Block gas limit
285/// - `withdrawals`: Consensus layer withdrawals
286/// - `parent_beacon_block_root`: EIP-4788 beacon root
287///
288/// ## [`BlockAssembler`]
289///
290/// Takes the execution output and produces a complete block. It receives:
291/// - Transaction execution results (receipts, gas used)
292/// - Final state root after all executions
293/// - Bundle state with all changes
294/// - Execution context and environment
295///
296/// The assembler is responsible for:
297/// - Setting the correct block header fields
298/// - Including executed transactions
299/// - Setting gas used and receipts root
300/// - Applying any chain-specific rules
301///
302/// [`ExecutionCtx`]: BlockExecutorFactory::ExecutionCtx
303/// [`NextBlockEnvCtx`]: ConfigureEvm::NextBlockEnvCtx
304#[auto_impl::auto_impl(&, Arc)]
305pub trait ConfigureEvm: Clone + Debug + Send + Sync + Unpin {
306 /// The primitives type used by the EVM.
307 type Primitives: NodePrimitives;
308
309 /// The error type that is returned by [`Self::next_evm_env`].
310 type Error: Error + Send + Sync + 'static;
311
312 /// Context required for configuring next block environment.
313 ///
314 /// Contains values that can't be derived from the parent block.
315 type NextBlockEnvCtx: Debug + Clone;
316
317 /// Configured [`BlockExecutorFactory`], contains the EVM factory internally.
318 type BlockExecutorFactory: crate::execute::BlockExecutorFactory<
319 Transaction = TxTy<Self::Primitives>,
320 Receipt = ReceiptTy<Self::Primitives>,
321 EvmTypes: evm2::EvmTypes<
322 Tx: crate::execute::FromTxWithEncoded<TxTy<Self::Primitives>>
323 + crate::execute::TransactionEnvMut,
324 >,
325 >;
326
327 /// A type that knows how to build a block.
328 #[cfg(feature = "std")]
329 type BlockAssembler: crate::execute::BlockAssembler<
330 Self::BlockExecutorFactory,
331 Block = BlockTy<Self::Primitives>,
332 >;
333
334 /// Returns reference to the configured [`BlockExecutorFactory`].
335 #[cfg(feature = "std")]
336 fn block_executor_factory(&self) -> &Self::BlockExecutorFactory;
337
338 /// Returns reference to the configured [`BlockAssembler`].
339 #[cfg(feature = "std")]
340 fn block_assembler(&self) -> &Self::BlockAssembler;
341
342 /// Creates a new [`EvmEnv`] for the given header.
343 fn evm_env(&self, header: &HeaderTy<Self::Primitives>) -> Result<EvmEnvFor<Self>, Self::Error>;
344
345 /// Returns the configured [`EvmEnv`] for `parent + 1` block.
346 ///
347 /// This is intended for usage in block building after the merge and requires additional
348 /// attributes that can't be derived from the parent block: attributes that are determined by
349 /// the CL, such as the timestamp, suggested fee recipient, and randomness value.
350 ///
351 /// # Example
352 ///
353 /// ```rust,ignore
354 /// let evm_env = evm_config.next_evm_env(&parent_header, &attributes)?;
355 /// // evm_env now contains:
356 /// // - Correct spec ID based on timestamp and block number
357 /// // - Block environment with next block's parameters
358 /// // - Configuration like chain ID and blob parameters
359 /// ```
360 fn next_evm_env(
361 &self,
362 parent: &HeaderTy<Self::Primitives>,
363 attributes: &Self::NextBlockEnvCtx,
364 ) -> Result<EvmEnvFor<Self>, Self::Error>;
365
366 /// Returns the configured [`BlockExecutorFactory::ExecutionCtx`] for a given block.
367 fn context_for_block<'a>(
368 &self,
369 block: &'a SealedBlock<BlockTy<Self::Primitives>>,
370 ) -> Result<ExecutionCtxFor<'a, Self>, Self::Error>
371 where
372 Self: 'a;
373
374 /// Returns the configured [`BlockExecutorFactory::ExecutionCtx`] for `parent + 1`
375 /// block.
376 fn context_for_next_block(
377 &self,
378 parent: &SealedHeader<HeaderTy<Self::Primitives>>,
379 attributes: Self::NextBlockEnvCtx,
380 ) -> Result<ExecutionCtxFor<'_, Self>, Self::Error>;
381
382 /// Returns a transaction environment from a transaction.
383 fn tx_env(&self, transaction: impl IntoTxEnv<TxEnvFor<Self>>) -> TxEnvFor<Self> {
384 transaction.into_tx_env()
385 }
386
387 /// Provides a reference to the configured EVM factory state.
388 #[cfg(feature = "std")]
389 fn evm_factory(&self) -> &EvmFactoryFor<Self> {
390 self.block_executor_factory().evm_factory()
391 }
392
393 /// Returns a config with JIT support enabled for subsequently created EVMs, if supported.
394 ///
395 /// This is one of three gates required before an EVM can execute JIT-compiled code: the binary
396 /// must be built with the `jit` feature, runtime compilation must be enabled by `--jit` or the
397 /// `reth_jit` RPC method, and this local support flag must be enabled for the config that
398 /// creates the EVM.
399 #[auto_impl(keep_default_for(&, Arc))]
400 fn with_jit_support_enabled(self, _enabled: bool) -> Self
401 where
402 Self: Sized,
403 {
404 self
405 }
406
407 /// Returns a config with local JIT support enabled for subsequently created EVMs, if supported.
408 #[auto_impl(keep_default_for(&, Arc))]
409 fn with_jit_support(self) -> Self
410 where
411 Self: Sized,
412 {
413 self.with_jit_support_enabled(true)
414 }
415
416 /// Creates an EVM whose precompile results are cached in `cache_map`.
417 ///
418 /// Only the engine calls this, for the EVMs it executes and prewarms blocks with. Configs that
419 /// do not support precompile caching create an uncached EVM. `metrics_enabled` selects whether
420 /// the cache records hit, miss, and size metrics.
421 #[cfg(feature = "std")]
422 fn evm_with_precompile_cache<'a, DB>(
423 &self,
424 db: DB,
425 evm_env: EvmEnvFor<Self>,
426 _cache_map: precompile_cache::PrecompileCacheMap<SpecFor<Self>>,
427 _metrics_enabled: bool,
428 ) -> EvmFor<'a, Self>
429 where
430 DB: Database + 'a,
431 {
432 self.evm_with_env(db, evm_env)
433 }
434
435 /// Returns the JIT backend, if supported.
436 fn jit_backend(&self) -> Option<&dyn JitBackend> {
437 None
438 }
439
440 /// Returns a new [`Executor`] for executing blocks.
441 ///
442 /// The executor processes complete blocks including:
443 /// - All transactions in order
444 /// - Block rewards and fees
445 /// - Block level system calls
446 /// - State transitions
447 ///
448 /// # Example
449 ///
450 /// ```rust,ignore
451 /// // Create an executor
452 /// let mut executor = evm_config.executor(state_db);
453 ///
454 /// // Execute a single block
455 /// let output = executor.execute(&block)?;
456 ///
457 /// // Execute multiple blocks
458 /// let batch_output = executor.execute_batch(&blocks)?;
459 /// ```
460 #[auto_impl(keep_default_for(&, Arc))]
461 fn executor<DB>(
462 &self,
463 db: DB,
464 ) -> impl Executor<DB, Primitives = Self::Primitives, Error = BlockExecutionError>
465 where
466 DB: Database,
467 {
468 #[cfg(feature = "std")]
469 {
470 BasicBlockExecutor::new(self, db)
471 }
472
473 #[cfg(not(feature = "std"))]
474 {
475 let _ = db;
476 crate::execute::UnsupportedExecutor::default()
477 }
478 }
479
480 /// Returns a new [`BasicBlockExecutor`].
481 #[auto_impl(keep_default_for(&, Arc))]
482 fn batch_executor<DB>(
483 &self,
484 db: DB,
485 ) -> impl Executor<DB, Primitives = Self::Primitives, Error = BlockExecutionError>
486 where
487 DB: Database,
488 {
489 #[cfg(feature = "std")]
490 {
491 BasicBlockExecutor::new(self, db)
492 }
493
494 #[cfg(not(feature = "std"))]
495 {
496 let _ = db;
497 crate::execute::UnsupportedExecutor::default()
498 }
499 }
500
501 /// Creates a block executor for the given block.
502 #[cfg(feature = "std")]
503 fn executor_for_block<'a, DB>(
504 &'a self,
505 db: DB,
506 block: &'a SealedBlock<BlockTy<Self::Primitives>>,
507 ) -> Result<crate::BlockExecutorFor<'a, Self>, Self::Error>
508 where
509 Self: 'a,
510 DB: Database + 'a,
511 {
512 let evm = self.evm_for_block(db, block.header())?;
513 let ctx = self.context_for_block(block)?;
514 Ok(self.block_executor_factory().create_executor(evm, ctx))
515 }
516
517 /// Creates an EVM instance for single-transaction execution with the configured environment.
518 #[cfg(feature = "std")]
519 #[auto_impl(keep_default_for(&, Arc))]
520 fn evm_with_env<'a, DB>(&self, db: DB, evm_env: EvmEnvFor<Self>) -> EvmFor<'a, Self>
521 where
522 DB: Database + 'a,
523 {
524 self.block_executor_factory().evm_with_database(db, evm_env)
525 }
526
527 /// Creates an EVM instance for the given block.
528 #[cfg(feature = "std")]
529 fn evm_for_block<'a, DB>(
530 &self,
531 db: DB,
532 header: &HeaderTy<Self::Primitives>,
533 ) -> Result<EvmFor<'a, Self>, Self::Error>
534 where
535 DB: Database + 'a,
536 {
537 let evm_env = self.evm_env(header)?;
538 Ok(self.evm_with_env(db, evm_env))
539 }
540
541 /// Creates a [`BlockBuilder`]. Should be used when building a new block.
542 ///
543 /// Block builder wraps an inner [`BlockExecutor`] and has a similar interface. Builder
544 /// collects all of the executed transactions, and once [`BlockBuilder::finish`] is called, it
545 /// invokes the configured [`BlockAssembler`] to create a block.
546 ///
547 /// # Example
548 ///
549 /// ```rust,ignore
550 /// // Create a builder with specific EVM configuration
551 /// let evm = evm_config.evm_with_env(state_db, evm_env.clone());
552 /// let ctx = evm_config.context_for_next_block(&parent, attributes);
553 /// let builder = evm_config.create_block_builder(evm, evm_env, &parent, ctx);
554 /// ```
555 #[cfg(feature = "std")]
556 fn create_block_builder<'a>(
557 &'a self,
558 evm: EvmFor<'a, Self>,
559 evm_env: EvmEnvFor<Self>,
560 parent: &'a SealedHeader<HeaderTy<Self::Primitives>>,
561 ctx: ExecutionCtxFor<'a, Self>,
562 ) -> impl BlockBuilder<Primitives = Self::Primitives, Executor = crate::BlockExecutorFor<'a, Self>>
563 where
564 Self: 'a,
565 {
566 self.create_block_builder_with(evm, evm_env, parent, ctx, |executor| executor)
567 }
568
569 /// Creates a [`BlockBuilder`] like [`ConfigureEvm::create_block_builder`], with a customized
570 /// executor.
571 #[cfg(feature = "std")]
572 fn create_block_builder_with<'a, E>(
573 &'a self,
574 evm: EvmFor<'a, Self>,
575 evm_env: EvmEnvFor<Self>,
576 parent: &'a SealedHeader<HeaderTy<Self::Primitives>>,
577 ctx: ExecutionCtxFor<'a, Self>,
578 f: impl FnOnce(BlockExecutorFor<'a, Self>) -> E,
579 ) -> impl BlockBuilder<Primitives = Self::Primitives, Executor = E>
580 where
581 Self: 'a,
582 E: BlockExecutor<
583 Evm = EvmFor<'a, Self>,
584 Transaction = TxTy<Self::Primitives>,
585 Receipt = ReceiptTy<Self::Primitives>,
586 >,
587 {
588 BasicBlockBuilder {
589 executor: f(self.block_executor_factory().create_executor(evm, ctx.clone())),
590 evm_env,
591 transactions: Default::default(),
592 ctx,
593 parent,
594 assembler: self.block_assembler(),
595 }
596 }
597
598 /// Creates a [`BlockBuilder`] for building of a new block. This is a helper to invoke
599 /// [`ConfigureEvm::create_block_builder`].
600 ///
601 /// This is the primary method for building new blocks. It combines:
602 /// 1. Creating the EVM environment for the next block
603 /// 2. Setting up the execution context from attributes
604 /// 3. Initializing the block builder with proper configuration
605 ///
606 /// # Example
607 ///
608 /// ```rust,ignore
609 /// // Build a block with specific attributes
610 /// let mut builder = evm_config.builder_for_next_block(
611 /// state_db,
612 /// &parent_header,
613 /// attributes
614 /// )?;
615 ///
616 /// // Execute system calls (e.g., beacon root update)
617 /// builder.apply_pre_execution_changes()?;
618 ///
619 /// // Execute transactions
620 /// for tx in transactions {
621 /// builder.execute_transaction(tx)?;
622 /// }
623 ///
624 /// // Complete block building
625 /// let outcome = builder.finish(state_provider, None)?;
626 /// ```
627 #[cfg(feature = "std")]
628 fn builder_for_next_block<'a, DB>(
629 &'a self,
630 db: DB,
631 parent: &'a SealedHeader<HeaderTy<Self::Primitives>>,
632 attributes: Self::NextBlockEnvCtx,
633 ) -> Result<
634 impl BlockBuilder<Primitives = Self::Primitives, Executor = crate::BlockExecutorFor<'a, Self>>,
635 Self::Error,
636 >
637 where
638 Self: 'a,
639 DB: Database + 'a,
640 {
641 let evm_env = self.next_evm_env(parent, &attributes)?;
642 let evm = self.evm_with_env(db, evm_env.clone());
643 let ctx = self.context_for_next_block(parent, attributes)?;
644 Ok(self.create_block_builder(evm, evm_env, parent, ctx))
645 }
646
647 /// Applies block-level state changes required before transaction execution using the configured
648 /// block executor.
649 #[cfg(feature = "std")]
650 fn pre_block_state_changes<'a, DB>(
651 &'a self,
652 db: DB,
653 evm_env: EvmEnvFor<Self>,
654 ctx: ExecutionCtxFor<'a, Self>,
655 ) -> Result<BundleState, Box<dyn Error + Send + Sync>>
656 where
657 Self: 'a,
658 DB: DynDatabase + 'a,
659 {
660 let factory = self.block_executor_factory();
661 let evm = factory.evm_with_env(db, evm_env);
662 let mut executor = factory.create_executor(evm, ctx);
663 executor
664 .apply_pre_execution_changes()
665 .map_err(|err| -> Box<dyn Error + Send + Sync> { Box::new(err) })?;
666 Ok(executor.into_state())
667 }
668
669 /// Returns whether engine validation may commit transaction results from speculative prewarm
670 /// execution instead of executing the transactions again.
671 ///
672 /// Return `true` only if all of these hold, see also [`Self::prewarm_tx_result`]:
673 /// - the block executor executes a transaction by checking that its gas limit, capped by the
674 /// transaction gas limit cap, fits into the block gas limit minus the last receipt's
675 /// cumulative gas used, and then running [`Evm::transact`] with the transaction environment;
676 /// - [`Evm::transact`] performs the standard caller nonce and balance validation; speculative
677 /// results additionally reject the largest nonce before reuse;
678 /// - EVMs created by this configuration with JIT support disabled call inspector hooks for
679 /// every executed instruction;
680 /// - execution depends only on recorded database reads and the transaction and block
681 /// environments reproduced during prewarming, with no unrecorded external state.
682 ///
683 /// [`Evm::transact`]: Evm::transact
684 fn reuses_prewarm_results(&self) -> bool {
685 false
686 }
687
688 /// Wraps a speculative prewarm execution result of `tx` into the result consumed by
689 /// [`BlockExecutor::commit_transaction`].
690 ///
691 /// Only called if [`Self::reuses_prewarm_results`] returns `true`.
692 /// Returning `None` rejects and consumes this speculative result; the engine executes the
693 /// transaction normally instead.
694 #[cfg(feature = "std")]
695 fn prewarm_tx_result<'a>(
696 &self,
697 tx: &TxTy<Self::Primitives>,
698 result: TxResultWithStateFor<Self>,
699 ) -> Option<TxExecutionResultFor<'a, Self>>
700 where
701 Self: 'a,
702 {
703 let _ = (tx, result);
704 None
705 }
706
707 /// Returns the predicted environment of the block after `parent` with `beneficiary`, in which
708 /// engine validation speculatively executes pool transactions before the block arrives.
709 ///
710 /// Validation reuses such results only for blocks whose environment matches the predicted
711 /// one, apart from the beneficiary, timestamp, prevrandao and gas limit, which the
712 /// transactions must not have observed. Only called if [`Self::reuses_prewarm_results`]
713 /// returns `true`. Returns `None` if the environment cannot be predicted, which disables
714 /// recording pool transaction results. Custom block environment extensions must remain
715 /// identical to canonical execution; the engine compares only standard environment fields.
716 fn speculative_next_evm_env(
717 &self,
718 parent: &SealedHeader<HeaderTy<Self::Primitives>>,
719 beneficiary: Address,
720 ) -> Option<EvmEnvFor<Self>> {
721 let _ = (parent, beneficiary);
722 None
723 }
724}
725
726/// JIT backend controls exposed by an EVM configuration.
727pub trait JitBackend: Send + Sync {
728 /// Enables or disables JIT compilation.
729 fn set_enabled(&self, enabled: bool) -> Result<(), String>;
730
731 /// Pauses JIT helper execution while keeping queueing and resident compiled code available.
732 fn pause(&self);
733
734 /// Resumes background JIT work.
735 fn resume(&self);
736
737 /// Clears JIT runtime state.
738 fn clear(&self);
739}
740
741/// Represents additional attributes required to configure the next block.
742///
743/// This struct contains all the information needed to build a new block that cannot be
744/// derived from the parent block header alone. These attributes are typically provided
745/// by the consensus layer (CL) through the Engine API during payload building.
746///
747/// # Relationship with [`ConfigureEvm`] and [`BlockAssembler`]
748///
749/// The flow for building a new block involves:
750///
751/// 1. **Receive attributes** from the consensus layer containing:
752/// - Timestamp for the new block
753/// - Fee recipient (coinbase/beneficiary)
754/// - Randomness value (prevRandao)
755/// - Withdrawals to process
756/// - Parent beacon block root for EIP-4788
757///
758/// 2. **Configure EVM environment** using these attributes: ```rust,ignore let evm_env =
759/// evm_config.next_evm_env(&parent, &attributes)?; ```
760///
761/// 3. **Build the block** with transactions: ```rust,ignore let mut builder =
762/// evm_config.builder_for_next_block( state, &parent, attributes )?; ```
763///
764/// 4. **Assemble the final block** using [`BlockAssembler`] which takes:
765/// - Execution results from all transactions
766/// - The attributes used during execution
767/// - Final state root after all changes
768///
769/// This design cleanly separates:
770/// - **Configuration** (what parameters to use) - handled by `NextBlockEnvAttributes`
771/// - **Execution** (running transactions) - handled by [`BlockExecutor`]
772/// - **Assembly** (creating the final block) - handled by [`BlockAssembler`]
773#[derive(Debug, Clone, PartialEq, Eq)]
774pub struct NextBlockEnvAttributes {
775 /// The timestamp of the next block.
776 pub timestamp: u64,
777 /// The suggested fee recipient for the next block.
778 pub suggested_fee_recipient: Address,
779 /// The randomness value for the next block.
780 pub prev_randao: B256,
781 /// Block gas limit.
782 pub gas_limit: u64,
783 /// The parent beacon block root.
784 pub parent_beacon_block_root: Option<B256>,
785 /// Withdrawals
786 pub withdrawals: Option<Withdrawals>,
787 /// Optional extra data.
788 pub extra_data: Bytes,
789 /// Optional slot number for post-Amsterdam payloads.
790 pub slot_number: Option<u64>,
791}