revm_database/states/
state_builder.rs

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