Skip to main content

foundry_evm/executors/
builder.rs

1use crate::{executors::Executor, inspectors::InspectorStackBuilder};
2use foundry_evm_core::{
3    backend::Backend,
4    evm::{BlockEnvFor, EvmEnvFor, FoundryEvmNetwork, SpecFor, TxEnvFor},
5};
6use revm::context::{Block, Transaction};
7
8/// The builder that allows to configure an evm [`Executor`] which a stack of optional
9/// [`revm::Inspector`]s, such as [`Cheatcodes`].
10///
11/// By default, the [`Executor`] will be configured with an empty [`InspectorStack`].
12///
13/// [`Cheatcodes`]: super::Cheatcodes
14/// [`InspectorStack`]: super::InspectorStack
15#[derive(Debug, Clone)]
16#[must_use = "builders do nothing unless you call `build` on them"]
17pub struct ExecutorBuilder<FEN: FoundryEvmNetwork> {
18    /// The configuration used to build an `InspectorStack`.
19    stack: InspectorStackBuilder<BlockEnvFor<FEN>>,
20    /// The gas limit.
21    gas_limit: Option<u64>,
22    /// The spec override. When `None`, the spec from `EvmEnv::cfg_env` is preserved.
23    spec: Option<SpecFor<FEN>>,
24    legacy_assertions: bool,
25}
26
27impl<FEN: FoundryEvmNetwork> Default for ExecutorBuilder<FEN> {
28    #[inline]
29    fn default() -> Self {
30        Self {
31            stack: InspectorStackBuilder::new(),
32            gas_limit: None,
33            spec: None,
34            legacy_assertions: false,
35        }
36    }
37}
38
39impl<FEN: FoundryEvmNetwork> ExecutorBuilder<FEN> {
40    /// Modify the inspector stack.
41    #[inline]
42    pub fn inspectors(
43        mut self,
44        f: impl FnOnce(
45            InspectorStackBuilder<BlockEnvFor<FEN>>,
46        ) -> InspectorStackBuilder<BlockEnvFor<FEN>>,
47    ) -> Self {
48        self.stack = f(self.stack);
49        self
50    }
51
52    /// Sets the EVM spec to use.
53    #[inline]
54    pub fn spec_id(mut self, spec: SpecFor<FEN>) -> Self {
55        self.spec = Some(spec);
56        self
57    }
58
59    /// Optionally sets the EVM spec. When `None`, the spec from `EvmEnv::cfg_env` is preserved.
60    #[inline]
61    pub fn spec_id_opt(self, spec: Option<SpecFor<FEN>>) -> Self {
62        if let Some(spec) = spec { self.spec_id(spec) } else { self }
63    }
64
65    /// Sets the executor gas limit.
66    #[inline]
67    pub fn gas_limit(mut self, gas_limit: u64) -> Self {
68        self.gas_limit = Some(gas_limit);
69        self
70    }
71
72    /// Sets the `legacy_assertions` flag.
73    #[inline]
74    pub fn legacy_assertions(mut self, legacy_assertions: bool) -> Self {
75        self.legacy_assertions = legacy_assertions;
76        self
77    }
78
79    /// Builds the executor as configured.
80    #[inline]
81    pub fn build(
82        self,
83        mut evm_env: EvmEnvFor<FEN>,
84        tx_env: TxEnvFor<FEN>,
85        db: Backend<FEN>,
86    ) -> Executor<FEN> {
87        let Self { mut stack, gas_limit, spec, legacy_assertions, .. } = self;
88        if stack.block.is_none() {
89            stack.block = Some(evm_env.block_env.clone());
90        }
91        if stack.gas_price.is_none() {
92            stack.gas_price = Some(tx_env.gas_price());
93        }
94        let gas_limit = gas_limit.unwrap_or(evm_env.block_env.gas_limit());
95        if let Some(spec) = spec {
96            evm_env.cfg_env.set_spec_and_mainnet_gas_params(spec);
97        }
98        Executor::new(db, evm_env, tx_env, stack.build(), gas_limit, legacy_assertions)
99    }
100}