Skip to content

Commit

Permalink
feat: allow any config to be defined inline (#9430)
Browse files Browse the repository at this point in the history
* feat: allow any config to be defined inline

* com

* rm duplicate

* don't update everything

* bump

* bump
  • Loading branch information
DaniPopes authored Dec 2, 2024
1 parent c4d81b9 commit 3e6d3b8
Show file tree
Hide file tree
Showing 23 changed files with 679 additions and 478 deletions.
15 changes: 13 additions & 2 deletions crates/cheatcodes/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ impl CheatsConfig {
running_version: Option<Version>,
) -> Self {
let mut allowed_paths = vec![config.root.clone()];
allowed_paths.extend(config.libs.clone());
allowed_paths.extend(config.allow_paths.clone());
allowed_paths.extend(config.libs.iter().cloned());
allowed_paths.extend(config.allow_paths.iter().cloned());

let rpc_endpoints = config.rpc_endpoints.clone().resolved();
trace!(?rpc_endpoints, "using resolved rpc endpoints");
Expand Down Expand Up @@ -101,6 +101,17 @@ impl CheatsConfig {
}
}

/// Returns a new `CheatsConfig` configured with the given `Config` and `EvmOpts`.
pub fn clone_with(&self, config: &Config, evm_opts: EvmOpts) -> Self {
Self::new(
config,
evm_opts,
self.available_artifacts.clone(),
self.running_contract.clone(),
self.running_version.clone(),
)
}

/// Attempts to canonicalize (see [std::fs::canonicalize]) the path.
///
/// Canonicalization fails for non-existing paths, in which case we just normalize the path.
Expand Down
4 changes: 2 additions & 2 deletions crates/cheatcodes/src/inspector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ pub struct Cheatcodes {
/// Scripting based transactions
pub broadcastable_transactions: BroadcastableTransactions,

/// Additional, user configurable context this Inspector has access to when inspecting a call
/// Additional, user configurable context this Inspector has access to when inspecting a call.
pub config: Arc<CheatsConfig>,

/// Test-scoped context holding data that needs to be reset every test run
Expand Down Expand Up @@ -540,7 +540,7 @@ impl Cheatcodes {

/// Returns the configured wallets if available, else creates a new instance.
pub fn wallets(&mut self) -> &Wallets {
self.wallets.get_or_insert(Wallets::new(MultiWallet::default(), None))
self.wallets.get_or_insert_with(|| Wallets::new(MultiWallet::default(), None))
}

/// Sets the unlocked wallets.
Expand Down
2 changes: 1 addition & 1 deletion crates/chisel/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ impl SessionSource {
)
})
.gas_limit(self.config.evm_opts.gas_limit())
.spec(self.config.foundry_config.evm_spec_id())
.spec_id(self.config.foundry_config.evm_spec_id())
.legacy_assertions(self.config.foundry_config.legacy_assertions)
.build(env, backend);

Expand Down
32 changes: 25 additions & 7 deletions crates/config/src/inline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use figment::{
value::{Dict, Map, Value},
Figment, Profile, Provider,
};
use foundry_compilers::ProjectCompileOutput;
use itertools::Itertools;

mod natspec;
Expand Down Expand Up @@ -53,6 +54,20 @@ impl InlineConfig {
Self::default()
}

/// Tries to create a new instance by detecting inline configurations from the project compile
/// output.
pub fn new_parsed(output: &ProjectCompileOutput, config: &Config) -> eyre::Result<Self> {
let natspecs: Vec<NatSpec> = NatSpec::parse(output, &config.root);
let profiles = &config.profiles;
let mut inline = Self::new();
for natspec in &natspecs {
inline.insert(natspec)?;
// Validate after parsing as TOML.
natspec.validate_profiles(profiles)?;
}
Ok(inline)
}

/// Inserts a new [`NatSpec`] into the [`InlineConfig`].
pub fn insert(&mut self, natspec: &NatSpec) -> Result<(), InlineConfigError> {
let map = if let Some(function) = &natspec.function {
Expand Down Expand Up @@ -92,13 +107,16 @@ impl InlineConfig {
Figment::from(base).merge(self.provide(contract, function))
}

/// Returns `true` if a configuration is present at the given contract and function level.
pub fn contains(&self, contract: &str, function: &str) -> bool {
// Order swapped to avoid allocation in `get_function` since order doesn't matter here.
self.get_contract(contract)
.filter(|map| !map.is_empty())
.or_else(|| self.get_function(contract, function))
.is_some_and(|map| !map.is_empty())
/// Returns `true` if a configuration is present at the given contract level.
pub fn contains_contract(&self, contract: &str) -> bool {
self.get_contract(contract).is_some_and(|map| !map.is_empty())
}

/// Returns `true` if a configuration is present at the function level.
///
/// Does not include contract-level configurations.
pub fn contains_function(&self, contract: &str, function: &str) -> bool {
self.get_function(contract, function).is_some_and(|map| !map.is_empty())
}

fn get_contract(&self, contract: &str) -> Option<&DataMap> {
Expand Down
2 changes: 1 addition & 1 deletion crates/config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1125,7 +1125,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, self.alphanet)
evm_spec_id(self.evm_version, self.alphanet)
}

/// Returns whether the compiler version should be auto-detected
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 @@ -259,7 +259,7 @@ impl FromStr for Numeric {

/// Returns the [SpecId] derived from [EvmVersion]
#[inline]
pub fn evm_spec_id(evm_version: &EvmVersion, alphanet: bool) -> SpecId {
pub fn evm_spec_id(evm_version: EvmVersion, alphanet: bool) -> SpecId {
if alphanet {
return SpecId::OSAKA;
}
Expand Down
3 changes: 1 addition & 2 deletions crates/evm/core/src/opts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,8 @@ impl EvmOpts {
/// And the block that was used to configure the environment.
pub async fn fork_evm_env(
&self,
fork_url: impl AsRef<str>,
fork_url: &str,
) -> eyre::Result<(revm::primitives::Env, AnyRpcBlock)> {
let fork_url = fork_url.as_ref();
let provider = ProviderBuilder::new(fork_url)
.compute_units_per_second(self.get_compute_units_per_second())
.build()?;
Expand Down
5 changes: 1 addition & 4 deletions crates/evm/core/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,7 @@ pub fn apply_chain_and_block_specific_env_changes<N: Network>(

return;
}
NamedChain::Arbitrum |
NamedChain::ArbitrumGoerli |
NamedChain::ArbitrumNova |
NamedChain::ArbitrumTestnet => {
c if c.is_arbitrum() => {
// on arbitrum `block.number` is the L1 block which is included in the
// `l1BlockNumber` field
if let Some(l1_block_number) = block
Expand Down
2 changes: 1 addition & 1 deletion crates/evm/evm/src/executors/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl ExecutorBuilder {

/// Sets the EVM spec to use.
#[inline]
pub fn spec(mut self, spec: SpecId) -> Self {
pub fn spec_id(mut self, spec: SpecId) -> Self {
self.spec_id = spec;
self
}
Expand Down
40 changes: 31 additions & 9 deletions crates/evm/evm/src/executors/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,7 @@ pub struct Executor {
env: EnvWithHandlerCfg,
/// The Revm inspector stack.
inspector: InspectorStack,
/// The gas limit for calls and deployments. This is different from the gas limit imposed by
/// the passed in environment, as those limits are used by the EVM for certain opcodes like
/// `gaslimit`.
/// The gas limit for calls and deployments.
gas_limit: u64,
/// Whether `failed()` should be called on the test contract to determine if the test failed.
legacy_assertions: bool,
Expand Down Expand Up @@ -166,6 +164,36 @@ impl Executor {
self.env.spec_id()
}

/// Sets the EVM spec ID.
pub fn set_spec_id(&mut self, spec_id: SpecId) {
self.env.handler_cfg.spec_id = spec_id;
}

/// Returns the gas limit for calls and deployments.
///
/// This is different from the gas limit imposed by the passed in environment, as those limits
/// are used by the EVM for certain opcodes like `gaslimit`.
pub fn gas_limit(&self) -> u64 {
self.gas_limit
}

/// Sets the gas limit for calls and deployments.
pub fn set_gas_limit(&mut self, gas_limit: u64) {
self.gas_limit = gas_limit;
}

/// Returns whether `failed()` should be called on the test contract to determine if the test
/// failed.
pub fn legacy_assertions(&self) -> bool {
self.legacy_assertions
}

/// Sets whether `failed()` should be called on the test contract to determine if the test
/// failed.
pub fn set_legacy_assertions(&mut self, legacy_assertions: bool) {
self.legacy_assertions = legacy_assertions;
}

/// Creates the default CREATE2 Contract Deployer for local tests and scripts.
pub fn deploy_create2_deployer(&mut self) -> eyre::Result<()> {
trace!("deploying local create2 deployer");
Expand Down Expand Up @@ -235,12 +263,6 @@ impl Executor {
self
}

#[inline]
pub fn set_gas_limit(&mut self, gas_limit: u64) -> &mut Self {
self.gas_limit = gas_limit;
self
}

#[inline]
pub fn create2_deployer(&self) -> Address {
self.inspector().create2_deployer()
Expand Down
2 changes: 1 addition & 1 deletion crates/evm/evm/src/executors/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ impl TracingExecutor {
.alphanet(alphanet)
.create2_deployer(create2_deployer)
})
.spec(evm_spec_id(&version.unwrap_or_default(), alphanet))
.spec_id(evm_spec_id(version.unwrap_or_default(), alphanet))
.build(env, db),
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/evm/traces/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,8 +349,8 @@ impl TraceMode {
}
}

pub fn with_verbosity(self, verbosiy: u8) -> Self {
if verbosiy >= 3 {
pub fn with_verbosity(self, verbosity: u8) -> Self {
if verbosity >= 3 {
std::cmp::max(self, Self::Call)
} else {
self
Expand Down
3 changes: 1 addition & 2 deletions crates/forge/bin/cmd/coverage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use forge::{
},
opts::EvmOpts,
utils::IcPcMap,
MultiContractRunnerBuilder, TestOptions,
MultiContractRunnerBuilder,
};
use foundry_cli::utils::{LoadConfig, STATIC_FUZZ_SEED};
use foundry_common::{compile::ProjectCompiler, fs};
Expand Down Expand Up @@ -233,7 +233,6 @@ impl CoverageArgs {
.evm_spec(config.evm_spec_id())
.sender(evm_opts.sender)
.with_fork(evm_opts.get_fork(&config, env.clone()))
.with_test_options(TestOptions::new(output, config.clone())?)
.set_coverage(true)
.build(&root, output, env, evm_opts)?;

Expand Down
7 changes: 2 additions & 5 deletions crates/forge/bin/cmd/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use forge::{
identifier::SignaturesIdentifier,
CallTraceDecoderBuilder, InternalTraceMode, TraceKind,
},
MultiContractRunner, MultiContractRunnerBuilder, TestFilter, TestOptions,
MultiContractRunner, MultiContractRunnerBuilder, TestFilter,
};
use foundry_cli::{
opts::{CoreBuildArgs, GlobalOpts},
Expand Down Expand Up @@ -317,9 +317,6 @@ impl TestArgs {
}
}

let config = Arc::new(config);
let test_options = TestOptions::new(&output, config.clone())?;

let should_debug = self.debug.is_some();
let should_draw = self.flamegraph || self.flamechart;

Expand All @@ -346,14 +343,14 @@ impl TestArgs {
};

// Prepare the test builder.
let config = Arc::new(config);
let runner = MultiContractRunnerBuilder::new(config.clone())
.set_debug(should_debug)
.set_decode_internal(decode_internal)
.initial_balance(evm_opts.initial_balance)
.evm_spec(config.evm_spec_id())
.sender(evm_opts.sender)
.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)?;
Expand Down
Loading

0 comments on commit 3e6d3b8

Please sign in to comment.