reth_evm/
test_utils.rs

1//! Helpers for testing.
2
3use crate::{
4    execute::{BasicBlockExecutor, BlockExecutionOutput, BlockExecutorProvider, Executor},
5    Database, OnStateHook,
6};
7use alloc::{sync::Arc, vec::Vec};
8use alloy_eips::eip7685::Requests;
9use parking_lot::Mutex;
10use reth_ethereum_primitives::EthPrimitives;
11use reth_execution_errors::BlockExecutionError;
12use reth_execution_types::{BlockExecutionResult, ExecutionOutcome};
13use reth_primitives_traits::{NodePrimitives, RecoveredBlock};
14use revm::database::State;
15
16/// A [`BlockExecutorProvider`] that returns mocked execution results.
17#[derive(Clone, Debug, Default)]
18pub struct MockExecutorProvider {
19    exec_results: Arc<Mutex<Vec<ExecutionOutcome>>>,
20}
21
22impl MockExecutorProvider {
23    /// Extend the mocked execution results
24    pub fn extend(&self, results: impl IntoIterator<Item = impl Into<ExecutionOutcome>>) {
25        self.exec_results.lock().extend(results.into_iter().map(Into::into));
26    }
27}
28
29impl BlockExecutorProvider for MockExecutorProvider {
30    type Primitives = EthPrimitives;
31
32    type Executor<DB: Database> = Self;
33
34    fn executor<DB>(&self, _: DB) -> Self::Executor<DB>
35    where
36        DB: Database,
37    {
38        self.clone()
39    }
40}
41
42impl<DB: Database> Executor<DB> for MockExecutorProvider {
43    type Primitives = EthPrimitives;
44    type Error = BlockExecutionError;
45
46    fn execute_one(
47        &mut self,
48        _block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
49    ) -> Result<BlockExecutionResult<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
50    {
51        let ExecutionOutcome { bundle: _, receipts, requests, first_block: _ } =
52            self.exec_results.lock().pop().unwrap();
53        Ok(BlockExecutionResult {
54            receipts: receipts.into_iter().flatten().collect(),
55            requests: requests.into_iter().fold(Requests::default(), |mut reqs, req| {
56                reqs.extend(req);
57                reqs
58            }),
59            gas_used: 0,
60        })
61    }
62
63    fn execute_one_with_state_hook<F>(
64        &mut self,
65        block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
66        _state_hook: F,
67    ) -> Result<BlockExecutionResult<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
68    where
69        F: OnStateHook + 'static,
70    {
71        <Self as Executor<DB>>::execute_one(self, block)
72    }
73
74    fn execute(
75        self,
76        _block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
77    ) -> Result<BlockExecutionOutput<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
78    {
79        let ExecutionOutcome { bundle, receipts, requests, first_block: _ } =
80            self.exec_results.lock().pop().unwrap();
81        Ok(BlockExecutionOutput {
82            state: bundle,
83            result: BlockExecutionResult {
84                receipts: receipts.into_iter().flatten().collect(),
85                requests: requests.into_iter().fold(Requests::default(), |mut reqs, req| {
86                    reqs.extend(req);
87                    reqs
88                }),
89                gas_used: 0,
90            },
91        })
92    }
93
94    fn execute_with_state_closure<F>(
95        self,
96        block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
97        _f: F,
98    ) -> Result<BlockExecutionOutput<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
99    where
100        F: FnMut(&revm::database::State<DB>),
101    {
102        <Self as Executor<DB>>::execute(self, block)
103    }
104
105    fn execute_with_state_hook<F>(
106        self,
107        block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
108        _state_hook: F,
109    ) -> Result<BlockExecutionOutput<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
110    where
111        F: OnStateHook + 'static,
112    {
113        <Self as Executor<DB>>::execute(self, block)
114    }
115
116    fn into_state(self) -> revm::database::State<DB> {
117        unreachable!()
118    }
119
120    fn size_hint(&self) -> usize {
121        0
122    }
123}
124
125impl<Factory, DB> BasicBlockExecutor<Factory, DB> {
126    /// Provides safe read access to the state
127    pub fn with_state<F, R>(&self, f: F) -> R
128    where
129        F: FnOnce(&State<DB>) -> R,
130    {
131        f(&self.db)
132    }
133
134    /// Provides safe write access to the state
135    pub fn with_state_mut<F, R>(&mut self, f: F) -> R
136    where
137        F: FnOnce(&mut State<DB>) -> R,
138    {
139        f(&mut self.db)
140    }
141}