-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: remove
foundry_config::Config
dep from `MultiContractRunn…
…er` (#530)
- Loading branch information
Showing
8 changed files
with
229 additions
and
134 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
mod config; | ||
mod runner; | ||
mod test_results; | ||
mod test_suite; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
use std::{collections::HashMap, path::PathBuf}; | ||
|
||
use alloy_primitives::{address, Address}; | ||
use edr_eth::U256; | ||
use forge::{ | ||
inspectors::cheatcodes::CheatsConfigOptions, | ||
opts::{Env as EvmEnv, EvmOpts}, | ||
}; | ||
use foundry_compilers::ProjectPathsConfig; | ||
use foundry_config::{ | ||
cache::StorageCachingConfig, fs_permissions::PathPermission, FsPermissions, FuzzConfig, | ||
GasLimit, InvariantConfig, RpcEndpoint, RpcEndpoints, | ||
}; | ||
|
||
/// Solidity tests configuration | ||
#[derive(Clone, Debug)] | ||
pub(super) struct SolidityTestsConfig { | ||
/// Project paths configuration | ||
pub project_paths_config: ProjectPathsConfig, | ||
/// Cheats configuration options | ||
pub cheats_config_options: CheatsConfigOptions, | ||
/// EVM options | ||
pub evm_opts: EvmOpts, | ||
/// Configuration for fuzz testing | ||
pub fuzz: FuzzConfig, | ||
/// Configuration for invariant testing | ||
pub invariant: InvariantConfig, | ||
} | ||
|
||
/// Default address for tx.origin for Foundry | ||
/// | ||
/// `0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38` | ||
const DEFAULT_SENDER: Address = address!("1804c8AB1F12E6bbf3894d4083f33e07309d1f38"); | ||
|
||
impl SolidityTestsConfig { | ||
/// Create a new `SolidityTestsConfig` instance | ||
pub fn new(gas_report: bool) -> Self { | ||
// Matches Foundry config defaults | ||
let gas_limit: GasLimit = i64::MAX.into(); | ||
let evm_opts = EvmOpts { | ||
env: EvmEnv { | ||
gas_limit: gas_limit.into(), | ||
chain_id: None, | ||
tx_origin: DEFAULT_SENDER, | ||
block_number: 1, | ||
block_timestamp: 1, | ||
..Default::default() | ||
}, | ||
sender: DEFAULT_SENDER, | ||
initial_balance: U256::from(0xffffffffffffffffffffffffu128), | ||
ffi: false, | ||
verbosity: 0, | ||
memory_limit: 1 << 27, // 2**27 = 128MiB = 134_217_728 bytes | ||
..EvmOpts::default() | ||
}; | ||
|
||
// Matches Foundry config defaults | ||
let mut fuzz = FuzzConfig::new("cache/fuzz".into()); | ||
let mut invariant = InvariantConfig::new("cache/invariant".into()); | ||
if !gas_report { | ||
fuzz.gas_report_samples = 0; | ||
invariant.gas_report_samples = 0; | ||
} | ||
let project_root = PathBuf::from(concat!( | ||
env!("CARGO_MANIFEST_DIR"), | ||
"/../../crates/foundry/testdata" | ||
)); | ||
|
||
// TODO https://github.com/NomicFoundation/edr/issues/487 | ||
let project_paths_config = ProjectPathsConfig::builder().build_with_root(project_root); | ||
|
||
let artifacts: PathBuf = project_paths_config | ||
.artifacts | ||
.file_name() | ||
.expect("artifacts are not relative") | ||
.into(); | ||
|
||
// Matches Foundry config defaults | ||
let cheats_config_options = CheatsConfigOptions { | ||
rpc_endpoints: RpcEndpoints::new([( | ||
"alchemy", | ||
RpcEndpoint::Url("${ALCHEMY_URL}".to_string()), | ||
)]), | ||
unchecked_cheatcode_artifacts: false, | ||
prompt_timeout: 0, | ||
rpc_storage_caching: StorageCachingConfig::default(), | ||
fs_permissions: FsPermissions::new([PathPermission::read(artifacts)]), | ||
labels: HashMap::default(), | ||
}; | ||
|
||
Self { | ||
project_paths_config, | ||
cheats_config_options, | ||
evm_opts, | ||
fuzz, | ||
invariant, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,119 +1,54 @@ | ||
/// Based on `crates/foundry/forge/tests/it/test_helpers.rs`. | ||
use std::{path::PathBuf, sync::Arc}; | ||
use std::sync::Arc; | ||
|
||
use alloy_primitives::U256; | ||
/// Based on `crates/foundry/forge/tests/it/test_helpers.rs`. | ||
use forge::{ | ||
constants::CALLER, | ||
decode::RevertDecoder, | ||
multi_runner::TestContract, | ||
opts::{Env as EvmEnv, EvmOpts}, | ||
revm::primitives::SpecId, | ||
MultiContractRunner, MultiContractRunnerBuilder, TestOptionsBuilder, | ||
decode::RevertDecoder, multi_runner::TestContract, revm::primitives::SpecId, | ||
MultiContractRunner, TestOptionsBuilder, | ||
}; | ||
use foundry_compilers::ArtifactId; | ||
use foundry_config::{Config, RpcEndpoint, RpcEndpoints}; | ||
|
||
use crate::solidity_tests::config::SolidityTestsConfig; | ||
|
||
pub(super) fn build_runner( | ||
test_suites: Vec<(ArtifactId, TestContract)>, | ||
gas_report: bool, | ||
) -> napi::Result<MultiContractRunner> { | ||
let config = foundry_config(gas_report); | ||
let config = SolidityTestsConfig::new(gas_report); | ||
|
||
let mut evm_opts = evm_opts(); | ||
evm_opts.isolate = config.isolate; | ||
evm_opts.verbosity = config.verbosity; | ||
evm_opts.memory_limit = config.memory_limit; | ||
evm_opts.env.gas_limit = config.gas_limit.into(); | ||
let SolidityTestsConfig { | ||
evm_opts, | ||
project_paths_config, | ||
cheats_config_options, | ||
fuzz, | ||
invariant, | ||
} = config; | ||
|
||
let test_options = TestOptionsBuilder::default() | ||
.fuzz(config.fuzz.clone()) | ||
.invariant(config.invariant.clone()) | ||
.fuzz(fuzz) | ||
.invariant(invariant) | ||
.build_hardhat() | ||
.expect("Config loaded"); | ||
|
||
let builder = MultiContractRunnerBuilder::new(Arc::new(config)) | ||
.sender(evm_opts.sender) | ||
.with_test_options(test_options); | ||
.map_err(|e| napi::Error::new(napi::Status::GenericFailure, format!("{e:?}")))?; | ||
|
||
let abis = test_suites.iter().map(|(_, contract)| &contract.abi); | ||
let revert_decoder = RevertDecoder::new().with_abis(abis); | ||
|
||
let sender = Some(evm_opts.sender); | ||
let evm_env = evm_opts.local_evm_env(); | ||
|
||
Ok(MultiContractRunner { | ||
project_paths_config: Arc::new(project_paths_config), | ||
cheats_config_opts: Arc::new(cheats_config_options), | ||
contracts: test_suites.into_iter().collect(), | ||
evm_opts, | ||
env: evm_env, | ||
evm_spec: builder.evm_spec.unwrap_or(SpecId::MERGE), | ||
sender: builder.sender, | ||
evm_spec: SpecId::MERGE, | ||
sender, | ||
revert_decoder, | ||
fork: builder.fork, | ||
config: builder.config, | ||
coverage: builder.coverage, | ||
debug: builder.debug, | ||
test_options: builder.test_options.unwrap_or_default(), | ||
isolation: builder.isolation, | ||
fork: None, | ||
coverage: false, | ||
debug: false, | ||
test_options, | ||
isolation: false, | ||
output: None, | ||
}) | ||
} | ||
|
||
fn project_root() -> PathBuf { | ||
PathBuf::from(concat!( | ||
env!("CARGO_MANIFEST_DIR"), | ||
"/../../crates/foundry/testdata" | ||
)) | ||
} | ||
|
||
fn foundry_config(gas_report: bool) -> Config { | ||
const TEST_PROFILE: &str = "default"; | ||
|
||
// Forge project root. | ||
let root = project_root(); | ||
|
||
let mut config = Config::with_root(&root); | ||
|
||
config.ast = true; | ||
config.src = root.join(TEST_PROFILE); | ||
config.out = root.join("out").join(TEST_PROFILE); | ||
config.cache_path = root.join("cache").join(TEST_PROFILE); | ||
config.libraries = | ||
vec!["fork/Fork.t.sol:DssExecLib:0xfD88CeE74f7D78697775aBDAE53f9Da1559728E4".to_string()]; | ||
|
||
config.rpc_endpoints = rpc_endpoints(); | ||
// TODO https://github.com/NomicFoundation/edr/issues/487 | ||
// config.allow_paths.push(manifest_root().to_path_buf()); | ||
|
||
// no prompt testing | ||
config.prompt_timeout = 0; | ||
|
||
if !gas_report { | ||
config.fuzz.gas_report_samples = 0; | ||
config.invariant.gas_report_samples = 0; | ||
} | ||
|
||
config | ||
} | ||
|
||
fn evm_opts() -> EvmOpts { | ||
EvmOpts { | ||
env: EvmEnv { | ||
gas_limit: u64::MAX, | ||
chain_id: None, | ||
tx_origin: CALLER, | ||
block_number: 1, | ||
block_timestamp: 1, | ||
..Default::default() | ||
}, | ||
sender: CALLER, | ||
initial_balance: U256::MAX, | ||
ffi: true, | ||
verbosity: 3, | ||
memory_limit: 1 << 26, | ||
..Default::default() | ||
} | ||
} | ||
|
||
/// The RPC endpoints used during tests. | ||
fn rpc_endpoints() -> RpcEndpoints { | ||
RpcEndpoints::new([("alchemy", RpcEndpoint::Url("${ALCHEMY_URL}".to_string()))]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.