revm/db/states/
state_builder.rs

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