Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: implement Default for other databases #691

Merged
merged 2 commits into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crates/interpreter/src/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ impl Gas {
true
}

#[inline]
#[deprecated = "Use `record_refund` instead"]
#[doc(hidden)]
#[deprecated = "use `record_refund` instead"]
#[inline]
pub fn gas_refund(&mut self, refund: i64) {
self.record_refund(refund);
}
Expand Down
26 changes: 18 additions & 8 deletions crates/primitives/src/db.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
pub mod components;

use crate::AccountInfo;
use crate::U256;
use crate::{Account, Bytecode};
use crate::{B160, B256};
use auto_impl::auto_impl;
use hashbrown::HashMap as Map;

pub mod components;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this style and not moving pub used componnets behind pub mod?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there's a style guide for this, but I like when it's mod x; use x::*; groups, like: https://github.com/alloy-rs/core/blob/d9d0ded3ca4e2dde992dad1afe6410015158d6b1/crates/syn-solidity/src/lib.rs

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer a little bit of a different order.

// use if needed. or maybe even put reexports.
use std::..

// list all modules in one place
mod components;
mod tests;

// reexport module items here.
pub use components::*

Something like this is easier to my eyes: https://github.com/bluealloy/revm/blob/main/crates/revm/src/db/states.rs
having mod * grouped together.

Just bikesheding, this change in general is nice

pub use components::{
BlockHash, BlockHashRef, DatabaseComponentError, DatabaseComponents, State, StateRef,
};

/// EVM database interface.
#[auto_impl(&mut, Box)]
pub trait Database {
type Error;

/// Get basic account information.
fn basic(&mut self, address: B160) -> Result<Option<AccountInfo>, Self::Error>;
/// Get account code by its hash

/// Get account code by its hash.
fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error>;

/// Get storage value of address at index.
fn storage(&mut self, address: B160, index: U256) -> Result<U256, Self::Error>;

// History related
/// Get block hash by block number.
fn block_hash(&mut self, number: U256) -> Result<B256, Self::Error>;
}

Expand All @@ -36,39 +39,46 @@ pub trait DatabaseCommit {
fn commit(&mut self, changes: Map<B160, Account>);
}

/// Same as [Database], but uses immutable references.
#[auto_impl(&, Box, Arc)]
pub trait DatabaseRef {
type Error;
/// Whether account at address exists.
//fn exists(&self, address: B160) -> Option<AccountInfo>;

/// Get basic account information.
fn basic(&self, address: B160) -> Result<Option<AccountInfo>, Self::Error>;
/// Get account code by its hash

/// Get account code by its hash.
fn code_by_hash(&self, code_hash: B256) -> Result<Bytecode, Self::Error>;

/// Get storage value of address at index.
fn storage(&self, address: B160, index: U256) -> Result<U256, Self::Error>;

// History related
/// Get block hash by block number.
fn block_hash(&self, number: U256) -> Result<B256, Self::Error>;
}

/// Wraps a [`DatabaseRef`] to provide a [`Database`] implementation.
pub struct WrapDatabaseRef<T: DatabaseRef>(pub T);

impl<T: DatabaseRef> Database for WrapDatabaseRef<T> {
type Error = T::Error;

#[inline]
fn basic(&mut self, address: B160) -> Result<Option<AccountInfo>, Self::Error> {
self.0.basic(address)
}

#[inline]
fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
self.0.code_by_hash(code_hash)
}

#[inline]
fn storage(&mut self, address: B160, index: U256) -> Result<U256, Self::Error> {
self.0.storage(address, index)
}

#[inline]
fn block_hash(&mut self, number: U256) -> Result<B256, Self::Error> {
self.0.block_hash(number)
}
Expand Down
80 changes: 53 additions & 27 deletions crates/revm/src/db/emptydb.rs
Original file line number Diff line number Diff line change
@@ -1,80 +1,106 @@
use core::{convert::Infallible, marker::PhantomData};
use core::{convert::Infallible, fmt, marker::PhantomData};
use revm_interpreter::primitives::{
db::{Database, DatabaseRef},
keccak256, AccountInfo, Bytecode, B160, B256, U256,
AccountInfo, Bytecode, B160, B256, U256,
};

