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

fix: revm breaking changes #2967

Merged
merged 18 commits into from
Sep 5, 2022
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
8 changes: 5 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,5 @@ debug = 0
#ethers-solc = { path = "../ethers-rs/ethers-solc" }

[patch.crates-io]
#revm = { path = "../../revm/crates/revm" }
revm = { git = "https://github.com/onbjerg/revm", branch = "onbjerg/bytecode-hash" }
#revm = { path = "../revm/crates/revm" }
revm = { git = "https://github.com/bluealloy/revm" }
23 changes: 13 additions & 10 deletions anvil/src/eth/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ use ethers::{
};
use forge::{executor::DatabaseRef, revm::BlockEnv};
use foundry_common::ProviderBuilder;
use foundry_evm::revm::{return_ok, return_revert, Return};
use foundry_evm::{
executor::backend::DatabaseError,
revm::{return_ok, return_revert, Return},
};
use futures::channel::mpsc::Receiver;
use parking_lot::RwLock;
use std::{sync::Arc, time::Duration};
Expand Down Expand Up @@ -749,7 +752,7 @@ impl EthApi {
// pre-validate
self.backend.validate_pool_transaction(&pending_transaction).await?;

let on_chain_nonce = self.backend.current_nonce(*pending_transaction.sender()).await;
let on_chain_nonce = self.backend.current_nonce(*pending_transaction.sender()).await?;
let from = *pending_transaction.sender();
let nonce = *pending_transaction.transaction.nonce();
let requires = required_marker(nonce, on_chain_nonce, from);
Expand Down Expand Up @@ -784,7 +787,7 @@ impl EthApi {
if fork.predates_fork(number.as_u64()) {
if overrides.is_some() {
return Err(BlockchainError::StateOverrideError(
"not available on past forked blocks".into(),
"not available on past forked blocks".to_string(),
))
}
return Ok(fork.call(&request, Some(number.into())).await?)
Expand Down Expand Up @@ -1238,7 +1241,7 @@ impl EthApi {
/// Handler for ETH RPC call: `anvil_impersonateAccount`
pub async fn anvil_impersonate_account(&self, address: Address) -> Result<()> {
node_info!("anvil_impersonateAccount");
self.backend.impersonate(address).await;
self.backend.impersonate(address).await?;
Ok(())
}

Expand All @@ -1247,7 +1250,7 @@ impl EthApi {
/// Handler for ETH RPC call: `anvil_stopImpersonatingAccount`
pub async fn anvil_stop_impersonating_account(&self, address: Address) -> Result<()> {
node_info!("anvil_stopImpersonatingAccount");
self.backend.stop_impersonating(address).await;
self.backend.stop_impersonating(address).await?;
Ok(())
}

Expand Down Expand Up @@ -1339,7 +1342,7 @@ impl EthApi {
/// Handler for RPC call: `anvil_setBalance`
pub async fn anvil_set_balance(&self, address: Address, balance: U256) -> Result<()> {
node_info!("anvil_setBalance");
self.backend.set_balance(address, balance).await;
self.backend.set_balance(address, balance).await?;
Ok(())
}

Expand All @@ -1348,7 +1351,7 @@ impl EthApi {
/// Handler for RPC call: `anvil_setCode`
pub async fn anvil_set_code(&self, address: Address, code: Bytes) -> Result<()> {
node_info!("anvil_setCode");
self.backend.set_code(address, code).await;
self.backend.set_code(address, code).await?;
Ok(())
}

Expand All @@ -1357,7 +1360,7 @@ impl EthApi {
/// Handler for RPC call: `anvil_setNonce`
pub async fn anvil_set_nonce(&self, address: Address, nonce: U256) -> Result<()> {
node_info!("anvil_setNonce");
self.backend.set_nonce(address, nonce).await;
self.backend.set_nonce(address, nonce).await?;
Ok(())
}

Expand All @@ -1371,7 +1374,7 @@ impl EthApi {
val: H256,
) -> Result<bool> {
node_info!("anvil_setStorageAt");
self.backend.set_storage_at(address, slot, val).await;
self.backend.set_storage_at(address, slot, val).await?;
Ok(true)
}

Expand Down Expand Up @@ -1723,7 +1726,7 @@ impl EthApi {
block_env: BlockEnv,
) -> Result<U256>
where
D: DatabaseRef,
D: DatabaseRef<Error = DatabaseError>,
{
// call takes at least this amount
const MIN_GAS: U256 = U256([21_000, 0, 0, 0]);
Expand Down
66 changes: 39 additions & 27 deletions anvil/src/eth/backend/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use ethers::{
use forge::revm::KECCAK_EMPTY;
use foundry_evm::{
executor::{
backend::{snapshot::StateSnapshot, MemDb},
backend::{snapshot::StateSnapshot, DatabaseError, DatabaseResult, MemDb},
DatabaseRef,
},
revm::{
Expand All @@ -21,14 +21,14 @@ use foundry_evm::{
};
use hash_db::HashDB;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::fmt;

/// Type alias for the `HashDB` representation of the Database
pub type AsHashDB = Box<dyn HashDB<KeccakHasher, Vec<u8>>>;

/// Helper trait get access to the data in `HashDb` form
#[auto_impl::auto_impl(Box)]
pub trait MaybeHashDatabase: DatabaseRef {
pub trait MaybeHashDatabase: DatabaseRef<Error = DatabaseError> {
/// Return the DB as read-only hashdb and the root key
fn maybe_as_hash_db(&self) -> Option<(AsHashDB, H256)> {
None
Expand All @@ -47,7 +47,7 @@ pub trait MaybeHashDatabase: DatabaseRef {

impl<'a, T: 'a + MaybeHashDatabase + ?Sized> MaybeHashDatabase for &'a T
where
&'a T: DatabaseRef,
&'a T: DatabaseRef<Error = DatabaseError>,
{
fn maybe_as_hash_db(&self) -> Option<(AsHashDB, H256)> {
T::maybe_as_hash_db(self)
Expand All @@ -64,27 +64,37 @@ where
}

/// This bundles all required revm traits
pub trait Db: DatabaseRef + Database + DatabaseCommit + MaybeHashDatabase + Send + Sync {
pub trait Db:
DatabaseRef<Error = DatabaseError>
+ Database<Error = DatabaseError>
+ DatabaseCommit
+ MaybeHashDatabase
+ fmt::Debug
+ Send
+ Sync
{
/// Inserts an account
fn insert_account(&mut self, address: Address, account: AccountInfo);

/// Sets the nonce of the given address
fn set_nonce(&mut self, address: Address, nonce: u64) {
let mut info = self.basic(address);
fn set_nonce(&mut self, address: Address, nonce: u64) -> DatabaseResult<()> {
let mut info = self.basic(address)?.unwrap_or_default();
info.nonce = nonce;
self.insert_account(address, info);
Ok(())
}

/// Sets the balance of the given address
fn set_balance(&mut self, address: Address, balance: U256) {
let mut info = self.basic(address);
fn set_balance(&mut self, address: Address, balance: U256) -> DatabaseResult<()> {
let mut info = self.basic(address)?.unwrap_or_default();
info.balance = balance;
self.insert_account(address, info);
Ok(())
}

/// Sets the balance of the given address
fn set_code(&mut self, address: Address, code: Bytes) {
let mut info = self.basic(address);
fn set_code(&mut self, address: Address, code: Bytes) -> DatabaseResult<()> {
let mut info = self.basic(address)?.unwrap_or_default();
let code_hash = if code.as_ref().is_empty() {
KECCAK_EMPTY
} else {
Expand All @@ -93,19 +103,20 @@ pub trait Db: DatabaseRef + Database + DatabaseCommit + MaybeHashDatabase + Send
info.code_hash = code_hash;
info.code = Some(Bytecode::new_raw(code.0).to_checked());
self.insert_account(address, info);
Ok(())
}

/// Sets the balance of the given address
fn set_storage_at(&mut self, address: Address, slot: U256, val: U256);
fn set_storage_at(&mut self, address: Address, slot: U256, val: U256) -> DatabaseResult<()>;

/// inserts a blockhash for the given number
fn insert_block_hash(&mut self, number: U256, hash: H256);

/// Write all chain data to serialized bytes buffer
fn dump_state(&self) -> Option<SerializableState>;
fn dump_state(&self) -> DatabaseResult<Option<SerializableState>>;

/// Deserialize and add all chain data to the backend storage
fn load_state(&mut self, buf: SerializableState) -> bool;
fn load_state(&mut self, buf: SerializableState) -> DatabaseResult<bool>;

/// Creates a new snapshot
fn snapshot(&mut self) -> U256;
Expand All @@ -128,25 +139,25 @@ pub trait Db: DatabaseRef + Database + DatabaseCommit + MaybeHashDatabase + Send
/// This is useful to create blocks without actually writing to the `Db`, but rather in the cache of
/// the `CacheDB` see also
/// [Backend::pending_block()](crate::eth::backend::mem::Backend::pending_block())
impl<T: DatabaseRef + Send + Sync + Clone> Db for CacheDB<T> {
impl<T: DatabaseRef<Error = DatabaseError> + Send + Sync + Clone + fmt::Debug> Db for CacheDB<T> {
fn insert_account(&mut self, address: Address, account: AccountInfo) {
self.insert_account_info(address, account)
}

fn set_storage_at(&mut self, address: Address, slot: U256, val: U256) {
fn set_storage_at(&mut self, address: Address, slot: U256, val: U256) -> DatabaseResult<()> {
self.insert_account_storage(address, slot, val)
}

fn insert_block_hash(&mut self, number: U256, hash: H256) {
self.block_hashes.insert(number, hash);
}

fn dump_state(&self) -> Option<SerializableState> {
None
fn dump_state(&self) -> DatabaseResult<Option<SerializableState>> {
Ok(None)
}

fn load_state(&mut self, _buf: SerializableState) -> bool {
false
fn load_state(&mut self, _buf: SerializableState) -> DatabaseResult<bool> {
Ok(false)
}

fn snapshot(&mut self) -> U256 {
Expand All @@ -162,14 +173,14 @@ impl<T: DatabaseRef + Send + Sync + Clone> Db for CacheDB<T> {
}
}

impl<T: DatabaseRef> MaybeHashDatabase for CacheDB<T> {
impl<T: DatabaseRef<Error = DatabaseError>> MaybeHashDatabase for CacheDB<T> {
fn maybe_as_hash_db(&self) -> Option<(AsHashDB, H256)> {
Some(trie_hash_db(&self.accounts))
}
fn clear_into_snapshot(&mut self) -> StateSnapshot {
let db_accounts = std::mem::take(&mut self.accounts);
let mut accounts = BTreeMap::new();
let mut account_storage = BTreeMap::new();
let mut accounts = HashMap::new();
let mut account_storage = HashMap::new();

for (addr, mut acc) in db_accounts {
account_storage.insert(addr, std::mem::take(&mut acc.storage));
Expand Down Expand Up @@ -213,19 +224,20 @@ impl StateDb {
}

impl DatabaseRef for StateDb {
fn basic(&self, address: H160) -> AccountInfo {
type Error = DatabaseError;
fn basic(&self, address: H160) -> DatabaseResult<Option<AccountInfo>> {
self.0.basic(address)
}

fn code_by_hash(&self, code_hash: H256) -> Bytecode {
fn code_by_hash(&self, code_hash: H256) -> DatabaseResult<Bytecode> {
self.0.code_by_hash(code_hash)
}

fn storage(&self, address: H160, index: U256) -> U256 {
fn storage(&self, address: H160, index: U256) -> DatabaseResult<U256> {
self.0.storage(address, index)
}

fn block_hash(&self, number: U256) -> H256 {
fn block_hash(&self, number: U256) -> DatabaseResult<H256> {
self.0.block_hash(number)
}
}
Expand Down
15 changes: 14 additions & 1 deletion anvil/src/eth/backend/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use ethers::{
};
use forge::revm::ExecutionResult;
use foundry_evm::{
executor::backend::DatabaseError,
revm,
revm::{BlockEnv, CfgEnv, Env, Return, SpecId, TransactOut},
trace::{node::CallTraceNode, CallTraceArena},
Expand Down Expand Up @@ -132,6 +133,12 @@ impl<'a, DB: Db + ?Sized, Validator: TransactionValidator> TransactionExecutor<'
invalid.push(tx);
continue
}
TransactionExecutionOutcome::DatabaseError(_, err) => {
// Note: this is only possible in forking mode, if for example a rpc request
// failed
trace!(target: "backend", ?err, "Failed to execute transaction due to database error");
continue
}
};
let receipt = tx.create_receipt();
cumulative_gas_used = cumulative_gas_used.saturating_add(receipt.gas_used());
Expand Down Expand Up @@ -206,6 +213,8 @@ pub enum TransactionExecutionOutcome {
Invalid(Arc<PoolTransaction>, InvalidTransactionError),
/// Execution skipped because could exceed gas limit
Exhausted(Arc<PoolTransaction>),
/// When an error occurred during execution
DatabaseError(Arc<PoolTransaction>, DatabaseError),
}

impl<'a, 'b, DB: Db + ?Sized, Validator: TransactionValidator> Iterator
Expand All @@ -215,7 +224,11 @@ impl<'a, 'b, DB: Db + ?Sized, Validator: TransactionValidator> Iterator

fn next(&mut self) -> Option<Self::Item> {
let transaction = self.pending.next()?;
let account = self.db.basic(*transaction.pending_transaction.sender());
let sender = *transaction.pending_transaction.sender();
let account = match self.db.basic(sender).map(|acc| acc.unwrap_or_default()) {
Ok(account) => account,
Err(err) => return Some(TransactionExecutionOutcome::DatabaseError(transaction, err)),
};
let env = self.env_for(&transaction.pending_transaction);
// check that we comply with the block's gas limit
let max_gas = self.gas_used.saturating_add(U256::from(env.tx.gas_limit));
Expand Down
10 changes: 7 additions & 3 deletions anvil/src/eth/backend/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use ethers::{
types::{Address, U256},
};
use forge::revm::KECCAK_EMPTY;
use foundry_evm::revm::AccountInfo;
use foundry_evm::{executor::backend::DatabaseResult, revm::AccountInfo};
use parking_lot::Mutex;
use std::sync::Arc;
use tokio::sync::RwLockWriteGuard;
Expand Down Expand Up @@ -47,17 +47,21 @@ impl GenesisConfig {
}

/// If an initial `genesis.json` was provided, this applies the account alloc to the db
pub fn apply_genesis_json_alloc(&self, mut db: RwLockWriteGuard<'_, dyn Db>) {
pub fn apply_genesis_json_alloc(
&self,
mut db: RwLockWriteGuard<'_, dyn Db>,
) -> DatabaseResult<()> {
if let Some(ref genesis) = self.genesis_init {
for (addr, mut acc) in genesis.alloc.accounts.clone() {
let storage = std::mem::take(&mut acc.storage);
// insert all accounts
db.insert_account(addr, acc.into());
// insert all storage values
for (k, v) in storage.iter() {
db.set_storage_at(addr, k.into_uint(), v.into_uint());
db.set_storage_at(addr, k.into_uint(), v.into_uint())?;
}
}
}
Ok(())
}
}
Loading