#![cfg_attr(not(test), warn(unused_crate_dependencies))]
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(not(feature = "std"))]
extern crate alloc as std;
use core::convert::Infallible;
use auto_impl::auto_impl;
use primitives::{address, Address, AddressMap, StorageKey, StorageValue, B256, U256};
use state::{Account, AccountInfo, Bytecode};
use std::vec::Vec;
pub const FFADDRESS: Address = address!("0xffffffffffffffffffffffffffffffffffffffff");
pub const BENCH_TARGET: Address = FFADDRESS;
pub const TEST_BALANCE: U256 = U256::from_limbs([10_000_000_000_000_000, 0, 0, 0]);
pub const BENCH_TARGET_BALANCE: U256 = TEST_BALANCE;
pub const EEADDRESS: Address = address!("0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee");
pub const BENCH_CALLER: Address = EEADDRESS;
pub const BENCH_CALLER_BALANCE: U256 = TEST_BALANCE;
pub use primitives;
pub use state;
#[cfg(feature = "asyncdb")]
pub mod async_db;
pub mod bal;
pub mod either;
pub mod empty_db;
pub mod erased_error;
pub mod try_commit;
#[cfg(feature = "asyncdb")]
pub use async_db::{DatabaseAsync, WrapDatabaseAsync};
pub use empty_db::{EmptyDB, EmptyDBTyped};
pub use erased_error::ErasedError;
pub use try_commit::{ArcUpgradeError, TryDatabaseCommit};
pub trait DBErrorMarker: core::error::Error + Send + Sync + 'static {}
impl DBErrorMarker for Infallible {}
impl DBErrorMarker for ErasedError {}
#[auto_impl(&mut, Box)]
pub trait Database {
type Error: DBErrorMarker;
fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error>;
fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error>;
fn storage(&mut self, address: Address, index: StorageKey)
-> Result<StorageValue, Self::Error>;
#[inline]
fn storage_by_account_id(
&mut self,
address: Address,
account_id: usize,
storage_key: StorageKey,
) -> Result<StorageValue, Self::Error> {
let _ = account_id;
self.storage(address, storage_key)
}
fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error>;
}
#[auto_impl(&mut, Box)]
pub trait DatabaseCommit {
fn commit(&mut self, changes: AddressMap<Account>);
fn commit_iter(&mut self, changes: &mut dyn Iterator<Item = (Address, Account)>) {
let changes: AddressMap<Account> = changes.collect();
self.commit(changes);
}
}
impl dyn DatabaseCommit {
#[inline]
pub fn commit_from_iter(&mut self, changes: impl IntoIterator<Item = (Address, Account)>) {
self.commit_iter(&mut changes.into_iter())
}
}
#[auto_impl(&, &mut, Box, Rc, Arc)]
pub trait DatabaseRef {
type Error: DBErrorMarker;
fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error>;
fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error>;
fn storage_ref(&self, address: Address, index: StorageKey)
-> Result<StorageValue, Self::Error>;
#[inline]
fn storage_by_account_id_ref(
&self,
address: Address,
account_id: usize,
storage_key: StorageKey,
) -> Result<StorageValue, Self::Error> {
let _ = account_id;
self.storage_ref(address, storage_key)
}
fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error>;
}
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WrapDatabaseRef<T: DatabaseRef>(pub T);
impl<F: DatabaseRef> From<F> for WrapDatabaseRef<F> {
#[inline]
fn from(f: F) -> Self {
WrapDatabaseRef(f)
}
}
impl<T: DatabaseRef> Database for WrapDatabaseRef<T> {
type Error = T::Error;
#[inline]
fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
self.0.basic_ref(address)
}
#[inline]
fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
self.0.code_by_hash_ref(code_hash)
}
#[inline]
fn storage(
&mut self,
address: Address,
index: StorageKey,
) -> Result<StorageValue, Self::Error> {
self.0.storage_ref(address, index)
}
#[inline]
fn storage_by_account_id(
&mut self,
address: Address,
account_id: usize,
storage_key: StorageKey,
) -> Result<StorageValue, Self::Error> {
self.0
.storage_by_account_id_ref(address, account_id, storage_key)
}
#[inline]
fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
self.0.block_hash_ref(number)
}
}
impl<T: DatabaseRef + DatabaseCommit> DatabaseCommit for WrapDatabaseRef<T> {
#[inline]
fn commit(&mut self, changes: AddressMap<Account>) {
self.0.commit(changes)
}
}
impl<T: DatabaseRef> DatabaseRef for WrapDatabaseRef<T> {
type Error = T::Error;
#[inline]
fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
self.0.basic_ref(address)
}
#[inline]
fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
self.0.code_by_hash_ref(code_hash)
}
#[inline]
fn storage_ref(
&self,
address: Address,
index: StorageKey,
) -> Result<StorageValue, Self::Error> {
self.0.storage_ref(address, index)
}
#[inline]
fn storage_by_account_id_ref(
&self,
address: Address,
account_id: usize,
storage_key: StorageKey,
) -> Result<StorageValue, Self::Error> {
self.0
.storage_by_account_id_ref(address, account_id, storage_key)
}
#[inline]
fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
self.0.block_hash_ref(number)
}
}
impl<T: Database + DatabaseCommit> DatabaseCommitExt for T {
}
pub trait DatabaseCommitExt: Database + DatabaseCommit {
fn increment_balances(
&mut self,
balances: impl IntoIterator<Item = (Address, u128)>,
) -> Result<(), Self::Error> {
let transitions = balances
.into_iter()
.map(|(address, balance)| {
let mut original_account = match self.basic(address)? {
Some(acc_info) => Account::from(acc_info),
None => Account::new_not_existing(0),
};
original_account.info.balance = original_account
.info
.balance
.saturating_add(U256::from(balance));
original_account.mark_touch();
Ok((address, original_account))
})
.collect::<Result<Vec<_>, _>>()?;
self.commit_iter(&mut transitions.into_iter());
Ok(())
}
fn drain_balances(
&mut self,
addresses: impl IntoIterator<Item = Address>,
) -> Result<Vec<u128>, Self::Error> {
let addresses_iter = addresses.into_iter();
let (lower, _) = addresses_iter.size_hint();
let mut transitions = Vec::with_capacity(lower);
let balances = addresses_iter
.map(|address| {
let mut original_account = match self.basic(address)? {
Some(acc_info) => Account::from(acc_info),
None => Account::new_not_existing(0),
};
let balance = core::mem::take(&mut original_account.info.balance);
original_account.mark_touch();
transitions.push((address, original_account));
Ok(balance.try_into().unwrap())
})
.collect::<Result<Vec<_>, _>>()?;
self.commit_iter(&mut transitions.into_iter());
Ok(balances)
}
}
#[cfg(test)]
mod tests {
use super::*;
struct _DatabaseCommitObjectSafe(dyn DatabaseCommit);
#[test]
fn test_dyn_database_commit() {
use std::collections::HashMap as StdHashMap;
struct MockDb {
commits: Vec<StdHashMap<Address, Account>>,
}
impl DatabaseCommit for MockDb {
fn commit(&mut self, changes: AddressMap<Account>) {
let std_map: StdHashMap<_, _> = changes.into_iter().collect();
self.commits.push(std_map);
}
}
let mut db = MockDb { commits: vec![] };
let items: Vec<(Address, Account)> = vec![];
db.commit_iter(&mut items.into_iter());
assert_eq!(db.commits.len(), 1);
{
let db_dyn: &mut dyn DatabaseCommit = &mut db;
db_dyn.commit(AddressMap::default());
}
assert_eq!(db.commits.len(), 2);
{
let db_dyn: &mut dyn DatabaseCommit = &mut db;
let items: Vec<(Address, Account)> = vec![];
db_dyn.commit_iter(&mut items.into_iter());
}
assert_eq!(db.commits.len(), 3);
{
let db_dyn: &mut dyn DatabaseCommit = &mut db;
db_dyn.commit_from_iter(vec![]);
}
assert_eq!(db.commits.len(), 4);
}
}