reth_evm/
builder.rs

1//! Builder for creating an EVM with a database and environment.
2
3use alloc::boxed::Box;
4use revm::{inspector_handle_register, Database, Evm, EvmBuilder, GetInspector};
5use revm_primitives::EnvWithHandlerCfg;
6
7/// Builder for creating an EVM with a database and environment.
8///
9/// Wrapper around [`EvmBuilder`] that allows for setting the database and environment for the EVM.
10///
11/// This is useful for creating an EVM with a custom database and environment without having to
12/// necessarily rely on Revm inspector.
13#[derive(Debug)]
14pub struct RethEvmBuilder<DB: Database, EXT = ()> {
15    /// The database to use for the EVM.
16    db: DB,
17    /// The environment to use for the EVM.
18    env: Option<Box<EnvWithHandlerCfg>>,
19    /// The external context for the EVM.
20    external_context: EXT,
21}
22
23impl<DB, EXT> RethEvmBuilder<DB, EXT>
24where
25    DB: Database,
26{
27    /// Create a new EVM builder with the given database.
28    pub const fn new(db: DB, external_context: EXT) -> Self {
29        Self { db, env: None, external_context }
30    }
31
32    /// Set the environment for the EVM.
33    pub fn with_env(mut self, env: Box<EnvWithHandlerCfg>) -> Self {
34        self.env = Some(env);
35        self
36    }
37
38    /// Set the external context for the EVM.
39    pub fn with_external_context<EXT1>(self, external_context: EXT1) -> RethEvmBuilder<DB, EXT1> {
40        RethEvmBuilder { db: self.db, env: self.env, external_context }
41    }
42
43    /// Build the EVM with the given database and environment.
44    pub fn build<'a>(self) -> Evm<'a, EXT, DB> {
45        let mut builder =
46            EvmBuilder::default().with_db(self.db).with_external_context(self.external_context);
47
48        //hardcoding for now
49        if let Some(env) = self.env {
50            builder = builder.with_spec_id(env.spec_id());
51            builder = builder.with_env(env.env);
52        }
53
54        builder.build()
55    }
56
57    /// Build the EVM with the given database and environment, using the given inspector.
58    pub fn build_with_inspector<'a, I>(self, inspector: I) -> Evm<'a, I, DB>
59    where
60        I: GetInspector<DB>,
61        EXT: 'a,
62    {
63        let mut builder =
64            EvmBuilder::default().with_db(self.db).with_external_context(self.external_context);
65        if let Some(env) = self.env {
66            builder = builder.with_spec_id(env.spec_id());
67            builder = builder.with_env(env.env);
68        }
69        builder
70            .with_external_context(inspector)
71            .append_handler_register(inspector_handle_register)
72            .build()
73    }
74}
75
76/// Trait for configuring an EVM builder.
77pub trait ConfigureEvmBuilder {
78    /// The type of EVM builder that this trait can configure.
79    type Builder<'a, DB: Database>: EvmFactory;
80}
81
82/// Trait for configuring the EVM for executing full blocks.
83pub trait EvmFactory {
84    /// Associated type for the default external context that should be configured for the EVM.
85    type DefaultExternalContext<'a>;
86
87    /// Provides the default external context.
88    fn default_external_context<'a>(&self) -> Self::DefaultExternalContext<'a>;
89
90    /// Returns new EVM with the given database
91    ///
92    /// This does not automatically configure the EVM with [`crate::ConfigureEvmEnv`] methods. It is
93    /// up to the caller to call an appropriate method to fill the transaction and block
94    /// environment before executing any transactions using the provided EVM.
95    fn evm<DB: Database>(self, db: DB) -> Evm<'static, Self::DefaultExternalContext<'static>, DB>
96    where
97        Self: Sized,
98    {
99        RethEvmBuilder::new(db, self.default_external_context()).build()
100    }
101
102    /// Returns a new EVM with the given database configured with the given environment settings,
103    /// including the spec id.
104    ///
105    /// This will preserve any handler modifications
106    fn evm_with_env<'a, DB: Database + 'a>(
107        &self,
108        db: DB,
109        env: EnvWithHandlerCfg,
110    ) -> Evm<'a, Self::DefaultExternalContext<'a>, DB> {
111        RethEvmBuilder::new(db, self.default_external_context()).with_env(env.into()).build()
112    }
113
114    /// Returns a new EVM with the given database configured with the given environment settings,
115    /// including the spec id.
116    ///
117    /// This will use the given external inspector as the EVM external context.
118    ///
119    /// This will preserve any handler modifications
120    fn evm_with_env_and_inspector<DB, I>(
121        &self,
122        db: DB,
123        env: EnvWithHandlerCfg,
124        inspector: I,
125    ) -> Evm<'_, I, DB>
126    where
127        DB: Database,
128        I: GetInspector<DB>,
129    {
130        RethEvmBuilder::new(db, self.default_external_context())
131            .with_env(env.into())
132            .build_with_inspector(inspector)
133    }
134
135    /// Returns a new EVM with the given inspector.
136    ///
137    /// Caution: This does not automatically configure the EVM with [`crate::ConfigureEvmEnv`]
138    /// methods. It is up to the caller to call an appropriate method to fill the transaction
139    /// and block environment before executing any transactions using the provided EVM.
140    fn evm_with_inspector<DB, I>(&self, db: DB, inspector: I) -> Evm<'_, I, DB>
141    where
142        DB: Database,
143        I: GetInspector<DB>,
144    {
145        RethEvmBuilder::new(db, self.default_external_context()).build_with_inspector(inspector)
146    }
147}
148
149impl<DB: Database, EXT: Clone> EvmFactory for RethEvmBuilder<DB, EXT> {
150    type DefaultExternalContext<'a> = EXT;
151
152    fn default_external_context<'a>(&self) -> Self::DefaultExternalContext<'a> {
153        self.external_context.clone()
154    }
155}