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::{bal::DecodedBal, compute_block_access_list_hash_with_buf, 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::TrieUpdatesSorted, 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    /// Sorted trie updates collected during state root calculation.
314    pub trie_updates: Arc<TrieUpdatesSorted>,
315    /// The built block.
316    pub block: RecoveredBlock<N::Block>,
317    /// Block access list built during execution (EIP-7928, Amsterdam), with its RLP bytes and
318    /// hash.
319    pub block_access_list: Option<DecodedBal>,
320}
321
322/// A type that knows how to execute and build a block.
323///
324/// It wraps an inner [`BlockExecutor`] and provides a way to execute transactions and
325/// construct a block.
326///
327/// This is a helper to erase `BasicBlockBuilder` type.
328pub trait BlockBuilder {
329    /// The primitive types used by the inner [`BlockExecutor`].
330    type Primitives: NodePrimitives;
331    /// Inner [`BlockExecutor`].
332    type Executor: BlockExecutor<
333        Transaction = TxTy<Self::Primitives>,
334        Receipt = ReceiptTy<Self::Primitives>,
335    >;
336
337    /// Invokes [`BlockExecutor::apply_pre_execution_changes`].
338    fn apply_pre_execution_changes(&mut self) -> Result<(), BlockExecutionError>;
339
340    /// Invokes [`BlockExecutor::execute_transaction_with_commit_condition`] and saves the
341    /// transaction in internal state only if the transaction was committed.
342    fn execute_transaction_with_commit_condition(
343        &mut self,
344        tx: impl ExecutorTx<Self::Executor>,
345        f: impl FnOnce(&<Self::Executor as BlockExecutor>::Result) -> CommitChanges,
346    ) -> Result<Option<GasOutput>, BlockExecutionError>;
347
348    /// Invokes [`BlockExecutor::execute_transaction_with_result_closure`] and saves the
349    /// transaction in internal state.
350    fn execute_transaction_with_result_closure(
351        &mut self,
352        tx: impl ExecutorTx<Self::Executor>,
353        f: impl FnOnce(&<Self::Executor as BlockExecutor>::Result),
354    ) -> Result<GasOutput, BlockExecutionError> {
355        self.execute_transaction_with_commit_condition(tx, |res| {
356            f(res);
357            CommitChanges::Yes
358        })
359        .map(Option::unwrap_or_default)
360    }
361
362    /// Invokes [`BlockExecutor::execute_transaction`] and saves the transaction in
363    /// internal state.
364    fn execute_transaction(
365        &mut self,
366        tx: impl ExecutorTx<Self::Executor>,
367    ) -> Result<GasOutput, BlockExecutionError> {
368        self.execute_transaction_with_result_closure(tx, |_| ())
369    }
370
371    /// Completes the block building process and returns the [`BlockBuilderOutcome`].
372    ///
373    /// When `state_root_precomputed` is `None`, the state root is computed internally via
374    /// `state_root_with_updates()` and its updates are sorted. When `Some`, the provided root
375    /// and shared sorted updates are used directly (e.g. when using the sparse trie pipeline).
376    fn finish(
377        self,
378        state_provider: impl StateProvider,
379        state_root_precomputed: Option<(B256, Arc<TrieUpdatesSorted>)>,
380    ) -> Result<BlockBuilderOutcome<Self::Primitives>, BlockExecutionError>;
381
382    /// Provides mutable access to the inner [`BlockExecutor`].
383    fn executor_mut(&mut self) -> &mut Self::Executor;
384
385    /// Provides access to the inner [`BlockExecutor`].
386    fn executor(&self) -> &Self::Executor;
387
388    /// Helper to access inner [`BlockExecutor::Evm`] mutably.
389    fn evm_mut(&mut self) -> &mut <Self::Executor as BlockExecutor>::Evm {
390        self.executor_mut().evm_mut()
391    }
392
393    /// Helper to access inner [`BlockExecutor::Evm`].
394    fn evm(&self) -> &<Self::Executor as BlockExecutor>::Evm {
395        self.executor().evm()
396    }
397
398    /// Consumes the type and returns the underlying [`BlockExecutor`].
399    fn into_executor(self) -> Self::Executor;
400}
401
402/// A type that constructs a block from transactions and execution results.
403#[derive(Debug)]
404pub struct BasicBlockBuilder<'a, F, Executor, Builder, N: NodePrimitives>
405where
406    F: BlockExecutorFactory,
407{
408    /// The block executor used to execute transactions.
409    pub executor: Executor,
410    /// The transactions executed in this block.
411    pub transactions: Vec<Recovered<TxTy<N>>>,
412    /// The parent block execution context.
413    pub ctx: F::ExecutionCtx<'a>,
414    /// The sealed parent block header.
415    pub parent: &'a SealedHeader<HeaderTy<N>>,
416    /// The assembler used to build the block.
417    pub assembler: Builder,
418}
419
420/// Conversions for executable transactions.
421pub trait ExecutorTx<Executor: BlockExecutor> {
422    /// Converts the transaction into a tuple of [`TxEnvFor`] and [`Recovered`].
423    fn into_parts(self) -> (<Executor::Evm as Evm>::Tx, Recovered<Executor::Transaction>);
424}
425
426impl<Executor: BlockExecutor> ExecutorTx<Executor>
427    for WithEncoded<Recovered<Executor::Transaction>>
428{
429    fn into_parts(self) -> (<Executor::Evm as Evm>::Tx, Recovered<Executor::Transaction>) {
430        (self.to_tx_env(), self.1)
431    }
432}
433
434impl<Executor: BlockExecutor> ExecutorTx<Executor> for Recovered<Executor::Transaction> {
435    fn into_parts(self) -> (<Executor::Evm as Evm>::Tx, Self) {
436        (self.to_tx_env(), self)
437    }
438}
439
440impl<Executor: BlockExecutor> ExecutorTx<Executor>
441    for (<Executor::Evm as Evm>::Tx, Recovered<Executor::Transaction>)
442{
443    fn into_parts(self) -> (<Executor::Evm as Evm>::Tx, Recovered<Executor::Transaction>) {
444        self
445    }
446}
447
448impl<Executor> ExecutorTx<Executor>
449    for WithTxEnv<<Executor::Evm as Evm>::Tx, Recovered<Executor::Transaction>>
450where
451    Executor: BlockExecutor<Transaction: Clone>,
452{
453    fn into_parts(self) -> (<Executor::Evm as Evm>::Tx, Recovered<Executor::Transaction>) {
454        (self.tx_env, Arc::unwrap_or_clone(self.tx))
455    }
456}
457
458impl<'a, F, DB, Executor, Builder, N> BlockBuilder
459    for BasicBlockBuilder<'a, F, Executor, Builder, N>
460where
461    F: BlockExecutorFactory<Transaction = N::SignedTx, Receipt = N::Receipt>,
462    Executor: BlockExecutor<
463        Evm: Evm<
464            Spec = <F::EvmFactory as EvmFactory>::Spec,
465            HaltReason = <F::EvmFactory as EvmFactory>::HaltReason,
466            BlockEnv = <F::EvmFactory as EvmFactory>::BlockEnv,
467            DB = &'a mut State<DB>,
468        >,
469        Transaction = N::SignedTx,
470        Receipt = N::Receipt,
471    >,
472    DB: Database + 'a,
473    Builder: BlockAssembler<F, Block = N::Block>,
474    N: NodePrimitives,
475{
476    type Primitives = N;
477    type Executor = Executor;
478
479    fn apply_pre_execution_changes(&mut self) -> Result<(), BlockExecutionError> {
480        self.executor.apply_pre_execution_changes()?;
481        self.executor.evm_mut().db_mut().bump_bal_index();
482
483        Ok(())
484    }
485
486    fn execute_transaction_with_commit_condition(
487        &mut self,
488        tx: impl ExecutorTx<Self::Executor>,
489        f: impl FnOnce(&<Self::Executor as BlockExecutor>::Result) -> CommitChanges,
490    ) -> Result<Option<GasOutput>, BlockExecutionError> {
491        let (tx_env, tx) = tx.into_parts();
492        if let Some(gas_used) =
493            self.executor.execute_transaction_with_commit_condition((tx_env, &tx), f)?
494        {
495            self.transactions.push(tx);
496            self.executor.evm_mut().db_mut().bump_bal_index();
497            Ok(Some(gas_used))
498        } else {
499            Ok(None)
500        }
501    }
502
503    fn finish(
504        self,
505        state: impl StateProvider,
506        state_root_precomputed: Option<(B256, Arc<TrieUpdatesSorted>)>,
507    ) -> Result<BlockBuilderOutcome<N>, BlockExecutionError> {
508        let (evm, result) = self.executor.finish()?;
509        let (db, evm_env) = evm.finish();
510
511        // merge all transitions into bundle state
512        db.merge_transitions(BundleRetention::Reverts);
513
514        // Encode the built BAL once and keep the bytes, so callers don't re-encode it.
515        let block_access_list = db.take_built_alloy_bal().map(|bal| {
516            let mut raw = Vec::new();
517            let hash = compute_block_access_list_hash_with_buf(&bal, &mut raw);
518            DecodedBal::new_unchecked(bal.into(), raw.into(), hash)
519        });
520        let block_access_list_hash = block_access_list.as_ref().map(DecodedBal::hash);
521
522        let hashed_state =
523            state.hashed_post_state(&db.bundle_state).map_err(BlockExecutionError::other)?;
524        let (state_root, trie_updates) = match state_root_precomputed {
525            Some(precomputed) => precomputed,
526            None => {
527                let (root, updates) = state
528                    .state_root_with_updates(hashed_state.clone())
529                    .map_err(BlockExecutionError::other)?;
530                (root, Arc::new(updates.into_sorted()))
531            }
532        };
533
534        let (transactions, senders) =
535            self.transactions.into_iter().map(|tx| tx.into_parts()).unzip();
536
537        let block = self.assembler.assemble_block(BlockAssemblerInput {
538            evm_env,
539            execution_ctx: self.ctx,
540            parent: self.parent,
541            transactions,
542            output: &result,
543            bundle_state: &db.bundle_state,
544            state_provider: &state,
545            state_root,
546            block_access_list_hash,
547        })?;
548
549        let block = RecoveredBlock::new_unhashed(block, senders);
550
551        Ok(BlockBuilderOutcome {
552            execution_result: result,
553            hashed_state,
554            trie_updates,
555            block,
556            block_access_list,
557        })
558    }
559
560    fn executor_mut(&mut self) -> &mut Self::Executor {
561        &mut self.executor
562    }
563
564    fn executor(&self) -> &Self::Executor {
565        &self.executor
566    }
567
568    fn into_executor(self) -> Self::Executor {
569        self.executor
570    }
571}
572
573/// A generic block executor that uses a [`BlockExecutor`] to
574/// execute blocks.
575#[expect(missing_debug_implementations)]
576pub struct BasicBlockExecutor<F, DB> {
577    /// Block execution strategy.
578    pub(crate) strategy_factory: F,
579    /// Database.
580    pub(crate) db: State<DB>,
581}
582
583impl<F, DB: Database> BasicBlockExecutor<F, DB> {
584    /// Creates a new `BasicBlockExecutor` with the given strategy.
585    pub fn new(strategy_factory: F, db: DB) -> Self {
586        let db = State::builder().with_database(db).with_bundle_update().build();
587        Self { strategy_factory, db }
588    }
589}
590
591impl<F, DB> Executor<DB> for BasicBlockExecutor<F, DB>
592where
593    F: ConfigureEvm,
594    DB: Database,
595{
596    type Primitives = F::Primitives;
597    type Error = BlockExecutionError;
598
599    fn execute_one(
600        &mut self,
601        block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
602    ) -> Result<BlockExecutionResult<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
603    {
604        let mut executor = self
605            .strategy_factory
606            .executor_for_block(&mut self.db, block)
607            .map_err(BlockExecutionError::other)?;
608
609        let has_bal = block.header().block_access_list_hash().is_some();
610
611        if has_bal {
612            executor.evm_mut().db_mut().bal_state.bal_builder = Some(Bal::new());
613        } else {
614            executor.evm_mut().db_mut().bal_state.bal_builder = None;
615        }
616
617        executor.apply_pre_execution_changes()?;
618
619        if has_bal {
620            executor.evm_mut().db_mut().bump_bal_index();
621        }
622
623        for tx in block.transactions_recovered() {
624            executor.execute_transaction(tx)?;
625            if has_bal {
626                executor.evm_mut().db_mut().bump_bal_index();
627            }
628        }
629
630        let result = executor.apply_post_execution_changes()?;
631
632        self.db.merge_transitions(BundleRetention::Reverts);
633
634        Ok(result)
635    }
636
637    fn execute_one_with_state_hook<H>(
638        &mut self,
639        block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
640        state_hook: H,
641    ) -> Result<BlockExecutionResult<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
642    where
643        H: OnStateHook + 'static,
644    {
645        let mut executor = self
646            .strategy_factory
647            .executor_for_block(&mut self.db, block)
648            .map_err(BlockExecutionError::other)?;
649
650        executor.evm_mut().db_mut().set_state_hook(Some(Box::new(state_hook)));
651
652        let result = executor.execute_block(block.transactions_recovered());
653
654        self.db.set_state_hook(None);
655        self.db.merge_transitions(BundleRetention::Reverts);
656
657        result
658    }
659
660    fn into_state(self) -> State<DB> {
661        self.db
662    }
663
664    fn size_hint(&self) -> usize {
665        self.db.bundle_size_hint()
666    }
667
668    fn take_bal(&mut self) -> Option<BlockAccessList> {
669        self.db.take_built_alloy_bal()
670    }
671}
672
673/// A helper trait marking a 'static type that can be converted into an [`ExecutableTxParts`] for
674/// block executor.
675pub trait ExecutableTxFor<Evm: ConfigureEvm>:
676    ExecutableTxParts<TxEnvFor<Evm>, TxTy<Evm::Primitives>> + RecoveredTx<TxTy<Evm::Primitives>>
677{
678}
679
680impl<T, Evm: ConfigureEvm> ExecutableTxFor<Evm> for T where
681    T: ExecutableTxParts<TxEnvFor<Evm>, TxTy<Evm::Primitives>> + RecoveredTx<TxTy<Evm::Primitives>>
682{
683}
684
685/// A transaction stored together with its `TxEnv`.
686///
687/// See also [`ExecutableTxParts`] for types that can be split into a transaction environment and
688/// recovered transaction.
689#[derive(Debug)]
690pub struct WithTxEnv<TxEnv, T> {
691    /// The transaction environment for EVM.
692    pub tx_env: TxEnv,
693    /// The recovered transaction.
694    pub tx: Arc<T>,
695}
696
697impl<TxEnv, T> WithTxEnv<TxEnv, T> {
698    /// Creates a transaction/environment pair from a type that can be split with
699    /// [`ExecutableTxParts::into_parts`].
700    pub fn new<Tx, InnerTx>(tx: Tx) -> Self
701    where
702        Tx: ExecutableTxParts<TxEnv, InnerTx, Recovered = T>,
703    {
704        let (tx_env, tx) = tx.into_parts();
705        Self { tx_env, tx: Arc::new(tx) }
706    }
707}
708
709impl<TxEnv: Clone, T> Clone for WithTxEnv<TxEnv, T> {
710    fn clone(&self) -> Self {
711        Self { tx_env: self.tx_env.clone(), tx: self.tx.clone() }
712    }
713}
714
715impl<TxEnv, Tx, T: RecoveredTx<Tx>> RecoveredTx<Tx> for WithTxEnv<TxEnv, T> {
716    fn tx(&self) -> &Tx {
717        self.tx.tx()
718    }
719
720    fn signer(&self) -> &Address {
721        self.tx.signer()
722    }
723}
724
725impl<TxEnv, T: RecoveredTx<Tx>, Tx> ExecutableTxParts<TxEnv, Tx> for WithTxEnv<TxEnv, T> {
726    type Recovered = Arc<T>;
727
728    fn into_parts(self) -> (TxEnv, Self::Recovered) {
729        (self.tx_env, self.tx)
730    }
731}
732
733#[cfg(test)]
734mod tests {
735    use super::*;
736    use core::marker::PhantomData;
737    use reth_ethereum_primitives::EthPrimitives;
738    use revm::database::{CacheDB, EmptyDB};
739
740    #[derive(Clone, Debug, Default)]
741    struct TestExecutorProvider;
742
743    impl TestExecutorProvider {
744        fn executor<DB>(&self, _db: DB) -> TestExecutor<DB>
745        where
746            DB: Database,
747        {
748            TestExecutor(PhantomData)
749        }
750    }
751
752    struct TestExecutor<DB>(PhantomData<DB>);
753
754    impl<DB: Database> Executor<DB> for TestExecutor<DB> {
755        type Primitives = EthPrimitives;
756        type Error = BlockExecutionError;
757
758        fn execute_one(
759            &mut self,
760            _block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
761        ) -> Result<BlockExecutionResult<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
762        {
763            Err(BlockExecutionError::msg("execution unavailable for tests"))
764        }
765
766        fn execute_one_with_state_hook<F>(
767            &mut self,
768            _block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
769            _state_hook: F,
770        ) -> Result<BlockExecutionResult<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
771        where
772            F: OnStateHook + 'static,
773        {
774            Err(BlockExecutionError::msg("execution unavailable for tests"))
775        }
776
777        fn into_state(self) -> State<DB> {
778            unreachable!()
779        }
780
781        fn size_hint(&self) -> usize {
782            0
783        }
784
785        fn take_bal(&mut self) -> Option<BlockAccessList> {
786            None
787        }
788    }
789
790    #[test]
791    fn test_provider() {
792        let provider = TestExecutorProvider;
793        let db = CacheDB::<EmptyDB>::default();
794        let executor = provider.executor(db);
795        let _ = executor.execute(&Default::default());
796    }
797}