diff --git a/crates/anvil/src/eth/backend/executor.rs b/crates/anvil/src/eth/backend/executor.rs index 0d9c1aa805ce..0296240ee1cd 100644 --- a/crates/anvil/src/eth/backend/executor.rs +++ b/crates/anvil/src/eth/backend/executor.rs @@ -7,7 +7,7 @@ use crate::{ error::InvalidTransactionError, pool::transactions::PoolTransaction, }, - // inject_precompiles, + inject_precompiles, mem::inspector::AnvilInspector, PrecompileFactory, }; @@ -15,7 +15,7 @@ use alloy_consensus::{ constants::EMPTY_WITHDRAWALS, proofs::calculate_receipt_root, Receipt, ReceiptWithBloom, }; use alloy_eips::{eip7685::EMPTY_REQUESTS_HASH, eip7840::BlobParams}; -use alloy_evm::{eth::EthEvmContext, EthEvm, Evm}; +use alloy_evm::{eth::EthEvmContext, precompiles::PrecompilesMap, EthEvm, Evm}; use alloy_op_evm::OpEvm; use alloy_primitives::{Bloom, BloomInput, Log, B256}; use anvil_core::eth::{ @@ -25,14 +25,15 @@ use anvil_core::eth::{ }, }; use foundry_evm::{backend::DatabaseError, traces::CallTraceNode}; -use foundry_evm_core::{either_evm::EitherEvm, evm::FoundryPrecompiles}; -use op_revm::{L1BlockInfo, OpContext}; +use foundry_evm_core::either_evm::EitherEvm; +use op_revm::{precompiles::OpPrecompiles, L1BlockInfo, OpContext}; use revm::{ context::{Block as RevmBlock, BlockEnv, CfgEnv, Evm as RevmEvm, JournalTr, LocalContext}, context_interface::result::{EVMError, ExecutionResult, Output}, database::WrapDatabaseRef, - handler::instructions::EthInstructions, + handler::{instructions::EthInstructions, EthPrecompiles}, interpreter::InstructionResult, + precompile::{PrecompileSpecId, Precompiles}, primitives::hardfork::SpecId, Database, DatabaseRef, Inspector, Journal, }; @@ -328,9 +329,9 @@ impl Iterator for &mut TransactionExec let exec_result = { let mut evm = new_evm_with_inspector(&mut *self.db, &env, &mut inspector); - // if let Some(factory) = &self.precompile_factory { - // inject_precompiles(&mut evm, factory.precompiles()); - // } + if let Some(factory) = &self.precompile_factory { + inject_precompiles(&mut evm, factory.precompiles()); + } trace!(target: "backend", "[{:?}] executing", transaction.hash()); // transact and commit the transaction @@ -422,12 +423,15 @@ pub fn new_evm_with_inspector( db: DB, env: &Env, inspector: I, -) -> EitherEvm +) -> EitherEvm where DB: Database, I: Inspector> + Inspector>, { if env.is_optimism { + // TODO: we currently pin to `OpSpecId::BEDROCK` as it is primarily used in the context of + // testing deposit transactions. We should make this configurable in the future. + let op_cfg = env.evm_env.cfg_env.clone().with_spec(op_revm::OpSpecId::BEDROCK); let op_context = OpContext { journaled_state: { let mut journal = Journal::new(db); @@ -436,28 +440,30 @@ where journal }, block: env.evm_env.block_env.clone(), - cfg: env.evm_env.cfg_env.clone().with_spec(op_revm::OpSpecId::BEDROCK), + cfg: op_cfg.clone(), tx: env.tx.clone(), chain: L1BlockInfo::default(), local: LocalContext::default(), error: Ok(()), }; - let evm = op_revm::OpEvm(RevmEvm::new_with_inspector( + let op_precompiles = OpPrecompiles::new_with_spec(op_cfg.spec).precompiles(); + let op_evm = op_revm::OpEvm(RevmEvm::new_with_inspector( op_context, inspector, EthInstructions::default(), - FoundryPrecompiles::default(), + PrecompilesMap::from_static(op_precompiles), )); - let op = OpEvm::new(evm, true); + let op = OpEvm::new(op_evm, true); EitherEvm::Op(op) } else { - let evm_context = EthEvmContext { + let spec = env.evm_env.cfg_env.spec; + let eth_context = EthEvmContext { journaled_state: { let mut journal = Journal::new(db); - journal.set_spec_id(env.evm_env.cfg_env.spec); + journal.set_spec_id(spec); journal }, block: env.evm_env.block_env.clone(), @@ -468,14 +474,19 @@ where error: Ok(()), }; - let evm = RevmEvm::new_with_inspector( - evm_context, + let eth_precompiles = EthPrecompiles { + precompiles: Precompiles::new(PrecompileSpecId::from_spec_id(spec)), + spec, + } + .precompiles; + let eth_evm = RevmEvm::new_with_inspector( + eth_context, inspector, EthInstructions::default(), - FoundryPrecompiles::new(), + PrecompilesMap::from_static(eth_precompiles), ); - let eth = EthEvm::new(evm, true); + let eth = EthEvm::new(eth_evm, true); EitherEvm::Eth(eth) } @@ -486,7 +497,7 @@ pub fn new_evm_with_inspector_ref<'db, DB, I>( db: &'db DB, env: &Env, inspector: &'db mut I, -) -> EitherEvm, &'db mut I, FoundryPrecompiles> +) -> EitherEvm, &'db mut I, PrecompilesMap> where DB: DatabaseRef + 'db + ?Sized, I: Inspector>> diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index b6d0cdee08db..f1a39d20c501 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -26,14 +26,12 @@ use crate::{ sign::build_typed_transaction, util::get_precompiles_for, }, - // inject_precompiles, + inject_precompiles, mem::{ inspector::AnvilInspector, storage::{BlockchainStorage, InMemoryBlockStates, MinedBlockOutcome}, }, - ForkChoice, - NodeConfig, - PrecompileFactory, + ForkChoice, NodeConfig, PrecompileFactory, }; use alloy_chains::NamedChain; use alloy_consensus::{ @@ -51,7 +49,7 @@ use alloy_eips::{ eip4844::MAX_BLOBS_PER_BLOCK_DENCUN, eip7840::BlobParams, }; -use alloy_evm::{eth::EthEvmContext, Database, Evm}; +use alloy_evm::{eth::EthEvmContext, precompiles::PrecompilesMap, Database, Evm}; use alloy_network::{ AnyHeader, AnyRpcBlock, AnyRpcHeader, AnyRpcTransaction, AnyTxEnvelope, AnyTxType, EthereumWallet, UnknownTxEnvelope, UnknownTypedTransaction, @@ -102,7 +100,7 @@ use foundry_evm::{ inspectors::AccessListInspector, traces::TracingInspectorConfig, }; -use foundry_evm_core::{either_evm::EitherEvm, evm::FoundryPrecompiles}; +use foundry_evm_core::either_evm::EitherEvm; use futures::channel::mpsc::{unbounded, UnboundedSender}; use op_alloy_consensus::{TxDeposit, DEPOSIT_TX_TYPE_ID}; use op_revm::{ @@ -1101,7 +1099,7 @@ impl Backend { ) -> EitherEvm< WrapDatabaseRef<&'db dyn DatabaseRef>, &'db mut I, - FoundryPrecompiles, + PrecompilesMap, > where I: Inspector>>> @@ -1109,11 +1107,13 @@ impl Backend { WrapDatabaseRef<&'db dyn DatabaseRef>: Database, { - new_evm_with_inspector_ref(db, env, inspector) - // TODO(yash): inject precompiles - // if let Some(factory) = &self.precompile_factory { - // inject_precompiles(&mut evm, factory.precompiles()); - // } + let mut evm = new_evm_with_inspector_ref(db, env, inspector); + + if let Some(factory) = &self.precompile_factory { + inject_precompiles(&mut evm, factory.precompiles()); + } + + evm } /// executes the transactions without writing to the underlying database diff --git a/crates/anvil/src/evm.rs b/crates/anvil/src/evm.rs index 53ace61eaf85..7be5e3a29bfb 100644 --- a/crates/anvil/src/evm.rs +++ b/crates/anvil/src/evm.rs @@ -1,84 +1,278 @@ use std::fmt::Debug; -use alloy_primitives::Address; -use revm::precompile::Precompiles; +use alloy_evm::{ + eth::EthEvmContext, + precompiles::{DynPrecompile, PrecompilesMap}, + Database, Evm, +}; +use foundry_evm_core::either_evm::EitherEvm; +use op_revm::OpContext; +use revm::{precompile::PrecompileWithAddress, Inspector}; /// Object-safe trait that enables injecting extra precompiles when using /// `anvil` as a library. pub trait PrecompileFactory: Send + Sync + Unpin + Debug { /// Returns a set of precompiles to extend the EVM with. - fn precompiles(&self) -> Vec<(Address, Precompiles)>; + fn precompiles(&self) -> Vec; } -// /// Appends a handler register to `evm` that injects the given `precompiles`. -// /// -// /// This will add an additional handler that extends the default precompiles with the given set -// of /// precompiles. -// pub fn inject_precompiles( -// evm: &mut revm::Evm<'_, I, DB>, -// precompiles: Precompiles, -// ) { -// evm.handler.append_handler_register_box(Box::new(move |handler| { -// let precompiles = precompiles.clone(); -// let prev = handler.pre_execution.load_precompiles.clone(); -// handler.pre_execution.load_precompiles = Arc::new(move || { -// let mut cx = prev(); -// cx.extend(precompiles.iter().cloned().map(|(a, b)| (a, b.into()))); -// cx -// }); -// })); -// } - -// #[cfg(test)] -// mod tests { -// use crate::{evm::inject_precompiles, PrecompileFactory}; -// use alloy_primitives::{address, Address, Bytes}; -// use revm::{ -// precompile::{PrecompileOutput, PrecompileResult, Precompiles}, -// primitives::hardfork::SpecId, -// }; - -// #[test] -// fn build_evm_with_extra_precompiles() { -// const PRECOMPILE_ADDR: Address = address!("0x0000000000000000000000000000000000000071"); - -// fn my_precompile(_bytes: &Bytes, _gas_limit: u64) -> PrecompileResult { -// Ok(PrecompileOutput { bytes: Bytes::new(), gas_used: 0 }) -// } - -// #[derive(Debug)] -// struct CustomPrecompileFactory; - -// impl PrecompileFactory for CustomPrecompileFactory { -// fn precompiles(&self) -> Vec<(Address, Precompile)> { -// vec![(PRECOMPILE_ADDR, Precompile::Standard(my_precompile))] -// } -// } - -// let db = revm::db::EmptyDB::default(); -// let env = Box::::default(); -// let spec = SpecId::default(); -// let handler_cfg = revm::primitives::HandlerCfg::new(spec); -// let inspector = revm::inspectors::NoOpInspector; -// let context = revm::Context::new(revm::EvmContext::new_with_env(db, env), inspector); -// let handler = revm::Handler::new(handler_cfg); -// let mut evm = revm::Evm::new(context, handler); -// assert!(!evm -// .handler -// .pre_execution() -// .load_precompiles() -// .addresses() -// .any(|&addr| addr == PRECOMPILE_ADDR)); - -// inject_precompiles(&mut evm, CustomPrecompileFactory.precompiles()); -// assert!(evm -// .handler -// .pre_execution() -// .load_precompiles() -// .addresses() -// .any(|&addr| addr == PRECOMPILE_ADDR)); - -// let result = evm.transact().unwrap(); -// assert!(result.result.is_success()); -// } -// } +/// Inject precompiles into the EVM dynamically. +pub fn inject_precompiles( + evm: &mut EitherEvm, + precompiles: Vec, +) where + DB: Database, + I: Inspector> + Inspector>, +{ + for p in precompiles { + evm.precompiles_mut() + .apply_precompile(p.address(), |_| Some(DynPrecompile::from(*p.precompile()))); + } +} + +#[cfg(test)] +mod tests { + use std::convert::Infallible; + + use alloy_evm::{eth::EthEvmContext, precompiles::PrecompilesMap, EthEvm, Evm, EvmEnv}; + use alloy_op_evm::OpEvm; + use alloy_primitives::{address, Address, Bytes, TxKind}; + use foundry_evm_core::either_evm::EitherEvm; + use itertools::Itertools; + use op_revm::{precompiles::OpPrecompiles, L1BlockInfo, OpContext, OpSpecId, OpTransaction}; + use revm::{ + context::{CfgEnv, Evm as RevmEvm, JournalTr, LocalContext, TxEnv}, + database::{EmptyDB, EmptyDBTyped}, + handler::{instructions::EthInstructions, EthPrecompiles}, + inspector::NoOpInspector, + interpreter::interpreter::EthInterpreter, + precompile::{ + PrecompileOutput, PrecompileResult, PrecompileSpecId, PrecompileWithAddress, + Precompiles, + }, + primitives::hardfork::SpecId, + Journal, + }; + + use crate::{inject_precompiles, PrecompileFactory}; + + // A precompile activated in the `Prague` spec. + const ETH_PRAGUE_PRECOMPILE: Address = address!("0x0000000000000000000000000000000000000011"); + + // A precompile activated in the `Fjord` spec. + const OP_FROJD_PRECOMPILE: Address = address!("0x0000000000000000000000000000000000000100"); + + // A custom precompile address and payload for testing. + const PRECOMPILE_ADDR: Address = address!("0x0000000000000000000000000000000000000071"); + const PAYLOAD: &[u8] = &[0xde, 0xad, 0xbe, 0xef]; + + #[derive(Debug)] + struct CustomPrecompileFactory; + + impl PrecompileFactory for CustomPrecompileFactory { + fn precompiles(&self) -> Vec { + vec![PrecompileWithAddress::from(( + PRECOMPILE_ADDR, + custom_echo_precompile as fn(&[u8], u64) -> PrecompileResult, + ))] + } + } + + /// Custom precompile that echoes the input data. + /// In this example it uses `0xdeadbeef` as the input data, returning it as output. + fn custom_echo_precompile(input: &[u8], _gas_limit: u64) -> PrecompileResult { + Ok(PrecompileOutput { bytes: Bytes::copy_from_slice(input), gas_used: 0 }) + } + + /// Creates a new EVM instance with the custom precompile factory. + fn create_eth_evm( + spec: SpecId, + ) -> (foundry_evm::Env, EitherEvm, NoOpInspector, PrecompilesMap>) + { + let eth_env = foundry_evm::Env { + evm_env: EvmEnv { block_env: Default::default(), cfg_env: CfgEnv::new_with_spec(spec) }, + tx: TxEnv { + kind: TxKind::Call(PRECOMPILE_ADDR), + data: PAYLOAD.into(), + ..Default::default() + }, + }; + + let eth_evm_context = EthEvmContext { + journaled_state: Journal::new(EmptyDB::default()), + block: eth_env.evm_env.block_env.clone(), + cfg: eth_env.evm_env.cfg_env.clone(), + tx: eth_env.tx.clone(), + chain: (), + local: LocalContext::default(), + error: Ok(()), + }; + + let eth_precompiles = EthPrecompiles { + precompiles: Precompiles::new(PrecompileSpecId::from_spec_id(spec)), + spec, + } + .precompiles; + let eth_evm = EitherEvm::Eth(EthEvm::new( + RevmEvm::new_with_inspector( + eth_evm_context, + NoOpInspector, + EthInstructions::>::default(), + PrecompilesMap::from_static(eth_precompiles), + ), + true, + )); + + (eth_env, eth_evm) + } + + /// Creates a new OP EVM instance with the custom precompile factory. + fn create_op_evm( + spec: SpecId, + op_spec: OpSpecId, + ) -> ( + crate::eth::backend::env::Env, + EitherEvm, NoOpInspector, PrecompilesMap>, + ) { + let op_env = crate::eth::backend::env::Env { + evm_env: EvmEnv { block_env: Default::default(), cfg_env: CfgEnv::new_with_spec(spec) }, + tx: OpTransaction:: { + base: TxEnv { + kind: TxKind::Call(PRECOMPILE_ADDR), + data: PAYLOAD.into(), + ..Default::default() + }, + ..Default::default() + }, + is_optimism: true, + }; + + let op_cfg = op_env.evm_env.cfg_env.clone().with_spec(op_spec); + let op_evm_context = OpContext { + journaled_state: { + let mut journal = Journal::new(EmptyDB::default()); + // Converting SpecId into OpSpecId + journal.set_spec_id(op_env.evm_env.cfg_env.spec); + journal + }, + block: op_env.evm_env.block_env.clone(), + cfg: op_cfg.clone(), + tx: op_env.tx.clone(), + chain: L1BlockInfo::default(), + local: LocalContext::default(), + error: Ok(()), + }; + + let op_precompiles = OpPrecompiles::new_with_spec(op_cfg.spec).precompiles(); + let op_evm = EitherEvm::Op(OpEvm::new( + op_revm::OpEvm(RevmEvm::new_with_inspector( + op_evm_context, + NoOpInspector, + EthInstructions::>::default(), + PrecompilesMap::from_static(op_precompiles), + )), + true, + )); + + (op_env, op_evm) + } + + #[test] + fn build_eth_evm_with_extra_precompiles_default_spec() { + let (env, mut evm) = create_eth_evm(SpecId::default()); + + // Check that the Prague precompile IS present when using the default spec. + assert!(evm.precompiles_mut().addresses().contains(Ð_PRAGUE_PRECOMPILE)); + + assert!(!evm.precompiles_mut().addresses().contains(&PRECOMPILE_ADDR)); + + inject_precompiles(&mut evm, CustomPrecompileFactory.precompiles()); + + assert!(evm.precompiles_mut().addresses().contains(&PRECOMPILE_ADDR)); + + let result = match &mut evm { + EitherEvm::Eth(eth_evm) => eth_evm.transact(env.tx).unwrap(), + _ => unreachable!(), + }; + + assert!(result.result.is_success()); + assert_eq!(result.result.output(), Some(&PAYLOAD.into())); + } + + #[test] + fn build_eth_evm_with_extra_precompiles_london_spec() { + let (env, mut evm) = create_eth_evm(SpecId::LONDON); + + // Check that the Prague precompile IS NOT present when using the London spec. + assert!(!evm.precompiles_mut().addresses().contains(Ð_PRAGUE_PRECOMPILE)); + + assert!(!evm.precompiles_mut().addresses().contains(&PRECOMPILE_ADDR)); + + inject_precompiles(&mut evm, CustomPrecompileFactory.precompiles()); + + assert!(evm.precompiles_mut().addresses().contains(&PRECOMPILE_ADDR)); + + let result = match &mut evm { + EitherEvm::Eth(eth_evm) => eth_evm.transact(env.tx).unwrap(), + _ => unreachable!(), + }; + + assert!(result.result.is_success()); + assert_eq!(result.result.output(), Some(&PAYLOAD.into())); + } + + #[test] + fn build_op_evm_with_extra_precompiles_default_spec() { + let (env, mut evm) = create_op_evm( + SpecId::default(), + // TODO: OpSpecId::ISTHMUS is not yet supported, fails with: `Missing operator fee + // scalar for isthmus L1 Block`. + OpSpecId::HOLOCENE, + ); + + // Check that the Fjord precompile IS present when using the default spec. + assert!(evm.precompiles_mut().addresses().contains(&OP_FROJD_PRECOMPILE)); + + // Check that the Prague precompile is NOT present when using the default spec. + assert!(!evm.precompiles_mut().addresses().contains(Ð_PRAGUE_PRECOMPILE)); + + assert!(!evm.precompiles_mut().addresses().contains(&PRECOMPILE_ADDR)); + + inject_precompiles(&mut evm, CustomPrecompileFactory.precompiles()); + + assert!(evm.precompiles_mut().addresses().contains(&PRECOMPILE_ADDR)); + + let result = match &mut evm { + EitherEvm::Op(op_evm) => op_evm.transact(env.tx).unwrap(), + _ => unreachable!(), + }; + + assert!(result.result.is_success()); + assert_eq!(result.result.output(), Some(&PAYLOAD.into())); + } + + #[test] + fn build_op_evm_with_extra_precompiles_bedrock_spec() { + let (env, mut evm) = create_op_evm(SpecId::default(), OpSpecId::BEDROCK); + + // Check that the Fjord precompile IS NOT present when using the `OpSpecId::BEDROCK` spec. + assert!(!evm.precompiles_mut().addresses().contains(&OP_FROJD_PRECOMPILE)); + + // Check that the Prague precompile IS NOT present when using the `OpSpecId::BEDROCK` spec. + assert!(!evm.precompiles_mut().addresses().contains(Ð_PRAGUE_PRECOMPILE)); + + assert!(!evm.precompiles_mut().addresses().contains(&PRECOMPILE_ADDR)); + + inject_precompiles(&mut evm, CustomPrecompileFactory.precompiles()); + + assert!(evm.precompiles_mut().addresses().contains(&PRECOMPILE_ADDR)); + + let result = match &mut evm { + EitherEvm::Op(op_evm) => op_evm.transact(env.tx).unwrap(), + _ => unreachable!(), + }; + + assert!(result.result.is_success()); + assert_eq!(result.result.output(), Some(&PAYLOAD.into())); + } +} diff --git a/crates/anvil/src/lib.rs b/crates/anvil/src/lib.rs index b48ad1197569..77e072e0aa1f 100644 --- a/crates/anvil/src/lib.rs +++ b/crates/anvil/src/lib.rs @@ -53,8 +53,7 @@ pub use hardfork::{EthereumHardfork, OptimismHardfork}; pub mod eth; /// Evm related abstractions mod evm; -// pub use evm::{inject_precompiles, PrecompileFactory}; -pub use evm::PrecompileFactory; +pub use evm::{inject_precompiles, PrecompileFactory}; /// support for polling filters pub mod filter; diff --git a/crates/evm/core/src/evm.rs b/crates/evm/core/src/evm.rs index 9beb14461c62..b5938c109f04 100644 --- a/crates/evm/core/src/evm.rs +++ b/crates/evm/core/src/evm.rs @@ -4,7 +4,7 @@ use crate::{ backend::DatabaseExt, constants::DEFAULT_CREATE2_DEPLOYER_CODEHASH, Env, InspectorExt, }; use alloy_consensus::constants::KECCAK_EMPTY; -use alloy_evm::{eth::EthEvmContext, Evm, EvmEnv}; +use alloy_evm::{eth::EthEvmContext, precompiles::PrecompilesMap, Evm, EvmEnv}; use alloy_primitives::{Address, Bytes, U256}; use foundry_fork_db::DatabaseError; use revm::{ @@ -14,65 +14,19 @@ use revm::{ }, handler::{ instructions::EthInstructions, EthFrame, EthPrecompiles, FrameInitOrResult, FrameResult, - Handler, ItemOrResult, MainnetHandler, PrecompileProvider, + Handler, ItemOrResult, MainnetHandler, }, inspector::InspectorHandler, interpreter::{ interpreter::EthInterpreter, return_ok, CallInput, CallInputs, CallOutcome, CallScheme, - CallValue, CreateInputs, CreateOutcome, FrameInput, Gas, InputsImpl, InstructionResult, + CallValue, CreateInputs, CreateOutcome, FrameInput, Gas, InstructionResult, InterpreterResult, }, + precompile::{PrecompileSpecId, Precompiles}, primitives::hardfork::SpecId, Context, ExecuteEvm, Journal, }; -pub struct FoundryPrecompiles { - inner: EthPrecompiles, -} - -impl FoundryPrecompiles { - pub fn new() -> Self { - Self { inner: EthPrecompiles::default() } - } -} - -impl Default for FoundryPrecompiles { - fn default() -> Self { - Self::new() - } -} - -impl PrecompileProvider for FoundryPrecompiles { - type Output = InterpreterResult; - - /// Set the spec for the precompiles. - fn set_spec(&mut self, spec: <::Cfg as revm::context::Cfg>::Spec) -> bool { - PrecompileProvider::::set_spec(&mut self.inner, spec) - } - - /// Run the precompile. - fn run( - &mut self, - context: &mut CTX, - address: &Address, - inputs: &InputsImpl, - is_static: bool, - gas_limit: u64, - ) -> Result, String> { - self.inner.run(context, address, inputs, is_static, gas_limit) - } - - /// Get the warm addresses. - fn warm_addresses(&self) -> Box> { - self.inner.warm_addresses() - } - - /// Check if the address is a precompile. - fn contains(&self, address: &Address) -> bool { - self.inner.contains(address) - } -} - pub fn new_evm_with_inspector<'i, 'db, I: InspectorExt + ?Sized>( db: &'db mut dyn DatabaseExt, env: Env, @@ -91,13 +45,19 @@ pub fn new_evm_with_inspector<'i, 'db, I: InspectorExt + ?Sized>( local: LocalContext::default(), error: Ok(()), }; + let spec = ctx.cfg.spec; + let precompiles = EthPrecompiles { + precompiles: Precompiles::new(PrecompileSpecId::from_spec_id(spec)), + spec, + } + .precompiles; FoundryEvm { inner: RevmEvm::new_with_inspector( ctx, inspector, EthInstructions::default(), - FoundryPrecompiles::default(), + PrecompilesMap::from_static(precompiles), ), } } @@ -106,12 +66,19 @@ pub fn new_evm_with_existing_context<'a>( ctx: EthEvmContext<&'a mut dyn DatabaseExt>, inspector: &'a mut dyn InspectorExt, ) -> FoundryEvm<'a, &'a mut dyn InspectorExt> { + let spec = ctx.cfg.spec; + let precompiles = EthPrecompiles { + precompiles: Precompiles::new(PrecompileSpecId::from_spec_id(spec)), + spec, + } + .precompiles; + FoundryEvm { inner: RevmEvm::new_with_inspector( ctx, inspector, EthInstructions::default(), - FoundryPrecompiles::default(), + PrecompilesMap::from_static(precompiles), ), } } @@ -142,7 +109,7 @@ pub struct FoundryEvm<'db, I: InspectorExt> { EthEvmContext<&'db mut dyn DatabaseExt>, I, EthInstructions>, - FoundryPrecompiles, + PrecompilesMap, >, } @@ -165,7 +132,7 @@ impl FoundryEvm<'_, I> { } impl<'db, I: InspectorExt> Evm for FoundryEvm<'db, I> { - type Precompiles = FoundryPrecompiles; + type Precompiles = PrecompilesMap; type Inspector = I; type DB = &'db mut dyn DatabaseExt; type Error = EVMError; @@ -246,7 +213,7 @@ pub struct FoundryHandler<'db, I: InspectorExt> { EthEvmContext<&'db mut dyn DatabaseExt>, I, EthInstructions>, - FoundryPrecompiles, + PrecompilesMap, >, EVMError, EthFrame< @@ -254,7 +221,7 @@ pub struct FoundryHandler<'db, I: InspectorExt> { EthEvmContext<&'db mut dyn DatabaseExt>, I, EthInstructions>, - FoundryPrecompiles, + PrecompilesMap, >, EVMError, EthInterpreter, @@ -274,7 +241,7 @@ impl<'db, I: InspectorExt> Handler for FoundryHandler<'db, I> { EthEvmContext<&'db mut dyn DatabaseExt>, I, EthInstructions>, - FoundryPrecompiles, + PrecompilesMap, >; type Error = EVMError; type Frame = EthFrame< @@ -282,7 +249,7 @@ impl<'db, I: InspectorExt> Handler for FoundryHandler<'db, I> { EthEvmContext<&'db mut dyn DatabaseExt>, I, EthInstructions>, - FoundryPrecompiles, + PrecompilesMap, >, EVMError, EthInterpreter, diff --git a/testdata/default/cheats/Etch.t.sol b/testdata/default/cheats/Etch.t.sol index f60ea4cad650..5e93dfb81213 100644 --- a/testdata/default/cheats/Etch.t.sol +++ b/testdata/default/cheats/Etch.t.sol @@ -8,7 +8,7 @@ contract EtchTest is DSTest { Vm constant vm = Vm(HEVM_ADDRESS); function testEtch() public { - address target = address(11); + address target = address(7070707); bytes memory code = hex"1010"; vm.etch(target, code); assertEq(string(code), string(target.code));