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