Skip to content

Commit 63e043e

Browse files
authored
refactor: rewrite revert and precompile decoding (#6222)
* wip * rm ugly ass brute force decoding * improve decoding * decode precompiles * chore: rewrite hardhat console patcher * fixes * chore: clippy * further * addtest
1 parent 6958dc1 commit 63e043e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+652
-683
lines changed

Cargo.lock

+75-63
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/anvil/src/eth/backend/mem/mod.rs

+17-52
Original file line numberDiff line numberDiff line change
@@ -53,19 +53,18 @@ use ethers::{
5353
DefaultFrame, Filter, FilteredParams, GethDebugTracingOptions, GethTrace, Log, OtherFields,
5454
Trace, Transaction, TransactionReceipt, H160,
5555
},
56-
utils::{hex, keccak256, rlp},
56+
utils::{keccak256, rlp},
5757
};
5858
use flate2::{read::GzDecoder, write::GzEncoder, Compression};
59-
use foundry_common::fmt::format_token;
6059
use foundry_evm::{
6160
backend::{DatabaseError, DatabaseResult},
6261
constants::DEFAULT_CREATE2_DEPLOYER_RUNTIME_CODE,
63-
decode::{decode_custom_error_args, decode_revert},
62+
decode::decode_revert,
6463
inspectors::AccessListTracer,
6564
revm::{
6665
self,
6766
db::CacheDB,
68-
interpreter::{return_ok, InstructionResult},
67+
interpreter::InstructionResult,
6968
primitives::{
7069
Account, BlockEnv, CreateScheme, EVMError, Env, ExecutionResult, InvalidHeader, Output,
7170
SpecId, TransactTo, TxEnv, KECCAK_EMPTY,
@@ -285,7 +284,7 @@ impl Backend {
285284
fork_genesis_infos.clear();
286285

287286
for res in genesis_accounts {
288-
let (address, mut info) = res??;
287+
let (address, mut info) = res.map_err(DatabaseError::display)??;
289288
info.balance = self.genesis.balance;
290289
db.insert_account(address, info.clone());
291290

@@ -910,54 +909,20 @@ impl Backend {
910909
// insert all transactions
911910
for (info, receipt) in transactions.into_iter().zip(receipts) {
912911
// log some tx info
913-
{
914-
node_info!(" Transaction: {:?}", info.transaction_hash);
915-
if let Some(ref contract) = info.contract_address {
916-
node_info!(" Contract created: {:?}", contract);
917-
}
918-
node_info!(" Gas used: {}", receipt.gas_used());
919-
match info.exit {
920-
return_ok!() => (),
921-
InstructionResult::OutOfFund => {
922-
node_info!(" Error: reverted due to running out of funds");
923-
}
924-
InstructionResult::CallTooDeep => {
925-
node_info!(" Error: reverted with call too deep");
926-
}
927-
InstructionResult::Revert => {
928-
if let Some(ref r) = info.out {
929-
if let Ok(reason) = decode_revert(r.as_ref(), None, None) {
930-
node_info!(" Error: reverted with '{}'", reason);
931-
} else {
932-
match decode_custom_error_args(r, 5) {
933-
// assuming max 5 args
934-
Some(token) => {
935-
node_info!(
936-
" Error: reverted with custom error: {:?}",
937-
format_token(&token)
938-
);
939-
}
940-
None => {
941-
node_info!(
942-
" Error: reverted with custom error: {}",
943-
hex::encode(r)
944-
);
945-
}
946-
}
947-
}
948-
} else {
949-
node_info!(" Error: reverted without a reason");
950-
}
951-
}
952-
InstructionResult::OutOfGas => {
953-
node_info!(" Error: ran out of gas");
954-
}
955-
reason => {
956-
node_info!(" Error: failed due to {:?}", reason);
957-
}
958-
}
959-
node_info!("");
912+
node_info!(" Transaction: {:?}", info.transaction_hash);
913+
if let Some(contract) = &info.contract_address {
914+
node_info!(" Contract created: {contract:?}");
915+
}
916+
node_info!(" Gas used: {}", receipt.gas_used());
917+
if !info.exit.is_ok() {
918+
let r = decode_revert(
919+
info.out.as_deref().unwrap_or_default(),
920+
None,
921+
Some(info.exit),
922+
);
923+
node_info!(" Error: reverted with: {r}");
960924
}
925+
node_info!("");
961926

962927
let mined_tx = MinedTransaction {
963928
info,

crates/cast/Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ alloy-dyn-abi.workspace = true
3535
foundry-compilers = { workspace = true, default-features = false }
3636
foundry-block-explorers = { workspace = true }
3737

38-
3938
chrono.workspace = true
4039
evm-disassembler = "0.3"
4140
eyre.workspace = true

crates/config/src/utils.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ pub fn get_available_profiles(toml_path: impl AsRef<Path>) -> eyre::Result<Vec<S
203203
let doc = read_toml(toml_path)?;
204204

205205
if let Some(Item::Table(profiles)) = doc.as_table().get(Config::PROFILE_SECTION) {
206-
for (profile, _) in profiles.iter() {
206+
for (profile, _) in profiles {
207207
let p = profile.to_string();
208208
if !result.contains(&p) {
209209
result.push(p);

crates/evm/core/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ repository.workspace = true
1212

1313
[dependencies]
1414
foundry-abi.workspace = true
15+
foundry-cheatcodes-defs.workspace = true
1516
foundry-common.workspace = true
1617
foundry-compilers.workspace = true
1718
foundry-config.workspace = true
@@ -53,5 +54,4 @@ once_cell = "1"
5354

5455
# Misc
5556
url = "2"
56-
auto_impl = "1"
5757
itertools.workspace = true

crates/evm/core/src/abi/mod.rs

+16-16
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
//! Several ABI-related utilities for executors.
22
3+
use once_cell::sync::Lazy;
4+
use std::collections::HashMap;
5+
36
pub use foundry_abi::{
4-
console::{self, ConsoleEvents, CONSOLE_ABI},
5-
hardhat_console::{self, HardhatConsoleCalls, HARDHATCONSOLE_ABI as HARDHAT_CONSOLE_ABI},
7+
console::{ConsoleEvents, CONSOLE_ABI},
8+
hardhat_console::{HardhatConsoleCalls, HARDHATCONSOLE_ABI as HARDHAT_CONSOLE_ABI},
69
hevm::HEVM_ABI,
710
};
8-
use once_cell::sync::Lazy;
9-
use std::collections::HashMap;
1011

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

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

547547
#[test]
548-
fn hardhat_console_path_works() {
549-
for (hh, abigen) in HARDHAT_CONSOLE_SELECTOR_PATCHES.iter() {
550-
let mut hh = (*hh).to_vec();
548+
fn hardhat_console_patch() {
549+
for (hh, generated) in HARDHAT_CONSOLE_SELECTOR_PATCHES.iter() {
550+
let mut hh = *hh;
551551
patch_hardhat_console_selector(&mut hh);
552-
assert_eq!((*abigen).to_vec(), hh);
552+
assert_eq!(hh, *generated);
553553
}
554554
}
555555
}

crates/evm/core/src/backend/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ const GLOBAL_FAILURE_SLOT: B256 =
6969
b256!("6661696c65640000000000000000000000000000000000000000000000000000");
7070

7171
/// An extension trait that allows us to easily extend the `revm::Inspector` capabilities
72-
#[auto_impl::auto_impl(&mut, Box)]
7372
pub trait DatabaseExt: Database<Error = DatabaseError> {
7473
/// Creates a new snapshot at the current point of execution.
7574
///

crates/evm/core/src/debug.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{abi::HEVM_ABI, utils::CallKind};
1+
use crate::utils::CallKind;
22
use alloy_primitives::{Address, U256};
33
use revm::interpreter::{Memory, OpCode};
44
use serde::{Deserialize, Serialize};
@@ -178,11 +178,12 @@ impl Display for Instruction {
178178
Instruction::Cheatcode(cheat) => write!(
179179
f,
180180
"VM_{}",
181-
&*HEVM_ABI
182-
.functions()
183-
.find(|func| func.short_signature() == *cheat)
181+
foundry_cheatcodes_defs::Vm::CHEATCODES
182+
.iter()
183+
.map(|c| &c.func)
184+
.find(|c| c.selector_bytes == *cheat)
184185
.expect("unknown cheatcode found in debugger")
185-
.name
186+
.id
186187
.to_uppercase()
187188
),
188189
}

0 commit comments

Comments
 (0)