Skip to content

Commit

Permalink
fix(anvil): Fix AccessList generation (#2839)
Browse files Browse the repository at this point in the history
* chore: latest ethers-solc (bumped up svm versions)

* fix(anvil): Fix AccessList generation

Co-authored-by: Rohit Narurkar <rohit.narurkar@protonmail.com>
  • Loading branch information
ngotchac and roynalnaruto authored Aug 22, 2022
1 parent 7e9e6a5 commit d2cdea0
Show file tree
Hide file tree
Showing 11 changed files with 333 additions and 94 deletions.
34 changes: 19 additions & 15 deletions Cargo.lock

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

2 changes: 0 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,3 @@ debug = 0

[patch.crates-io]
#revm = { path = "../../revm/crates/revm" }
svm-rs = { git = "https://github.com/onbjerg/svm-rs", branch = "onbjerg/linux-aarch-bump" }
svm-rs-builds = { git = "https://github.com/onbjerg/svm-rs", branch = "onbjerg/linux-aarch-bump" }
1 change: 1 addition & 0 deletions anvil/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ ethers = { git = "https://github.com/gakonst/ethers-rs", features = ["ws"] }
trie-db = { version = "0.23" }
hash-db = { version = "0.15" }
memory-db = { version = "0.29" }
revm_precompiles = "1.1.0"

# axum related
axum = { version = "0.5", features = ["ws"] }
Expand Down
64 changes: 28 additions & 36 deletions anvil/src/eth/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use crate::{
},
sign,
sign::Signer,
util::PRECOMPILES,
},
filter::{EthFilter, Filters, LogsFilter},
mem::transaction_build,
Expand All @@ -42,7 +41,7 @@ use ethers::{
providers::ProviderError,
types::{
transaction::{
eip2930::{AccessList, AccessListItem, AccessListWithGasUsed},
eip2930::{AccessList, AccessListWithGasUsed},
eip712::TypedData,
},
Address, Block, BlockId, BlockNumber, Bytes, FeeHistory, Filter, FilteredParams, Log,
Expand All @@ -53,10 +52,7 @@ use ethers::{
};
use forge::{executor::DatabaseRef, revm::BlockEnv};
use foundry_common::ProviderBuilder;
use foundry_evm::{
revm::{return_ok, return_revert, Return},
utils::u256_to_h256_be,
};
use foundry_evm::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 @@ -804,37 +800,33 @@ impl EthApi {
}
}

// ensure tx succeeds
let (exit, out, _, mut state) =
self.backend.call(request.clone(), FeeDetails::zero(), Some(block_request)).await?;

ensure_return_ok(exit, &out)?;

// cleanup state map
if let Some(from) = request.from {
// remove the sender
let _ = state.remove(&from);
}

// remove all precompiles
for precompile in PRECOMPILES.iter() {
let _ = state.remove(precompile);
}

let items = state
.into_iter()
.map(|(address, acc)| {
let storage_keys = acc.storage.into_keys().map(u256_to_h256_be).collect();
AccessListItem { address, storage_keys }
self.backend
.with_database_at(Some(block_request), |state, block_env| {
let (exit, out, _, access_list) = self.backend.build_access_list_with_state(
&state,
request.clone(),
FeeDetails::zero(),
block_env.clone(),
)?;
ensure_return_ok(exit, &out)?;

// execute again but with access list set
request.access_list = Some(access_list.0.clone());

let (exit, out, gas_used, _) = self.backend.call_with_state(
&state,
request.clone(),
FeeDetails::zero(),
block_env,
)?;
ensure_return_ok(exit, &out)?;

Ok(AccessListWithGasUsed {
access_list: AccessList(access_list.0),
gas_used: gas_used.into(),
})
})
.collect::<Vec<_>>();

// execute again but with access list set
request.access_list = Some(items.clone());

let gas_used = self.do_estimate_gas(request, block_number).await?;

Ok(AccessListWithGasUsed { access_list: AccessList(items), gas_used })
.await?
}

/// Estimate gas needed for execution of given contract.
Expand Down
74 changes: 61 additions & 13 deletions anvil/src/eth/backend/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::{
fees::{FeeDetails, FeeManager},
macros::node_info,
pool::transactions::PoolTransaction,
util::get_precompiles_for,
},
mem::{
in_memory_db::MemDb,
Expand All @@ -42,17 +43,20 @@ use ethers::{
abi::ethereum_types::BigEndianHash,
prelude::{BlockNumber, TxHash, H256, U256, U64},
types::{
Address, Block as EthersBlock, BlockId, Bytes, Filter, FilteredParams, Log, Trace,
Transaction, TransactionReceipt,
transaction::eip2930::AccessList, Address, Block as EthersBlock, BlockId, Bytes, Filter,
FilteredParams, Log, Trace, Transaction, TransactionReceipt,
},
utils::{keccak256, rlp},
utils::{get_contract_address, keccak256, rlp},
};
use forge::{
executor::inspector::AccessListTracer,
revm::{return_ok, return_revert, BlockEnv, Return},
};
use forge::revm::{return_ok, return_revert, BlockEnv};
use foundry_evm::{
decode::decode_revert,
revm,
revm::{
db::CacheDB, Account, CreateScheme, Env, Return, SpecId, TransactOut, TransactTo, TxEnv,
db::CacheDB, Account, CreateScheme, Env, SpecId, TransactOut, TransactTo, TxEnv,
KECCAK_EMPTY,
},
utils::u256_to_h256_be,
Expand Down Expand Up @@ -280,6 +284,10 @@ impl Backend {
self.fork.is_some()
}

pub fn precompiles(&self) -> Vec<Address> {
get_precompiles_for(self.env().read().cfg.spec_id)
}

/// Resets the fork to a fresh state
pub async fn reset_fork(&self, forking: Forking) -> Result<(), BlockchainError> {
if let Some(fork) = self.get_fork() {
Expand Down Expand Up @@ -753,16 +761,12 @@ impl Backend {
}).await?
}

pub fn call_with_state<D>(
fn build_call_env(
&self,
state: D,
request: EthTransactionRequest,
fee_details: FeeDetails,
block_env: BlockEnv,
) -> Result<(Return, TransactOut, u64, State), BlockchainError>
where
D: DatabaseRef,
{
) -> Env {
let EthTransactionRequest { from, to, gas, value, data, nonce, access_list, .. } = request;

let FeeDetails { gas_price, max_fee_per_gas, max_priority_fee_per_gas } = fee_details;
Expand All @@ -776,9 +780,10 @@ impl Backend {
}

let gas_price = gas_price.or(max_fee_per_gas).unwrap_or_else(|| self.gas_price());
let caller = from.unwrap_or_default();

env.tx = TxEnv {
caller: from.unwrap_or_default(),
caller,
gas_limit: gas_limit.as_u64(),
gas_price,
gas_priority_fee: max_priority_fee_per_gas,
Expand All @@ -792,16 +797,59 @@ impl Backend {
nonce: nonce.map(|n| n.as_u64()),
access_list: to_access_list(access_list.unwrap_or_default()),
};
env
}

pub fn call_with_state<D>(
&self,
state: D,
request: EthTransactionRequest,
fee_details: FeeDetails,
block_env: BlockEnv,
) -> Result<(Return, TransactOut, u64, State), BlockchainError>
where
D: DatabaseRef,
{
let mut inspector = Inspector::default();
let mut evm = revm::EVM::new();
evm.env = env;
evm.env = self.build_call_env(request, fee_details, block_env);
evm.database(state);
let (exit, out, gas, state, _) = evm.inspect_ref(&mut inspector);
inspector.print_logs();
Ok((exit, out, gas, state))
}

pub fn build_access_list_with_state<D>(
&self,
state: D,
request: EthTransactionRequest,
fee_details: FeeDetails,
block_env: BlockEnv,
) -> Result<(Return, TransactOut, u64, AccessList), BlockchainError>
where
D: DatabaseRef,
{
let from = request.from.unwrap_or_default();
let to = request.to.unwrap_or_else(|| {
let nonce = state.basic(from).nonce;
get_contract_address(from, nonce)
});

let mut tracer = AccessListTracer::new(
AccessList(request.access_list.clone().unwrap_or_default()),
from,
to,
self.precompiles(),
);

let mut evm = revm::EVM::new();
evm.env = self.build_call_env(request, fee_details, block_env);
evm.database(state);
let (exit, out, gas, _, _) = evm.inspect_ref(&mut tracer);
let access_list = tracer.access_list();
Ok((exit, out, gas, access_list))
}

/// returns all receipts for the given transactions
fn get_receipts(&self, tx_hashes: impl IntoIterator<Item = TxHash>) -> Vec<TypedReceipt> {
let storage = self.blockchain.storage.read();
Expand Down
Loading

0 comments on commit d2cdea0

Please sign in to comment.