Skip to main content

reth_evm/
execute.rs

1//! Traits for execution.
2
3use crate::{ConfigureEvm, Database, OnStateHook, TxEnvFor};
4use alloc::{boxed::Box, sync::Arc, vec::Vec};
5use alloy_consensus::{BlockHeader, Header};
6use alloy_eip7928::{compute_block_access_list_hash, BlockAccessList};
7use alloy_eips::eip2718::WithEncoded;
8pub use alloy_evm::block::{BlockExecutor, BlockExecutorFactory, GasOutput};
9use alloy_evm::{
10    block::{CommitChanges, ExecutableTxParts},
11    Evm, EvmEnv, EvmFactory, RecoveredTx, ToTxEnv,
12};
13use alloy_primitives::{Address, B256};
14pub use reth_execution_errors::{
15    BlockExecutionError, BlockValidationError, InternalBlockExecutionError,
16};
17use reth_execution_types::BlockExecutionResult;
18pub use reth_execution_types::{BlockExecutionOutput, ExecutionOutcome};
19use reth_primitives_traits::{
20    Block, HeaderTy, NodePrimitives, ReceiptTy, Recovered, RecoveredBlock, SealedHeader, TxTy,
21};
22use reth_storage_api::StateProvider;
23pub use reth_storage_errors::provider::ProviderError;
24use reth_trie_common::{updates::TrieUpdates, HashedPostState};
25use revm::{
26    database::{states::bundle_state::BundleRetention, BundleState, State},
27    state::bal::Bal,
28};
29
30/// A type that knows how to execute a block. It is assumed to operate on a
31/// [`crate::Evm`] internally and use [`State`] as database.
32pub trait Executor<DB: Database>: Sized {
33    /// The primitive types used by the executor.
34    type Primitives: NodePrimitives;
35    /// The error type returned by the executor.
36    type Error;
37
38    /// Executes a single block and returns [`BlockExecutionResult`], without the state changes.
39    fn execute_one(
40        &mut self,
41        block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
42    ) -> Result<BlockExecutionResult<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>;
43
44    /// Executes the EVM with the given input and accepts a state hook closure that is invoked with
45    /// the EVM state after execution.
46    fn execute_one_with_state_hook<F>(
47        &mut self,
48        block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
49        state_hook: F,
50    ) -> Result<BlockExecutionResult<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
51    where
52        F: OnStateHook + 'static;
53
54    /// Consumes the type and executes the block.
55    ///
56    /// # Note
57    /// Execution happens without any validation of the output.
58    ///
59    /// # Returns
60    /// The output of the block execution.
61    fn execute(
62        mut self,
63        block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
64    ) -> Result<BlockExecutionOutput<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
65    {
66        let result = self.execute_one(block)?;
67        let mut state = self.into_state();
68        Ok(BlockExecutionOutput { state: state.take_bundle(), result })
69    }
70
71    /// Executes multiple inputs in the batch, and returns an aggregated [`ExecutionOutcome`].
72    fn execute_batch<'a, I>(
73        mut self,
74        blocks: I,
75    ) -> Result<ExecutionOutcome<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
76    where
77        I: IntoIterator<Item = &'a RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>>,
78    {
79        let blocks_iter = blocks.into_iter();
80        let capacity = blocks_iter.size_hint().0;
81        let mut results = Vec::with_capacity(capacity);
82        let mut first_block = None;
83        for block in blocks_iter {
84            if first_block.is_none() {
85                first_block = Some(block.header().number());
86            }
87            results.push(self.execute_one(block)?);
88        }
89
90        Ok(ExecutionOutcome::from_blocks(
91            first_block.unwrap_or_default(),
92            self.into_state().take_bundle(),
93            results,
94        ))
95    }
96
97    /// Executes the EVM with the given input and accepts a state closure that is invoked with
98    /// the EVM state after execution.
99    fn execute_with_state_closure<F>(
100        mut self,
101        block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
102        mut f: F,
103    ) -> Result<BlockExecutionOutput<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
104    where
105        F: FnMut(&State<DB>),
106    {
107        let result = self.execute_one(block)?;
108        let mut state = self.into_state();
109        f(&state);
110        Ok(BlockExecutionOutput { state: state.take_bundle(), result })
111    }
112
113    /// Executes the EVM with the given input and accepts a state closure that is always invoked
114    /// with the EVM state after execution, even after failure.
115    fn execute_with_state_closure_always<F>(
116        mut self,
117        block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
118        mut f: F,
119    ) -> Result<BlockExecutionOutput<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
120    where
121        F: FnMut(&State<DB>),
122    {
123        let result = self.execute_one(block);
124        let mut state = self.into_state();
125        f(&state);
126
127        Ok(BlockExecutionOutput { state: state.take_bundle(), result: result? })
128    }
129
130    /// Executes the EVM with the given input and accepts a state hook closure that is invoked with
131    /// the EVM state after execution.
132    fn execute_with_state_hook<F>(
133        mut self,
134        block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
135        state_hook: F,
136    ) -> Result<BlockExecutionOutput<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
137    where
138        F: OnStateHook + 'static,
139    {
140        let result = self.execute_one_with_state_hook(block, state_hook)?;
141        let mut state = self.into_state();
142        Ok(BlockExecutionOutput { state: state.take_bundle(), result })
143    }
144
145    /// Consumes the executor and returns the [`State`] containing all state changes.
146    fn into_state(self) -> State<DB>;
147
148    /// The size hint of the batch's tracked state size.
149    ///
150    /// This is used to optimize DB commits depending on the size of the state.
151    fn size_hint(&self) -> usize;
152
153    /// Takes built [`BlockAccessList`] from executor.
154    fn take_bal(&mut self) -> Option<BlockAccessList>;
155}
156
157/// Input for block building. Consumed by [`BlockAssembler`].
158///
159/// This struct contains all the data needed by the [`BlockAssembler`] to create
160/// a complete block after transaction execution.
161///
162/// # Fields Overview
163///
164/// - `evm_env`: The EVM configuration used during execution (spec ID, block env, etc.)
165/// - `execution_ctx`: Additional context like withdrawals and ommers
166/// - `parent`: The parent block header this block builds on
167/// - `transactions`: All transactions that were successfully executed
168/// - `output`: Execution results including receipts and gas used
169/// - `bundle_state`: Accumulated state changes from all transactions
170/// - `state_provider`: Access to the current state for additional lookups
171/// - `state_root`: The calculated state root after all changes
172/// - `block_access_list_hash`: Block access list hash (EIP-7928, Amsterdam)
173///
174/// # Usage
175///
176/// This is typically created internally by [`BlockBuilder::finish`] after all
177/// transactions have been executed:
178///
179/// ```rust,ignore
180/// let input = BlockAssemblerInput {
181///     evm_env: builder.evm_env(),
182///     execution_ctx: builder.context(),
183///     parent: &parent_header,
184///     transactions: executed_transactions,
185///     output: &execution_result,
186///     bundle_state: &state_changes,
187///     state_provider: &state,
188///     state_root: calculated_root,
189///     block_access_list_hash: Some(calculated_bal_hash),
190/// };
191///
192/// let block = assembler.assemble_block(input)?;
193/// ```
194#[derive(derive_more::Debug)]
195#[non_exhaustive]
196pub struct BlockAssemblerInput<'a, 'b, F: BlockExecutorFactory, H = Header> {
197    /// Configuration of EVM used when executing the block.
198    ///
199    /// Contains context relevant to EVM such as [`revm::context::BlockEnv`].
200    pub evm_env:
201        EvmEnv<<F::EvmFactory as EvmFactory>::Spec, <F::EvmFactory as EvmFactory>::BlockEnv>,
202    /// [`BlockExecutorFactory::ExecutionCtx`] used to execute the block.
203    pub execution_ctx: F::ExecutionCtx<'a>,
204    /// Parent block header.
205    pub parent: &'a SealedHeader<H>,
206    /// Transactions that were executed in this block.
207    pub transactions: Vec<F::Transaction>,
208    /// Output of block execution.
209    pub output: &'b BlockExecutionResult<F::Receipt>,
210    /// [`BundleState`] after the block execution.
211    pub bundle_state: &'a BundleState,
212    /// Provider with access to state.
213    #[debug(skip)]
214    pub state_provider: &'b dyn StateProvider,
215    /// State root for this block.
216    pub state_root: B256,
217    /// Block access list hash (EIP-7928, Amsterdam).
218    pub block_access_list_hash: Option<B256>,
219}
220
221impl<'a, 'b, F: BlockExecutorFactory, H> BlockAssemblerInput<'a, 'b, F, H> {
222    /// Creates a new [`BlockAssemblerInput`].
223    #[expect(clippy::too_many_arguments)]
224    pub fn new(
225        evm_env: EvmEnv<
226            <F::EvmFactory as EvmFactory>::Spec,
227            <F::EvmFactory as EvmFactory>::BlockEnv,
228        >,
229        execution_ctx: F::ExecutionCtx<'a>,
230        parent: &'a SealedHeader<H>,
231        transactions: Vec<F::Transaction>,
232        output: &'b BlockExecutionResult<F::Receipt>,
233        bundle_state: &'a BundleState,
234        state_provider: &'b dyn StateProvider,
235        state_root: B256,
236        block_access_list_hash: Option<B256>,
237    ) -> Self {
238        Self {
239            evm_env,
240            execution_ctx,
241            parent,
242            transactions,
243            output,
244            bundle_state,
245            state_provider,
246            state_root,
247            block_access_list_hash,
248        }
249    }
250}
251
252/// A type that knows how to assemble a block from execution results.
253///
254/// The [`BlockAssembler`] is the final step in block production. After transactions
255/// have been executed by the [`BlockExecutor`], the assembler takes all the execution
256/// outputs and creates a properly formatted block.
257///
258/// # Responsibilities
259///
260/// The assembler is responsible for:
261/// - Setting the correct block header fields (gas used, receipts root, logs bloom, etc.)
262/// - Including the executed transactions in the correct order
263/// - Setting the state root from the post-execution state
264/// - Applying any chain-specific rules or adjustments
265///
266/// # Example Flow
267///
268/// ```rust,ignore
269/// // 1. Execute transactions and get results
270/// let execution_result = block_executor.finish()?;
271///
272/// // 2. Calculate state root from changes
273/// let state_root = state_provider.state_root(&bundle_state)?;
274///
275/// // 3. Assemble the final block
276/// let block = assembler.assemble_block(BlockAssemblerInput {
277///     evm_env,           // Environment used during execution
278///     execution_ctx,     // Context like withdrawals, ommers
279///     parent,            // Parent block header
280///     transactions,      // Executed transactions
281///     output,            // Execution results (receipts, gas)
282///     bundle_state,      // All state changes
283///     state_provider,    // For additional lookups if needed
284///     state_root,        // Computed state root
285/// })?;
286/// ```
287///
288/// # Relationship with Block Building
289///
290/// The assembler works together with:
291/// - `NextBlockEnvAttributes`: Provides the configuration for the new block
292/// - [`BlockExecutor`]: Executes transactions and produces results
293/// - [`BlockBuilder`]: Orchestrates the entire process and calls the assembler
294#[auto_impl::auto_impl(&, Arc)]
295pub trait BlockAssembler<F: BlockExecutorFactory> {
296    /// The block type produced by the assembler.
297    type Block: Block;
298
299    /// Builds a block. see [`BlockAssemblerInput`] documentation for more details.
300    fn assemble_block(
301        &self,
302        input: BlockAssemblerInput<'_, '_, F, <Self::Block as Block>::Header>,
303    ) -> Result<Self::Block, BlockExecutionError>;
304}
305
306/// Output of block building.
307#[derive(Debug, Clone)]
308pub struct BlockBuilderOutcome<N: NodePrimitives> {
309    /// Result of block execution.
310    pub execution_result: BlockExecutionResult<N::Receipt>,
311    /// Hashed state after execution.
312    pub hashed_state: HashedPostState,
313    /// Trie updates collected during state root calculation.
314    pub trie_updates: TrieUpdates,
315    /// The built block.
316    pub block: RecoveredBlock<N::Block>,
317    /// Block access list built during execution (EIP-7928, Amsterdam).
318    pub block_access_list: Option<BlockAccessList>,
319}
320
321/// A type that knows how to execute and build a block.
322///
323/// It wraps an inner [`BlockExecutor`] and provides a way to execute transactions and
324/// construct a block.
325///
326/// This is a helper to erase `BasicBlockBuilder` type.
327pub trait BlockBuilder {
328    /// The primitive types used by the inner [`BlockExecutor`].
329    type Primitives: NodePrimitives;
330    /// Inner [`BlockExecutor`].
331    type Executor: BlockExecutor<
332        Transaction = TxTy<Self::Primitives>,
333        Receipt = ReceiptTy<Self::Primitives>,
334    >;
335
336    /// Invokes [`BlockExecutor::apply_pre_execution_changes`].
337    fn apply_pre_execution_changes(&mut self) -> Result<(), BlockExecutionError>;
338
339    /// Invokes [`BlockExecutor::execute_transaction_with_commit_condition`] and saves the
340    /// transaction in internal state only if the transaction was committed.
341    fn execute_transaction_with_commit_condition(
342        &mut self,
343        tx: impl ExecutorTx<Self::Executor>,
344        f: impl FnOnce(&<Self::Executor as BlockExecutor>::Result) -> CommitChanges,
345    ) -> Result<Option<GasOutput>, BlockExecutionError>;
346
347    /// Invokes [`BlockExecutor::execute_transaction_with_result_closure`] and saves the
348    /// transaction in internal state.
349    fn execute_transaction_with_result_closure(
350        &mut self,
351        tx: impl ExecutorTx<Self::Executor>,
352        f: impl FnOnce(&<Self::Executor as BlockExecutor>::Result),
353    ) -> Result<GasOutput, BlockExecutionError> {
354        self.execute_transaction_with_commit_condition(tx, |res| {
355            f(res);
356            CommitChanges::Yes
357        })
358        .map(Option::unwrap_or_default)
359    }
360
361    /// Invokes [`BlockExecutor::execute_transaction`] and saves the transaction in
362    /// internal state.
363    fn execute_transaction(
364        &mut self,
365        tx: impl ExecutorTx<Self::Executor>,
366    ) -> Result<GasOutput, BlockExecutionError> {
367        self.execute_transaction_with_result_closure(tx, |_| ())
368    }
369
370    /// Completes the block building process and returns the [`BlockBuilderOutcome`].
371    ///
372    /// When `state_root_precomputed` is `None`, the state root is computed internally via
373    /// `state_root_with_updates()`. When `Some`, the provided root and trie updates are used
374    /// directly, skipping the expensive computation (e.g. when using the sparse trie pipeline).
375    fn finish(
376        self,
377        state_provider: impl StateProvider,
378        state_root_precomputed: Option<(B256, TrieUpdates)>,
379    ) -> Result<BlockBuilderOutcome<Self::Primitives>, BlockExecutionError>;
380
381    /// Provides mutable access to the inner [`BlockExecutor`].
382    fn executor_mut(&mut self) -> &mut Self::Executor;
383
384    /// Provides access to the inner [`BlockExecutor`].
385    fn executor(&self) -> &Self::Executor;
386
387    /// Helper to access inner [`BlockExecutor::Evm`] mutably.
388    fn evm_mut(&mut self) -> &mut <Self::Executor as BlockExecutor>::Evm {
389        self.executor_mut().evm_mut()
390    }
391
392    /// Helper to access inner [`BlockExecutor::Evm`].
393    fn evm(&self) -> &<Self::Executor as BlockExecutor>::Evm {
394        self.executor().evm()
395    }
396
397    /// Consumes the type and returns the underlying [`BlockExecutor`].
398    fn into_executor(self) -> Self::Executor;
399}
400
401/// A type that constructs a block from transactions and execution results.
402#[derive(Debug)]
403pub struct BasicBlockBuilder<'a, F, Executor, Builder, N: NodePrimitives>
404where
405    F: BlockExecutorFactory,
406{
407    /// The block executor used to execute transactions.
408    pub executor: Executor,
409    /// The transactions executed in this block.
410    pub transactions: Vec<Recovered<TxTy<N>>>,
411    /// The parent block execution context.
412    pub ctx: F::ExecutionCtx<'a>,
413    /// The sealed parent block header.
414    pub parent: &'a SealedHeader<HeaderTy<N>>,
415    /// The assembler used to build the block.
416    pub assembler: Builder,
417}
418
419/// Conversions for executable transactions.
420pub trait ExecutorTx<Executor: BlockExecutor> {
421    /// Converts the transaction into a tuple of [`TxEnvFor`] and [`Recovered`].
422    fn into_parts(self) -> (<Executor::Evm as Evm>::Tx, Recovered<Executor::Transaction>);
423}
424
425impl<Executor: BlockExecutor> ExecutorTx<Executor>
426    for WithEncoded<Recovered<Executor::Transaction>>
427{
428    fn into_parts(self) -> (<Executor::Evm as Evm>::Tx, Recovered<Executor::Transaction>) {
429        (self.to_tx_env(), self.1)
430    }
431}
432
433impl<Executor: BlockExecutor> ExecutorTx<Executor> for Recovered<Executor::Transaction> {
434    fn into_parts(self) -> (<Executor::Evm as Evm>::Tx, Self) {
435        (self.to_tx_env(), self)
436    }
437}
438
439impl<Executor: BlockExecutor> ExecutorTx<Executor>
440    for (<Executor::Evm as Evm>::Tx, Recovered<Executor::Transaction>)
441{
442    fn into_parts(self) -> (<Executor::Evm as Evm>::Tx, Recovered<Executor::Transaction>) {
443        self
444    }
445}
446
447impl<Executor> ExecutorTx<Executor>
448    for WithTxEnv<<Executor::Evm as Evm>::Tx, Recovered<Executor::Transaction>>
449where
450    Executor: BlockExecutor<Transaction: Clone>,
451{
452    fn into_parts(self) -> (<Executor::Evm as Evm>::Tx, Recovered<Executor::Transaction>) {
453        (self.tx_env, Arc::unwrap_or_clone(self.tx))
454    }
455}
456
457impl<'a, F, DB, Executor, Builder, N> BlockBuilder
458    for BasicBlockBuilder<'a, F, Executor, Builder, N>
459where
460    F: BlockExecutorFactory<Transaction = N::SignedTx, Receipt = N::Receipt>,
461    Executor: BlockExecutor<
462        Evm: Evm<
463            Spec = <F::EvmFactory as EvmFactory>::Spec,
464            HaltReason = <F::EvmFactory as EvmFactory>::HaltReason,
465            BlockEnv = <F::EvmFactory as EvmFactory>::BlockEnv,
466            DB = &'a mut State<DB>,
467        >,
468        Transaction = N::SignedTx,
469        Receipt = N::Receipt,
470    >,
471    DB: Database + 'a,
472    Builder: BlockAssembler<F, Block = N::Block>,
473    N: NodePrimitives,
474{
475    type Primitives = N;
476    type Executor = Executor;
477
478    fn apply_pre_execution_changes(&mut self) -> Result<(), BlockExecutionError> {
479        self.executor.apply_pre_execution_changes()?;
480        self.executor.evm_mut().db_mut().bump_bal_index();
481
482        Ok(())
483    }
484
485    fn execute_transaction_with_commit_condition(
486        &mut self,
487        tx: impl ExecutorTx<Self::Executor>,
488        f: impl FnOnce(&<Self::Executor as BlockExecutor>::Result) -> CommitChanges,
489    ) -> Result<Option<GasOutput>, BlockExecutionError> {
490        let (tx_env, tx) = tx.into_parts();
491        if let Some(gas_used) =
492            self.executor.execute_transaction_with_commit_condition((tx_env, &tx), f)?
493        {
494            self.transactions.push(tx);
495            self.executor.evm_mut().db_mut().bump_bal_index();
496            Ok(Some(gas_used))
497        } else {
498            Ok(None)
499        }
500    }
501
502    fn finish(
503        self,
504        state: impl StateProvider,
505        state_root_precomputed: Option<(B256, TrieUpdates)>,
506    ) -> Result<BlockBuilderOutcome<N>, BlockExecutionError> {
507        let (evm, result) = self.executor.finish()?;
508        let (db, evm_env) = evm.finish();
509
510        // merge all transitions into bundle state
511        db.merge_transitions(BundleRetention::Reverts);
512
513        let block_access_list = db.take_built_alloy_bal();
514        let block_access_list_hash =
515            block_access_list.as_ref().map(|bal| compute_block_access_list_hash(bal.as_slice()));
516
517        let hashed_state = state.hashed_post_state(&db.bundle_state);
518        let (state_root, trie_updates) = match state_root_precomputed {
519            Some(precomputed) => precomputed,
520            None => state
521                .state_root_with_updates(hashed_state.clone())
522                .map_err(BlockExecutionError::other)?,
523        };
524
525        let (transactions, senders) =
526            self.transactions.into_iter().map(|tx| tx.into_parts()).unzip();
527
528        let block = self.assembler.assemble_block(BlockAssemblerInput {
529            evm_env,
530            execution_ctx: self.ctx,
531            parent: self.parent,
532            transactions,
533            output: &result,
534            bundle_state: &db.bundle_state,
535            state_provider: &state,
536            state_root,
537            block_access_list_hash,
538        })?;
539
540        let block = RecoveredBlock::new_unhashed(block, senders);
541
542        Ok(BlockBuilderOutcome {
543            execution_result: result,
544            hashed_state,
545            trie_updates,
546            block,
547            block_access_list,
548        })
549    }
550
551    fn executor_mut(&mut self) -> &mut Self::Executor {
552        &mut self.executor
553    }
554
555    fn executor(&self) -> &Self::Executor {
556        &self.executor
557    }
558
559    fn into_executor(self) -> Self::Executor {
560        self.executor
561    }
562}
563
564/// A generic block executor that uses a [`BlockExecutor`] to
565/// execute blocks.
566#[expect(missing_debug_implementations)]
567pub struct BasicBlockExecutor<F, DB> {
568    /// Block execution strategy.
569    pub(crate) strategy_factory: F,
570    /// Database.
571    pub(crate) db: State<DB>,
572}
573
574impl<F, DB: Database> BasicBlockExecutor<F, DB> {
575    /// Creates a new `BasicBlockExecutor` with the given strategy.
576    pub fn new(strategy_factory: F, db: DB) -> Self {
577        let db = State::builder().with_database(db).with_bundle_update().build();
578        Self { strategy_factory, db }
579    }
580}
581
582impl<F, DB> Executor<DB> for BasicBlockExecutor<F, DB>
583where
584    F: ConfigureEvm,
585    DB: Database,
586{
587    type Primitives = F::Primitives;
588    type Error = BlockExecutionError;
589
590    fn execute_one(
591        &mut self,
592        block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
593    ) -> Result<BlockExecutionResult<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
594    {
595        let mut executor = self
596            .strategy_factory
597            .executor_for_block(&mut self.db, block)
598            .map_err(BlockExecutionError::other)?;
599
600        let has_bal = block.header().block_access_list_hash().is_some();
601
602        if has_bal {
603            executor.evm_mut().db_mut().bal_state.bal_builder = Some(Bal::new());
604        } else {
605            executor.evm_mut().db_mut().bal_state.bal_builder = None;
606        }
607
608        executor.apply_pre_execution_changes()?;
609
610        if has_bal {
611            executor.evm_mut().db_mut().bump_bal_index();
612        }
613
614        for tx in block.transactions_recovered() {
615            executor.execute_transaction(tx)?;
616            if has_bal {
617                executor.evm_mut().db_mut().bump_bal_index();
618            }
619        }
620
621        let result = executor.apply_post_execution_changes()?;
622
623        self.db.merge_transitions(BundleRetention::Reverts);
624
625        Ok(result)
626    }
627
628    fn execute_one_with_state_hook<H>(
629        &mut self,
630        block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
631        state_hook: H,
632    ) -> Result<BlockExecutionResult<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
633    where
634        H: OnStateHook + 'static,
635    {
636        let mut executor = self
637            .strategy_factory
638            .executor_for_block(&mut self.db, block)
639            .map_err(BlockExecutionError::other)?;
640
641        executor.evm_mut().db_mut().set_state_hook(Some(Box::new(state_hook)));
642
643        let result = executor.execute_block(block.transactions_recovered());
644
645        self.db.set_state_hook(None);
646        self.db.merge_transitions(BundleRetention::Reverts);
647
648        result
649    }
650
651    fn into_state(self) -> State<DB> {
652        self.db
653    }
654
655    fn size_hint(&self) -> usize {
656        self.db.bundle_state.size_hint()
657    }
658
659    fn take_bal(&mut self) -> Option<BlockAccessList> {
660        self.db.take_built_alloy_bal()
661    }
662}
663
664/// A helper trait marking a 'static type that can be converted into an [`ExecutableTxParts`] for
665/// block executor.
666pub trait ExecutableTxFor<Evm: ConfigureEvm>:
667    ExecutableTxParts<TxEnvFor<Evm>, TxTy<Evm::Primitives>> + RecoveredTx<TxTy<Evm::Primitives>>
668{
669}
670
671impl<T, Evm: ConfigureEvm> ExecutableTxFor<Evm> for T where
672    T: ExecutableTxParts<TxEnvFor<Evm>, TxTy<Evm::Primitives>> + RecoveredTx<TxTy<Evm::Primitives>>
673{
674}
675
676/// A transaction stored together with its `TxEnv`.
677///
678/// See also [`ExecutableTxParts`] for types that can be split into a transaction environment and
679/// recovered transaction.
680#[derive(Debug)]
681pub struct WithTxEnv<TxEnv, T> {
682    /// The transaction environment for EVM.
683    pub tx_env: TxEnv,
684    /// The recovered transaction.
685    pub tx: Arc<T>,
686}
687
688impl<TxEnv, T> WithTxEnv<TxEnv, T> {
689    /// Creates a transaction/environment pair from a type that can be split with
690    /// [`ExecutableTxParts::into_parts`].
691    pub fn new<Tx, InnerTx>(tx: Tx) -> Self
692    where
693        Tx: ExecutableTxParts<TxEnv, InnerTx, Recovered = T>,
694    {
695        let (tx_env, tx) = tx.into_parts();
696        Self { tx_env, tx: Arc::new(tx) }
697    }
698}
699
700impl<TxEnv: Clone, T> Clone for WithTxEnv<TxEnv, T> {
701    fn clone(&self) -> Self {
702        Self { tx_env: self.tx_env.clone(), tx: self.tx.clone() }
703    }
704}
705
706impl<TxEnv, Tx, T: RecoveredTx<Tx>> RecoveredTx<Tx> for WithTxEnv<TxEnv, T> {
707    fn tx(&self) -> &Tx {
708        self.tx.tx()
709    }
710
711    fn signer(&self) -> &Address {
712        self.tx.signer()
713    }
714}
715
716impl<TxEnv, T: RecoveredTx<Tx>, Tx> ExecutableTxParts<TxEnv, Tx> for WithTxEnv<TxEnv, T> {
717    type Recovered = Arc<T>;
718
719    fn into_parts(self) -> (TxEnv, Self::Recovered) {
720        (self.tx_env, self.tx)
721    }
722}
723
724#[cfg(test)]
725mod tests {
726    use super::*;
727    use core::marker::PhantomData;
728    use reth_ethereum_primitives::EthPrimitives;
729    use revm::database::{CacheDB, EmptyDB};
730
731    #[derive(Clone, Debug, Default)]
732    struct TestExecutorProvider;
733
734    impl TestExecutorProvider {
735        fn executor<DB>(&self, _db: DB) -> TestExecutor<DB>
736        where
737            DB: Database,
738        {
739            TestExecutor(PhantomData)
740        }
741    }
742
743    struct TestExecutor<DB>(PhantomData<DB>);
744
745    impl<DB: Database> Executor<DB> for TestExecutor<DB> {
746        type Primitives = EthPrimitives;
747        type Error = BlockExecutionError;
748
749        fn execute_one(
750            &mut self,
751            _block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
752        ) -> Result<BlockExecutionResult<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
753        {
754            Err(BlockExecutionError::msg("execution unavailable for tests"))
755        }
756
757        fn execute_one_with_state_hook<F>(
758            &mut self,
759            _block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
760            _state_hook: F,
761        ) -> Result<BlockExecutionResult<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
762        where
763            F: OnStateHook + 'static,
764        {
765            Err(BlockExecutionError::msg("execution unavailable for tests"))
766        }
767
768        fn into_state(self) -> State<DB> {
769            unreachable!()
770        }
771
772        fn size_hint(&self) -> usize {
773            0
774        }
775
776        fn take_bal(&mut self) -> Option<BlockAccessList> {
777            None
778        }
779    }
780
781    #[test]
782    fn test_provider() {
783        let provider = TestExecutorProvider;
784        let db = CacheDB::<EmptyDB>::default();
785        let executor = provider.executor(db);
786        let _ = executor.execute(&Default::default());
787    }
788}