reth_evm/
execute.rs

1//! Traits for execution.
2
3use alloy_consensus::BlockHeader;
4// Re-export execution types
5pub use reth_execution_errors::{
6    BlockExecutionError, BlockValidationError, InternalBlockExecutionError,
7};
8pub use reth_execution_types::{BlockExecutionInput, BlockExecutionOutput, ExecutionOutcome};
9use reth_primitives_traits::Block as _;
10pub use reth_storage_errors::provider::ProviderError;
11
12use crate::{system_calls::OnStateHook, TxEnvOverrides};
13use alloc::{boxed::Box, vec::Vec};
14use alloy_eips::eip7685::Requests;
15use alloy_primitives::{
16    map::{DefaultHashBuilder, HashMap},
17    Address, BlockNumber,
18};
19use core::fmt::Display;
20use reth_consensus::ConsensusError;
21use reth_primitives::{BlockWithSenders, NodePrimitives, Receipt};
22use reth_prune_types::PruneModes;
23use reth_revm::batch::BlockBatchRecord;
24use revm::{
25    db::{states::bundle_state::BundleRetention, BundleState},
26    State,
27};
28use revm_primitives::{db::Database, Account, AccountStatus, EvmState, U256};
29
30/// A general purpose executor trait that executes an input (e.g. block) and produces an output
31/// (e.g. state changes and receipts).
32///
33/// This executor does not validate the output, see [`BatchExecutor`] for that.
34pub trait Executor<DB> {
35    /// The input type for the executor.
36    type Input<'a>;
37    /// The output type for the executor.
38    type Output;
39    /// The error type returned by the executor.
40    type Error;
41
42    /// Initialize the executor with the given transaction environment overrides.
43    fn init(&mut self, _tx_env_overrides: Box<dyn TxEnvOverrides>) {}
44
45    /// Consumes the type and executes the block.
46    ///
47    /// # Note
48    /// Execution happens without any validation of the output. To validate the output, use the
49    /// [`BatchExecutor`].
50    ///
51    /// # Returns
52    /// The output of the block execution.
53    fn execute(self, input: Self::Input<'_>) -> Result<Self::Output, Self::Error>;
54
55    /// Executes the EVM with the given input and accepts a state closure that is invoked with
56    /// the EVM state after execution.
57    fn execute_with_state_closure<F>(
58        self,
59        input: Self::Input<'_>,
60        state: F,
61    ) -> Result<Self::Output, Self::Error>
62    where
63        F: FnMut(&State<DB>);
64
65    /// Executes the EVM with the given input and accepts a state hook closure that is invoked with
66    /// the EVM state after execution.
67    fn execute_with_state_hook<F>(
68        self,
69        input: Self::Input<'_>,
70        state_hook: F,
71    ) -> Result<Self::Output, Self::Error>
72    where
73        F: OnStateHook + 'static;
74}
75
76/// A general purpose executor that can execute multiple inputs in sequence, validate the outputs,
77/// and keep track of the state over the entire batch.
78pub trait BatchExecutor<DB> {
79    /// The input type for the executor.
80    type Input<'a>;
81    /// The output type for the executor.
82    type Output;
83    /// The error type returned by the executor.
84    type Error;
85
86    /// Executes the next block in the batch, verifies the output and updates the state internally.
87    fn execute_and_verify_one(&mut self, input: Self::Input<'_>) -> Result<(), Self::Error>;
88
89    /// Executes multiple inputs in the batch, verifies the output, and updates the state
90    /// internally.
91    ///
92    /// This method is a convenience function for calling [`BatchExecutor::execute_and_verify_one`]
93    /// for each input.
94    fn execute_and_verify_many<'a, I>(&mut self, inputs: I) -> Result<(), Self::Error>
95    where
96        I: IntoIterator<Item = Self::Input<'a>>,
97    {
98        for input in inputs {
99            self.execute_and_verify_one(input)?;
100        }
101        Ok(())
102    }
103
104    /// Executes the entire batch, verifies the output, and returns the final state.
105    ///
106    /// This method is a convenience function for calling [`BatchExecutor::execute_and_verify_many`]
107    /// and [`BatchExecutor::finalize`].
108    fn execute_and_verify_batch<'a, I>(mut self, batch: I) -> Result<Self::Output, Self::Error>
109    where
110        I: IntoIterator<Item = Self::Input<'a>>,
111        Self: Sized,
112    {
113        self.execute_and_verify_many(batch)?;
114        Ok(self.finalize())
115    }
116
117    /// Finishes the batch and return the final state.
118    fn finalize(self) -> Self::Output;
119
120    /// Set the expected tip of the batch.
121    ///
122    /// This can be used to optimize state pruning during execution.
123    fn set_tip(&mut self, tip: BlockNumber);
124
125    /// Set the prune modes.
126    ///
127    /// They are used to determine which parts of the state should be kept during execution.
128    fn set_prune_modes(&mut self, prune_modes: PruneModes);
129
130    /// The size hint of the batch's tracked state size.
131    ///
132    /// This is used to optimize DB commits depending on the size of the state.
133    fn size_hint(&self) -> Option<usize>;
134}
135
136/// A type that can create a new executor for block execution.
137pub trait BlockExecutorProvider: Send + Sync + Clone + Unpin + 'static {
138    /// Receipt type.
139    type Primitives: NodePrimitives;
140
141    /// An executor that can execute a single block given a database.
142    ///
143    /// # Verification
144    ///
145    /// The on [`Executor::execute`] the executor is expected to validate the execution output of
146    /// the input, this includes:
147    /// - Cumulative gas used must match the input's gas used.
148    /// - Receipts must match the input's receipts root.
149    ///
150    /// It is not expected to validate the state trie root, this must be done by the caller using
151    /// the returned state.
152    type Executor<DB: Database<Error: Into<ProviderError> + Display>>: for<'a> Executor<
153        DB,
154        Input<'a> = BlockExecutionInput<
155            'a,
156            BlockWithSenders<<Self::Primitives as NodePrimitives>::Block>,
157        >,
158        Output = BlockExecutionOutput<<Self::Primitives as NodePrimitives>::Receipt>,
159        Error = BlockExecutionError,
160    >;
161
162    /// An executor that can execute a batch of blocks given a database.
163    type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>>: for<'a> BatchExecutor<
164        DB,
165        Input<'a> = BlockExecutionInput<
166            'a,
167            BlockWithSenders<<Self::Primitives as NodePrimitives>::Block>,
168        >,
169        Output = ExecutionOutcome<<Self::Primitives as NodePrimitives>::Receipt>,
170        Error = BlockExecutionError,
171    >;
172
173    /// Creates a new executor for single block execution.
174    ///
175    /// This is used to execute a single block and get the changed state.
176    fn executor<DB>(&self, db: DB) -> Self::Executor<DB>
177    where
178        DB: Database<Error: Into<ProviderError> + Display>;
179
180    /// Creates a new batch executor with the given database and pruning modes.
181    ///
182    /// Batch executor is used to execute multiple blocks in sequence and keep track of the state
183    /// during historical sync which involves executing multiple blocks in sequence.
184    fn batch_executor<DB>(&self, db: DB) -> Self::BatchExecutor<DB>
185    where
186        DB: Database<Error: Into<ProviderError> + Display>;
187}
188
189/// Helper type for the output of executing a block.
190#[derive(Debug, Clone)]
191pub struct ExecuteOutput<R = Receipt> {
192    /// Receipts obtained after executing a block.
193    pub receipts: Vec<R>,
194    /// Cumulative gas used in the block execution.
195    pub gas_used: u64,
196}
197
198/// Defines the strategy for executing a single block.
199pub trait BlockExecutionStrategy {
200    /// Database this strategy operates on.
201    type DB: Database;
202
203    /// Primitive types used by the strategy.
204    type Primitives: NodePrimitives;
205
206    /// The error type returned by this strategy's methods.
207    type Error: From<ProviderError> + core::error::Error;
208
209    /// Initialize the strategy with the given transaction environment overrides.
210    fn init(&mut self, _tx_env_overrides: Box<dyn TxEnvOverrides>) {}
211
212    /// Applies any necessary changes before executing the block's transactions.
213    fn apply_pre_execution_changes(
214        &mut self,
215        block: &BlockWithSenders<<Self::Primitives as NodePrimitives>::Block>,
216        total_difficulty: U256,
217    ) -> Result<(), Self::Error>;
218
219    /// Executes all transactions in the block.
220    fn execute_transactions(
221        &mut self,
222        block: &BlockWithSenders<<Self::Primitives as NodePrimitives>::Block>,
223        total_difficulty: U256,
224    ) -> Result<ExecuteOutput<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>;
225
226    /// Applies any necessary changes after executing the block's transactions.
227    fn apply_post_execution_changes(
228        &mut self,
229        block: &BlockWithSenders<<Self::Primitives as NodePrimitives>::Block>,
230        total_difficulty: U256,
231        receipts: &[<Self::Primitives as NodePrimitives>::Receipt],
232    ) -> Result<Requests, Self::Error>;
233
234    /// Returns a reference to the current state.
235    fn state_ref(&self) -> &State<Self::DB>;
236
237    /// Returns a mutable reference to the current state.
238    fn state_mut(&mut self) -> &mut State<Self::DB>;
239
240    /// Sets a hook to be called after each state change during execution.
241    fn with_state_hook(&mut self, _hook: Option<Box<dyn OnStateHook>>) {}
242
243    /// Returns the final bundle state.
244    fn finish(&mut self) -> BundleState {
245        self.state_mut().merge_transitions(BundleRetention::Reverts);
246        self.state_mut().take_bundle()
247    }
248
249    /// Validate a block with regard to execution results.
250    fn validate_block_post_execution(
251        &self,
252        _block: &BlockWithSenders<<Self::Primitives as NodePrimitives>::Block>,
253        _receipts: &[<Self::Primitives as NodePrimitives>::Receipt],
254        _requests: &Requests,
255    ) -> Result<(), ConsensusError> {
256        Ok(())
257    }
258}
259
260/// A strategy factory that can create block execution strategies.
261pub trait BlockExecutionStrategyFactory: Send + Sync + Clone + Unpin + 'static {
262    /// Primitive types used by the strategy.
263    type Primitives: NodePrimitives;
264
265    /// Associated strategy type.
266    type Strategy<DB: Database<Error: Into<ProviderError> + Display>>: BlockExecutionStrategy<
267        DB = DB,
268        Primitives = Self::Primitives,
269        Error = BlockExecutionError,
270    >;
271
272    /// Creates a strategy using the give database.
273    fn create_strategy<DB>(&self, db: DB) -> Self::Strategy<DB>
274    where
275        DB: Database<Error: Into<ProviderError> + Display>;
276}
277
278impl<F> Clone for BasicBlockExecutorProvider<F>
279where
280    F: Clone,
281{
282    fn clone(&self) -> Self {
283        Self { strategy_factory: self.strategy_factory.clone() }
284    }
285}
286
287/// A generic block executor provider that can create executors using a strategy factory.
288#[allow(missing_debug_implementations)]
289pub struct BasicBlockExecutorProvider<F> {
290    strategy_factory: F,
291}
292
293impl<F> BasicBlockExecutorProvider<F> {
294    /// Creates a new `BasicBlockExecutorProvider` with the given strategy factory.
295    pub const fn new(strategy_factory: F) -> Self {
296        Self { strategy_factory }
297    }
298}
299
300impl<F> BlockExecutorProvider for BasicBlockExecutorProvider<F>
301where
302    F: BlockExecutionStrategyFactory,
303{
304    type Primitives = F::Primitives;
305
306    type Executor<DB: Database<Error: Into<ProviderError> + Display>> =
307        BasicBlockExecutor<F::Strategy<DB>>;
308
309    type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>> =
310        BasicBatchExecutor<F::Strategy<DB>>;
311
312    fn executor<DB>(&self, db: DB) -> Self::Executor<DB>
313    where
314        DB: Database<Error: Into<ProviderError> + Display>,
315    {
316        let strategy = self.strategy_factory.create_strategy(db);
317        BasicBlockExecutor::new(strategy)
318    }
319
320    fn batch_executor<DB>(&self, db: DB) -> Self::BatchExecutor<DB>
321    where
322        DB: Database<Error: Into<ProviderError> + Display>,
323    {
324        let strategy = self.strategy_factory.create_strategy(db);
325        let batch_record = BlockBatchRecord::default();
326        BasicBatchExecutor::new(strategy, batch_record)
327    }
328}
329
330/// A generic block executor that uses a [`BlockExecutionStrategy`] to
331/// execute blocks.
332#[allow(missing_debug_implementations, dead_code)]
333pub struct BasicBlockExecutor<S> {
334    /// Block execution strategy.
335    pub(crate) strategy: S,
336}
337
338impl<S> BasicBlockExecutor<S> {
339    /// Creates a new `BasicBlockExecutor` with the given strategy.
340    pub const fn new(strategy: S) -> Self {
341        Self { strategy }
342    }
343}
344
345impl<S, DB> Executor<DB> for BasicBlockExecutor<S>
346where
347    S: BlockExecutionStrategy<DB = DB>,
348    DB: Database<Error: Into<ProviderError> + Display>,
349{
350    type Input<'a> =
351        BlockExecutionInput<'a, BlockWithSenders<<S::Primitives as NodePrimitives>::Block>>;
352    type Output = BlockExecutionOutput<<S::Primitives as NodePrimitives>::Receipt>;
353    type Error = S::Error;
354
355    fn init(&mut self, env_overrides: Box<dyn TxEnvOverrides>) {
356        self.strategy.init(env_overrides);
357    }
358
359    fn execute(mut self, input: Self::Input<'_>) -> Result<Self::Output, Self::Error> {
360        let BlockExecutionInput { block, total_difficulty } = input;
361
362        self.strategy.apply_pre_execution_changes(block, total_difficulty)?;
363        let ExecuteOutput { receipts, gas_used } =
364            self.strategy.execute_transactions(block, total_difficulty)?;
365        let requests =
366            self.strategy.apply_post_execution_changes(block, total_difficulty, &receipts)?;
367        let state = self.strategy.finish();
368
369        Ok(BlockExecutionOutput { state, receipts, requests, gas_used })
370    }
371
372    fn execute_with_state_closure<F>(
373        mut self,
374        input: Self::Input<'_>,
375        mut state: F,
376    ) -> Result<Self::Output, Self::Error>
377    where
378        F: FnMut(&State<DB>),
379    {
380        let BlockExecutionInput { block, total_difficulty } = input;
381
382        self.strategy.apply_pre_execution_changes(block, total_difficulty)?;
383        let ExecuteOutput { receipts, gas_used } =
384            self.strategy.execute_transactions(block, total_difficulty)?;
385        let requests =
386            self.strategy.apply_post_execution_changes(block, total_difficulty, &receipts)?;
387
388        state(self.strategy.state_ref());
389
390        let state = self.strategy.finish();
391
392        Ok(BlockExecutionOutput { state, receipts, requests, gas_used })
393    }
394
395    fn execute_with_state_hook<H>(
396        mut self,
397        input: Self::Input<'_>,
398        state_hook: H,
399    ) -> Result<Self::Output, Self::Error>
400    where
401        H: OnStateHook + 'static,
402    {
403        let BlockExecutionInput { block, total_difficulty } = input;
404
405        self.strategy.with_state_hook(Some(Box::new(state_hook)));
406
407        self.strategy.apply_pre_execution_changes(block, total_difficulty)?;
408        let ExecuteOutput { receipts, gas_used } =
409            self.strategy.execute_transactions(block, total_difficulty)?;
410        let requests =
411            self.strategy.apply_post_execution_changes(block, total_difficulty, &receipts)?;
412
413        let state = self.strategy.finish();
414
415        Ok(BlockExecutionOutput { state, receipts, requests, gas_used })
416    }
417}
418
419/// A generic batch executor that uses a [`BlockExecutionStrategy`] to
420/// execute batches.
421#[allow(missing_debug_implementations)]
422pub struct BasicBatchExecutor<S>
423where
424    S: BlockExecutionStrategy,
425{
426    /// Batch execution strategy.
427    pub(crate) strategy: S,
428    /// Keeps track of batch execution receipts and requests.
429    pub(crate) batch_record: BlockBatchRecord<<S::Primitives as NodePrimitives>::Receipt>,
430}
431
432impl<S> BasicBatchExecutor<S>
433where
434    S: BlockExecutionStrategy,
435{
436    /// Creates a new `BasicBatchExecutor` with the given strategy.
437    pub const fn new(
438        strategy: S,
439        batch_record: BlockBatchRecord<<S::Primitives as NodePrimitives>::Receipt>,
440    ) -> Self {
441        Self { strategy, batch_record }
442    }
443}
444
445impl<S, DB> BatchExecutor<DB> for BasicBatchExecutor<S>
446where
447    S: BlockExecutionStrategy<DB = DB, Error = BlockExecutionError>,
448    DB: Database<Error: Into<ProviderError> + Display>,
449{
450    type Input<'a> =
451        BlockExecutionInput<'a, BlockWithSenders<<S::Primitives as NodePrimitives>::Block>>;
452    type Output = ExecutionOutcome<<S::Primitives as NodePrimitives>::Receipt>;
453    type Error = BlockExecutionError;
454
455    fn execute_and_verify_one(&mut self, input: Self::Input<'_>) -> Result<(), Self::Error> {
456        let BlockExecutionInput { block, total_difficulty } = input;
457
458        if self.batch_record.first_block().is_none() {
459            self.batch_record.set_first_block(block.header().number());
460        }
461
462        self.strategy.apply_pre_execution_changes(block, total_difficulty)?;
463        let ExecuteOutput { receipts, .. } =
464            self.strategy.execute_transactions(block, total_difficulty)?;
465        let requests =
466            self.strategy.apply_post_execution_changes(block, total_difficulty, &receipts)?;
467
468        self.strategy.validate_block_post_execution(block, &receipts, &requests)?;
469
470        // prepare the state according to the prune mode
471        let retention = self.batch_record.bundle_retention(block.header().number());
472        self.strategy.state_mut().merge_transitions(retention);
473
474        // store receipts in the set
475        self.batch_record.save_receipts(receipts)?;
476
477        // store requests in the set
478        self.batch_record.save_requests(requests);
479
480        Ok(())
481    }
482
483    fn finalize(mut self) -> Self::Output {
484        ExecutionOutcome::new(
485            self.strategy.state_mut().take_bundle(),
486            self.batch_record.take_receipts(),
487            self.batch_record.first_block().unwrap_or_default(),
488            self.batch_record.take_requests(),
489        )
490    }
491
492    fn set_tip(&mut self, tip: BlockNumber) {
493        self.batch_record.set_tip(tip);
494    }
495
496    fn set_prune_modes(&mut self, prune_modes: PruneModes) {
497        self.batch_record.set_prune_modes(prune_modes);
498    }
499
500    fn size_hint(&self) -> Option<usize> {
501        Some(self.strategy.state_ref().bundle_state.size_hint())
502    }
503}
504
505/// Creates an `EvmState` from a map of balance increments and the current state
506/// to load accounts from. No balance increment is done in the function.
507/// Zero balance increments are ignored and won't create state entries.
508pub fn balance_increment_state<DB>(
509    balance_increments: &HashMap<Address, u128, DefaultHashBuilder>,
510    state: &mut State<DB>,
511) -> Result<EvmState, BlockExecutionError>
512where
513    DB: Database,
514{
515    let mut load_account = |address: &Address| -> Result<(Address, Account), BlockExecutionError> {
516        let cache_account = state.load_cache_account(*address).map_err(|_| {
517            BlockExecutionError::msg("could not load account for balance increment")
518        })?;
519
520        let account = cache_account.account.as_ref().ok_or_else(|| {
521            BlockExecutionError::msg("could not load account for balance increment")
522        })?;
523
524        Ok((
525            *address,
526            Account {
527                info: account.info.clone(),
528                storage: Default::default(),
529                status: AccountStatus::Touched,
530            },
531        ))
532    };
533
534    balance_increments
535        .iter()
536        .filter(|(_, &balance)| balance != 0)
537        .map(|(addr, _)| load_account(addr))
538        .collect::<Result<EvmState, _>>()
539}
540
541#[cfg(test)]
542mod tests {
543    use super::*;
544    use alloy_primitives::U256;
545    use core::marker::PhantomData;
546    use reth_chainspec::{ChainSpec, MAINNET};
547    use reth_primitives::EthPrimitives;
548    use revm::db::{CacheDB, EmptyDBTyped};
549    use revm_primitives::{address, bytes, AccountInfo, TxEnv, KECCAK_EMPTY};
550    use std::sync::Arc;
551
552    #[derive(Clone, Default)]
553    struct TestExecutorProvider;
554
555    impl BlockExecutorProvider for TestExecutorProvider {
556        type Primitives = EthPrimitives;
557        type Executor<DB: Database<Error: Into<ProviderError> + Display>> = TestExecutor<DB>;
558        type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>> = TestExecutor<DB>;
559
560        fn executor<DB>(&self, _db: DB) -> Self::Executor<DB>
561        where
562            DB: Database<Error: Into<ProviderError> + Display>,
563        {
564            TestExecutor(PhantomData)
565        }
566
567        fn batch_executor<DB>(&self, _db: DB) -> Self::BatchExecutor<DB>
568        where
569            DB: Database<Error: Into<ProviderError> + Display>,
570        {
571            TestExecutor(PhantomData)
572        }
573    }
574
575    struct TestExecutor<DB>(PhantomData<DB>);
576
577    impl<DB> Executor<DB> for TestExecutor<DB> {
578        type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
579        type Output = BlockExecutionOutput<Receipt>;
580        type Error = BlockExecutionError;
581
582        fn execute(self, _input: Self::Input<'_>) -> Result<Self::Output, Self::Error> {
583            Err(BlockExecutionError::msg("execution unavailable for tests"))
584        }
585
586        fn execute_with_state_closure<F>(
587            self,
588            _: Self::Input<'_>,
589            _: F,
590        ) -> Result<Self::Output, Self::Error>
591        where
592            F: FnMut(&State<DB>),
593        {
594            Err(BlockExecutionError::msg("execution unavailable for tests"))
595        }
596
597        fn execute_with_state_hook<F>(
598            self,
599            _: Self::Input<'_>,
600            _: F,
601        ) -> Result<Self::Output, Self::Error>
602        where
603            F: OnStateHook,
604        {
605            Err(BlockExecutionError::msg("execution unavailable for tests"))
606        }
607    }
608
609    impl<DB> BatchExecutor<DB> for TestExecutor<DB> {
610        type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
611        type Output = ExecutionOutcome;
612        type Error = BlockExecutionError;
613
614        fn execute_and_verify_one(&mut self, _input: Self::Input<'_>) -> Result<(), Self::Error> {
615            Ok(())
616        }
617
618        fn finalize(self) -> Self::Output {
619            todo!()
620        }
621
622        fn set_tip(&mut self, _tip: BlockNumber) {
623            todo!()
624        }
625
626        fn set_prune_modes(&mut self, _prune_modes: PruneModes) {
627            todo!()
628        }
629
630        fn size_hint(&self) -> Option<usize> {
631            None
632        }
633    }
634
635    struct TestExecutorStrategy<DB, EvmConfig> {
636        // chain spec and evm config here only to illustrate how the strategy
637        // factory can use them in a real use case.
638        _chain_spec: Arc<ChainSpec>,
639        _evm_config: EvmConfig,
640        state: State<DB>,
641        execute_transactions_result: ExecuteOutput<Receipt>,
642        apply_post_execution_changes_result: Requests,
643        finish_result: BundleState,
644    }
645
646    #[derive(Clone)]
647    struct TestExecutorStrategyFactory {
648        execute_transactions_result: ExecuteOutput<Receipt>,
649        apply_post_execution_changes_result: Requests,
650        finish_result: BundleState,
651    }
652
653    impl BlockExecutionStrategyFactory for TestExecutorStrategyFactory {
654        type Primitives = EthPrimitives;
655        type Strategy<DB: Database<Error: Into<ProviderError> + Display>> =
656            TestExecutorStrategy<DB, TestEvmConfig>;
657
658        fn create_strategy<DB>(&self, db: DB) -> Self::Strategy<DB>
659        where
660            DB: Database<Error: Into<ProviderError> + Display>,
661        {
662            let state = State::builder()
663                .with_database(db)
664                .with_bundle_update()
665                .without_state_clear()
666                .build();
667
668            TestExecutorStrategy {
669                _chain_spec: MAINNET.clone(),
670                _evm_config: TestEvmConfig {},
671                execute_transactions_result: self.execute_transactions_result.clone(),
672                apply_post_execution_changes_result: self
673                    .apply_post_execution_changes_result
674                    .clone(),
675                finish_result: self.finish_result.clone(),
676                state,
677            }
678        }
679    }
680
681    impl<DB> BlockExecutionStrategy for TestExecutorStrategy<DB, TestEvmConfig>
682    where
683        DB: Database,
684    {
685        type DB = DB;
686        type Primitives = EthPrimitives;
687        type Error = BlockExecutionError;
688
689        fn apply_pre_execution_changes(
690            &mut self,
691            _block: &BlockWithSenders,
692            _total_difficulty: U256,
693        ) -> Result<(), Self::Error> {
694            Ok(())
695        }
696
697        fn execute_transactions(
698            &mut self,
699            _block: &BlockWithSenders,
700            _total_difficulty: U256,
701        ) -> Result<ExecuteOutput<Receipt>, Self::Error> {
702            Ok(self.execute_transactions_result.clone())
703        }
704
705        fn apply_post_execution_changes(
706            &mut self,
707            _block: &BlockWithSenders,
708            _total_difficulty: U256,
709            _receipts: &[Receipt],
710        ) -> Result<Requests, Self::Error> {
711            Ok(self.apply_post_execution_changes_result.clone())
712        }
713
714        fn state_ref(&self) -> &State<DB> {
715            &self.state
716        }
717
718        fn state_mut(&mut self) -> &mut State<DB> {
719            &mut self.state
720        }
721
722        fn with_state_hook(&mut self, _hook: Option<Box<dyn OnStateHook>>) {}
723
724        fn finish(&mut self) -> BundleState {
725            self.finish_result.clone()
726        }
727
728        fn validate_block_post_execution(
729            &self,
730            _block: &BlockWithSenders,
731            _receipts: &[Receipt],
732            _requests: &Requests,
733        ) -> Result<(), ConsensusError> {
734            Ok(())
735        }
736    }
737
738    #[derive(Clone)]
739    struct TestEvmConfig {}
740
741    #[test]
742    fn test_provider() {
743        let provider = TestExecutorProvider;
744        let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
745        let executor = provider.executor(db);
746        let _ = executor.execute(BlockExecutionInput::new(&Default::default(), U256::ZERO));
747    }
748
749    #[test]
750    fn test_strategy() {
751        let expected_gas_used = 10;
752        let expected_receipts = vec![Receipt::default()];
753        let expected_execute_transactions_result = ExecuteOutput::<Receipt> {
754            receipts: expected_receipts.clone(),
755            gas_used: expected_gas_used,
756        };
757        let expected_apply_post_execution_changes_result = Requests::new(vec![bytes!("deadbeef")]);
758        let expected_finish_result = BundleState::default();
759
760        let strategy_factory = TestExecutorStrategyFactory {
761            execute_transactions_result: expected_execute_transactions_result,
762            apply_post_execution_changes_result: expected_apply_post_execution_changes_result
763                .clone(),
764            finish_result: expected_finish_result.clone(),
765        };
766        let provider = BasicBlockExecutorProvider::new(strategy_factory);
767        let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
768        let executor = provider.executor(db);
769        let result = executor.execute(BlockExecutionInput::new(&Default::default(), U256::ZERO));
770
771        assert!(result.is_ok());
772        let block_execution_output = result.unwrap();
773        assert_eq!(block_execution_output.gas_used, expected_gas_used);
774        assert_eq!(block_execution_output.receipts, expected_receipts);
775        assert_eq!(block_execution_output.requests, expected_apply_post_execution_changes_result);
776        assert_eq!(block_execution_output.state, expected_finish_result);
777    }
778
779    #[test]
780    fn test_tx_env_overrider() {
781        let strategy_factory = TestExecutorStrategyFactory {
782            execute_transactions_result: ExecuteOutput {
783                receipts: vec![Receipt::default()],
784                gas_used: 10,
785            },
786            apply_post_execution_changes_result: Requests::new(vec![bytes!("deadbeef")]),
787            finish_result: BundleState::default(),
788        };
789        let provider = BasicBlockExecutorProvider::new(strategy_factory);
790        let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
791
792        // if we want to apply tx env overrides the executor must be mut.
793        let mut executor = provider.executor(db);
794        // execute consumes the executor, so we can only call it once.
795        // let result = executor.execute(BlockExecutionInput::new(&Default::default(), U256::ZERO));
796        executor.init(Box::new(|tx_env: &mut TxEnv| {
797            tx_env.nonce.take();
798        }));
799        let result = executor.execute(BlockExecutionInput::new(&Default::default(), U256::ZERO));
800        assert!(result.is_ok());
801    }
802
803    fn setup_state_with_account(
804        addr: Address,
805        balance: u128,
806        nonce: u64,
807    ) -> State<CacheDB<EmptyDBTyped<BlockExecutionError>>> {
808        let db = CacheDB::<EmptyDBTyped<BlockExecutionError>>::default();
809        let mut state = State::builder().with_database(db).with_bundle_update().build();
810
811        let account_info = AccountInfo {
812            balance: U256::from(balance),
813            nonce,
814            code_hash: KECCAK_EMPTY,
815            code: None,
816        };
817        state.insert_account(addr, account_info);
818        state
819    }
820
821    #[test]
822    fn test_balance_increment_state_zero() {
823        let addr = address!("1000000000000000000000000000000000000000");
824        let mut state = setup_state_with_account(addr, 100, 1);
825
826        let mut increments = HashMap::<Address, u128, DefaultHashBuilder>::default();
827        increments.insert(addr, 0);
828
829        let result = balance_increment_state(&increments, &mut state).unwrap();
830        assert!(result.is_empty(), "Zero increments should be ignored");
831    }
832
833    #[test]
834    fn test_balance_increment_state_empty_increments_map() {
835        let mut state = State::builder()
836            .with_database(CacheDB::<EmptyDBTyped<BlockExecutionError>>::default())
837            .with_bundle_update()
838            .build();
839
840        let increments = HashMap::<Address, u128, DefaultHashBuilder>::default();
841        let result = balance_increment_state(&increments, &mut state).unwrap();
842        assert!(result.is_empty(), "Empty increments map should return empty state");
843    }
844
845    #[test]
846    fn test_balance_increment_state_multiple_valid_increments() {
847        let addr1 = address!("1000000000000000000000000000000000000000");
848        let addr2 = address!("2000000000000000000000000000000000000000");
849
850        let mut state = setup_state_with_account(addr1, 100, 1);
851
852        let account2 =
853            AccountInfo { balance: U256::from(200), nonce: 1, code_hash: KECCAK_EMPTY, code: None };
854        state.insert_account(addr2, account2);
855
856        let mut increments = HashMap::<Address, u128, DefaultHashBuilder>::default();
857        increments.insert(addr1, 50);
858        increments.insert(addr2, 100);
859
860        let result = balance_increment_state(&increments, &mut state).unwrap();
861
862        assert_eq!(result.len(), 2);
863        assert_eq!(result.get(&addr1).unwrap().info.balance, U256::from(100));
864        assert_eq!(result.get(&addr2).unwrap().info.balance, U256::from(200));
865    }
866
867    #[test]
868    fn test_balance_increment_state_mixed_zero_and_nonzero_increments() {
869        let addr1 = address!("1000000000000000000000000000000000000000");
870        let addr2 = address!("2000000000000000000000000000000000000000");
871
872        let mut state = setup_state_with_account(addr1, 100, 1);
873
874        let account2 =
875            AccountInfo { balance: U256::from(200), nonce: 1, code_hash: KECCAK_EMPTY, code: None };
876        state.insert_account(addr2, account2);
877
878        let mut increments = HashMap::<Address, u128, DefaultHashBuilder>::default();
879        increments.insert(addr1, 0);
880        increments.insert(addr2, 100);
881
882        let result = balance_increment_state(&increments, &mut state).unwrap();
883
884        assert_eq!(result.len(), 1, "Only non-zero increments should be included");
885        assert!(!result.contains_key(&addr1), "Zero increment account should not be included");
886        assert_eq!(result.get(&addr2).unwrap().info.balance, U256::from(200));
887    }
888}