Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions crates/forge/tests/it/cheats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
use crate::{
config::*,
test_helpers::{
ForgeTestData, RE_PATH_SEPARATOR, TEST_DATA_DEFAULT, TEST_DATA_MULTI_VERSION,
TEST_DATA_PARIS,
ForgeTestData, RE_PATH_SEPARATOR, TEST_DATA_DEFAULT, TEST_DATA_DEFAULT_RESOLC,
TEST_DATA_MULTI_VERSION, TEST_DATA_MULTI_VERSION_RESOLC, TEST_DATA_PARIS,
TEST_DATA_PARIS_RESOLC,
},
};
use alloy_primitives::U256;
Expand Down Expand Up @@ -80,3 +81,28 @@ async fn test_cheats_local_multi_version() {
async fn test_cheats_local_paris() {
test_cheats_local(&TEST_DATA_PARIS).await
}

#[tokio::test(flavor = "multi_thread")]
async fn test_resolc_cheats_local_default() {
test_cheats_local(&TEST_DATA_DEFAULT_RESOLC).await
}

#[tokio::test(flavor = "multi_thread")]
async fn test_resolc_cheats_local_default_isolated() {
test_cheats_local_isolated(&TEST_DATA_DEFAULT_RESOLC).await
}

#[tokio::test(flavor = "multi_thread")]
async fn test_resolc_cheats_local_default_with_seed() {
test_cheats_local_with_seed(&TEST_DATA_DEFAULT_RESOLC).await
}

#[tokio::test(flavor = "multi_thread")]
async fn test_resolc_cheats_local_multi_version() {
test_cheats_local(&TEST_DATA_MULTI_VERSION_RESOLC).await
}

#[tokio::test(flavor = "multi_thread")]
async fn test_resolc_cheats_local_paris() {
test_cheats_local(&TEST_DATA_PARIS_RESOLC).await
}
128 changes: 105 additions & 23 deletions crates/forge/tests/it/test_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,26 @@ use forge::{
executors::ExecutorStrategy, revm::primitives::SpecId, MultiContractRunner,
MultiContractRunnerBuilder,
};
use foundry_cli::utils::install_crypto_provider;
use foundry_cli::utils::{get_executor_strategy, install_crypto_provider};
use foundry_common::{compile::ProjectCompiler, shell};
use foundry_compilers::{
artifacts::{EvmVersion, Libraries, Settings},
compilers::multi::MultiCompiler,
resolc::dual_compiled_contracts::DualCompiledContracts,
utils::RuntimeOrHandle,
Project, ProjectCompileOutput, SolcConfig, Vyper,
};
use foundry_config::{
fs_permissions::PathPermission, Config, FsPermissions, FuzzConfig, FuzzDictionaryConfig,
InvariantConfig, RpcEndpointUrl, RpcEndpoints,
fs_permissions::PathPermission, revive, Config, FsPermissions, FuzzConfig,
FuzzDictionaryConfig, InvariantConfig, RpcEndpointUrl, RpcEndpoints,
};
use foundry_evm::{constants::CALLER, opts::EvmOpts};
use foundry_test_utils::{
fd_lock, init_tracing,
rpc::{next_http_archive_rpc_url, next_rpc_endpoint},
};
use std::{
collections::BTreeSet,
env, fmt,
io::Write,
path::{Path, PathBuf},
Expand All @@ -35,25 +38,25 @@ static VYPER: LazyLock<PathBuf> = LazyLock::new(|| std::env::temp_dir().join("vy

/// Profile for the tests group. Used to configure separate configurations for test runs.
pub enum ForgeTestProfile {
Default,
Paris,
MultiVersion,
Default { resolc: bool },
Paris { resolc: bool },
MultiVersion { resolc: bool },
}

impl fmt::Display for ForgeTestProfile {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Default => write!(f, "default"),
Self::Paris => write!(f, "paris"),
Self::MultiVersion => write!(f, "multi-version"),
Self::Default { resolc: _ } => write!(f, "default"),
Self::Paris { resolc: _ } => write!(f, "paris"),
Self::MultiVersion { resolc: _ } => write!(f, "multi-version"),
}
}
}

impl ForgeTestProfile {
/// Returns true if the profile is Paris.
pub fn is_paris(&self) -> bool {
matches!(self, Self::Paris)
matches!(self, Self::Paris { resolc: _ })
}

pub fn root(&self) -> PathBuf {
Expand All @@ -68,7 +71,7 @@ impl ForgeTestProfile {
let mut settings =
Settings { libraries: Libraries::parse(&libs).unwrap(), ..Default::default() };

if matches!(self, Self::Paris) {
if matches!(self, Self::Paris { resolc: _ }) {
settings.evm_version = Some(EvmVersion::Paris);
}

Expand Down Expand Up @@ -159,6 +162,33 @@ impl ForgeTestProfile {
show_solidity: false,
};

if matches!(
self,
Self::Default { resolc: true } |
Self::Paris { resolc: true } |
Self::MultiVersion { resolc: true }
) {
config.resolc.resolc_compile = true;
config.resolc.resolc_startup = true;
config.skip = vec![
"*testdata/default/fork/*".parse().unwrap(),
"*testdata/default/repros/*".parse().unwrap(),
"*testdata/default/fuzz/*".parse().unwrap(),
"*testdata/default/linking/*".parse().unwrap(),
"*testdata/default/cheats/AttachDelegation.t.sol*".parse().unwrap(),
"*testdata/default/cheats/GetArtifactPath.t.sol*".parse().unwrap(),
"*testdata/default/cheats/GetDeployedCode.t.sol*".parse().unwrap(),
"*testdata/default/cheats/DeployCode.t.sol*".parse().unwrap(),
"*testdata/default/cheats/dumpState.t.sol*".parse().unwrap(),
"*testdata/default/cheats/Etch.t.sol*".parse().unwrap(),
"*testdata/default/cheats/GetCode.t.sol*".parse().unwrap(),
"*testdata/default/cheats/loadAllocs.t.sol*".parse().unwrap(),
"*testdata/default/cheats/RecordAccountAccesses.t.sol*".parse().unwrap(),
"*testdata/default/cheats/Broadcast.t.sol*".parse().unwrap(),
"*testdata/default/cheats/MemSafety.t.sol*".parse().unwrap(),
];
}

config.sanitized()
}
}
Expand All @@ -169,6 +199,7 @@ pub struct ForgeTestData {
pub output: ProjectCompileOutput,
pub config: Arc<Config>,
pub profile: ForgeTestProfile,
pub dual_compiled_contracts: Option<DualCompiledContracts>,
}

impl ForgeTestData {
Expand All @@ -180,8 +211,46 @@ impl ForgeTestData {
init_tracing();
let config = Arc::new(profile.config());
let mut project = config.project().unwrap();
let output = get_compiled(&mut project);
Self { project, output, config, profile }

let sources_to_compile = project
.sources()
.expect("Could not read sources")
.keys()
.cloned()
.collect::<BTreeSet<_>>();

// Handle compilation based on whether dual compilation is enabled
let (output, dual_compiled_contracts) = if config.resolc.resolc_compile {
// Dual compilation mode: compile both solc and resolc

// Compile with solc to a subdirectory
let mut solc_config = config.as_ref().clone();
solc_config.out = solc_config.out.join(revive::SOLC_ARTIFACTS_SUBDIR);
solc_config.resolc = Default::default();
solc_config.build_info_path = Some(solc_config.out.join("build-info"));
let mut solc_project = solc_config.project().expect("Could not create solc project");

let solc_output = get_compiled(&mut solc_project);

// Compile with resolc to the main output directory
let mut resolc_project =
config.clone().project().expect("Could not create resolc project");

let resolc_output = get_compiled(&mut resolc_project);

// Create dual compiled contracts
let dual_compiled_contracts = DualCompiledContracts::new(
&solc_output,
&resolc_output,
&solc_project.paths,
&resolc_project.paths,
);

(solc_output, Some(dual_compiled_contracts))
} else {
(get_compiled(&mut project), None)
};
Self { project, output, config, profile, dual_compiled_contracts }
}

/// Builds a base runner
Expand Down Expand Up @@ -222,16 +291,17 @@ impl ForgeTestData {
let config = Arc::new(config);
let root = self.project.root();
builder.config = config.clone();
let mut strategy = get_executor_strategy(&config);

strategy.runner.revive_set_dual_compiled_contracts(
strategy.context.as_mut(),
self.dual_compiled_contracts.clone().unwrap_or_default(),
);

builder
.enable_isolation(opts.isolate)
.sender(config.sender)
.build::<MultiCompiler>(
ExecutorStrategy::new_evm(),
root,
&self.output,
opts.local_evm_env(),
opts,
)
.build::<MultiCompiler>(strategy, root, &self.output, opts.local_evm_env(), opts)
.unwrap()
}

Expand Down Expand Up @@ -346,15 +416,27 @@ pub fn get_compiled(project: &mut Project) -> ProjectCompileOutput {

/// Default data for the tests group.
pub static TEST_DATA_DEFAULT: LazyLock<ForgeTestData> =
LazyLock::new(|| ForgeTestData::new(ForgeTestProfile::Default));
LazyLock::new(|| ForgeTestData::new(ForgeTestProfile::Default { resolc: false }));

/// Data for tests requiring Paris support on Solc and EVM level.
pub static TEST_DATA_PARIS: LazyLock<ForgeTestData> =
LazyLock::new(|| ForgeTestData::new(ForgeTestProfile::Paris));
LazyLock::new(|| ForgeTestData::new(ForgeTestProfile::Paris { resolc: false }));

/// Data for tests requiring Cancun support on Solc and EVM level.
pub static TEST_DATA_MULTI_VERSION: LazyLock<ForgeTestData> =
LazyLock::new(|| ForgeTestData::new(ForgeTestProfile::MultiVersion));
LazyLock::new(|| ForgeTestData::new(ForgeTestProfile::MultiVersion { resolc: false }));

/// Default data for the tests group with resolc enabled.
pub static TEST_DATA_DEFAULT_RESOLC: LazyLock<ForgeTestData> =
LazyLock::new(|| ForgeTestData::new(ForgeTestProfile::Default { resolc: true }));

/// Data for tests requiring Paris support on Solc and EVM level with resolc enabled.
pub static TEST_DATA_PARIS_RESOLC: LazyLock<ForgeTestData> =
LazyLock::new(|| ForgeTestData::new(ForgeTestProfile::Paris { resolc: true }));

/// Data for tests requiring Cancun support on Solc and EVM level with resolc enabled.
pub static TEST_DATA_MULTI_VERSION_RESOLC: LazyLock<ForgeTestData> =
LazyLock::new(|| ForgeTestData::new(ForgeTestProfile::MultiVersion { resolc: true }));

pub fn manifest_root() -> &'static Path {
let mut root = Path::new(env!("CARGO_MANIFEST_DIR"));
Expand Down
Loading