revm_database/states/
state_builder.rs

1use super::{cache::CacheState, state::DBBox, BundleState, State, TransitionState};
2use database_interface::{DBErrorMarker, Database, DatabaseRef, EmptyDB, WrapDatabaseRef};
3use primitives::B256;
4use std::collections::BTreeMap;
5
6/// Allows building of State and initializing it with different options.
7#[derive(Clone, Debug, PartialEq, Eq)]
8pub struct StateBuilder<DB> {
9    /// Database that we use to fetch data from
10    database: DB,
11    /// Enabled state clear flag that is introduced in Spurious Dragon hardfork
12    ///
13    /// Default is true as spurious dragon happened long time ago.
14    with_state_clear: bool,
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: BTreeMap<u64, B256>,
32}
33
34impl StateBuilder<EmptyDB> {
35    /// Creates a new builder with an empty database.
36    ///
37    /// If you want to instantiate it with a specific database, use
38    /// [`new_with_database`](Self::new_with_database).
39    pub fn new() -> Self {
40        Self::default()
41    }
42}
43
44impl<DB: Database + Default> Default for StateBuilder<DB> {
45    fn default() -> Self {
46        Self::new_with_database(DB::default())
47    }
48}
49
50impl<DB: Database> StateBuilder<DB> {
51    /// Create a new builder with the given database.
52    pub fn new_with_database(database: DB) -> Self {
53        Self {
54            database,
55            with_state_clear: true,
56            with_cache_prestate: None,
57            with_bundle_prestate: None,
58            with_bundle_update: false,
59            with_background_transition_merge: false,
60            with_block_hashes: BTreeMap::new(),
61        }
62    }
63
64    /// Set the database.
65    pub fn with_database<ODB: Database>(self, database: ODB) -> StateBuilder<ODB> {
66        // Cast to the different database.
67        // Note that we return different type depending on the database NewDBError.
68        StateBuilder {
69            with_state_clear: self.with_state_clear,
70            database,
71            with_cache_prestate: self.with_cache_prestate,
72            with_bundle_prestate: self.with_bundle_prestate,
73            with_bundle_update: self.with_bundle_update,
74            with_background_transition_merge: self.with_background_transition_merge,
75            with_block_hashes: self.with_block_hashes,
76        }
77    }
78
79    /// Takes [DatabaseRef] and wraps it with [WrapDatabaseRef].
80    pub fn with_database_ref<ODB: DatabaseRef>(
81        self,
82        database: ODB,
83    ) -> StateBuilder<WrapDatabaseRef<ODB>> {
84        self.with_database(WrapDatabaseRef(database))
85    }
86
87    /// With boxed version of database.
88    pub fn with_database_boxed<Error: DBErrorMarker + core::error::Error>(
89        self,
90        database: DBBox<'_, Error>,
91    ) -> StateBuilder<DBBox<'_, Error>> {
92        self.with_database(database)
93    }
94
95    /// By default state clear flag is enabled but for initial sync on mainnet
96    /// we want to disable it so proper consensus changes are in place.
97    pub fn without_state_clear(self) -> Self {
98        Self {
99            with_state_clear: false,
100            ..self
101        }
102    }
103
104    /// Allows setting prestate that is going to be used for execution.
105    ///
106    /// # Note
107    /// This bundle state will act as additional layer of cache.
108    ///
109    /// And State after not finding data inside StateCache will try to find it inside BundleState.
110    ///
111    /// On update Bundle state will be changed and updated.
112    pub fn with_bundle_prestate(self, bundle: BundleState) -> Self {
113        Self {
114            with_bundle_prestate: Some(bundle),
115            ..self
116        }
117    }
118
119    /// Makes transitions and update bundle state.
120    ///
121    /// This is needed option if we want to create reverts
122    /// and getting output of changed states.
123    pub fn with_bundle_update(self) -> Self {
124        Self {
125            with_bundle_update: true,
126            ..self
127        }
128    }
129
130    /// It will use different cache for the state.
131    ///
132    /// **Note**: If set, it will ignore bundle prestate.
133    ///
134    /// And will ignore `without_state_clear` flag as cache contains its own state_clear flag.
135    ///
136    /// This is useful for testing.
137    pub fn with_cached_prestate(self, cache: CacheState) -> Self {
138        Self {
139            with_cache_prestate: Some(cache),
140            ..self
141        }
142    }
143
144    /// Starts the thread that will take transitions and do merge to the bundle state
145    /// in the background.
146    pub fn with_background_transition_merge(self) -> Self {
147        Self {
148            with_background_transition_merge: true,
149            ..self
150        }
151    }
152
153    pub fn with_block_hashes(self, block_hashes: BTreeMap<u64, B256>) -> Self {
154        Self {
155            with_block_hashes: block_hashes,
156            ..self
157        }
158    }
159
160    pub fn build(mut self) -> State<DB> {
161        let use_preloaded_bundle = if self.with_cache_prestate.is_some() {
162            self.with_bundle_prestate = None;
163            false
164        } else {
165            self.with_bundle_prestate.is_some()
166        };
167        State {
168            cache: self
169                .with_cache_prestate
170                .unwrap_or_else(|| CacheState::new(self.with_state_clear)),
171            database: self.database,
172            transition_state: self.with_bundle_update.then(TransitionState::default),
173            bundle_state: self.with_bundle_prestate.unwrap_or_default(),
174            use_preloaded_bundle,
175            block_hashes: self.with_block_hashes,
176        }
177    }
178}