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;
89/// 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.
13database: DB,
14/// Enabled state clear flag that is introduced in Spurious Dragon hardfork.
15 /// Default is true as spurious dragon happened long time ago.
16with_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.
19with_bundle_prestate: Option<BundleState>,
20/// This will initialize cache to this state.
21with_cache_prestate: Option<CacheState>,
22/// Do we want to create reverts and update bundle state.
23 /// Default is false.
24with_bundle_update: bool,
25/// Do we want to merge transitions in background.
26 /// This will allows evm to continue executing.
27 /// Default is false.
28with_background_transition_merge: bool,
29/// If we want to set different block hashes
30with_block_hashes: BTreeMap<u64, B256>,
31}
3233impl 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).
38pub fn new() -> Self {
39Self::default()
40 }
41}
4243impl<DB: Database + Default> Default for StateBuilder<DB> {
44fn default() -> Self {
45Self::new_with_database(DB::default())
46 }
47}
4849impl<DB: Database> StateBuilder<DB> {
50/// Create a new builder with the given database.
51pub fn new_with_database(database: DB) -> Self {
52Self {
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 }
6263/// Set the database.
64pub 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.
67StateBuilder {
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 }
7778/// Takes [DatabaseRef] and wraps it with [WrapDatabaseRef].
79pub fn with_database_ref<ODB: DatabaseRef>(
80self,
81 database: ODB,
82 ) -> StateBuilder<WrapDatabaseRef<ODB>> {
83self.with_database(WrapDatabaseRef(database))
84 }
8586/// With boxed version of database.
87pub fn with_database_boxed<Error>(
88self,
89 database: DBBox<'_, Error>,
90 ) -> StateBuilder<DBBox<'_, Error>> {
91self.with_database(database)
92 }
9394/// 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.
96pub fn without_state_clear(self) -> Self {
97Self {
98 with_state_clear: false,
99 ..self
100}
101 }
102103/// 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.
108pub fn with_bundle_prestate(self, bundle: BundleState) -> Self {
109Self {
110 with_bundle_prestate: Some(bundle),
111 ..self
112}
113 }
114115/// 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.
119pub fn with_bundle_update(self) -> Self {
120Self {
121 with_bundle_update: true,
122 ..self
123}
124 }
125126/// 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.
130pub fn with_cached_prestate(self, cache: CacheState) -> Self {
131Self {
132 with_cache_prestate: Some(cache),
133 ..self
134}
135 }
136137/// Starts the thread that will take transitions and do merge to the bundle state
138 /// in the background.
139pub fn with_background_transition_merge(self) -> Self {
140Self {
141 with_background_transition_merge: true,
142 ..self
143}
144 }
145146pub fn with_block_hashes(self, block_hashes: BTreeMap<u64, B256>) -> Self {
147Self {
148 with_block_hashes: block_hashes,
149 ..self
150}
151 }
152153pub fn build(mut self) -> State<DB> {
154let use_preloaded_bundle = if self.with_cache_prestate.is_some() {
155self.with_bundle_prestate = None;
156false
157} else {
158self.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}