From 60a8f35202d23064e589b3334be331fc42e31993 Mon Sep 17 00:00:00 2001 From: Tincho Date: Wed, 29 Jan 2025 15:20:35 -0300 Subject: [PATCH] feat: Cache invalidation on zksolc version change (#871) --------- Co-authored-by: elfedy Co-authored-by: Jrigada --- crates/common/src/compile.rs | 6 +- crates/config/src/zksync.rs | 51 ++++------ crates/linking/src/zksync.rs | 8 +- crates/script/src/build/zksync.rs | 14 ++- .../zksync/src/executor/runner/libraries.rs | 8 +- crates/verify/src/etherscan/flatten.rs | 3 +- crates/verify/src/zk_provider.rs | 4 +- crates/zksync/compilers/Cargo.toml | 1 + .../compilers/src/compilers/zksolc/input.rs | 7 +- .../compilers/src/compilers/zksolc/mod.rs | 20 +--- .../src/compilers/zksolc/settings.rs | 55 ++++++++++- crates/zksync/compilers/src/link.rs | 14 +-- crates/zksync/compilers/tests/zksync_tests.rs | 96 ++++++++++++++----- 13 files changed, 183 insertions(+), 104 deletions(-) diff --git a/crates/common/src/compile.rs b/crates/common/src/compile.rs index c9d54835a..566a0be42 100644 --- a/crates/common/src/compile.rs +++ b/crates/common/src/compile.rs @@ -20,11 +20,11 @@ use foundry_compilers::{ Artifact, Project, ProjectBuilder, ProjectCompileOutput, ProjectPathsConfig, SolcConfig, }; use foundry_zksync_compilers::compilers::{ - artifact_output::zk::ZkArtifactOutput, - zksolc::{ZkSolc, ZkSolcCompiler}, + artifact_output::zk::ZkArtifactOutput, zksolc::ZkSolcCompiler, }; use num_format::{Locale, ToFormattedString}; + use std::{ collections::BTreeMap, fmt::Display, @@ -330,7 +330,7 @@ impl ProjectCompiler { let files = self.files.clone(); { - let zksolc_version = ZkSolc::get_version_for_path(&project.compiler.zksolc)?; + let zksolc_version = project.settings.zksolc_version_ref(); Report::new(SpinnerReporter::spawn_with(format!("Using zksolc-{zksolc_version}"))); } self.zksync_compile_with(|| { diff --git a/crates/config/src/zksync.rs b/crates/config/src/zksync.rs index 1997aad7d..61f1e5666 100644 --- a/crates/config/src/zksync.rs +++ b/crates/config/src/zksync.rs @@ -114,7 +114,8 @@ impl ZkSyncConfig { libraries: Libraries, evm_version: EvmVersion, via_ir: bool, - ) -> ZkSolcSettings { + offline: bool, + ) -> Result { let optimizer = Optimizer { enabled: Some(self.optimizer), mode: Some(self.optimizer_mode), @@ -124,7 +125,7 @@ impl ZkSyncConfig { jump_table_density_threshold: None, }; - let zk_settings = ZkSettings { + let settings = ZkSettings { libraries, optimizer, evm_version: Some(evm_version), @@ -146,8 +147,22 @@ impl ZkSyncConfig { suppressed_errors: self.suppressed_errors.clone(), }; + let zksolc_path = if let Some(path) = config_ensure_zksolc(self.zksolc.as_ref(), offline)? { + path + } else if !offline { + let default_version = semver::Version::new(1, 5, 11); + let mut zksolc = ZkSolc::find_installed_version(&default_version)?; + if zksolc.is_none() { + ZkSolc::blocking_install(&default_version)?; + zksolc = ZkSolc::find_installed_version(&default_version)?; + } + zksolc.unwrap_or_else(|| panic!("Could not install zksolc v{default_version}")) + } else { + "zksolc".into() + }; + // `cli_settings` get set from `Project` values when building `ZkSolcVersionedInput` - ZkSolcSettings { settings: zk_settings, cli_settings: CliSettings::default() } + ZkSolcSettings::new_from_path(settings, CliSettings::default(), zksolc_path) } } @@ -163,34 +178,10 @@ pub fn config_zksolc_settings(config: &Config) -> Result return Err(SolcError::msg(format!("Failed to parse libraries: {e}"))), }; - Ok(config.zksync.settings(libraries, config.evm_version, config.via_ir)) -} - -/// Return the configured `zksolc` compiler -/// -/// If not `offline`, will install the default version automatically -/// Will fallback to `zksolc` present in the environment -pub fn config_zksolc_compiler(config: &Config) -> Result { - let zksolc = if let Some(zksolc) = - config_ensure_zksolc(config.zksync.zksolc.as_ref(), config.offline)? - { - zksolc - } else if !config.offline { - let default_version = semver::Version::new(1, 5, 11); - let mut zksolc = ZkSolc::find_installed_version(&default_version)?; - if zksolc.is_none() { - ZkSolc::blocking_install(&default_version)?; - zksolc = ZkSolc::find_installed_version(&default_version)?; - } - zksolc.unwrap_or_else(|| panic!("Could not install zksolc v{default_version}")) - } else { - "zksolc".into() - }; - - Ok(ZkSolcCompiler { zksolc, solc: config_solc_compiler(config)? }) + config.zksync.settings(libraries, config.evm_version, config.via_ir, config.offline) } -/// Create a new zkSync project +/// Create a new ZKsync project pub fn config_create_project( config: &Config, cached: bool, @@ -217,7 +208,7 @@ pub fn config_create_project( builder = builder.sparse_output(filter); } - let zksolc_compiler = config_zksolc_compiler(config)?; + let zksolc_compiler = ZkSolcCompiler { solc: config_solc_compiler(config)? }; let project = builder.build(zksolc_compiler)?; diff --git a/crates/linking/src/zksync.rs b/crates/linking/src/zksync.rs index 5afa522e1..ee649793c 100644 --- a/crates/linking/src/zksync.rs +++ b/crates/linking/src/zksync.rs @@ -44,7 +44,7 @@ pub const DEPLOY_TIME_LINKING_ZKSOLC_MIN_VERSION: Version = Version::new(1, 5, 9 #[derive(Debug)] pub struct ZkLinker<'a> { pub linker: Linker<'a>, - pub compiler: ZkSolcCompiler, + pub compiler: PathBuf, pub compiler_output: &'a ProjectCompileOutput, } @@ -57,7 +57,7 @@ impl<'a> ZkLinker<'a> { pub fn new( root: impl Into, contracts: ArtifactContracts>, - compiler: ZkSolcCompiler, + compiler: PathBuf, compiler_output: &'a ProjectCompileOutput, ) -> Self { Self { linker: Linker::new(root, contracts), compiler, compiler_output } @@ -299,7 +299,7 @@ impl<'a> ZkLinker<'a> { contracts: &ArtifactContracts>, target: &ArtifactId, libraries: &Libraries, - zksolc: &ZkSolcCompiler, + zksolc_path: &Path, ) -> Result, ZkLinkerError> { let artifact_to_link_id = |id: &ArtifactId| format!("{}:{}", id.source.display(), id.name); @@ -336,7 +336,7 @@ impl<'a> ZkLinker<'a> { .collect::>(); let mut link_output = - zk_link::zksolc_link(zksolc, zk_link::LinkJsonInput { bytecodes, libraries }) + zk_link::zksolc_link(zksolc_path, zk_link::LinkJsonInput { bytecodes, libraries }) .expect("able to call zksolc --link"); // TODO(zk): proper error check let link_id = &artifact_to_link_id(target); diff --git a/crates/script/src/build/zksync.rs b/crates/script/src/build/zksync.rs index 43d5245a3..25727347d 100644 --- a/crates/script/src/build/zksync.rs +++ b/crates/script/src/build/zksync.rs @@ -18,23 +18,27 @@ use super::BuildData; impl BuildData { fn get_zk_linker(&self, script_config: &ScriptConfig) -> Result> { - let zksolc = foundry_config::zksync::config_zksolc_compiler(&script_config.config) + let zksolc_settings = foundry_config::zksync::config_zksolc_settings(&script_config.config) .context("retrieving zksolc compiler to be used for linking")?; - let version = zksolc.version().context("trying to determine zksolc version")?; + let version = zksolc_settings.zksolc_version_ref(); let Some(input) = self.zk_output.as_ref() else { eyre::bail!("unable to link zk artifacts if no zk compilation output is provided") }; - let linker = - ZkLinker::new(self.project_root.clone(), input.artifact_ids().collect(), zksolc, input); + let linker = ZkLinker::new( + self.project_root.clone(), + input.artifact_ids().collect(), + zksolc_settings.zksolc_path(), + input, + ); let mut libs = Default::default(); linker.zk_collect_dependencies(&self.target, &mut libs, None)?; // if there are no no libs, no linking will happen // so we can skip version check - if !libs.is_empty() && version < DEPLOY_TIME_LINKING_ZKSOLC_MIN_VERSION { + if !libs.is_empty() && version < &DEPLOY_TIME_LINKING_ZKSOLC_MIN_VERSION { eyre::bail!( "deploy-time linking not supported. minimum: {}, given: {}", DEPLOY_TIME_LINKING_ZKSOLC_MIN_VERSION, diff --git a/crates/strategy/zksync/src/executor/runner/libraries.rs b/crates/strategy/zksync/src/executor/runner/libraries.rs index 6ef500412..e3833dd24 100644 --- a/crates/strategy/zksync/src/executor/runner/libraries.rs +++ b/crates/strategy/zksync/src/executor/runner/libraries.rs @@ -56,14 +56,14 @@ impl ZksyncExecutorStrategyRunner { let contracts: ArtifactContracts> = input.artifact_ids().collect(); - let Ok(zksolc) = foundry_config::zksync::config_zksolc_compiler(config) else { + let Ok(zksolc_settings) = foundry_config::zksync::config_zksolc_settings(config) else { tracing::error!("unable to determine zksolc compiler to be used for linking"); // TODO(zk): better error return Err(LinkerError::CyclicDependency); }; - let version = zksolc.version().map_err(|_| LinkerError::CyclicDependency)?; + let version = zksolc_settings.zksolc_version_ref(); - let linker = ZkLinker::new(root, contracts.clone(), zksolc, input); + let linker = ZkLinker::new(root, contracts.clone(), zksolc_settings.zksolc_path(), input); let zk_linker_error_to_linker = |zk_error| match zk_error { ZkLinkerError::Inner(err) => err, @@ -93,7 +93,7 @@ impl ZksyncExecutorStrategyRunner { // so we can skip the version check if !libraries.is_empty() { // TODO(zk): better error - if version < DEPLOY_TIME_LINKING_ZKSOLC_MIN_VERSION { + if version < &DEPLOY_TIME_LINKING_ZKSOLC_MIN_VERSION { tracing::error!( %version, minimum_version = %DEPLOY_TIME_LINKING_ZKSOLC_MIN_VERSION, diff --git a/crates/verify/src/etherscan/flatten.rs b/crates/verify/src/etherscan/flatten.rs index 40ae50908..184b7072a 100644 --- a/crates/verify/src/etherscan/flatten.rs +++ b/crates/verify/src/etherscan/flatten.rs @@ -188,6 +188,7 @@ Diagnostics: {diags}", }, solc_version: solc_version.clone(), cli_settings: CliSettings::default(), + zksolc_path, }; let solc_compiler = if compiler_version.is_zksync_solc { @@ -199,7 +200,7 @@ Diagnostics: {diags}", SolcCompiler::Specific(solc) }; - let zksolc_compiler = ZkSolcCompiler { zksolc: zksolc_path, solc: solc_compiler }; + let zksolc_compiler = ZkSolcCompiler { solc: solc_compiler }; let out = zksolc_compiler.compile(&input)?; if out.errors.iter().any(|e| e.is_error()) { diff --git a/crates/verify/src/zk_provider.rs b/crates/verify/src/zk_provider.rs index 1f85797f4..4834c5d83 100644 --- a/crates/verify/src/zk_provider.rs +++ b/crates/verify/src/zk_provider.rs @@ -45,7 +45,7 @@ impl ZkVerificationContext { let mut project = foundry_config::zksync::config_create_project(&config, config.cache, false)?; project.no_artifacts = true; - let zksolc_version = ZkSolc::get_version_for_path(&project.compiler.zksolc)?; + let zksolc_version = project.settings.zksolc_version_ref(); let (solc_version, is_zksync_solc) = if let Some(solc) = &config.zksync.solc_path { let solc_type_and_version = zksolc::get_solc_version_info(solc)?; @@ -68,7 +68,7 @@ impl ZkVerificationContext { }; let compiler_version = - ZkVersion { zksolc: zksolc_version, solc: solc_version, is_zksync_solc }; + ZkVersion { zksolc: zksolc_version.clone(), solc: solc_version, is_zksync_solc }; Ok(Self { config, project, target_name, target_path, compiler_version }) } diff --git a/crates/zksync/compilers/Cargo.toml b/crates/zksync/compilers/Cargo.toml index 0cc213ec5..9f538b587 100644 --- a/crates/zksync/compilers/Cargo.toml +++ b/crates/zksync/compilers/Cargo.toml @@ -37,3 +37,4 @@ similar-asserts.workspace = true fd-lock = "4.0.2" tempfile.workspace = true foundry-test-utils.workspace = true + diff --git a/crates/zksync/compilers/src/compilers/zksolc/input.rs b/crates/zksync/compilers/src/compilers/zksolc/input.rs index ffa4cbdc7..cbe74a188 100644 --- a/crates/zksync/compilers/src/compilers/zksolc/input.rs +++ b/crates/zksync/compilers/src/compilers/zksolc/input.rs @@ -25,6 +25,8 @@ pub struct ZkSolcVersionedInput { pub solc_version: Version, /// zksolc cli settings pub cli_settings: solc::CliSettings, + /// zksolc binary path + pub zksolc_path: PathBuf, } impl CompilerInput for ZkSolcVersionedInput { @@ -40,10 +42,11 @@ impl CompilerInput for ZkSolcVersionedInput { language: Self::Language, version: Version, ) -> Self { - let ZkSolcSettings { settings, cli_settings } = settings; + let zksolc_path = settings.zksolc_path(); + let ZkSolcSettings { settings, cli_settings, .. } = settings; let input = ZkSolcInput::new(language, sources, settings).sanitized(&version); - Self { solc_version: version, input, cli_settings } + Self { solc_version: version, input, cli_settings, zksolc_path } } fn language(&self) -> Self::Language { diff --git a/crates/zksync/compilers/src/compilers/zksolc/mod.rs b/crates/zksync/compilers/src/compilers/zksolc/mod.rs index e273ec462..eaf0a2075 100644 --- a/crates/zksync/compilers/src/compilers/zksolc/mod.rs +++ b/crates/zksync/compilers/src/compilers/zksolc/mod.rs @@ -121,22 +121,12 @@ impl ZkSolcOS { } /// ZkSolc compiler -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct ZkSolcCompiler { - /// zksolc path - pub zksolc: PathBuf, /// solc compiler to use along zksolc pub solc: SolcCompiler, } -impl Default for ZkSolcCompiler { - fn default() -> Self { - let zksolc = - ZkSolc::get_path_for_version(&ZKSOLC_VERSION).expect("Could not install zksolc"); - Self { zksolc, solc: Default::default() } - } -} - impl Compiler for ZkSolcCompiler { type Input = ZkSolcVersionedInput; type CompilationError = Error; @@ -152,6 +142,7 @@ impl Compiler for ZkSolcCompiler { let zksolc = self.zksolc(input)?; let mut zk_output = zksolc.compile(&input.input)?; + let mut metadata = BTreeMap::new(); if let Some(solc_version) = zk_output.version.take() { metadata.insert("solcVersion".to_string(), solc_version.into()); @@ -236,7 +227,7 @@ impl ZkSolcCompiler { } }; - let mut zksolc = ZkSolc::new(self.zksolc.clone(), solc)?; + let mut zksolc = ZkSolc::new(input.zksolc_path.clone(), solc)?; zksolc.base_path.clone_from(&input.cli_settings.base_path); zksolc.allow_paths.clone_from(&input.cli_settings.allow_paths); @@ -244,11 +235,6 @@ impl ZkSolcCompiler { Ok(zksolc) } - - /// Retrieve the version of the specified `zksolc` - pub fn version(&self) -> Result { - ZkSolc::get_version_for_path(self.zksolc.as_ref()) - } } /// Version metadata. Will include `zksync_version` if compiler is zksync solc. diff --git a/crates/zksync/compilers/src/compilers/zksolc/settings.rs b/crates/zksync/compilers/src/compilers/zksolc/settings.rs index 904175666..e7cc0d2c1 100644 --- a/crates/zksync/compilers/src/compilers/zksolc/settings.rs +++ b/crates/zksync/compilers/src/compilers/zksolc/settings.rs @@ -4,6 +4,7 @@ use era_solc::standard_json::input::settings::{error_type::ErrorType, warning_ty use foundry_compilers::{ artifacts::{serde_helpers, EvmVersion, Libraries}, compilers::CompilerSettings, + error::Result, solc, CompilerSettingsRestrictions, }; use foundry_compilers_artifacts_solc::{output_selection::OutputSelection, remappings::Remapping}; @@ -15,6 +16,8 @@ use std::{ path::{Path, PathBuf}, str::FromStr, }; + +use super::{ZkSolc, ZKSOLC_VERSION}; /// /// The Solidity compiler codegen. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -90,7 +93,7 @@ pub struct ZkSettings { } /// Analogous to SolcSettings for zksolc compiler -#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct ZkSolcSettings { /// JSON settings expected by Solc @@ -99,6 +102,53 @@ pub struct ZkSolcSettings { /// Additional CLI args configuration #[serde(flatten)] pub cli_settings: solc::CliSettings, + /// The version of the zksolc compiler to use. Retrieved from `zksolc_path` + zksolc_version: Version, + /// zksolc path + zksolc_path: PathBuf, +} + +impl Default for ZkSolcSettings { + fn default() -> Self { + let zksolc_path = ZkSolc::get_path_for_version(&ZKSOLC_VERSION) + .expect("failed getting default zksolc version path"); + Self { + settings: Default::default(), + cli_settings: Default::default(), + zksolc_version: ZKSOLC_VERSION, + zksolc_path, + } + } +} + +impl ZkSolcSettings { + /// Initialize settings for a given zksolc path + pub fn new_from_path( + settings: ZkSettings, + cli_settings: solc::CliSettings, + zksolc_path: PathBuf, + ) -> Result { + let zksolc_version = ZkSolc::get_version_for_path(&zksolc_path)?; + Ok(Self { settings, cli_settings, zksolc_path, zksolc_version }) + } + + /// Get zksolc path + pub fn zksolc_path(&self) -> PathBuf { + self.zksolc_path.clone() + } + + /// Get zksolc version + pub fn zksolc_version_ref(&self) -> &Version { + &self.zksolc_version + } + + /// Set a specific zksolc version + pub fn set_zksolc_version(&mut self, zksolc_version: Version) -> Result<()> { + let zksolc_path = ZkSolc::get_path_for_version(&zksolc_version)?; + self.zksolc_version = zksolc_version; + self.zksolc_path = zksolc_path; + Ok(()) + } } impl ZkSettings { @@ -222,7 +272,8 @@ impl CompilerSettings for ZkSolcSettings { *force_evmla == other.settings.force_evmla && *codegen == other.settings.codegen && *suppressed_warnings == other.settings.suppressed_warnings && - *suppressed_errors == other.settings.suppressed_errors + *suppressed_errors == other.settings.suppressed_errors && + self.zksolc_version == other.zksolc_version } fn with_remappings(mut self, remappings: &[Remapping]) -> Self { diff --git a/crates/zksync/compilers/src/link.rs b/crates/zksync/compilers/src/link.rs index 05d84c5e7..b9a97c507 100644 --- a/crates/zksync/compilers/src/link.rs +++ b/crates/zksync/compilers/src/link.rs @@ -12,8 +12,6 @@ use alloy_primitives::{ use foundry_compilers::error::SolcError; use serde::{Deserialize, Serialize}; -use crate::compilers::zksolc::ZkSolcCompiler; - type LinkId = String; /// A library that zksolc will link against @@ -108,12 +106,8 @@ fn map_io_err(zksolc_path: &Path) -> impl FnOnce(std::io::Error) -> SolcError + /// Invoke `zksolc link` given the `zksolc` binary and json input to use #[tracing::instrument(level = tracing::Level::TRACE, ret)] -pub fn zksolc_link( - zksolc: &ZkSolcCompiler, - input: LinkJsonInput, -) -> Result { - let zksolc = &zksolc.zksolc; - let mut cmd = Command::new(zksolc); +pub fn zksolc_link(zksolc_path: &Path, input: LinkJsonInput) -> Result { + let mut cmd = Command::new(zksolc_path); cmd.arg("--standard-json") .arg("--link") @@ -121,12 +115,12 @@ pub fn zksolc_link( .stderr(Stdio::piped()) .stdout(Stdio::piped()); - let mut child = cmd.spawn().map_err(map_io_err(zksolc))?; + let mut child = cmd.spawn().map_err(map_io_err(zksolc_path))?; let stdin = child.stdin.as_mut().unwrap(); let _ = serde_json::to_writer(stdin, &input); - let output = child.wait_with_output().map_err(map_io_err(zksolc))?; + let output = child.wait_with_output().map_err(map_io_err(zksolc_path))?; tracing::trace!(?output); if output.status.success() { diff --git a/crates/zksync/compilers/tests/zksync_tests.rs b/crates/zksync/compilers/tests/zksync_tests.rs index bb3e4a2d1..2ff3cf948 100644 --- a/crates/zksync/compilers/tests/zksync_tests.rs +++ b/crates/zksync/compilers/tests/zksync_tests.rs @@ -16,9 +16,10 @@ use foundry_zksync_compilers::{ artifacts::{contract::Contract, error::Error}, compilers::{ artifact_output::zk::ZkArtifactOutput, - zksolc::{input::ZkSolcInput, ZkSolc, ZkSolcCompiler, ZkSolcSettings}, + zksolc::{input::ZkSolcInput, ZkSolcCompiler, ZkSolcSettings, ZKSOLC_VERSION}, }, }; +use semver::Version; #[test] fn zksync_can_compile_dapp_sample() { @@ -51,13 +52,14 @@ fn zksync_can_compile_dapp_sample() { assert_eq!(cache, updated_cache); } -fn test_zksync_can_compile_contract_with_suppressed_errors(compiler: ZkSolcCompiler) { +fn test_zksync_can_compile_contract_with_suppressed_errors(zksolc_version: Version) { // let _ = tracing_subscriber::fmt() // .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) // .try_init() // .ok(); + let mut project = TempProject::::dapptools().unwrap(); - project.project_mut().compiler = compiler; + project.project_mut().settings.set_zksolc_version(zksolc_version).unwrap(); project .add_source( @@ -76,37 +78,35 @@ fn test_zksync_can_compile_contract_with_suppressed_errors(compiler: ZkSolcCompi .unwrap(); let compiled = project.compile().unwrap(); + assert!(compiled.has_compiler_errors()); project.project_mut().settings.settings.suppressed_errors = HashSet::from([ErrorType::SendTransfer]); let compiled = project.compile().unwrap(); + compiled.assert_success(); assert!(compiled.find_first("Erroneous").is_some()); } #[test] fn zksync_can_compile_contract_with_suppressed_errors() { - test_zksync_can_compile_contract_with_suppressed_errors(ZkSolcCompiler::default()); + test_zksync_can_compile_contract_with_suppressed_errors(ZKSOLC_VERSION); } #[test] fn zksync_pre_1_5_7_can_compile_contract_with_suppressed_errors() { - let compiler = ZkSolcCompiler { - zksolc: ZkSolc::get_path_for_version(&semver::Version::new(1, 5, 6)).unwrap(), - solc: Default::default(), - }; - test_zksync_can_compile_contract_with_suppressed_errors(compiler); + test_zksync_can_compile_contract_with_suppressed_errors(Version::new(1, 5, 6)); } -fn test_zksync_can_compile_contract_with_suppressed_warnings(compiler: ZkSolcCompiler) { +fn test_zksync_can_compile_contract_with_suppressed_warnings(zksolc_version: Version) { // let _ = tracing_subscriber::fmt() // .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) // .try_init() // .ok(); let mut project = TempProject::::dapptools().unwrap(); - project.project_mut().compiler = compiler; + project.project_mut().settings.set_zksolc_version(zksolc_version).unwrap(); project .add_source( @@ -154,23 +154,19 @@ fn test_zksync_can_compile_contract_with_suppressed_warnings(compiler: ZkSolcCom #[test] fn zksync_can_compile_contract_with_suppressed_warnings() { - test_zksync_can_compile_contract_with_suppressed_warnings(ZkSolcCompiler::default()); + test_zksync_can_compile_contract_with_suppressed_warnings(ZKSOLC_VERSION); } #[test] fn zksync_pre_1_5_7_can_compile_contract_with_suppressed_warnings() { - let compiler = ZkSolcCompiler { - zksolc: ZkSolc::get_path_for_version(&semver::Version::new(1, 5, 6)).unwrap(), - solc: Default::default(), - }; - test_zksync_can_compile_contract_with_suppressed_warnings(compiler); + test_zksync_can_compile_contract_with_suppressed_warnings(Version::new(1, 5, 6)); } fn test_zksync_can_compile_contract_with_assembly_create_suppressed_warnings( - compiler: ZkSolcCompiler, + zksolc_version: Version, ) { let mut project = TempProject::::dapptools().unwrap(); - project.project_mut().compiler = compiler; + project.project_mut().settings.set_zksolc_version(zksolc_version).unwrap(); project .add_source( @@ -222,11 +218,9 @@ fn test_zksync_can_compile_contract_with_assembly_create_suppressed_warnings( #[test] fn zksync_can_compile_contract_with_assembly_create_suppressed_warnings_1_5_10() { - let compiler = ZkSolcCompiler { - zksolc: ZkSolc::get_path_for_version(&semver::Version::new(1, 5, 10)).unwrap(), - solc: Default::default(), - }; - test_zksync_can_compile_contract_with_assembly_create_suppressed_warnings(compiler); + test_zksync_can_compile_contract_with_assembly_create_suppressed_warnings(Version::new( + 1, 5, 10, + )); } #[test] @@ -654,3 +648,57 @@ fn zksync_can_compile_yul_sample() { assert!(!yul_bytecode.is_empty(), "SimpleStore bytecode is empty"); } + +#[test] +fn zksync_detects_change_on_cache_if_zksolc_version_changes() { + let mut project = TempProject::::dapptools().unwrap(); + + project.project_mut().build_info = true; + + project + .add_source( + "A", + r#" +pragma solidity ^0.8.10; +import "./B.sol"; +contract A { } +"#, + ) + .unwrap(); + + project + .add_source( + "B", + r" +pragma solidity ^0.8.10; +contract B { } +", + ) + .unwrap(); + + project.project_mut().settings.set_zksolc_version(Version::new(1, 5, 6)).unwrap(); + + let compiled_1 = project.compile().unwrap(); + compiled_1.assert_success(); + + for bi in compiled_1.output().build_infos.iter() { + let zksolc_version = + bi.build_info.get("output").unwrap()["metadata"]["zksolcVersion"].to_string(); + assert_eq!(zksolc_version, "\"1.5.6\""); + } + + let compiled_2 = project.compile().unwrap(); + assert!(compiled_2.is_unchanged()); + + project.project_mut().settings.set_zksolc_version(Version::new(1, 5, 7)).unwrap(); + + let compiled_3 = project.compile().unwrap(); + compiled_3.assert_success(); + assert!(!compiled_3.is_unchanged()); + + for bi in compiled_3.output().build_infos.iter() { + let zksolc_version = + bi.build_info.get("output").unwrap()["metadata"]["zksolcVersion"].to_string(); + assert_eq!(zksolc_version, "\"1.5.7\""); + } +}