From f8aa4afec04cc0b7d364a5d78f0cde9e64fd14bf Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Sat, 17 Aug 2024 02:41:29 +0800 Subject: [PATCH] feat: `--alphanet` flag and config option (#8680) * --alphanet * fix tests * fix doc * anvil support * better cast and anvil * fix doc --- crates/anvil/src/cmd.rs | 5 ++ crates/anvil/src/config.rs | 16 +++++- crates/anvil/src/eth/backend/executor.rs | 3 +- crates/anvil/src/eth/backend/mem/inspector.rs | 14 +++++- crates/anvil/src/eth/backend/mem/mod.rs | 7 ++- crates/cast/bin/cmd/call.rs | 47 +++++++++++++++--- crates/cast/bin/cmd/run.rs | 49 ++++++++++++++++--- crates/common/src/evm.rs | 9 ++++ crates/config/src/lib.rs | 6 ++- crates/config/src/utils.rs | 5 +- crates/evm/core/src/lib.rs | 4 ++ crates/evm/core/src/opts.rs | 3 ++ crates/evm/core/src/precompiles.rs | 30 +++++++++++- crates/evm/core/src/utils.rs | 32 ++++++++++-- crates/evm/evm/src/executors/trace.rs | 9 ++-- crates/evm/evm/src/inspectors/stack.rs | 27 ++++++++++ crates/forge/bin/cmd/test/mod.rs | 1 + crates/forge/src/multi_runner.rs | 12 +++++ crates/forge/tests/cli/config.rs | 1 + crates/script/src/lib.rs | 4 +- crates/verify/src/bytecode.rs | 12 +++-- 21 files changed, 264 insertions(+), 32 deletions(-) diff --git a/crates/anvil/src/cmd.rs b/crates/anvil/src/cmd.rs index a2802e059177..e21f12d365f5 100644 --- a/crates/anvil/src/cmd.rs +++ b/crates/anvil/src/cmd.rs @@ -252,6 +252,7 @@ impl NodeArgs { .with_transaction_block_keeper(self.transaction_block_keeper) .with_max_persisted_states(self.max_persisted_states) .with_optimism(self.evm_opts.optimism) + .with_alphanet(self.evm_opts.alphanet) .with_disable_default_create2_deployer(self.evm_opts.disable_default_create2_deployer) .with_slots_in_an_epoch(self.slots_in_an_epoch) .with_memory_limit(self.evm_opts.memory_limit) @@ -550,6 +551,10 @@ pub struct AnvilEvmArgs { /// The memory limit per EVM execution in bytes. #[arg(long)] pub memory_limit: Option, + + /// Enable Alphanet features + #[arg(long, visible_alias = "alphanet")] + pub alphanet: bool, } /// Resolves an alias passed as fork-url to the matching url defined in the rpc_endpoints section diff --git a/crates/anvil/src/config.rs b/crates/anvil/src/config.rs index 5e8ef0f9a1b6..a94d5b827d00 100644 --- a/crates/anvil/src/config.rs +++ b/crates/anvil/src/config.rs @@ -183,6 +183,8 @@ pub struct NodeConfig { pub memory_limit: Option, /// Factory used by `anvil` to extend the EVM's precompiles. pub precompile_factory: Option>, + /// Enable Alphanet features. + pub alphanet: bool, } impl NodeConfig { @@ -437,6 +439,7 @@ impl Default for NodeConfig { slots_in_an_epoch: 32, memory_limit: None, precompile_factory: None, + alphanet: false, } } } @@ -471,8 +474,11 @@ impl NodeConfig { } } - /// Returns the base fee to use + /// Returns the hardfork to use pub fn get_hardfork(&self) -> Hardfork { + if self.alphanet { + return Hardfork::PragueEOF; + } self.hardfork.unwrap_or_default() } @@ -918,6 +924,13 @@ impl NodeConfig { self } + /// Sets whether to enable Alphanet support + #[must_use] + pub fn with_alphanet(mut self, alphanet: bool) -> Self { + self.alphanet = alphanet; + self + } + /// Configures everything related to env, backend and database and returns the /// [Backend](mem::Backend) /// @@ -994,6 +1007,7 @@ impl NodeConfig { Arc::new(RwLock::new(fork)), self.enable_steps_tracing, self.print_logs, + self.alphanet, self.prune_history, self.max_persisted_states, self.transaction_block_keeper, diff --git a/crates/anvil/src/eth/backend/executor.rs b/crates/anvil/src/eth/backend/executor.rs index d56db9069f81..b46f29c38a97 100644 --- a/crates/anvil/src/eth/backend/executor.rs +++ b/crates/anvil/src/eth/backend/executor.rs @@ -105,6 +105,7 @@ pub struct TransactionExecutor<'a, Db: ?Sized, Validator: TransactionValidator> /// Cumulative blob gas used by all executed transactions pub blob_gas_used: u128, pub enable_steps_tracing: bool, + pub alphanet: bool, pub print_logs: bool, /// Precompiles to inject to the EVM. pub precompile_factory: Option>, @@ -302,7 +303,7 @@ impl<'a, 'b, DB: Db + ?Sized, Validator: TransactionValidator> Iterator let nonce = account.nonce; // records all call and step traces - let mut inspector = Inspector::default().with_tracing(); + let mut inspector = Inspector::default().with_tracing().with_alphanet(self.alphanet); if self.enable_steps_tracing { inspector = inspector.with_steps_tracing(); } diff --git a/crates/anvil/src/eth/backend/mem/inspector.rs b/crates/anvil/src/eth/backend/mem/inspector.rs index 2095e9d5034a..56e53acc3452 100644 --- a/crates/anvil/src/eth/backend/mem/inspector.rs +++ b/crates/anvil/src/eth/backend/mem/inspector.rs @@ -23,6 +23,8 @@ pub struct Inspector { pub tracer: Option, /// collects all `console.sol` logs pub log_collector: Option, + /// Whether to enable Alphanet support + pub alphanet: bool, } impl Inspector { @@ -57,6 +59,12 @@ impl Inspector { self.log_collector = Some(Default::default()); self } + + /// Enables Alphanet features + pub fn with_alphanet(mut self, yes: bool) -> Self { + self.alphanet = yes; + self + } } impl revm::Inspector for Inspector { @@ -168,7 +176,11 @@ impl revm::Inspector for Inspector { } } -impl InspectorExt for Inspector {} +impl InspectorExt for Inspector { + fn is_alphanet(&self) -> bool { + self.alphanet + } +} /// Prints all the logs pub fn print_logs(logs: &[Log]) { diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index 9d21b9bf2a44..5180e4a0484d 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -174,6 +174,7 @@ pub struct Backend { active_snapshots: Arc>>, enable_steps_tracing: bool, print_logs: bool, + alphanet: bool, /// How to keep history state prune_state_history_config: PruneStateHistoryConfig, /// max number of blocks with transactions in memory @@ -198,6 +199,7 @@ impl Backend { fork: Arc>>, enable_steps_tracing: bool, print_logs: bool, + alphanet: bool, prune_state_history_config: PruneStateHistoryConfig, max_persisted_states: Option, transaction_block_keeper: Option, @@ -256,6 +258,7 @@ impl Backend { active_snapshots: Arc::new(Mutex::new(Default::default())), enable_steps_tracing, print_logs, + alphanet, prune_state_history_config, transaction_block_keeper, node_config, @@ -908,6 +911,7 @@ impl Backend { enable_steps_tracing: self.enable_steps_tracing, print_logs: self.print_logs, precompile_factory: self.precompile_factory.clone(), + alphanet: self.alphanet, }; // create a new pending block @@ -980,6 +984,7 @@ impl Backend { blob_gas_used: 0, enable_steps_tracing: self.enable_steps_tracing, print_logs: self.print_logs, + alphanet: self.alphanet, precompile_factory: self.precompile_factory.clone(), }; let executed_tx = executor.execute(); @@ -1203,7 +1208,7 @@ impl Backend { /// Builds [`Inspector`] with the configured options fn build_inspector(&self) -> Inspector { - let mut inspector = Inspector::default(); + let mut inspector = Inspector::default().with_alphanet(self.alphanet); if self.print_logs { inspector = inspector.with_log_collector(); diff --git a/crates/cast/bin/cmd/call.rs b/crates/cast/bin/cmd/call.rs index e9db0084e2ec..9a553e38507c 100644 --- a/crates/cast/bin/cmd/call.rs +++ b/crates/cast/bin/cmd/call.rs @@ -10,7 +10,14 @@ use foundry_cli::{ }; use foundry_common::ens::NameOrAddress; use foundry_compilers::artifacts::EvmVersion; -use foundry_config::{find_project_root_path, Config}; +use foundry_config::{ + figment::{ + self, + value::{Dict, Map}, + Figment, Metadata, Profile, + }, + Config, +}; use foundry_evm::{executors::TracingExecutor, opts::EvmOpts}; use std::str::FromStr; @@ -66,6 +73,10 @@ pub struct CallArgs { #[arg(long, short, help_heading = "Display options")] json: bool, + /// Enable Alphanet features. + #[arg(long)] + pub alphanet: bool, + #[command(subcommand)] command: Option, @@ -102,6 +113,10 @@ pub enum CallSubcommands { impl CallArgs { pub async fn run(self) -> Result<()> { + let figment = Into::::into(&self.eth).merge(&self); + let evm_opts = figment.extract::()?; + let mut config = Config::try_from(figment)?.sanitized(); + let Self { to, mut sig, @@ -117,13 +132,13 @@ impl CallArgs { labels, data, json, + .. } = self; if let Some(data) = data { sig = Some(data); } - let mut config = Config::from(ð); let provider = utils::get_provider(&config)?; let sender = SenderKind::from_wallet_opts(eth.wallet).await?; let from = sender.address(); @@ -160,22 +175,20 @@ impl CallArgs { .await?; if trace { - let figment = - Config::figment_with_root(find_project_root_path(None).unwrap()).merge(eth.rpc); - let evm_opts = figment.extract::()?; if let Some(BlockId::Number(BlockNumberOrTag::Number(block_number))) = self.block { // Override Config `fork_block_number` (if set) with CLI value. config.fork_block_number = Some(block_number); } - let (mut env, fork, chain) = + let (mut env, fork, chain, alphanet) = TracingExecutor::get_fork_material(&config, evm_opts).await?; // modify settings that usually set in eth_call env.cfg.disable_block_gas_limit = true; env.block.gas_limit = U256::MAX; - let mut executor = TracingExecutor::new(env, fork, evm_version, debug, decode_internal); + let mut executor = + TracingExecutor::new(env, fork, evm_version, debug, decode_internal, alphanet); let value = tx.value.unwrap_or_default(); let input = tx.inner.input.into_input().unwrap_or_default(); @@ -202,6 +215,26 @@ impl CallArgs { } } +impl figment::Provider for CallArgs { + fn metadata(&self) -> Metadata { + Metadata::named("CallArgs") + } + + fn data(&self) -> Result, figment::Error> { + let mut map = Map::new(); + + if self.alphanet { + map.insert("alphanet".into(), self.alphanet.into()); + } + + if let Some(evm_version) = self.evm_version { + map.insert("evm_version".into(), figment::value::Value::serialize(evm_version)?); + } + + Ok(Map::from([(Config::selected_profile(), map)])) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/cast/bin/cmd/run.rs b/crates/cast/bin/cmd/run.rs index b7f31cfc7514..7a5e7980ceee 100644 --- a/crates/cast/bin/cmd/run.rs +++ b/crates/cast/bin/cmd/run.rs @@ -10,7 +10,14 @@ use foundry_cli::{ }; use foundry_common::{is_known_system_sender, SYSTEM_TRANSACTION_TYPE}; use foundry_compilers::artifacts::EvmVersion; -use foundry_config::{find_project_root_path, Config}; +use foundry_config::{ + figment::{ + self, + value::{Dict, Map}, + Figment, Metadata, Profile, + }, + Config, +}; use foundry_evm::{ executors::{EvmError, TracingExecutor}, opts::EvmOpts, @@ -75,6 +82,10 @@ pub struct RunArgs { /// See also, https://docs.alchemy.com/reference/compute-units#what-are-cups-compute-units-per-second #[arg(long, value_name = "NO_RATE_LIMITS", visible_alias = "no-rpc-rate-limit")] pub no_rate_limit: bool, + + /// Enables Alphanet features. + #[arg(long)] + pub alphanet: bool, } impl RunArgs { @@ -84,8 +95,7 @@ impl RunArgs { /// /// Note: This executes the transaction(s) as is: Cheatcodes are disabled pub async fn run(self) -> Result<()> { - let figment = - Config::figment_with_root(find_project_root_path(None).unwrap()).merge(self.rpc); + let figment = Into::::into(&self.rpc).merge(&self); let evm_opts = figment.extract::()?; let mut config = Config::try_from(figment)?.sanitized(); @@ -122,7 +132,8 @@ impl RunArgs { // we need to fork off the parent block config.fork_block_number = Some(tx_block_number - 1); - let (mut env, fork, chain) = TracingExecutor::get_fork_material(&config, evm_opts).await?; + let (mut env, fork, chain, alphanet) = + TracingExecutor::get_fork_material(&config, evm_opts).await?; let mut evm_version = self.evm_version; @@ -146,8 +157,14 @@ impl RunArgs { } } - let mut executor = - TracingExecutor::new(env.clone(), fork, evm_version, self.debug, self.decode_internal); + let mut executor = TracingExecutor::new( + env.clone(), + fork, + evm_version, + self.debug, + self.decode_internal, + alphanet, + ); let mut env = EnvWithHandlerCfg::new_with_spec_id(Box::new(env.clone()), executor.spec_id()); @@ -230,3 +247,23 @@ impl RunArgs { Ok(()) } } + +impl figment::Provider for RunArgs { + fn metadata(&self) -> Metadata { + Metadata::named("RunArgs") + } + + fn data(&self) -> Result, figment::Error> { + let mut map = Map::new(); + + if self.alphanet { + map.insert("alphanet".into(), self.alphanet.into()); + } + + if let Some(evm_version) = self.evm_version { + map.insert("evm_version".into(), figment::value::Value::serialize(evm_version)?); + } + + Ok(Map::from([(Config::selected_profile(), map)])) + } +} diff --git a/crates/common/src/evm.rs b/crates/common/src/evm.rs index 98355c890da5..43f2d5c53477 100644 --- a/crates/common/src/evm.rs +++ b/crates/common/src/evm.rs @@ -144,6 +144,11 @@ pub struct EvmArgs { #[arg(long)] #[serde(skip)] pub isolate: bool, + + /// Whether to enable Alphanet features. + #[arg(long)] + #[serde(skip)] + pub alphanet: bool, } // Make this set of options a `figment::Provider` so that it can be merged into the `Config` @@ -170,6 +175,10 @@ impl Provider for EvmArgs { dict.insert("isolate".to_string(), self.isolate.into()); } + if self.alphanet { + dict.insert("alphanet".to_string(), self.alphanet.into()); + } + if self.always_use_create_2_factory { dict.insert( "always_use_create_2_factory".to_string(), diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 7033cc31a0dc..ca7226e18da4 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -447,6 +447,9 @@ pub struct Config { #[serde(default, skip_serializing_if = "Option::is_none")] pub eof_version: Option, + /// Whether to enable Alphanet features. + pub alphanet: bool, + /// Warnings gathered when loading the Config. See [`WarningsProvider`] for more information #[serde(rename = "__warnings", default, skip_serializing)] pub warnings: Vec, @@ -910,7 +913,7 @@ impl Config { /// Returns the [SpecId] derived from the configured [EvmVersion] #[inline] pub fn evm_spec_id(&self) -> SpecId { - evm_spec_id(&self.evm_version) + evm_spec_id(&self.evm_version, self.alphanet) } /// Returns whether the compiler version should be auto-detected @@ -2139,6 +2142,7 @@ impl Default for Config { warnings: vec![], extra_args: vec![], eof_version: None, + alphanet: false, _non_exhaustive: (), } } diff --git a/crates/config/src/utils.rs b/crates/config/src/utils.rs index d8d23711c3bd..dff36e4fda40 100644 --- a/crates/config/src/utils.rs +++ b/crates/config/src/utils.rs @@ -296,7 +296,10 @@ impl FromStr for Numeric { /// Returns the [SpecId] derived from [EvmVersion] #[inline] -pub fn evm_spec_id(evm_version: &EvmVersion) -> SpecId { +pub fn evm_spec_id(evm_version: &EvmVersion, alphanet: bool) -> SpecId { + if alphanet { + return SpecId::PRAGUE_EOF; + } match evm_version { EvmVersion::Homestead => SpecId::HOMESTEAD, EvmVersion::TangerineWhistle => SpecId::TANGERINE, diff --git a/crates/evm/core/src/lib.rs b/crates/evm/core/src/lib.rs index ed10c5d75146..26b392c433f3 100644 --- a/crates/evm/core/src/lib.rs +++ b/crates/evm/core/src/lib.rs @@ -47,6 +47,10 @@ pub trait InspectorExt: Inspector { // Simulates `console.log` invocation. fn console_log(&mut self, _input: String) {} + + fn is_alphanet(&self) -> bool { + false + } } impl InspectorExt for NoOpInspector {} diff --git a/crates/evm/core/src/opts.rs b/crates/evm/core/src/opts.rs index d676c90b363e..f9e674e09a26 100644 --- a/crates/evm/core/src/opts.rs +++ b/crates/evm/core/src/opts.rs @@ -63,6 +63,9 @@ pub struct EvmOpts { /// Whether to disable block gas limit checks. pub disable_block_gas_limit: bool, + + /// whether to enable Alphanet features. + pub alphanet: bool, } impl EvmOpts { diff --git a/crates/evm/core/src/precompiles.rs b/crates/evm/core/src/precompiles.rs index 03ab18dffd96..2544258d3443 100644 --- a/crates/evm/core/src/precompiles.rs +++ b/crates/evm/core/src/precompiles.rs @@ -1,4 +1,8 @@ -use alloy_primitives::{address, Address}; +use alloy_primitives::{address, Address, Bytes, B256}; +use revm::{ + precompile::{secp256r1::p256_verify as revm_p256_verify, PrecompileWithAddress}, + primitives::{Precompile, PrecompileResult}, +}; /// The ECRecover precompile address. pub const EC_RECOVER: Address = address!("0000000000000000000000000000000000000001"); @@ -42,4 +46,28 @@ pub const PRECOMPILES: &[Address] = &[ EC_PAIRING, BLAKE_2F, POINT_EVALUATION, + ALPHANET_P256_ADDRESS, ]; + +/// [EIP-7212](https://eips.ethereum.org/EIPS/eip-7212) secp256r1 precompile address on Alphanet. +/// +/// +pub const ALPHANET_P256_ADDRESS: Address = address!("0000000000000000000000000000000000000014"); + +/// Wrapper around revm P256 precompile, matching EIP-7212 spec. +/// +/// Per Optimism implementation, P256 precompile returns empty bytes on failure, but per EIP-7212 it +/// should be 32 bytes of zeros instead. +pub fn p256_verify(input: &Bytes, gas_limit: u64) -> PrecompileResult { + revm_p256_verify(input, gas_limit).map(|mut result| { + if result.bytes.is_empty() { + result.bytes = B256::default().into(); + } + + result + }) +} + +/// [EIP-7212](https://eips.ethereum.org/EIPS/eip-7212#specification) secp256r1 precompile. +pub const ALPHANET_P256: PrecompileWithAddress = + PrecompileWithAddress(ALPHANET_P256_ADDRESS, Precompile::Standard(p256_verify)); diff --git a/crates/evm/core/src/utils.rs b/crates/evm/core/src/utils.rs index 8860b1683a4c..21284e78035b 100644 --- a/crates/evm/core/src/utils.rs +++ b/crates/evm/core/src/utils.rs @@ -1,5 +1,5 @@ pub use crate::ic::*; -use crate::{constants::DEFAULT_CREATE2_DEPLOYER, InspectorExt}; +use crate::{constants::DEFAULT_CREATE2_DEPLOYER, precompiles::ALPHANET_P256, InspectorExt}; use alloy_json_abi::{Function, JsonAbi}; use alloy_primitives::{Address, Selector, TxKind, U256}; use alloy_rpc_types::{Block, Transaction}; @@ -207,6 +207,20 @@ pub fn create2_handler_register>( }); } +/// Adds Alphanet P256 precompile to the list of loaded precompiles. +pub fn alphanet_handler_register>( + handler: &mut EvmHandler<'_, I, DB>, +) { + let prev = handler.pre_execution.load_precompiles.clone(); + handler.pre_execution.load_precompiles = Arc::new(move || { + let mut loaded_precompiles = prev(); + + loaded_precompiles.extend([ALPHANET_P256]); + + loaded_precompiles + }); +} + /// Creates a new EVM with the given inspector. pub fn new_evm_with_inspector<'a, DB, I>( db: DB, @@ -232,10 +246,15 @@ where .build() */ - let context = revm::Context::new(revm::EvmContext::new_with_env(db, env), inspector); let mut handler = revm::Handler::new(handler_cfg); handler.append_handler_register_plain(revm::inspector_handle_register); + if inspector.is_alphanet() { + handler.append_handler_register_plain(alphanet_handler_register); + } handler.append_handler_register_plain(create2_handler_register); + + let context = revm::Context::new(revm::EvmContext::new_with_env(db, env), inspector); + revm::Evm::new(context, handler) } @@ -261,11 +280,16 @@ where I: InspectorExt, { let handler_cfg = HandlerCfg::new(inner.spec_id()); - let context = - revm::Context::new(revm::EvmContext { inner, precompiles: Default::default() }, inspector); + let mut handler = revm::Handler::new(handler_cfg); handler.append_handler_register_plain(revm::inspector_handle_register); + if inspector.is_alphanet() { + handler.append_handler_register_plain(alphanet_handler_register); + } handler.append_handler_register_plain(create2_handler_register); + + let context = + revm::Context::new(revm::EvmContext { inner, precompiles: Default::default() }, inspector); revm::Evm::new(context, handler) } diff --git a/crates/evm/evm/src/executors/trace.rs b/crates/evm/evm/src/executors/trace.rs index cc3e687766f8..69c68442b65c 100644 --- a/crates/evm/evm/src/executors/trace.rs +++ b/crates/evm/evm/src/executors/trace.rs @@ -18,6 +18,7 @@ impl TracingExecutor { version: Option, debug: bool, decode_internal: bool, + alphanet: bool, ) -> Self { let db = Backend::spawn(fork); let trace_mode = @@ -30,8 +31,8 @@ impl TracingExecutor { // configures a bare version of the evm executor: no cheatcode inspector is enabled, // tracing will be enabled only for the targeted transaction executor: ExecutorBuilder::new() - .inspectors(|stack| stack.trace_mode(trace_mode)) - .spec(evm_spec_id(&version.unwrap_or_default())) + .inspectors(|stack| stack.trace_mode(trace_mode).alphanet(alphanet)) + .spec(evm_spec_id(&version.unwrap_or_default(), alphanet)) .build(env, db), } } @@ -45,7 +46,7 @@ impl TracingExecutor { pub async fn get_fork_material( config: &Config, mut evm_opts: EvmOpts, - ) -> eyre::Result<(Env, Option, Option)> { + ) -> eyre::Result<(Env, Option, Option, bool)> { evm_opts.fork_url = Some(config.get_rpc_url_or_localhost_http()?.into_owned()); evm_opts.fork_block_number = config.fork_block_number; @@ -53,7 +54,7 @@ impl TracingExecutor { let fork = evm_opts.get_fork(config, env.clone()); - Ok((env, fork, evm_opts.get_remote_chain_id().await)) + Ok((env, fork, evm_opts.get_remote_chain_id().await, evm_opts.alphanet)) } } diff --git a/crates/evm/evm/src/inspectors/stack.rs b/crates/evm/evm/src/inspectors/stack.rs index a6f2f3a1f55d..719998365874 100644 --- a/crates/evm/evm/src/inspectors/stack.rs +++ b/crates/evm/evm/src/inspectors/stack.rs @@ -58,6 +58,8 @@ pub struct InspectorStackBuilder { /// In isolation mode all top-level calls are executed as a separate transaction in a separate /// EVM context, enabling more precise gas accounting and transaction state changes. pub enable_isolation: bool, + /// Whether to enable Alphanet features. + pub alphanet: bool, } impl InspectorStackBuilder { @@ -140,6 +142,14 @@ impl InspectorStackBuilder { self } + /// Set whether to enable Alphanet features. + /// For description of call isolation, see [`InspectorStack::enable_isolation`]. + #[inline] + pub fn alphanet(mut self, yes: bool) -> Self { + self.alphanet = yes; + self + } + /// Builds the stack of inspectors to use when transacting/committing on the EVM. pub fn build(self) -> InspectorStack { let Self { @@ -153,6 +163,7 @@ impl InspectorStackBuilder { print, chisel_state, enable_isolation, + alphanet, } = self; let mut stack = InspectorStack::new(); @@ -172,6 +183,7 @@ impl InspectorStackBuilder { stack.tracing(trace_mode); stack.enable_isolation(enable_isolation); + stack.alphanet(alphanet); // environment, must come after all of the inspectors if let Some(block) = block { @@ -284,6 +296,7 @@ pub struct InspectorStackInner { pub printer: Option, pub tracer: Option, pub enable_isolation: bool, + pub alphanet: bool, /// Flag marking if we are in the inner EVM context. pub in_inner_context: bool, @@ -392,6 +405,12 @@ impl InspectorStack { self.enable_isolation = yes; } + /// Set whether to enable call isolation. + #[inline] + pub fn alphanet(&mut self, yes: bool) { + self.alphanet = yes; + } + /// Set whether to enable the log collector. #[inline] pub fn collect_logs(&mut self, yes: bool) { @@ -914,6 +933,10 @@ impl<'a, DB: DatabaseExt> InspectorExt for InspectorStackRefMut<'a> { inspector, input )); } + + fn is_alphanet(&self) -> bool { + self.inner.alphanet + } } impl Inspector for InspectorStack { @@ -999,6 +1022,10 @@ impl InspectorExt for InspectorStack { ) -> bool { self.as_mut().should_use_create2_factory(ecx, inputs) } + + fn is_alphanet(&self) -> bool { + self.alphanet + } } impl<'a> Deref for InspectorStackRefMut<'a> { diff --git a/crates/forge/bin/cmd/test/mod.rs b/crates/forge/bin/cmd/test/mod.rs index 248d676db8de..ab868f5bc9d0 100644 --- a/crates/forge/bin/cmd/test/mod.rs +++ b/crates/forge/bin/cmd/test/mod.rs @@ -336,6 +336,7 @@ impl TestArgs { .with_fork(evm_opts.get_fork(&config, env.clone())) .with_test_options(test_options) .enable_isolation(evm_opts.isolate) + .alphanet(evm_opts.alphanet) .build(project_root, &output, env, evm_opts)?; let mut maybe_override_mt = |flag, maybe_regex: Option<&Regex>| { diff --git a/crates/forge/src/multi_runner.rs b/crates/forge/src/multi_runner.rs index 9ac3069a61d5..4df00f7944ee 100644 --- a/crates/forge/src/multi_runner.rs +++ b/crates/forge/src/multi_runner.rs @@ -72,6 +72,8 @@ pub struct MultiContractRunner { pub test_options: TestOptions, /// Whether to enable call isolation pub isolation: bool, + /// Whether to enable Alphanet features. + pub alphanet: bool, /// Known contracts linked with computed library addresses. pub known_contracts: ContractsByArtifact, /// Libraries to deploy. @@ -256,6 +258,7 @@ impl MultiContractRunner { .trace_mode(trace_mode) .coverage(self.coverage) .enable_isolation(self.isolation) + .alphanet(self.alphanet) }) .spec(self.evm_spec) .gas_limit(self.evm_opts.gas_limit()) @@ -315,6 +318,8 @@ pub struct MultiContractRunnerBuilder { pub decode_internal: InternalTraceMode, /// Whether to enable call isolation pub isolation: bool, + /// Whether to enable Alphanet features. + pub alphanet: bool, /// Settings related to fuzz and/or invariant tests pub test_options: Option, } @@ -332,6 +337,7 @@ impl MultiContractRunnerBuilder { isolation: Default::default(), test_options: Default::default(), decode_internal: Default::default(), + alphanet: Default::default(), } } @@ -380,6 +386,11 @@ impl MultiContractRunnerBuilder { self } + pub fn alphanet(mut self, enable: bool) -> Self { + self.alphanet = enable; + self + } + /// Given an EVM, proceeds to return a runner which is able to execute all tests /// against that evm pub fn build( @@ -448,6 +459,7 @@ impl MultiContractRunnerBuilder { decode_internal: self.decode_internal, test_options: self.test_options.unwrap_or_default(), isolation: self.isolation, + alphanet: self.alphanet, known_contracts, libs_to_deploy, libraries, diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index fcec5f15a84a..0e38e15e7d87 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -148,6 +148,7 @@ forgetest!(can_extract_config_values, |prj, cmd| { legacy_assertions: false, extra_args: vec![], eof_version: None, + alphanet: false, _non_exhaustive: (), }; prj.write_config(input.clone()); diff --git a/crates/script/src/lib.rs b/crates/script/src/lib.rs index e2f86ce3bcba..1b2618f91e87 100644 --- a/crates/script/src/lib.rs +++ b/crates/script/src/lib.rs @@ -580,7 +580,9 @@ impl ScriptConfig { // We need to enable tracing to decode contract names: local or external. let mut builder = ExecutorBuilder::new() .inspectors(|stack| { - stack.trace_mode(if debug { TraceMode::Debug } else { TraceMode::Call }) + stack + .trace_mode(if debug { TraceMode::Debug } else { TraceMode::Call }) + .alphanet(self.evm_opts.alphanet) }) .spec(self.config.evm_spec_id()) .gas_limit(self.evm_opts.gas_limit()) diff --git a/crates/verify/src/bytecode.rs b/crates/verify/src/bytecode.rs index aa3ffbe0ed56..11da12c43173 100644 --- a/crates/verify/src/bytecode.rs +++ b/crates/verify/src/bytecode.rs @@ -322,11 +322,17 @@ impl VerifyBytecodeArgs { fork_config.fork_block_number = Some(simulation_block - 1); fork_config.evm_version = etherscan_metadata.evm_version()?.unwrap_or(EvmVersion::default()); - let (mut env, fork, _chain) = + let (mut env, fork, _chain, alphanet) = TracingExecutor::get_fork_material(&fork_config, evm_opts).await?; - let mut executor = - TracingExecutor::new(env.clone(), fork, Some(fork_config.evm_version), false, false); + let mut executor = TracingExecutor::new( + env.clone(), + fork, + Some(fork_config.evm_version), + false, + false, + alphanet, + ); env.block.number = U256::from(simulation_block); let block = provider.get_block(simulation_block.into(), true.into()).await?;