foundry_evm_core/backend/
in_memory_db.rsuse crate::state_snapshot::StateSnapshots;
use alloy_primitives::{Address, B256, U256};
use foundry_fork_db::DatabaseError;
use revm::{
db::{CacheDB, DatabaseRef, EmptyDB},
primitives::{Account, AccountInfo, Bytecode, HashMap as Map},
Database, DatabaseCommit,
};
pub type FoundryEvmInMemoryDB = CacheDB<EmptyDBWrapper>;
#[derive(Debug)]
pub struct MemDb {
pub inner: FoundryEvmInMemoryDB,
pub state_snapshots: StateSnapshots<FoundryEvmInMemoryDB>,
}
impl Default for MemDb {
fn default() -> Self {
Self { inner: CacheDB::new(Default::default()), state_snapshots: Default::default() }
}
}
impl DatabaseRef for MemDb {
type Error = DatabaseError;
fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
DatabaseRef::basic_ref(&self.inner, address)
}
fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
DatabaseRef::code_by_hash_ref(&self.inner, code_hash)
}
fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
DatabaseRef::storage_ref(&self.inner, address, index)
}
fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
DatabaseRef::block_hash_ref(&self.inner, number)
}
}
impl Database for MemDb {
type Error = DatabaseError;
fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
Database::basic(&mut self.inner, address)
}
fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
Database::code_by_hash(&mut self.inner, code_hash)
}
fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
Database::storage(&mut self.inner, address, index)
}
fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
Database::block_hash(&mut self.inner, number)
}
}
impl DatabaseCommit for MemDb {
fn commit(&mut self, changes: Map<Address, Account>) {
DatabaseCommit::commit(&mut self.inner, changes)
}
}
#[derive(Clone, Debug, Default)]
pub struct EmptyDBWrapper(EmptyDB);
impl DatabaseRef for EmptyDBWrapper {
type Error = DatabaseError;
fn basic_ref(&self, _address: Address) -> Result<Option<AccountInfo>, Self::Error> {
Ok(Some(AccountInfo::default()))
}
fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
Ok(self.0.code_by_hash_ref(code_hash)?)
}
fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
Ok(self.0.storage_ref(address, index)?)
}
fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
Ok(self.0.block_hash_ref(number)?)
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloy_primitives::b256;
#[test]
fn cache_db_insert_basic_non_existing() {
let mut db = CacheDB::new(EmptyDB::default());
let address = Address::random();
let info = Database::basic(&mut db, address).unwrap();
assert!(info.is_none());
let mut info = info.unwrap_or_default();
info.balance = U256::from(500u64);
db.insert_account_info(address, info);
let info = Database::basic(&mut db, address).unwrap();
assert!(info.is_none());
}
#[test]
fn cache_db_insert_basic_default() {
let mut db = CacheDB::new(EmptyDB::default());
let address = Address::random();
let info = DatabaseRef::basic_ref(&db, address).unwrap();
assert!(info.is_none());
let mut info = info.unwrap_or_default();
info.balance = U256::from(500u64);
db.insert_account_info(address, info.clone());
let loaded = Database::basic(&mut db, address).unwrap();
assert!(loaded.is_some());
assert_eq!(loaded.unwrap(), info)
}
#[test]
fn mem_db_insert_basic_default() {
let mut db = MemDb::default();
let address = Address::from_word(b256!(
"000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045"
));
let info = Database::basic(&mut db, address).unwrap();
assert!(info.is_some());
let mut info = info.unwrap();
info.balance = U256::from(500u64);
db.inner.insert_account_info(address, info.clone());
let loaded = Database::basic(&mut db, address).unwrap();
assert!(loaded.is_some());
assert_eq!(loaded.unwrap(), info)
}
}