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