Skip to content

Commit

Permalink
chore(state): Make Database more generic. (bluealloy#687)
Browse files Browse the repository at this point in the history
* chore(state): Make database more generic

* doc
  • Loading branch information
rakita authored and Evalir committed Sep 14, 2023
1 parent 7bd1393 commit e9fef6f
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 19 deletions.
23 changes: 14 additions & 9 deletions crates/revm/src/db/states/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,16 @@ use revm_interpreter::primitives::{
hash_map, Account, AccountInfo, Bytecode, HashMap, Address, B256, BLOCK_HASH_HISTORY, U256,
};

/// More constrained version of State that uses Boxed database with a lifetime.
///
/// This is used to make it easier to use State.
pub type StateDBBox<'a, DBError> = State<Box<dyn Database<Error = DBError> + Send + 'a>>;

/// State of blockchain.
///
/// State clear flag is set inside CacheState and by default it is enabled.
/// If you want to disable it use `set_state_clear_flag` function.
pub struct State<'a, DBError> {
pub struct State<DB: Database> {
/// Cached state contains both changed from evm execution and cached/loaded account/storages
/// from database. This allows us to have only one layer of cache where we can fetch data.
/// Additionaly we can introduce some preloading of data from database.
Expand All @@ -22,7 +27,7 @@ pub struct State<'a, DBError> {
/// return not existing account and storage.
///
/// Note: It is marked as Send so database can be shared between threads.
pub database: Box<dyn Database<Error = DBError> + Send + 'a>,
pub database: DB, //Box<dyn Database<Error = DBError> + Send + 'a>,
/// Block state, it aggregates transactions transitions into one state.
///
/// Build reverts and state that gets applied to the state.
Expand All @@ -46,15 +51,15 @@ pub struct State<'a, DBError> {
pub block_hashes: BTreeMap<u64, B256>,
}

impl<'a, DBError> State<'a, DBError> {
impl<DB: Database> State<DB> {
/// Iterate over received balances and increment all account balances.
/// If account is not found inside cache state it will be loaded from database.
///
/// Update will create transitions for all accounts that are updated.
pub fn increment_balances(
&mut self,
balances: impl IntoIterator<Item = (Address, u128)>,
) -> Result<(), DBError> {
) -> Result<(), DB::Error> {
// make transition and update cache state
let mut transitions = Vec::new();
for (address, balance) in balances {
Expand All @@ -74,7 +79,7 @@ impl<'a, DBError> State<'a, DBError> {
pub fn drain_balances(
&mut self,
addresses: impl IntoIterator<Item = Address>,
) -> Result<Vec<u128>, DBError> {
) -> Result<Vec<u128>, DB::Error> {
// make transition and update cache state
let mut transitions = Vec::new();
let mut balances = Vec::new();
Expand Down Expand Up @@ -134,7 +139,7 @@ impl<'a, DBError> State<'a, DBError> {
}
}

pub fn load_cache_account(&mut self, address: Address) -> Result<&mut CacheAccount, DBError> {
pub fn load_cache_account(&mut self, address: Address) -> Result<&mut CacheAccount, DB::Error> {
match self.cache.accounts.entry(address) {
hash_map::Entry::Vacant(entry) => {
if self.use_preloaded_bundle {
Expand Down Expand Up @@ -171,8 +176,8 @@ impl<'a, DBError> State<'a, DBError> {
}
}

impl<'a, DBError> Database for State<'a, DBError> {
type Error = DBError;
impl<DB: Database> Database for State<DB> {
type Error = DB::Error;

fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
self.load_cache_account(address).map(|a| a.account_info())
Expand Down Expand Up @@ -254,7 +259,7 @@ impl<'a, DBError> Database for State<'a, DBError> {
}
}

impl<'a, DBError> DatabaseCommit for State<'a, DBError> {
impl<DB: Database> DatabaseCommit for State<DB> {
fn commit(&mut self, evm_state: HashMap<Address, Account>) {
let transitions = self.cache.apply_evm_state(evm_state);
self.apply_transition(transitions);
Expand Down
19 changes: 9 additions & 10 deletions crates/revm/src/db/states/state_builder.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
use super::{cache::CacheState, BundleState, State, TransitionState};
use crate::db::EmptyDB;
use alloc::collections::BTreeMap;
use core::convert::Infallible;
use revm_interpreter::primitives::{db::Database, B256};

/// Allows building of State and initializing it with different options.
pub struct StateBuilder<'a, DBError> {
pub struct StateBuilder<DB> {
pub with_state_clear: bool,
/// Optional database that we use to fetch data from. If database is not present, we will
/// return not existing account and storage.
///
/// Note: It is marked as Send so database can be shared between threads.
pub database: Box<dyn Database<Error = DBError> + Send + 'a>,
pub database: DB, //Box<dyn Database<Error = DBError> + Send + 'a>,
/// if there is prestate that we want to use.
/// This would mean that we have additional state layer between evm and disk/database.
pub with_bundle_prestate: Option<BundleState>,
Expand All @@ -28,7 +27,7 @@ pub struct StateBuilder<'a, DBError> {
pub with_block_hashes: BTreeMap<u64, B256>,
}

impl Default for StateBuilder<'_, Infallible> {
impl Default for StateBuilder<Box<EmptyDB>> {
fn default() -> Self {
Self {
with_state_clear: true,
Expand All @@ -42,16 +41,16 @@ impl Default for StateBuilder<'_, Infallible> {
}
}

impl<'a, DBError> StateBuilder<'a, DBError> {
impl<DB: Database> StateBuilder<DB> {
/// Create default instance of builder.
pub fn new() -> StateBuilder<'a, Infallible> {
StateBuilder::<'a, Infallible>::default()
pub fn new() -> StateBuilder<Box<EmptyDB>> {
StateBuilder::<Box<EmptyDB>>::default()
}

pub fn with_database<NewDBError>(
pub fn with_database_boxed<'a, NewDBError>(
self,
database: Box<dyn Database<Error = NewDBError> + Send + 'a>,
) -> StateBuilder<'a, NewDBError> {
) -> StateBuilder<Box<dyn Database<Error = NewDBError> + Send + 'a>> {
// cast to the different database,
// Note that we return different type depending of the database NewDBError.
StateBuilder {
Expand Down Expand Up @@ -124,7 +123,7 @@ impl<'a, DBError> StateBuilder<'a, DBError> {
}
}

pub fn build(mut self) -> State<'a, DBError> {
pub fn build(mut self) -> State<DB> {
let use_preloaded_bundle = if self.with_cache_prestate.is_some() {
self.with_bundle_prestate = None;
false
Expand Down

0 comments on commit e9fef6f

Please sign in to comment.