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

refactor: rewrite revert and precompile decoding #6222

Merged
merged 11 commits into from
Nov 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
138 changes: 75 additions & 63 deletions Cargo.lock

Large diffs are not rendered by default.

69 changes: 17 additions & 52 deletions crates/anvil/src/eth/backend/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,18 @@ use ethers::{
DefaultFrame, Filter, FilteredParams, GethDebugTracingOptions, GethTrace, Log, OtherFields,
Trace, Transaction, TransactionReceipt, H160,
},
utils::{hex, keccak256, rlp},
utils::{keccak256, rlp},
};
use flate2::{read::GzDecoder, write::GzEncoder, Compression};
use foundry_common::fmt::format_token;
use foundry_evm::{
backend::{DatabaseError, DatabaseResult},
constants::DEFAULT_CREATE2_DEPLOYER_RUNTIME_CODE,
decode::{decode_custom_error_args, decode_revert},
decode::decode_revert,
inspectors::AccessListTracer,
revm::{
self,
db::CacheDB,
interpreter::{return_ok, InstructionResult},
interpreter::InstructionResult,
primitives::{
Account, BlockEnv, CreateScheme, EVMError, Env, ExecutionResult, InvalidHeader, Output,
SpecId, TransactTo, TxEnv, KECCAK_EMPTY,
Expand Down Expand Up @@ -285,7 +284,7 @@ impl Backend {
fork_genesis_infos.clear();

for res in genesis_accounts {
let (address, mut info) = res??;
let (address, mut info) = res.map_err(DatabaseError::display)??;
info.balance = self.genesis.balance;
db.insert_account(address, info.clone());

Expand Down Expand Up @@ -910,54 +909,20 @@ impl Backend {
// insert all transactions
for (info, receipt) in transactions.into_iter().zip(receipts) {
// log some tx info
{
node_info!(" Transaction: {:?}", info.transaction_hash);
if let Some(ref contract) = info.contract_address {
node_info!(" Contract created: {:?}", contract);
}
node_info!(" Gas used: {}", receipt.gas_used());
match info.exit {
return_ok!() => (),
InstructionResult::OutOfFund => {
node_info!(" Error: reverted due to running out of funds");
}
InstructionResult::CallTooDeep => {
node_info!(" Error: reverted with call too deep");
}
InstructionResult::Revert => {
if let Some(ref r) = info.out {
if let Ok(reason) = decode_revert(r.as_ref(), None, None) {
node_info!(" Error: reverted with '{}'", reason);
} else {
match decode_custom_error_args(r, 5) {
// assuming max 5 args
Some(token) => {
node_info!(
" Error: reverted with custom error: {:?}",
format_token(&token)
);
}
None => {
node_info!(
" Error: reverted with custom error: {}",
hex::encode(r)
);
}
}
}
} else {
node_info!(" Error: reverted without a reason");
}
}
InstructionResult::OutOfGas => {
node_info!(" Error: ran out of gas");
}
reason => {
node_info!(" Error: failed due to {:?}", reason);
}
}
node_info!("");
node_info!(" Transaction: {:?}", info.transaction_hash);
if let Some(contract) = &info.contract_address {
node_info!(" Contract created: {contract:?}");
}
node_info!(" Gas used: {}", receipt.gas_used());
if !info.exit.is_ok() {
let r = decode_revert(
info.out.as_deref().unwrap_or_default(),
None,
Some(info.exit),
);
node_info!(" Error: reverted with: {r}");
}
node_info!("");

let mined_tx = MinedTransaction {
info,
Expand Down
1 change: 0 additions & 1 deletion crates/cast/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ alloy-dyn-abi.workspace = true
foundry-compilers = { workspace = true, default-features = false }
foundry-block-explorers = { workspace = true }


chrono.workspace = true
evm-disassembler = "0.3"
eyre.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion crates/config/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ pub fn get_available_profiles(toml_path: impl AsRef<Path>) -> eyre::Result<Vec<S
let doc = read_toml(toml_path)?;

if let Some(Item::Table(profiles)) = doc.as_table().get(Config::PROFILE_SECTION) {
for (profile, _) in profiles.iter() {
for (profile, _) in profiles {
let p = profile.to_string();
if !result.contains(&p) {
result.push(p);
Expand Down
2 changes: 1 addition & 1 deletion crates/evm/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ repository.workspace = true

[dependencies]
foundry-abi.workspace = true
foundry-cheatcodes-defs.workspace = true
foundry-common.workspace = true
foundry-compilers.workspace = true
foundry-config.workspace = true
Expand Down Expand Up @@ -53,5 +54,4 @@ once_cell = "1"

# Misc
url = "2"
auto_impl = "1"
itertools.workspace = true
32 changes: 16 additions & 16 deletions crates/evm/core/src/abi/mod.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
//! Several ABI-related utilities for executors.

use once_cell::sync::Lazy;
use std::collections::HashMap;

pub use foundry_abi::{
console::{self, ConsoleEvents, CONSOLE_ABI},
hardhat_console::{self, HardhatConsoleCalls, HARDHATCONSOLE_ABI as HARDHAT_CONSOLE_ABI},
console::{ConsoleEvents, CONSOLE_ABI},
hardhat_console::{HardhatConsoleCalls, HARDHATCONSOLE_ABI as HARDHAT_CONSOLE_ABI},
hevm::HEVM_ABI,
};
use once_cell::sync::Lazy;
use std::collections::HashMap;

/// If the input starts with a known `hardhat/console.log` `uint` selector, then this will replace
/// it with the selector `abigen!` bindings expect.
pub fn patch_hardhat_console_selector(input: &mut Vec<u8>) {
if input.len() < 4 {
return
}
let selector = unsafe { &mut *(input.get_unchecked_mut(..4) as *mut [u8] as *mut [u8; 4]) };
if let Some(abigen_selector) = HARDHAT_CONSOLE_SELECTOR_PATCHES.get(selector) {
*selector = *abigen_selector;
pub fn patch_hardhat_console_selector(input: &mut [u8]) {
if let Some(selector) = input.get_mut(..4) {
let selector: &mut [u8; 4] = selector.try_into().unwrap();
if let Some(generated_selector) = HARDHAT_CONSOLE_SELECTOR_PATCHES.get(selector) {
*selector = *generated_selector;
}
}
}

Expand All @@ -27,7 +27,7 @@ pub fn patch_hardhat_console_selector(input: &mut Vec<u8>) {
/// bindings which `abigen!` creates. `hardhat/console.log` logs its events in functions that accept
/// `uint` manually as `abi.encodeWithSignature("log(int)", p0)`, but `abigen!` uses `uint256` for
/// its call bindings (`HardhatConsoleCalls`) as generated by solc.
pub static HARDHAT_CONSOLE_SELECTOR_PATCHES: Lazy<HashMap<[u8; 4], [u8; 4]>> = Lazy::new(|| {
static HARDHAT_CONSOLE_SELECTOR_PATCHES: Lazy<HashMap<[u8; 4], [u8; 4]>> = Lazy::new(|| {
HashMap::from([
// log(bool,uint256,uint256,address)
([241, 97, 178, 33], [0, 221, 135, 185]),
Expand Down Expand Up @@ -545,11 +545,11 @@ mod tests {
use super::*;

#[test]
fn hardhat_console_path_works() {
for (hh, abigen) in HARDHAT_CONSOLE_SELECTOR_PATCHES.iter() {
let mut hh = (*hh).to_vec();
fn hardhat_console_patch() {
for (hh, generated) in HARDHAT_CONSOLE_SELECTOR_PATCHES.iter() {
let mut hh = *hh;
patch_hardhat_console_selector(&mut hh);
assert_eq!((*abigen).to_vec(), hh);
assert_eq!(hh, *generated);
}
}
}
1 change: 0 additions & 1 deletion crates/evm/core/src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ const GLOBAL_FAILURE_SLOT: B256 =
b256!("6661696c65640000000000000000000000000000000000000000000000000000");

/// An extension trait that allows us to easily extend the `revm::Inspector` capabilities
#[auto_impl::auto_impl(&mut, Box)]
pub trait DatabaseExt: Database<Error = DatabaseError> {
/// Creates a new snapshot at the current point of execution.
///
Expand Down
11 changes: 6 additions & 5 deletions crates/evm/core/src/debug.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{abi::HEVM_ABI, utils::CallKind};
use crate::utils::CallKind;
use alloy_primitives::{Address, U256};
use revm::interpreter::{Memory, OpCode};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -178,11 +178,12 @@ impl Display for Instruction {
Instruction::Cheatcode(cheat) => write!(
f,
"VM_{}",
&*HEVM_ABI
.functions()
.find(|func| func.short_signature() == *cheat)
foundry_cheatcodes_defs::Vm::CHEATCODES
.iter()
.map(|c| &c.func)
.find(|c| c.selector_bytes == *cheat)
.expect("unknown cheatcode found in debugger")
.name
.id
.to_uppercase()
),
}
Expand Down
Loading