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