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