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    /// If we want to set different block hashes,
25    with_block_hashes: BlockHashCache,
26    /// BAL state.
27    bal_state: BalState,
28}
29
30impl StateBuilder<EmptyDB> {
31    /// Creates a new builder with an empty database.
32    ///
33    /// If you want to instantiate it with a specific database, use
34    /// [`new_with_database`](Self::new_with_database).
35    pub fn new() -> Self {
36        Self::default()
37    }
38}
39
40impl<DB: Database + Default> Default for StateBuilder<DB> {
41    fn default() -> Self {
42        Self::new_with_database(DB::default())
43    }
44}
45
46impl<DB: Database> StateBuilder<DB> {
47    /// Create a new builder with the given database.
48    pub fn new_with_database(database: DB) -> Self {
49        Self {
50            database,
51            with_cache_prestate: None,
52            with_bundle_prestate: None,
53            with_bundle_update: false,
54            with_block_hashes: BlockHashCache::new(),
55            bal_state: BalState::default(),
56        }
57    }
58
59    /// Set the database.
60    pub fn with_database<ODB: Database>(self, database: ODB) -> StateBuilder<ODB> {
61        // Cast to the different database.
62        // Note that we return different type depending on the database NewDBError.
63        StateBuilder {
64            database,
65            with_cache_prestate: self.with_cache_prestate,
66            with_bundle_prestate: self.with_bundle_prestate,
67            with_bundle_update: self.with_bundle_update,
68            with_block_hashes: self.with_block_hashes,
69            bal_state: self.bal_state,
70        }
71    }
72
73    /// Takes [DatabaseRef] and wraps it with [WrapDatabaseRef].
74    pub fn with_database_ref<ODB: DatabaseRef>(
75        self,
76        database: ODB,
77    ) -> StateBuilder<WrapDatabaseRef<ODB>> {
78        self.with_database(WrapDatabaseRef(database))
79    }
80
81    /// With boxed version of database.
82    pub fn with_database_boxed<Error: DBErrorMarker>(
83        self,
84        database: DBBox<'_, Error>,
85    ) -> StateBuilder<DBBox<'_, Error>> {
86        self.with_database(database)
87    }
88
89    /// Allows setting prestate that is going to be used for execution.
90    ///
91    /// # Note
92    /// This bundle state will act as additional layer of cache.
93    ///
94    /// And State after not finding data inside StateCache will try to find it inside BundleState.
95    ///
96    /// On update Bundle state will be changed and updated.
97    pub fn with_bundle_prestate(self, bundle: BundleState) -> Self {
98        Self {
99            with_bundle_prestate: Some(bundle),
100            ..self
101        }
102    }
103
104    /// Makes transitions and update bundle state.
105    ///
106    /// This is needed option if we want to create reverts
107    /// and getting output of changed states.
108    pub fn with_bundle_update(self) -> Self {
109        Self {
110            with_bundle_update: true,
111            ..self
112        }
113    }
114
115    /// It will use different cache for the state.
116    ///
117    /// **Note**: If set, it will ignore bundle prestate.
118    ///
119    /// This is useful for testing.
120    pub fn with_cached_prestate(self, cache: CacheState) -> Self {
121        Self {
122            with_cache_prestate: Some(cache),
123            ..self
124        }
125    }
126
127    /// Sets the block hashes for the state.
128    pub fn with_block_hashes(self, block_hashes: BlockHashCache) -> Self {
129        Self {
130            with_block_hashes: block_hashes,
131            ..self
132        }
133    }
134
135    /// With BAL.
136    pub fn with_bal(mut self, bal: Arc<Bal>) -> Self {
137        self.bal_state.bal = Some(bal);
138        self
139    }
140
141    /// With BAL builder.
142    pub fn with_bal_builder(mut self) -> Self {
143        self.bal_state.bal_builder = Some(Bal::new());
144        self
145    }
146
147    /// Conditionally set BAL builder based on the flag.
148    pub fn with_bal_builder_if(mut self, enable: bool) -> Self {
149        if enable {
150            self.bal_state.bal_builder = Some(Bal::new());
151        }
152        self
153    }
154
155    /// Builds the State with the configured settings.
156    pub fn build(mut self) -> State<DB> {
157        let use_preloaded_bundle = if self.with_cache_prestate.is_some() {
158            self.with_bundle_prestate = None;
159            false
160        } else {
161            self.with_bundle_prestate.is_some()
162        };
163        State {
164            cache: self.with_cache_prestate.unwrap_or_default(),
165            database: self.database,
166            transition_state: self.with_bundle_update.then(TransitionState::default),
167            bundle_state: self.with_bundle_prestate.unwrap_or_default(),
168            use_preloaded_bundle,
169            block_hashes: self.with_block_hashes,
170            bal_state: self.bal_state,
171        }
172    }
173}