/// An empty database that always returns default values when queried.
pub type EmptyDB = EmptyDBTyped<Infallible>;

impl Default for EmptyDB {
/// An empty database that always returns default values when queried.
///
/// This is generic over a type which is used as the database error type.
pub struct EmptyDBTyped<E> {
_phantom: PhantomData<E>,
}

// Don't derive traits, because the type parameter is unused.
impl<E> Clone for EmptyDBTyped<E> {
fn clone(&self) -> Self {
*self
}
}

impl<E> Copy for EmptyDBTyped<E> {}

impl<E> Default for EmptyDBTyped<E> {
fn default() -> Self {
Self {
keccak_block_hash: false,
_phantom: PhantomData,
}
Self::new()
}
}

/// An empty database that always returns default values when queried.
#[derive(Debug, Clone)]
pub struct EmptyDBTyped<T> {
pub keccak_block_hash: bool,
pub _phantom: PhantomData<T>,
impl<E> fmt::Debug for EmptyDBTyped<E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EmptyDB").finish_non_exhaustive()
}
}

impl<E> PartialEq for EmptyDBTyped<E> {
fn eq(&self, _: &Self) -> bool {
true
}
}

impl<T> EmptyDBTyped<T> {
impl<E> Eq for EmptyDBTyped<E> {}

impl<E> EmptyDBTyped<E> {
pub fn new() -> Self {
Self {
keccak_block_hash: false,
_phantom: PhantomData,
}
}

#[doc(hidden)]
#[deprecated = "use `new` instead"]
pub fn new_keccak_block_hash() -> Self {
Self {
keccak_block_hash: true,
_phantom: PhantomData,
}
Self::new()
}
}

impl<T> Database for EmptyDBTyped<T> {
type Error = T;
impl<E> Database for EmptyDBTyped<E> {
type Error = E;

#[inline]
fn basic(&mut self, address: B160) -> Result<Option<AccountInfo>, Self::Error> {
<Self as DatabaseRef>::basic(self, address)
}

#[inline]
fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
<Self as DatabaseRef>::code_by_hash(self, code_hash)
}

#[inline]
fn storage(&mut self, address: B160, index: U256) -> Result<U256, Self::Error> {
<Self as DatabaseRef>::storage(self, address, index)
}

#[inline]
fn block_hash(&mut self, number: U256) -> Result<B256, Self::Error> {
<Self as DatabaseRef>::block_hash(self, number)
}
}

impl<T> DatabaseRef for EmptyDBTyped<T> {
type Error = T;
/// Get basic account information.
impl<E> DatabaseRef for EmptyDBTyped<E> {
type Error = E;

#[inline]
fn basic(&self, _address: B160) -> Result<Option<AccountInfo>, Self::Error> {
Ok(None)
}
/// Get account code by its hash

#[inline]
fn code_by_hash(&self, _code_hash: B256) -> Result<Bytecode, Self::Error> {
Ok(Bytecode::new())
}
/// Get storage value of address at index.
DaniPopes marked this conversation as resolved.
Show resolved Hide resolved

#[inline]
fn storage(&self, _address: B160, _index: U256) -> Result<U256, Self::Error> {
Ok(U256::default())
}

// History related
#[inline]
fn block_hash(&self, number: U256) -> Result<B256, Self::Error> {
Ok(keccak256(&number.to_be_bytes::<{ U256::BYTES }>()))
Ok(number.to_be_bytes().into())
}
DaniPopes marked this conversation as resolved.
Show resolved Hide resolved
}
20 changes: 5 additions & 15 deletions crates/revm/src/db/ethersdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,13 @@ use ethers_providers::Middleware;
use std::sync::Arc;
use tokio::runtime::{Handle, Runtime};

pub struct EthersDB<M>
where
M: Middleware,
{
pub struct EthersDB<M: Middleware> {
client: Arc<M>,
runtime: Option<Runtime>,
block_number: Option<BlockId>,
}

impl<M> EthersDB<M>
where
M: Middleware,
{
impl<M: Middleware> EthersDB<M> {
/// create ethers db connector inputs are url and block on what we are basing our database (None for latest)
pub fn new(client: Arc<M>, block_number: Option<BlockId>) -> Option<Self> {
let runtime = Handle::try_current()
Expand Down Expand Up @@ -52,10 +46,7 @@ where
}
}

impl<M> Database for EthersDB<M>
where
M: Middleware,
{
impl<M: Middleware> Database for EthersDB<M> {
type Error = ();

fn basic(&mut self, address: B160) -> Result<Option<AccountInfo>, Self::Error> {
Expand Down Expand Up @@ -124,14 +115,13 @@ where
}
}

/// Run tests with `cargo test -- --nocapture` to see print statements
// Run tests with `cargo test -- --nocapture` to see print statements
#[cfg(test)]
mod tests {
use std::str::FromStr;

use super::*;
use ethers_core::types::U256 as eU256;
use ethers_providers::{Http, Provider};
use std::str::FromStr;

#[test]
fn can_get_basic() {
Expand Down
27 changes: 9 additions & 18 deletions crates/revm/src/db/in_memory_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,9 @@ use crate::Database;
use alloc::vec::Vec;
use core::convert::Infallible;

/// A [Database] implementation that stores all state changes in memory.
pub type InMemoryDB = CacheDB<EmptyDB>;

impl Default for InMemoryDB {
fn default() -> Self {
CacheDB::new(EmptyDB {
keccak_block_hash: true,
_phantom: core::marker::PhantomData,
})
}
}

/// A [Database] implementation that stores all state changes in memory.
///
/// This implementation wraps a [DatabaseRef] that is used to load data ([AccountInfo]).
Expand All @@ -41,6 +33,12 @@ pub struct CacheDB<ExtDB: DatabaseRef> {
pub db: ExtDB,
}

impl<ExtDB: DatabaseRef + Default> Default for CacheDB<ExtDB> {
rakita marked this conversation as resolved.
Show resolved Hide resolved
fn default() -> Self {
Self::new(ExtDB::default())
}
}

impl<ExtDB: DatabaseRef> CacheDB<ExtDB> {
pub fn new(db: ExtDB) -> Self {
let mut contracts = HashMap::new();
Expand Down Expand Up @@ -302,6 +300,7 @@ impl DbAccount {
..Default::default()
}
}

pub fn info(&self) -> Option<AccountInfo> {
if matches!(self.account_state, AccountState::NotExisting) {
None
Expand All @@ -313,15 +312,7 @@ impl DbAccount {

impl From<Option<AccountInfo>> for DbAccount {
fn from(from: Option<AccountInfo>) -> Self {
if let Some(info) = from {
Self {
info,
account_state: AccountState::None,
..Default::default()
}
} else {
Self::new_not_existing()
}
from.map(Self::from).unwrap_or_else(Self::new_not_existing)
}
}

Expand Down
8 changes: 4 additions & 4 deletions crates/revm/src/db/states/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ mod tests {
states::reverts::AccountInfoRevert, AccountRevert, AccountStatus, BundleAccount,
RevertToSlot,
};
use revm_interpreter::primitives::{keccak256, StorageSlot};
use revm_interpreter::primitives::StorageSlot;

#[test]
fn block_hash_cache() {
Expand All @@ -305,9 +305,9 @@ mod tests {

let test_number = BLOCK_HASH_HISTORY as u64 + 2;

let block1_hash = keccak256(&U256::from(1).to_be_bytes::<{ U256::BYTES }>());
let block2_hash = keccak256(&U256::from(2).to_be_bytes::<{ U256::BYTES }>());
let block_test_hash = keccak256(&U256::from(test_number).to_be_bytes::<{ U256::BYTES }>());
let block1_hash = B256::from(U256::from(1).to_be_bytes());
let block2_hash = B256::from(U256::from(2).to_be_bytes());
let block_test_hash = B256::from(U256::from(test_number).to_be_bytes());

assert_eq!(
state.block_hashes,
Expand Down