Skip to main content

revm_database/states/
state_builder.rs

1use crate::states::block_hash_cache::BlockHashCache;
2
3use super::{cache::CacheState, state::DBBox, BundleState, State, TransitionState};
4use database_interface::{
5    bal::BalState, DBErrorMarker, Database, DatabaseRef, EmptyDB, WrapDatabaseRef,
6};
7use state::bal::Bal;
8use std::sync::Arc;
9
10/// Allows building of State and initializing it with different options.
11#[derive(Clone, Debug, PartialEq, Eq)]
12pub struct StateBuilder<DB> {
13    /// Database that we use to fetch data from
14    database: DB,
15    /// If there is prestate that we want to use,
16    /// this would mean that we have additional state layer between evm and disk/database.
17    with_bundle_prestate: Option<BundleState>,
18    /// This will initialize cache to this state.
19    with_cache_prestate: Option<CacheState>,
20    /// Do we want to create reverts and update bundle state?
21    ///
22    /// Default is false.
23    with_bundle_update: bool,
24    /// Do we want to merge transitions in background?
25    ///
26    /// This will allow evm to continue executing.
27    ///
28    /// Default is false.
29    with_background_transition_merge: bool,
30    /// If we want to set different block hashes,
31    with_block_hashes: BlockHashCache,
32    /// BAL state.
33    bal_state: BalState,
34}
35
36impl StateBuilder<EmptyDB> {
37    /// Creates a new builder with an empty database.
38    ///
39    /// If you want to instantiate it with a specific database, use
40    /// [`new_with_database`](Self::new_with_database).
41    pub fn new() -> Self {
42        Self::default()
43    }
44}
45
46impl<DB: Database + Default> Default for StateBuilder<DB> {
47    fn default() -> Self {
48        Self::new_with_database(DB::default())
49    }
50}
51
52impl<DB: Database> StateBuilder<DB> {
53    /// Create a new builder with the given database.
54    pub fn new_with_database(database: DB) -> Self {
55        Self {
56            database,
57            with_cache_prestate: None,
58            with_bundle_prestate: None,
59            with_bundle_update: false,
60            with_background_transition_merge: false,
61            with_block_hashes: BlockHashCache::new(),
62            bal_state: BalState::default(),
63        }
64    }
65
66    /// Set the database.
67    pub fn with_database<ODB: Database>(self, database: ODB) -> StateBuilder<ODB> {
68        // Cast to the different database.
69        // Note that we return different type depending on the database NewDBError.
70        StateBuilder {
71            database,
72            with_cache_prestate: self.with_cache_prestate,
73            with_bundle_prestate: self.with_bundle_prestate,
74            with_bundle_update: self.with_bundle_update,
75            with_background_transition_merge: self.with_background_transition_merge,
76            with_block_hashes: self.with_block_hashes,
77            bal_state: self.bal_state,
78        }
79    }
80
81    /// Takes [DatabaseRef] and wraps it with [WrapDatabaseRef].
82    pub fn with_database_ref<ODB: DatabaseRef>(
83        self,
84        database: ODB,
85    ) -> StateBuilder<WrapDatabaseRef<ODB>> {
86        self.with_database(WrapDatabaseRef(database))
87    }
88
89    /// With boxed version of database.
90    pub fn with_database_boxed<Error: DBErrorMarker>(
91        self,
92        database: DBBox<'_, Error>,
93    ) -> StateBuilder<DBBox<'_, Error>> {
94        self.with_database(database)
95    }
96
97    /// Allows setting prestate that is going to be used for execution.
98    ///
99    /// # Note
100    /// This bundle state will act as additional layer of cache.
101    ///
102    /// And State after not finding data inside StateCache will try to find it inside BundleState.
103    ///
104    /// On update Bundle state will be changed and updated.
105    pub fn with_bundle_prestate(self, bundle: BundleState) -> Self {
106        Self {
107            with_bundle_prestate: Some(bundle),
108            ..self
109        }
110    }
111
112    /// Makes transitions and update bundle state.
113    ///
114    /// This is needed option if we want to create reverts
115    /// and getting output of changed states.
116    pub fn with_bundle_update(self) -> Self {
117        Self {
118            with_bundle_update: true,
119            ..self
120        }
121    }
122
123    /// It will use different cache for the state.
124    ///
125    /// **Note**: If set, it will ignore bundle prestate.
126    ///
127    /// This is useful for testing.
128    pub fn with_cached_prestate(self, cache: CacheState) -> Self {
129        Self {
130            with_cache_prestate: Some(cache),
131            ..self
132        }
133    }
134
135    /// Starts the thread that will take transitions and do merge to the bundle state
136    /// in the background.
137    pub fn with_background_transition_merge(self) -> Self {
138        Self {
139            with_background_transition_merge: true,
140            ..self
141        }
142    }
143
144    /// Sets the block hashes for the state.
145    pub fn with_block_hashes(self, block_hashes: BlockHashCache) -> Self {
146        Self {
147            with_block_hashes: block_hashes,
148            ..self
149        }
150    }
151
152    /// With BAL.
153    pub fn with_bal(mut self, bal: Arc<Bal>) -> Self {
154        self.bal_state.bal = Some(bal);
155        self
156    }
157
158    /// With BAL builder.
159    pub fn with_bal_builder(mut self) -> Self {
160        self.bal_state.bal_builder = Some(Bal::new());
161        self
162    }
163
164    /// Conditionally set BAL builder based on the flag.
165    pub fn with_bal_builder_if(mut self, enable: bool) -> Self {
166        if enable {
167            self.bal_state.bal_builder = Some(Bal::new());
168        }
169        self
170    }
171
172    /// Builds the State with the configured settings.
173    pub fn build(mut self) -> State<DB> {
174        let use_preloaded_bundle = if self.with_cache_prestate.is_some() {
175            self.with_bundle_prestate = None;
176            false
177        } else {
178            self.with_bundle_prestate.is_some()
179        };
180        State {
181            cache: self.with_cache_prestate.unwrap_or_default(),
182            database: self.database,
183            transition_state: self.with_bundle_update.then(TransitionState::default),
184            bundle_state: self.with_bundle_prestate.unwrap_or_default(),
185            use_preloaded_bundle,
186            block_hashes: self.with_block_hashes,
187            bal_state: self.bal_state,
188        }
189    }
190}