reth_evm/
test_utils.rs

1//! Helpers for testing.
2
3use crate::{
4    execute::{
5        BasicBatchExecutor, BasicBlockExecutor, BatchExecutor, BlockExecutionInput,
6        BlockExecutionOutput, BlockExecutionStrategy, BlockExecutorProvider, Executor,
7    },
8    provider::EvmEnvProvider,
9    system_calls::OnStateHook,
10    ConfigureEvmEnv,
11};
12use alloy_eips::eip7685::Requests;
13use alloy_primitives::{BlockNumber, U256};
14use parking_lot::Mutex;
15use reth_execution_errors::BlockExecutionError;
16use reth_execution_types::ExecutionOutcome;
17use reth_primitives::{BlockWithSenders, EthPrimitives, NodePrimitives, Receipt, Receipts};
18use reth_prune_types::PruneModes;
19use reth_storage_errors::provider::{ProviderError, ProviderResult};
20use revm::State;
21use revm_primitives::{db::Database, BlockEnv, CfgEnvWithHandlerCfg};
22use std::{fmt::Display, sync::Arc};
23
24impl<C: Send + Sync, N: NodePrimitives> EvmEnvProvider<N::BlockHeader>
25    for reth_storage_api::noop::NoopProvider<C, N>
26{
27    fn env_with_header<EvmConfig>(
28        &self,
29        header: &N::BlockHeader,
30        evm_config: EvmConfig,
31    ) -> ProviderResult<(CfgEnvWithHandlerCfg, BlockEnv)>
32    where
33        EvmConfig: ConfigureEvmEnv<Header = N::BlockHeader>,
34    {
35        Ok(evm_config.cfg_and_block_env(header, U256::MAX))
36    }
37}
38
39/// A [`BlockExecutorProvider`] that returns mocked execution results.
40#[derive(Clone, Debug, Default)]
41pub struct MockExecutorProvider {
42    exec_results: Arc<Mutex<Vec<ExecutionOutcome>>>,
43}
44
45impl MockExecutorProvider {
46    /// Extend the mocked execution results
47    pub fn extend(&self, results: impl IntoIterator<Item = impl Into<ExecutionOutcome>>) {
48        self.exec_results.lock().extend(results.into_iter().map(Into::into));
49    }
50}
51
52impl BlockExecutorProvider for MockExecutorProvider {
53    type Primitives = EthPrimitives;
54
55    type Executor<DB: Database<Error: Into<ProviderError> + Display>> = Self;
56
57    type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>> = Self;
58
59    fn executor<DB>(&self, _: DB) -> Self::Executor<DB>
60    where
61        DB: Database<Error: Into<ProviderError> + Display>,
62    {
63        self.clone()
64    }
65
66    fn batch_executor<DB>(&self, _: DB) -> Self::BatchExecutor<DB>
67    where
68        DB: Database<Error: Into<ProviderError> + Display>,
69    {
70        self.clone()
71    }
72}
73
74impl<DB> Executor<DB> for MockExecutorProvider {
75    type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
76    type Output = BlockExecutionOutput<Receipt>;
77    type Error = BlockExecutionError;
78
79    fn execute(self, _: Self::Input<'_>) -> Result<Self::Output, Self::Error> {
80        let ExecutionOutcome { bundle, receipts, requests, first_block: _ } =
81            self.exec_results.lock().pop().unwrap();
82        Ok(BlockExecutionOutput {
83            state: bundle,
84            receipts: receipts.into_iter().flatten().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    fn execute_with_state_closure<F>(
94        self,
95        input: Self::Input<'_>,
96        _: F,
97    ) -> Result<Self::Output, Self::Error>
98    where
99        F: FnMut(&State<DB>),
100    {
101        <Self as Executor<DB>>::execute(self, input)
102    }
103
104    fn execute_with_state_hook<F>(
105        self,
106        input: Self::Input<'_>,
107        _: F,
108    ) -> Result<Self::Output, Self::Error>
109    where
110        F: OnStateHook,
111    {
112        <Self as Executor<DB>>::execute(self, input)
113    }
114}
115
116impl<DB> BatchExecutor<DB> for MockExecutorProvider {
117    type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
118    type Output = ExecutionOutcome;
119    type Error = BlockExecutionError;
120
121    fn execute_and_verify_one(&mut self, _: Self::Input<'_>) -> Result<(), Self::Error> {
122        Ok(())
123    }
124
125    fn finalize(self) -> Self::Output {
126        self.exec_results.lock().pop().unwrap()
127    }
128
129    fn set_tip(&mut self, _: BlockNumber) {}
130
131    fn set_prune_modes(&mut self, _: PruneModes) {}
132
133    fn size_hint(&self) -> Option<usize> {
134        None
135    }
136}
137
138impl<S> BasicBlockExecutor<S>
139where
140    S: BlockExecutionStrategy,
141{
142    /// Provides safe read access to the state
143    pub fn with_state<F, R>(&self, f: F) -> R
144    where
145        F: FnOnce(&State<S::DB>) -> R,
146    {
147        f(self.strategy.state_ref())
148    }
149
150    /// Provides safe write access to the state
151    pub fn with_state_mut<F, R>(&mut self, f: F) -> R
152    where
153        F: FnOnce(&mut State<S::DB>) -> R,
154    {
155        f(self.strategy.state_mut())
156    }
157}
158
159impl<S> BasicBatchExecutor<S>
160where
161    S: BlockExecutionStrategy,
162{
163    /// Provides safe read access to the state
164    pub fn with_state<F, R>(&self, f: F) -> R
165    where
166        F: FnOnce(&State<S::DB>) -> R,
167    {
168        f(self.strategy.state_ref())
169    }
170
171    /// Provides safe write access to the state
172    pub fn with_state_mut<F, R>(&mut self, f: F) -> R
173    where
174        F: FnOnce(&mut State<S::DB>) -> R,
175    {
176        f(self.strategy.state_mut())
177    }
178
179    /// Accessor for batch executor receipts.
180    pub const fn receipts(&self) -> &Receipts<<S::Primitives as NodePrimitives>::Receipt> {
181        self.batch_record.receipts()
182    }
183}