From 62d83841be8c45e615add0f5899cb3bbebb3a198 Mon Sep 17 00:00:00 2001 From: elfedy Date: Mon, 13 Jan 2025 16:23:37 -0300 Subject: [PATCH 01/19] add zksolc version list and basic compatibility test --- .../compilers/src/compilers/zksolc/mod.rs | 13 +++++++ crates/zksync/compilers/tests/zksync_tests.rs | 35 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/crates/zksync/compilers/src/compilers/zksolc/mod.rs b/crates/zksync/compilers/src/compilers/zksolc/mod.rs index 3c29ef998..890f12442 100644 --- a/crates/zksync/compilers/src/compilers/zksolc/mod.rs +++ b/crates/zksync/compilers/src/compilers/zksolc/mod.rs @@ -417,6 +417,19 @@ impl ZkSolc { } } + /// Get available zksolc versions + pub fn zksolc_available_versions() -> Vec { + let mut ret = vec![]; + let min_max_patch_by_minor_versions = vec![(5, 6, 9)]; + for (minor, min_patch, max_patch) in min_max_patch_by_minor_versions { + for i in min_patch..=max_patch { + ret.push(Version::new(1, minor, i)); + } + } + + ret + } + /// Get available zksync solc versions pub fn solc_available_versions() -> Vec { let mut ret = vec![]; diff --git a/crates/zksync/compilers/tests/zksync_tests.rs b/crates/zksync/compilers/tests/zksync_tests.rs index c78545951..074b68e42 100644 --- a/crates/zksync/compilers/tests/zksync_tests.rs +++ b/crates/zksync/compilers/tests/zksync_tests.rs @@ -54,6 +54,41 @@ fn zksync_can_compile_dapp_sample() { assert_eq!(cache, updated_cache); } +#[test] +fn zksync_can_compile_dapp_sample_with_supported_zksolc_versions() { + for version in ZkSolc::zksolc_available_versions() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/dapp-sample"); + let paths = ProjectPathsConfig::builder().sources(root.join("src")).lib(root.join("lib")); + let mut project = TempProject::::new(paths).unwrap(); + let compiler = ZkSolcCompiler { + zksolc: ZkSolc::get_path_for_version(&version).unwrap(), + solc: Default::default(), + }; + project.project_mut().compiler = compiler; + + let compiled = project.compile().unwrap(); + compiled.assert_success(); + assert_eq!( + compiled.compiled_artifacts().len(), + 3, + "zksolc {version} compilation yielded wrong number of artifacts" + ); + for (n, c) in compiled.artifacts() { + assert!( + c.bytecode + .as_ref() + .unwrap_or_else(|| panic!( + "zksolc {version} {n} artifact bytecode field should not be empty" + )) + .object() + .bytes_len() + > 0, + "zksolc {version} {n} artifact bytecode should yield more than 0 bytes", + ); + } + } +} + fn test_zksync_can_compile_contract_with_suppressed_errors(compiler: ZkSolcCompiler) { // let _ = tracing_subscriber::fmt() // .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) From 6fd4cc7aa73c9269fc58dd22b32b4b94bea72f8b Mon Sep 17 00:00:00 2001 From: elfedy Date: Tue, 14 Jan 2025 10:29:10 -0300 Subject: [PATCH 02/19] Warn about minimum supported version --- crates/common/src/compile.rs | 10 ++++++++-- crates/zksync/compilers/src/compilers/zksolc/mod.rs | 5 +++++ crates/zksync/compilers/tests/zksync_tests.rs | 4 ++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/crates/common/src/compile.rs b/crates/common/src/compile.rs index 9a408cdfc..0eb631f8b 100644 --- a/crates/common/src/compile.rs +++ b/crates/common/src/compile.rs @@ -333,8 +333,14 @@ impl ProjectCompiler { let files = self.files.clone(); { - let zksolc_version = ZkSolc::get_version_for_path(&project.compiler.zksolc)?; - Report::new(SpinnerReporter::spawn_with(format!("Using zksolc-{zksolc_version}"))); + let zksolc_current_version = ZkSolc::get_version_for_path(&project.compiler.zksolc)?; + let zksolc_min_supported_version = ZkSolc::zksolc_minimum_supported_version(); + if zksolc_current_version < zksolc_min_supported_version { + sh_warn!("Compiling with zksolc v{zksolc_current_version} which is not supported and may lead to unexpected errors. Minimum version supported is v{zksolc_min_supported_version}")?; + } + Report::new(SpinnerReporter::spawn_with(format!( + "Using zksolc-{zksolc_current_version}" + ))); } self.zksync_compile_with(&project.paths.root, || { let files_to_compile = diff --git a/crates/zksync/compilers/src/compilers/zksolc/mod.rs b/crates/zksync/compilers/src/compilers/zksolc/mod.rs index 890f12442..28c36dc98 100644 --- a/crates/zksync/compilers/src/compilers/zksolc/mod.rs +++ b/crates/zksync/compilers/src/compilers/zksolc/mod.rs @@ -430,6 +430,11 @@ impl ZkSolc { ret } + /// Get zksolc minimum supported version + pub fn zksolc_minimum_supported_version() -> Version { + ZkSolc::zksolc_available_versions().remove(0) + } + /// Get available zksync solc versions pub fn solc_available_versions() -> Vec { let mut ret = vec![]; diff --git a/crates/zksync/compilers/tests/zksync_tests.rs b/crates/zksync/compilers/tests/zksync_tests.rs index 074b68e42..6557586f8 100644 --- a/crates/zksync/compilers/tests/zksync_tests.rs +++ b/crates/zksync/compilers/tests/zksync_tests.rs @@ -81,8 +81,8 @@ fn zksync_can_compile_dapp_sample_with_supported_zksolc_versions() { "zksolc {version} {n} artifact bytecode field should not be empty" )) .object() - .bytes_len() - > 0, + .bytes_len() > + 0, "zksolc {version} {n} artifact bytecode should yield more than 0 bytes", ); } From 0fb4cb2823f652cfb348331137c8447b47c401fc Mon Sep 17 00:00:00 2001 From: elfedy Date: Wed, 15 Jan 2025 18:42:32 -0300 Subject: [PATCH 03/19] Add backwards compatibility for hash type --- crates/config/src/zksync.rs | 29 +++++--- .../compilers/src/compilers/zksolc/input.rs | 9 ++- .../src/compilers/zksolc/settings.rs | 30 ++++---- crates/zksync/compilers/tests/zksync_tests.rs | 68 ++++++++++++++++--- 4 files changed, 100 insertions(+), 36 deletions(-) diff --git a/crates/config/src/zksync.rs b/crates/config/src/zksync.rs index 0181bd18f..68432c0b9 100644 --- a/crates/config/src/zksync.rs +++ b/crates/config/src/zksync.rs @@ -46,8 +46,9 @@ pub struct ZkSyncConfig { /// solc path to use along the zksolc compiler pub solc_path: Option, - /// Whether to include the metadata hash for zksolc compiled bytecode. - pub bytecode_hash: Option, + /// Hash type for the the metadata hash appended by zksolc to the compiled bytecode. + #[serde(alias = "bytecode_hash")] + pub hash_type: Option, /// Whether to try to recompile with -Oz if the bytecode is too large. pub fallback_oz: bool, @@ -83,7 +84,7 @@ impl Default for ZkSyncConfig { startup: false, zksolc: Default::default(), solc_path: Default::default(), - bytecode_hash: Default::default(), + hash_type: Default::default(), fallback_oz: Default::default(), enable_eravm_extensions: Default::default(), force_evmla: Default::default(), @@ -128,7 +129,15 @@ impl ZkSyncConfig { libraries, optimizer, evm_version: Some(evm_version), - metadata: Some(SettingsMetadata { bytecode_hash: self.bytecode_hash }), + // NOTE: we set both `bytecode_hash` and `hash_type` fields to the same value abusing + // the fact that invalid json fields get ignored by zksolc. Only the correct field + // that the compiler version understands will be used while the other ignored. + // If this becomes a problem, we need to evaluate adding zksolc version aware + // sanitizing + metadata: Some(SettingsMetadata { + bytecode_hash: self.hash_type, + hash_type: self.hash_type, + }), via_ir: Some(via_ir), // Set in project paths. remappings: Vec::new(), @@ -229,12 +238,12 @@ pub fn config_create_project( fn config_solc_compiler(config: &Config) -> Result { if let Some(path) = &config.zksync.solc_path { if !path.is_file() { - return Err(SolcError::msg(format!("`solc` {} does not exist", path.display()))) + return Err(SolcError::msg(format!("`solc` {} does not exist", path.display()))); } let version = get_solc_version_info(path)?.version; let solc = Solc::new_with_version(path, Version::new(version.major, version.minor, version.patch)); - return Ok(SolcCompiler::Specific(solc)) + return Ok(SolcCompiler::Specific(solc)); } if let Some(ref solc) = config.solc { @@ -256,7 +265,7 @@ fn config_solc_compiler(config: &Config) -> Result { } SolcReq::Local(path) => { if !path.is_file() { - return Err(SolcError::msg(format!("`solc` {} does not exist", path.display()))) + return Err(SolcError::msg(format!("`solc` {} does not exist", path.display()))); } let version = get_solc_version_info(path)?.version; Solc::new_with_version( @@ -307,7 +316,7 @@ pub fn config_ensure_zksolc( if offline { return Err(SolcError::msg(format!( "can't install missing zksolc {version} in offline mode" - ))) + ))); } ZkSolc::blocking_install(version)?; zksolc = ZkSolc::find_installed_version(version)?; @@ -319,12 +328,12 @@ pub fn config_ensure_zksolc( return Err(SolcError::msg(format!( "`zksolc` {} does not exist", zksolc.display() - ))) + ))); } Some(zksolc.clone()) } }; - return Ok(zksolc) + return Ok(zksolc); } Ok(None) diff --git a/crates/zksync/compilers/src/compilers/zksolc/input.rs b/crates/zksync/compilers/src/compilers/zksolc/input.rs index 3172e518c..5835af994 100644 --- a/crates/zksync/compilers/src/compilers/zksolc/input.rs +++ b/crates/zksync/compilers/src/compilers/zksolc/input.rs @@ -108,9 +108,16 @@ impl Default for ZkSolcInput { } impl ZkSolcInput { - fn new(language: SolcLanguage, sources: Sources, settings: ZkSettings) -> Self { + fn new(language: SolcLanguage, sources: Sources, mut settings: ZkSettings) -> Self { + // zksolc <= 1.5.6 has suppressed warnings/errors in at the root input level let suppressed_warnings = settings.suppressed_warnings.clone(); let suppressed_errors = settings.suppressed_errors.clone(); + + // zksolc <= 1.5.6 uses "bytecode_hash" field for "hash_type" + if let Some(ref mut metadata) = settings.metadata { + metadata.bytecode_hash = metadata.hash_type; + }; + Self { language, sources, settings, suppressed_warnings, suppressed_errors } } diff --git a/crates/zksync/compilers/src/compilers/zksolc/settings.rs b/crates/zksync/compilers/src/compilers/zksolc/settings.rs index e111a4eb8..5e396c846 100644 --- a/crates/zksync/compilers/src/compilers/zksolc/settings.rs +++ b/crates/zksync/compilers/src/compilers/zksolc/settings.rs @@ -79,8 +79,6 @@ pub struct ZkSettings { /// The Solidity codegen. #[serde(default)] pub codegen: Codegen, - // TODO: era-compiler-solidity uses a BTreeSet of strings. In theory the serialization - // should be the same but maybe we should double check /// Solidity remappings #[serde(default, skip_serializing_if = "Vec::is_empty")] pub remappings: Vec, @@ -388,32 +386,25 @@ impl OptimizerDetails { /// Settings metadata #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct SettingsMetadata { /// Use the given hash method for the metadata hash that is appended to the bytecode. /// The metadata hash can be removed from the bytecode via option "none". - /// `zksolc` only supports keccak256 #[serde( default, - rename = "bytecodeHash", + skip_serializing_if = "Option::is_none", + with = "serde_helpers::display_from_str_opt" + )] + pub hash_type: Option, + /// hash_type field name for zksolc v1.5.6 and older + #[serde( + default, skip_serializing_if = "Option::is_none", with = "serde_helpers::display_from_str_opt" )] pub bytecode_hash: Option, } -impl SettingsMetadata { - /// New SettingsMetadata - pub fn new(hash: BytecodeHash) -> Self { - Self { bytecode_hash: Some(hash) } - } -} - -impl From for SettingsMetadata { - fn from(hash: BytecodeHash) -> Self { - Self { bytecode_hash: Some(hash) } - } -} - /// Determines the hash method for the metadata hash that is appended to the bytecode. /// Zksolc only supports keccak256 #[derive(Clone, Debug, Default, Copy, PartialEq, Eq, Serialize, Deserialize)] @@ -425,6 +416,9 @@ pub enum BytecodeHash { /// The default keccak256 hash. #[serde(rename = "keccak256")] Keccak256, + /// The `ipfs` hash. + #[serde(rename = "ipfs")] + Ipfs, } impl FromStr for BytecodeHash { @@ -433,6 +427,7 @@ impl FromStr for BytecodeHash { fn from_str(s: &str) -> Result { match s { "none" => Ok(Self::None), + "ipfs" => Ok(Self::Ipfs), "keccak256" => Ok(Self::Keccak256), s => Err(format!("Unknown bytecode hash: {s}")), } @@ -443,6 +438,7 @@ impl fmt::Display for BytecodeHash { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { Self::Keccak256 => "keccak256", + Self::Ipfs => "ipfs", Self::None => "none", }; f.write_str(s) diff --git a/crates/zksync/compilers/tests/zksync_tests.rs b/crates/zksync/compilers/tests/zksync_tests.rs index 6557586f8..f0fbb3f8e 100644 --- a/crates/zksync/compilers/tests/zksync_tests.rs +++ b/crates/zksync/compilers/tests/zksync_tests.rs @@ -17,7 +17,7 @@ use foundry_zksync_compilers::{ artifact_output::zk::ZkArtifactOutput, zksolc::{ input::ZkSolcInput, - settings::{ZkSolcError, ZkSolcWarning}, + settings::{SettingsMetadata, ZkSolcError, ZkSolcWarning}, ZkSolc, ZkSolcCompiler, ZkSolcSettings, }, }, @@ -68,27 +68,79 @@ fn zksync_can_compile_dapp_sample_with_supported_zksolc_versions() { let compiled = project.compile().unwrap(); compiled.assert_success(); - assert_eq!( - compiled.compiled_artifacts().len(), - 3, - "zksolc {version} compilation yielded wrong number of artifacts" - ); + assert_eq!(compiled.compiled_artifacts().len(), 3, "zksolc {version}"); for (n, c) in compiled.artifacts() { assert!( c.bytecode .as_ref() .unwrap_or_else(|| panic!( - "zksolc {version} {n} artifact bytecode field should not be empty" + "zksolc {version}: {n} artifact bytecode field should not be empty" )) .object() .bytes_len() > 0, - "zksolc {version} {n} artifact bytecode should yield more than 0 bytes", + "zksolc {version}", ); } } } +#[test] +fn zksync_can_set_hash_type_with_supported_versions() { + for version in ZkSolc::zksolc_available_versions() { + let mut project = TempProject::::dapptools().unwrap(); + let compiler = ZkSolcCompiler { + zksolc: ZkSolc::get_path_for_version(&version).unwrap(), + solc: Default::default(), + }; + project.project_mut().compiler = compiler; + project.project_mut().settings.settings.metadata = Some(SettingsMetadata { + hash_type: Some( + foundry_zksync_compilers::compilers::zksolc::settings::BytecodeHash::None, + ), + bytecode_hash: None, + }); + + project + .add_source( + "Contract", + r#" + // SPDX-License-Identifier: MIT OR Apache-2.0 + pragma solidity ^0.8.10; + contract Contract { + function call() public {} + } + "#, + ) + .unwrap(); + + let compiled = project.compile().unwrap(); + compiled.assert_success(); + let contract_none = compiled.find_first("Contract").unwrap(); + let bytecode_none = + contract_none.bytecode.as_ref().map(|b| b.object().into_bytes()).unwrap().unwrap(); + + project.project_mut().settings.settings.metadata = Some(SettingsMetadata { + hash_type: Some( + foundry_zksync_compilers::compilers::zksolc::settings::BytecodeHash::Keccak256, + ), + bytecode_hash: None, + }); + + let compiled = project.compile().unwrap(); + compiled.assert_success(); + let contract_keccak = compiled.find_first("Contract").unwrap(); + let bytecode_keccak = + contract_keccak.bytecode.as_ref().map(|b| b.object().into_bytes()).unwrap().unwrap(); + // NOTE: "none" value seems to pad 32 bytes of 0s at the end + assert_eq!(bytecode_none.len(), bytecode_keccak.len(), "zksolc {version}"); + assert_ne!(bytecode_none, bytecode_keccak, "zksolc {version}"); + + let end = bytecode_keccak.len() - 32; + assert_eq!(bytecode_none.slice(..end), bytecode_keccak.slice(..end), "zksolc {version}"); + } +} + fn test_zksync_can_compile_contract_with_suppressed_errors(compiler: ZkSolcCompiler) { // let _ = tracing_subscriber::fmt() // .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) From 7a7a7dc9f47f75b369b8b340d3e434f9538779ae Mon Sep 17 00:00:00 2001 From: elfedy Date: Thu, 16 Jan 2025 10:07:07 -0300 Subject: [PATCH 04/19] add latest supported version and an interface to sanitize bytecode hash --- crates/common/src/compile.rs | 4 ++++ crates/config/src/zksync.rs | 13 ++---------- crates/verify/src/etherscan/flatten.rs | 2 +- .../compilers/src/compilers/zksolc/input.rs | 9 ++++++++- .../compilers/src/compilers/zksolc/mod.rs | 20 +++++++++++-------- .../src/compilers/zksolc/settings.rs | 14 ++++++++++++- crates/zksync/compilers/tests/zksync_tests.rs | 18 +++++------------ 7 files changed, 45 insertions(+), 35 deletions(-) diff --git a/crates/common/src/compile.rs b/crates/common/src/compile.rs index 0eb631f8b..74bfe3e70 100644 --- a/crates/common/src/compile.rs +++ b/crates/common/src/compile.rs @@ -335,9 +335,13 @@ impl ProjectCompiler { { let zksolc_current_version = ZkSolc::get_version_for_path(&project.compiler.zksolc)?; let zksolc_min_supported_version = ZkSolc::zksolc_minimum_supported_version(); + let zksolc_latest_supported_version = ZkSolc::zksolc_latest_supported_version(); if zksolc_current_version < zksolc_min_supported_version { sh_warn!("Compiling with zksolc v{zksolc_current_version} which is not supported and may lead to unexpected errors. Minimum version supported is v{zksolc_min_supported_version}")?; } + if zksolc_current_version > zksolc_latest_supported_version { + sh_warn!("Compiling with zksolc v{zksolc_current_version} which is still not supported and may lead to unexpected errors. Latest version supported is v{zksolc_latest_supported_version}")?; + } Report::new(SpinnerReporter::spawn_with(format!( "Using zksolc-{zksolc_current_version}" ))); diff --git a/crates/config/src/zksync.rs b/crates/config/src/zksync.rs index 68432c0b9..f22ffe2bd 100644 --- a/crates/config/src/zksync.rs +++ b/crates/config/src/zksync.rs @@ -47,7 +47,6 @@ pub struct ZkSyncConfig { pub solc_path: Option, /// Hash type for the the metadata hash appended by zksolc to the compiled bytecode. - #[serde(alias = "bytecode_hash")] pub hash_type: Option, /// Whether to try to recompile with -Oz if the bytecode is too large. @@ -129,15 +128,7 @@ impl ZkSyncConfig { libraries, optimizer, evm_version: Some(evm_version), - // NOTE: we set both `bytecode_hash` and `hash_type` fields to the same value abusing - // the fact that invalid json fields get ignored by zksolc. Only the correct field - // that the compiler version understands will be used while the other ignored. - // If this becomes a problem, we need to evaluate adding zksolc version aware - // sanitizing - metadata: Some(SettingsMetadata { - bytecode_hash: self.hash_type, - hash_type: self.hash_type, - }), + metadata: Some(SettingsMetadata::new(self.hash_type)), via_ir: Some(via_ir), // Set in project paths. remappings: Vec::new(), @@ -207,7 +198,7 @@ pub fn config_create_project( { zksolc } else if !config.offline { - let default_version = semver::Version::new(1, 5, 7); + let default_version = ZkSolc::zksolc_latest_supported_version(); let mut zksolc = ZkSolc::find_installed_version(&default_version)?; if zksolc.is_none() { ZkSolc::blocking_install(&default_version)?; diff --git a/crates/verify/src/etherscan/flatten.rs b/crates/verify/src/etherscan/flatten.rs index 40ae50908..5cf318b5b 100644 --- a/crates/verify/src/etherscan/flatten.rs +++ b/crates/verify/src/etherscan/flatten.rs @@ -68,7 +68,7 @@ impl EtherscanSourceProvider for EtherscanFlattenedSource { context: &ZkVerificationContext, ) -> Result<(String, String, CodeFormat)> { let metadata = context.project.settings.settings.metadata.as_ref(); - let bch = metadata.and_then(|m| m.bytecode_hash).unwrap_or_default(); + let bch = metadata.and_then(|m| m.hash_type).unwrap_or_default(); eyre::ensure!( bch == foundry_zksync_compilers::compilers::zksolc::settings::BytecodeHash::Keccak256, diff --git a/crates/zksync/compilers/src/compilers/zksolc/input.rs b/crates/zksync/compilers/src/compilers/zksolc/input.rs index 5835af994..8f0b61f67 100644 --- a/crates/zksync/compilers/src/compilers/zksolc/input.rs +++ b/crates/zksync/compilers/src/compilers/zksolc/input.rs @@ -109,13 +109,20 @@ impl Default for ZkSolcInput { impl ZkSolcInput { fn new(language: SolcLanguage, sources: Sources, mut settings: ZkSettings) -> Self { + // TODO: Right now we abuse the fact that zksolc ignores invalid fields. Whenever + // there are fields that, for the same feature, are different accross compiler versions, + // we check and set them all to the same value. When compiling with a given version, the + // supported field is used and the other one is ignored. + // If this causes problems, we might need to make ZkSolcInput version aware and sanitize + // accordingly + // zksolc <= 1.5.6 has suppressed warnings/errors in at the root input level let suppressed_warnings = settings.suppressed_warnings.clone(); let suppressed_errors = settings.suppressed_errors.clone(); // zksolc <= 1.5.6 uses "bytecode_hash" field for "hash_type" if let Some(ref mut metadata) = settings.metadata { - metadata.bytecode_hash = metadata.hash_type; + metadata.sanitize(); }; Self { language, sources, settings, suppressed_warnings, suppressed_errors } diff --git a/crates/zksync/compilers/src/compilers/zksolc/mod.rs b/crates/zksync/compilers/src/compilers/zksolc/mod.rs index 28c36dc98..130ebec79 100644 --- a/crates/zksync/compilers/src/compilers/zksolc/mod.rs +++ b/crates/zksync/compilers/src/compilers/zksolc/mod.rs @@ -35,12 +35,8 @@ pub mod input; pub mod settings; pub use settings::{ZkSettings, ZkSolcSettings}; -/// zksolc command -pub const ZKSOLC: &str = "zksolc"; /// ZKsync solc release used for all ZKsync solc versions pub const ZKSYNC_SOLC_RELEASE: Version = Version::new(1, 0, 1); -/// Default zksolc version -pub const ZKSOLC_VERSION: Version = Version::new(1, 5, 7); #[cfg(test)] macro_rules! take_solc_installer_lock { @@ -131,8 +127,8 @@ pub struct ZkSolcCompiler { impl Default for ZkSolcCompiler { fn default() -> Self { - let zksolc = - ZkSolc::get_path_for_version(&ZKSOLC_VERSION).expect("Could not install zksolc"); + let zksolc = ZkSolc::get_path_for_version(&ZkSolc::zksolc_latest_supported_version()) + .expect("Could not install zksolc"); Self { zksolc, solc: Default::default() } } } @@ -420,7 +416,9 @@ impl ZkSolc { /// Get available zksolc versions pub fn zksolc_available_versions() -> Vec { let mut ret = vec![]; - let min_max_patch_by_minor_versions = vec![(5, 6, 9)]; + let min_max_patch_by_minor_versions = vec![ + (5, 6, 7), // 1.5.x + ]; for (minor, min_patch, max_patch) in min_max_patch_by_minor_versions { for i in min_patch..=max_patch { ret.push(Version::new(1, minor, i)); @@ -435,6 +433,11 @@ impl ZkSolc { ZkSolc::zksolc_available_versions().remove(0) } + /// Get zksolc minimum supported version + pub fn zksolc_latest_supported_version() -> Version { + ZkSolc::zksolc_available_versions().pop().expect("No supported zksolc versions") + } + /// Get available zksync solc versions pub fn solc_available_versions() -> Vec { let mut ret = vec![]; @@ -765,7 +768,8 @@ mod tests { use super::*; fn zksolc() -> ZkSolc { - let zksolc_path = ZkSolc::get_path_for_version(&ZKSOLC_VERSION).unwrap(); + let zksolc_path = + ZkSolc::get_path_for_version(&ZkSolc::zksolc_latest_supported_version()).unwrap(); let solc_version = "0.8.27"; take_solc_installer_lock!(_lock); diff --git a/crates/zksync/compilers/src/compilers/zksolc/settings.rs b/crates/zksync/compilers/src/compilers/zksolc/settings.rs index 5e396c846..279b8e28a 100644 --- a/crates/zksync/compilers/src/compilers/zksolc/settings.rs +++ b/crates/zksync/compilers/src/compilers/zksolc/settings.rs @@ -402,7 +402,19 @@ pub struct SettingsMetadata { skip_serializing_if = "Option::is_none", with = "serde_helpers::display_from_str_opt" )] - pub bytecode_hash: Option, + bytecode_hash: Option, +} + +impl SettingsMetadata { + /// Creates new SettingsMettadata + pub fn new(hash_type: Option) -> Self { + Self { hash_type, bytecode_hash: None } + } + + /// Makes SettingsMettadata version compatible + pub fn sanitize(&mut self) { + self.bytecode_hash = self.hash_type; + } } /// Determines the hash method for the metadata hash that is appended to the bytecode. diff --git a/crates/zksync/compilers/tests/zksync_tests.rs b/crates/zksync/compilers/tests/zksync_tests.rs index f0fbb3f8e..7661d9396 100644 --- a/crates/zksync/compilers/tests/zksync_tests.rs +++ b/crates/zksync/compilers/tests/zksync_tests.rs @@ -17,7 +17,7 @@ use foundry_zksync_compilers::{ artifact_output::zk::ZkArtifactOutput, zksolc::{ input::ZkSolcInput, - settings::{SettingsMetadata, ZkSolcError, ZkSolcWarning}, + settings::{BytecodeHash, SettingsMetadata, ZkSolcError, ZkSolcWarning}, ZkSolc, ZkSolcCompiler, ZkSolcSettings, }, }, @@ -94,12 +94,8 @@ fn zksync_can_set_hash_type_with_supported_versions() { solc: Default::default(), }; project.project_mut().compiler = compiler; - project.project_mut().settings.settings.metadata = Some(SettingsMetadata { - hash_type: Some( - foundry_zksync_compilers::compilers::zksolc::settings::BytecodeHash::None, - ), - bytecode_hash: None, - }); + project.project_mut().settings.settings.metadata = + Some(SettingsMetadata::new(Some(BytecodeHash::None))); project .add_source( @@ -120,12 +116,8 @@ fn zksync_can_set_hash_type_with_supported_versions() { let bytecode_none = contract_none.bytecode.as_ref().map(|b| b.object().into_bytes()).unwrap().unwrap(); - project.project_mut().settings.settings.metadata = Some(SettingsMetadata { - hash_type: Some( - foundry_zksync_compilers::compilers::zksolc::settings::BytecodeHash::Keccak256, - ), - bytecode_hash: None, - }); + project.project_mut().settings.settings.metadata = + Some(SettingsMetadata::new(Some(BytecodeHash::Keccak256))); let compiled = project.compile().unwrap(); compiled.assert_success(); From f819d999c5804dce78503db5927d70b74865f925 Mon Sep 17 00:00:00 2001 From: elfedy Date: Thu, 16 Jan 2025 12:32:15 -0300 Subject: [PATCH 05/19] use duplicate field instead of alias --- crates/config/src/zksync.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/crates/config/src/zksync.rs b/crates/config/src/zksync.rs index f22ffe2bd..cbbf5678c 100644 --- a/crates/config/src/zksync.rs +++ b/crates/config/src/zksync.rs @@ -21,7 +21,10 @@ use foundry_zksync_compilers::{ use semver::Version; use serde::{Deserialize, Serialize}; -use std::{collections::HashSet, path::PathBuf}; +use std::{ + collections::{BTreeMap, HashSet}, + path::PathBuf, +}; use crate::{Config, SkipBuildFilters, SolcReq}; @@ -49,6 +52,10 @@ pub struct ZkSyncConfig { /// Hash type for the the metadata hash appended by zksolc to the compiled bytecode. pub hash_type: Option, + /// Hash type for the the metadata hash appended by zksolc to the compiled bytecode. + /// Deprecated in favor of `hash_type` + pub bytecode_hash: Option, + /// Whether to try to recompile with -Oz if the bytecode is too large. pub fallback_oz: bool, @@ -84,6 +91,7 @@ impl Default for ZkSyncConfig { zksolc: Default::default(), solc_path: Default::default(), hash_type: Default::default(), + bytecode_hash: Default::default(), fallback_oz: Default::default(), enable_eravm_extensions: Default::default(), force_evmla: Default::default(), @@ -128,7 +136,7 @@ impl ZkSyncConfig { libraries, optimizer, evm_version: Some(evm_version), - metadata: Some(SettingsMetadata::new(self.hash_type)), + metadata: Some(SettingsMetadata::new(self.hash_type.or(self.bytecode_hash))), via_ir: Some(via_ir), // Set in project paths. remappings: Vec::new(), From 2eb60f262ead08637b3047fe1c91987dffb0f2bd Mon Sep 17 00:00:00 2001 From: elfedy Date: Thu, 16 Jan 2025 13:19:27 -0300 Subject: [PATCH 06/19] Remove stale import --- crates/config/src/zksync.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/config/src/zksync.rs b/crates/config/src/zksync.rs index cbbf5678c..70e0f4502 100644 --- a/crates/config/src/zksync.rs +++ b/crates/config/src/zksync.rs @@ -21,10 +21,7 @@ use foundry_zksync_compilers::{ use semver::Version; use serde::{Deserialize, Serialize}; -use std::{ - collections::{BTreeMap, HashSet}, - path::PathBuf, -}; +use std::{collections::HashSet, path::PathBuf}; use crate::{Config, SkipBuildFilters, SolcReq}; From 449e14e81a37ae31235efe6e65f89a295c774310 Mon Sep 17 00:00:00 2001 From: elfedy Date: Thu, 16 Jan 2025 13:31:58 -0300 Subject: [PATCH 07/19] fix typo --- crates/zksync/compilers/src/compilers/zksolc/input.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/zksync/compilers/src/compilers/zksolc/input.rs b/crates/zksync/compilers/src/compilers/zksolc/input.rs index 8f0b61f67..65eeb8566 100644 --- a/crates/zksync/compilers/src/compilers/zksolc/input.rs +++ b/crates/zksync/compilers/src/compilers/zksolc/input.rs @@ -110,7 +110,7 @@ impl Default for ZkSolcInput { impl ZkSolcInput { fn new(language: SolcLanguage, sources: Sources, mut settings: ZkSettings) -> Self { // TODO: Right now we abuse the fact that zksolc ignores invalid fields. Whenever - // there are fields that, for the same feature, are different accross compiler versions, + // there are fields that, for the same feature, are different across compiler versions, // we check and set them all to the same value. When compiling with a given version, the // supported field is used and the other one is ignored. // If this causes problems, we might need to make ZkSolcInput version aware and sanitize From 84294af5ee807c60a8b90eceb29fbf8df2f2a40e Mon Sep 17 00:00:00 2001 From: elfedy Date: Thu, 16 Jan 2025 14:11:28 -0300 Subject: [PATCH 08/19] improve wording --- crates/zksync/compilers/src/compilers/zksolc/mod.rs | 8 ++++---- crates/zksync/compilers/tests/zksync_tests.rs | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/zksync/compilers/src/compilers/zksolc/mod.rs b/crates/zksync/compilers/src/compilers/zksolc/mod.rs index 130ebec79..bfab9adc8 100644 --- a/crates/zksync/compilers/src/compilers/zksolc/mod.rs +++ b/crates/zksync/compilers/src/compilers/zksolc/mod.rs @@ -413,8 +413,8 @@ impl ZkSolc { } } - /// Get available zksolc versions - pub fn zksolc_available_versions() -> Vec { + /// Get supported zksolc versions + pub fn zksolc_supported_versions() -> Vec { let mut ret = vec![]; let min_max_patch_by_minor_versions = vec![ (5, 6, 7), // 1.5.x @@ -430,12 +430,12 @@ impl ZkSolc { /// Get zksolc minimum supported version pub fn zksolc_minimum_supported_version() -> Version { - ZkSolc::zksolc_available_versions().remove(0) + ZkSolc::zksolc_supported_versions().remove(0) } /// Get zksolc minimum supported version pub fn zksolc_latest_supported_version() -> Version { - ZkSolc::zksolc_available_versions().pop().expect("No supported zksolc versions") + ZkSolc::zksolc_supported_versions().pop().expect("No supported zksolc versions") } /// Get available zksync solc versions diff --git a/crates/zksync/compilers/tests/zksync_tests.rs b/crates/zksync/compilers/tests/zksync_tests.rs index 7661d9396..f95de8148 100644 --- a/crates/zksync/compilers/tests/zksync_tests.rs +++ b/crates/zksync/compilers/tests/zksync_tests.rs @@ -56,7 +56,7 @@ fn zksync_can_compile_dapp_sample() { #[test] fn zksync_can_compile_dapp_sample_with_supported_zksolc_versions() { - for version in ZkSolc::zksolc_available_versions() { + for version in ZkSolc::zksolc_supported_versions() { let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/dapp-sample"); let paths = ProjectPathsConfig::builder().sources(root.join("src")).lib(root.join("lib")); let mut project = TempProject::::new(paths).unwrap(); @@ -87,7 +87,7 @@ fn zksync_can_compile_dapp_sample_with_supported_zksolc_versions() { #[test] fn zksync_can_set_hash_type_with_supported_versions() { - for version in ZkSolc::zksolc_available_versions() { + for version in ZkSolc::zksolc_supported_versions() { let mut project = TempProject::::dapptools().unwrap(); let compiler = ZkSolcCompiler { zksolc: ZkSolc::get_path_for_version(&version).unwrap(), @@ -124,7 +124,7 @@ fn zksync_can_set_hash_type_with_supported_versions() { let contract_keccak = compiled.find_first("Contract").unwrap(); let bytecode_keccak = contract_keccak.bytecode.as_ref().map(|b| b.object().into_bytes()).unwrap().unwrap(); - // NOTE: "none" value seems to pad 32 bytes of 0s at the end + // NOTE: "none" value seems to pad 32 bytes of 0s at the end in this particular case assert_eq!(bytecode_none.len(), bytecode_keccak.len(), "zksolc {version}"); assert_ne!(bytecode_none, bytecode_keccak, "zksolc {version}"); From 6f19010f5e7cd278dc46963184d02c026aab74b2 Mon Sep 17 00:00:00 2001 From: elfedy Date: Thu, 16 Jan 2025 14:20:50 -0300 Subject: [PATCH 09/19] update docs --- crates/config/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/config/README.md b/crates/config/README.md index 960461eca..45880cffc 100644 --- a/crates/config/README.md +++ b/crates/config/README.md @@ -157,7 +157,7 @@ no_storage_caching = false # Whether to store the referenced sources in the metadata as literal data. use_literal_content = false # use ipfs method to generate the metadata hash, solc's default. -# To not include the metadata hash, to allow for deterministic code: https://docs.soliditylang.org/en/latest/metadata.html, use "none" +# To not include the metadata hash, to allow for deterministic code: https://docs.soliditylang.org/en/latest/metadata.html, use "none" (evm compilation only, field will be ignored for zksync) bytecode_hash = "ipfs" # Whether to append the metadata hash to the bytecode cbor_metadata = true @@ -232,7 +232,8 @@ startup = true zksolc = "1.5.0" # By default the corresponding solc patched version from matter-labs is used solc_path = "./solc-0.8.23-1.0.1" -bytecode_hash = "none" +# By default, no value is passed and the default for the compiler (keccak256) will be used +hash_type = "none" # Allow compiler to use mode 'z' if contracts won't fit in the EraVM bytecode # size limitations fallback_oz = false From 67861ecde7d591921a0e8a7e501a727755018109 Mon Sep 17 00:00:00 2001 From: elfedy Date: Thu, 16 Jan 2025 14:25:45 -0300 Subject: [PATCH 10/19] moar update docs --- crates/config/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/config/README.md b/crates/config/README.md index 45880cffc..b1ed4c332 100644 --- a/crates/config/README.md +++ b/crates/config/README.md @@ -228,7 +228,7 @@ The `zksync` settings must be prefixed with the profile they correspond to: compile = false # Enable zkVM at startup, needs `compile = true` to have effect startup = true -# By default the latest version is used +# By default the latest supported version is used zksolc = "1.5.0" # By default the corresponding solc patched version from matter-labs is used solc_path = "./solc-0.8.23-1.0.1" From 01eb12a53fdb6d9a4155a8cbc78859658eeb7b68 Mon Sep 17 00:00:00 2001 From: elfedy Date: Fri, 17 Jan 2025 15:15:06 -0300 Subject: [PATCH 11/19] Fail when specifying unsupported versions --- crates/zksync/compilers/src/compilers/zksolc/mod.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/crates/zksync/compilers/src/compilers/zksolc/mod.rs b/crates/zksync/compilers/src/compilers/zksolc/mod.rs index bfab9adc8..7a44cd733 100644 --- a/crates/zksync/compilers/src/compilers/zksolc/mod.rs +++ b/crates/zksync/compilers/src/compilers/zksolc/mod.rs @@ -583,6 +583,18 @@ impl ZkSolc { /// Get path for installed zksolc version. Returns `Ok(None)` if not installed pub fn find_installed_version(version: &Version) -> Result> { + let min_supported_version = Self::zksolc_minimum_supported_version(); + let latest_supported_version = Self::zksolc_latest_supported_version(); + if *version < min_supported_version { + return Err(SolcError::msg(format!( + "Specifying zksolc v{version} not supported. Minimum version supported is v{min_supported_version}" + ))); + } + if *version > latest_supported_version { + return Err(SolcError::msg(format!( + "Specifying zksolc v{version} not supported. Latest version supported is v{latest_supported_version}" + ))); + } let zksolc = Self::compiler_path(version)?; if !zksolc.is_file() { From df815ab4b2afaec4667e56aa1158b0205eb2d749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Rodr=C3=ADguez?= Date: Wed, 22 Jan 2025 10:27:12 -0300 Subject: [PATCH 12/19] Update crates/common/src/compile.rs Co-authored-by: Nisheeth Barthwal --- crates/common/src/compile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/common/src/compile.rs b/crates/common/src/compile.rs index 74bfe3e70..b0762e3f4 100644 --- a/crates/common/src/compile.rs +++ b/crates/common/src/compile.rs @@ -337,7 +337,7 @@ impl ProjectCompiler { let zksolc_min_supported_version = ZkSolc::zksolc_minimum_supported_version(); let zksolc_latest_supported_version = ZkSolc::zksolc_latest_supported_version(); if zksolc_current_version < zksolc_min_supported_version { - sh_warn!("Compiling with zksolc v{zksolc_current_version} which is not supported and may lead to unexpected errors. Minimum version supported is v{zksolc_min_supported_version}")?; + sh_warn!("Compiling with zksolc v{zksolc_current_version} which is not supported and may lead to unexpected errors. Minimum supported version is v{zksolc_min_supported_version}")?; } if zksolc_current_version > zksolc_latest_supported_version { sh_warn!("Compiling with zksolc v{zksolc_current_version} which is still not supported and may lead to unexpected errors. Latest version supported is v{zksolc_latest_supported_version}")?; From 26d75731770298560754f8bad7759e0633282f70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Rodr=C3=ADguez?= Date: Wed, 22 Jan 2025 10:27:21 -0300 Subject: [PATCH 13/19] Update crates/common/src/compile.rs Co-authored-by: Nisheeth Barthwal --- crates/common/src/compile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/common/src/compile.rs b/crates/common/src/compile.rs index b0762e3f4..ad4ba2161 100644 --- a/crates/common/src/compile.rs +++ b/crates/common/src/compile.rs @@ -340,7 +340,7 @@ impl ProjectCompiler { sh_warn!("Compiling with zksolc v{zksolc_current_version} which is not supported and may lead to unexpected errors. Minimum supported version is v{zksolc_min_supported_version}")?; } if zksolc_current_version > zksolc_latest_supported_version { - sh_warn!("Compiling with zksolc v{zksolc_current_version} which is still not supported and may lead to unexpected errors. Latest version supported is v{zksolc_latest_supported_version}")?; + sh_warn!("Compiling with zksolc v{zksolc_current_version} which is still not supported and may lead to unexpected errors. Latest supported version is v{zksolc_latest_supported_version}")?; } Report::new(SpinnerReporter::spawn_with(format!( "Using zksolc-{zksolc_current_version}" From 8ff768afca10bfe237c77f0f2dd654d4e7b17c7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Rodr=C3=ADguez?= Date: Wed, 22 Jan 2025 10:27:31 -0300 Subject: [PATCH 14/19] Update crates/zksync/compilers/src/compilers/zksolc/input.rs Co-authored-by: Nisheeth Barthwal --- crates/zksync/compilers/src/compilers/zksolc/input.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/zksync/compilers/src/compilers/zksolc/input.rs b/crates/zksync/compilers/src/compilers/zksolc/input.rs index 65eeb8566..c252a6a1b 100644 --- a/crates/zksync/compilers/src/compilers/zksolc/input.rs +++ b/crates/zksync/compilers/src/compilers/zksolc/input.rs @@ -109,7 +109,7 @@ impl Default for ZkSolcInput { impl ZkSolcInput { fn new(language: SolcLanguage, sources: Sources, mut settings: ZkSettings) -> Self { - // TODO: Right now we abuse the fact that zksolc ignores invalid fields. Whenever + // TODO: Right now we make use of the fact that zksolc ignores invalid fields. Whenever // there are fields that, for the same feature, are different across compiler versions, // we check and set them all to the same value. When compiling with a given version, the // supported field is used and the other one is ignored. From 93123a0167e367f85e2d313686be54a8e1fc8d85 Mon Sep 17 00:00:00 2001 From: elfedy Date: Wed, 22 Jan 2025 11:52:55 -0300 Subject: [PATCH 15/19] Use ranges to specify version ranges --- .../compilers/src/compilers/zksolc/mod.rs | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/crates/zksync/compilers/src/compilers/zksolc/mod.rs b/crates/zksync/compilers/src/compilers/zksolc/mod.rs index 7a44cd733..66287cb52 100644 --- a/crates/zksync/compilers/src/compilers/zksolc/mod.rs +++ b/crates/zksync/compilers/src/compilers/zksolc/mod.rs @@ -416,12 +416,11 @@ impl ZkSolc { /// Get supported zksolc versions pub fn zksolc_supported_versions() -> Vec { let mut ret = vec![]; - let min_max_patch_by_minor_versions = vec![ - (5, 6, 7), // 1.5.x - ]; - for (minor, min_patch, max_patch) in min_max_patch_by_minor_versions { - for i in min_patch..=max_patch { - ret.push(Version::new(1, minor, i)); + let version_ranges = vec![(1, 5, 6..=7)]; + + for (major, minor, patch_range) in version_ranges { + for patch in patch_range { + ret.push(Version::new(major, minor, patch)); } } @@ -441,11 +440,11 @@ impl ZkSolc { /// Get available zksync solc versions pub fn solc_available_versions() -> Vec { let mut ret = vec![]; - let min_max_patch_by_minor_versions = - vec![(4, 12, 26), (5, 0, 17), (6, 0, 12), (7, 0, 6), (8, 0, 28)]; - for (minor, min_patch, max_patch) in min_max_patch_by_minor_versions { - for i in min_patch..=max_patch { - ret.push(Version::new(0, minor, i)); + let version_ranges = + vec![(1, 4, 12..=26), (1, 5, 0..=17), (1, 6, 0..=12), (1, 7, 0..=6), (1, 8, 0..=28)]; + for (major, minor, patch_range) in version_ranges { + for patch in patch_range { + ret.push(Version::new(major, minor, patch)); } } From 21a919343a7fb0a8de14516bdd7a82fe28c8957b Mon Sep 17 00:00:00 2001 From: elfedy Date: Wed, 29 Jan 2025 15:45:37 -0300 Subject: [PATCH 16/19] make things compile again --- crates/common/src/compile.rs | 17 +++++++++-------- crates/config/src/zksync.rs | 5 +---- .../compilers/src/compilers/zksolc/settings.rs | 7 ++++--- crates/zksync/compilers/tests/zksync_tests.rs | 16 ++++++++++------ 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/crates/common/src/compile.rs b/crates/common/src/compile.rs index 3cad0615f..8eafd966f 100644 --- a/crates/common/src/compile.rs +++ b/crates/common/src/compile.rs @@ -20,7 +20,8 @@ use foundry_compilers::{ Artifact, Project, ProjectBuilder, ProjectCompileOutput, ProjectPathsConfig, SolcConfig, }; use foundry_zksync_compilers::compilers::{ - artifact_output::zk::ZkArtifactOutput, zksolc::ZkSolcCompiler, + artifact_output::zk::ZkArtifactOutput, + zksolc::{ZkSolc, ZkSolcCompiler}, }; use num_format::{Locale, ToFormattedString}; @@ -283,9 +284,9 @@ impl ProjectCompiler { let dev_functions = artifact.abi.as_ref().map(|abi| abi.functions()).into_iter().flatten().filter( |func| { - func.name.is_any_test() - || func.name.eq("IS_TEST") - || func.name.eq("IS_SCRIPT") + func.name.is_any_test() || + func.name.eq("IS_TEST") || + func.name.eq("IS_SCRIPT") }, ); @@ -333,10 +334,10 @@ impl ProjectCompiler { let zksolc_current_version = project.settings.zksolc_version_ref(); let zksolc_min_supported_version = ZkSolc::zksolc_minimum_supported_version(); let zksolc_latest_supported_version = ZkSolc::zksolc_latest_supported_version(); - if zksolc_current_version < zksolc_min_supported_version { + if zksolc_current_version < &zksolc_min_supported_version { sh_warn!("Compiling with zksolc v{zksolc_current_version} which is not supported and may lead to unexpected errors. Minimum supported version is v{zksolc_min_supported_version}")?; } - if zksolc_current_version > zksolc_latest_supported_version { + if zksolc_current_version > &zksolc_latest_supported_version { sh_warn!("Compiling with zksolc v{zksolc_current_version} which is still not supported and may lead to unexpected errors. Latest supported version is v{zksolc_latest_supported_version}")?; } Report::new(SpinnerReporter::spawn_with(format!( @@ -463,8 +464,8 @@ impl ProjectCompiler { .as_ref() .map(|abi| { abi.functions().any(|f| { - f.test_function_kind().is_known() - || matches!(f.name.as_str(), "IS_TEST" | "IS_SCRIPT") + f.test_function_kind().is_known() || + matches!(f.name.as_str(), "IS_TEST" | "IS_SCRIPT") }) }) .unwrap_or(false); diff --git a/crates/config/src/zksync.rs b/crates/config/src/zksync.rs index 07b691cc0..34209151a 100644 --- a/crates/config/src/zksync.rs +++ b/crates/config/src/zksync.rs @@ -260,10 +260,7 @@ fn config_solc_compiler(config: &Config) -> Result { } SolcReq::Local(path) => { if !path.is_file() { - return Err(SolcError::msg(format!( - "`solc` {} does not exist", - path.display() - ))); + return Err(SolcError::msg(format!("`solc` {} does not exist", path.display()))); } let version = get_solc_version_info(path)?.version; Solc::new_with_version( diff --git a/crates/zksync/compilers/src/compilers/zksolc/settings.rs b/crates/zksync/compilers/src/compilers/zksolc/settings.rs index 1ac230c14..f10e4c3b7 100644 --- a/crates/zksync/compilers/src/compilers/zksolc/settings.rs +++ b/crates/zksync/compilers/src/compilers/zksolc/settings.rs @@ -17,7 +17,7 @@ use std::{ str::FromStr, }; -use super::{ZkSolc, ZKSOLC_VERSION}; +use super::ZkSolc; /// /// The Solidity compiler codegen. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -108,12 +108,13 @@ pub struct ZkSolcSettings { impl Default for ZkSolcSettings { fn default() -> Self { - let zksolc_path = ZkSolc::get_path_for_version(&ZKSOLC_VERSION) + let version = ZkSolc::zksolc_latest_supported_version(); + let zksolc_path = ZkSolc::get_path_for_version(&version) .expect("failed getting default zksolc version path"); Self { settings: Default::default(), cli_settings: Default::default(), - zksolc_version: ZKSOLC_VERSION, + zksolc_version: version, zksolc_path, } } diff --git a/crates/zksync/compilers/tests/zksync_tests.rs b/crates/zksync/compilers/tests/zksync_tests.rs index 028b7caf0..374f26633 100644 --- a/crates/zksync/compilers/tests/zksync_tests.rs +++ b/crates/zksync/compilers/tests/zksync_tests.rs @@ -62,7 +62,7 @@ fn zksync_can_compile_dapp_sample_with_supported_zksolc_versions() { let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/dapp-sample"); let paths = ProjectPathsConfig::builder().sources(root.join("src")).lib(root.join("lib")); let mut project = TempProject::::new(paths).unwrap(); - project.project_mut().settings.set_zksolc_version(version); + project.project_mut().settings.set_zksolc_version(version.clone()).unwrap(); let compiled = project.compile().unwrap(); compiled.assert_success(); @@ -75,8 +75,8 @@ fn zksync_can_compile_dapp_sample_with_supported_zksolc_versions() { "zksolc {version}: {n} artifact bytecode field should not be empty" )) .object() - .bytes_len() - > 0, + .bytes_len() > + 0, "zksolc {version}", ); } @@ -87,7 +87,7 @@ fn zksync_can_compile_dapp_sample_with_supported_zksolc_versions() { fn zksync_can_set_hash_type_with_supported_versions() { for version in ZkSolc::zksolc_supported_versions() { let mut project = TempProject::::dapptools().unwrap(); - project.project_mut().settings.set_zksolc_version(version).unwrap(); + project.project_mut().settings.set_zksolc_version(version.clone()).unwrap(); project.project_mut().settings.settings.metadata = Some(SettingsMetadata::new(Some(BytecodeHash::None))); @@ -167,7 +167,9 @@ fn test_zksync_can_compile_contract_with_suppressed_errors(zksolc_version: Versi #[test] fn zksync_can_compile_contract_with_suppressed_errors() { - test_zksync_can_compile_contract_with_suppressed_errors(ZKSOLC_VERSION); + test_zksync_can_compile_contract_with_suppressed_errors( + ZkSolc::zksolc_latest_supported_version(), + ); } #[test] @@ -229,7 +231,9 @@ fn test_zksync_can_compile_contract_with_suppressed_warnings(zksolc_version: Ver #[test] fn zksync_can_compile_contract_with_suppressed_warnings() { - test_zksync_can_compile_contract_with_suppressed_warnings(ZKSOLC_VERSION); + test_zksync_can_compile_contract_with_suppressed_warnings( + ZkSolc::zksolc_latest_supported_version(), + ); } #[test] From 64c09e799b9d3257dbc4563ab1dee8181dc4da32 Mon Sep 17 00:00:00 2001 From: elfedy Date: Wed, 29 Jan 2025 16:02:24 -0300 Subject: [PATCH 17/19] implement version aware sanitizing --- .../compilers/src/compilers/zksolc/input.rs | 29 ++++++++++--------- .../src/compilers/zksolc/settings.rs | 7 +++-- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/crates/zksync/compilers/src/compilers/zksolc/input.rs b/crates/zksync/compilers/src/compilers/zksolc/input.rs index 67dadab3f..aa25d9e69 100644 --- a/crates/zksync/compilers/src/compilers/zksolc/input.rs +++ b/crates/zksync/compilers/src/compilers/zksolc/input.rs @@ -43,8 +43,10 @@ impl CompilerInput for ZkSolcVersionedInput { version: Version, ) -> Self { let zksolc_path = settings.zksolc_path(); + let zksolc_version = settings.zksolc_version_ref().clone(); let ZkSolcSettings { settings, cli_settings, .. } = settings; - let input = ZkSolcInput::new(language, sources, settings).sanitized(&version); + let input = + ZkSolcInput::new(language, sources, settings, &zksolc_version).sanitized(&version); Self { solc_version: version, input, cli_settings, zksolc_path } } @@ -109,21 +111,22 @@ impl Default for ZkSolcInput { } impl ZkSolcInput { - fn new(language: SolcLanguage, sources: Sources, mut settings: ZkSettings) -> Self { - // TODO: Right now we make use of the fact that zksolc ignores invalid fields. Whenever - // there are fields that, for the same feature, are different across compiler versions, - // we check and set them all to the same value. When compiling with a given version, the - // supported field is used and the other one is ignored. - // If this causes problems, we might need to make ZkSolcInput version aware and sanitize - // accordingly - + fn new( + language: SolcLanguage, + sources: Sources, + mut settings: ZkSettings, + zksolc_version: &Version, + ) -> Self { + let mut suppressed_warnings = HashSet::default(); + let mut suppressed_errors = HashSet::default(); // zksolc <= 1.5.6 has suppressed warnings/errors in at the root input level - let suppressed_warnings = settings.suppressed_warnings.clone(); - let suppressed_errors = settings.suppressed_errors.clone(); + if zksolc_version <= &Version::new(1, 5, 6) { + suppressed_warnings = std::mem::take(&mut settings.suppressed_warnings); + suppressed_errors = std::mem::take(&mut settings.suppressed_errors); + } - // zksolc <= 1.5.6 uses "bytecode_hash" field for "hash_type" if let Some(ref mut metadata) = settings.metadata { - metadata.sanitize(); + metadata.sanitize(zksolc_version); }; Self { language, sources, settings, suppressed_warnings, suppressed_errors } diff --git a/crates/zksync/compilers/src/compilers/zksolc/settings.rs b/crates/zksync/compilers/src/compilers/zksolc/settings.rs index f10e4c3b7..12faf13e8 100644 --- a/crates/zksync/compilers/src/compilers/zksolc/settings.rs +++ b/crates/zksync/compilers/src/compilers/zksolc/settings.rs @@ -425,8 +425,11 @@ impl SettingsMetadata { } /// Makes SettingsMettadata version compatible - pub fn sanitize(&mut self) { - self.bytecode_hash = self.hash_type; + pub fn sanitize(&mut self, zksolc_version: &Version) { + // zksolc <= 1.5.6 uses "bytecode_hash" field for "hash_type" + if zksolc_version <= &Version::new(1, 5, 6) { + self.bytecode_hash = self.hash_type.take(); + } } } From eb50b70bedda77bbf6c41e05f9938f0130771cf0 Mon Sep 17 00:00:00 2001 From: elfedy Date: Thu, 30 Jan 2025 10:33:11 -0300 Subject: [PATCH 18/19] Unsupport 1.5.9 and add deprecation warning --- crates/common/src/compile.rs | 9 ++++++--- .../compilers/src/compilers/zksolc/mod.rs | 20 +++++++------------ 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/crates/common/src/compile.rs b/crates/common/src/compile.rs index 8eafd966f..826b95ba6 100644 --- a/crates/common/src/compile.rs +++ b/crates/common/src/compile.rs @@ -21,7 +21,7 @@ use foundry_compilers::{ }; use foundry_zksync_compilers::compilers::{ artifact_output::zk::ZkArtifactOutput, - zksolc::{ZkSolc, ZkSolcCompiler}, + zksolc::{ZkSolc, ZkSolcCompiler, ZKSOLC_UNSUPPORTED_VERSIONS}, }; use num_format::{Locale, ToFormattedString}; @@ -334,11 +334,14 @@ impl ProjectCompiler { let zksolc_current_version = project.settings.zksolc_version_ref(); let zksolc_min_supported_version = ZkSolc::zksolc_minimum_supported_version(); let zksolc_latest_supported_version = ZkSolc::zksolc_latest_supported_version(); + if ZKSOLC_UNSUPPORTED_VERSIONS.contains(zksolc_current_version) { + sh_warn!("Compiling with zksolc v{zksolc_current_version} which is not supported and may lead to unexpected errors. Specifying an unsupported version is deprecated and will return an error in future versions of foundry-zksync.")?; + } if zksolc_current_version < &zksolc_min_supported_version { - sh_warn!("Compiling with zksolc v{zksolc_current_version} which is not supported and may lead to unexpected errors. Minimum supported version is v{zksolc_min_supported_version}")?; + sh_warn!("Compiling with zksolc v{zksolc_current_version} which is not supported and may lead to unexpected errors. Specifying an unsupported version is deprecated and will return an error in future versions of foundry-zksync. Minimum version supported is v{zksolc_min_supported_version}")?; } if zksolc_current_version > &zksolc_latest_supported_version { - sh_warn!("Compiling with zksolc v{zksolc_current_version} which is still not supported and may lead to unexpected errors. Latest supported version is v{zksolc_latest_supported_version}")?; + sh_warn!("Compiling with zksolc v{zksolc_current_version} which is still not supported and may lead to unexpected errors. Specifying an unsupported version is deprecated and will return an error in future versions of foundry-zksync. Latest version supported is v{zksolc_latest_supported_version}")?; } Report::new(SpinnerReporter::spawn_with(format!( "Using zksolc-{zksolc_current_version}" diff --git a/crates/zksync/compilers/src/compilers/zksolc/mod.rs b/crates/zksync/compilers/src/compilers/zksolc/mod.rs index eda6bbce3..2a17c367d 100644 --- a/crates/zksync/compilers/src/compilers/zksolc/mod.rs +++ b/crates/zksync/compilers/src/compilers/zksolc/mod.rs @@ -38,6 +38,9 @@ pub use settings::{ZkSettings, ZkSolcSettings}; /// ZKsync solc release used for all ZKsync solc versions pub const ZKSYNC_SOLC_RELEASE: Version = Version::new(1, 0, 1); +/// Get zksolc versions that are specifically not supported +pub const ZKSOLC_UNSUPPORTED_VERSIONS: [Version; 1] = [Version::new(1, 5, 9)]; + #[cfg(test)] macro_rules! take_solc_installer_lock { ($lock:ident) => { @@ -411,7 +414,10 @@ impl ZkSolc { for (major, minor, patch_range) in version_ranges { for patch in patch_range { - ret.push(Version::new(major, minor, patch)); + let v = Version::new(major, minor, patch); + if !ZKSOLC_UNSUPPORTED_VERSIONS.contains(&v) { + ret.push(v); + } } } @@ -573,18 +579,6 @@ impl ZkSolc { /// Get path for installed zksolc version. Returns `Ok(None)` if not installed pub fn find_installed_version(version: &Version) -> Result> { - let min_supported_version = Self::zksolc_minimum_supported_version(); - let latest_supported_version = Self::zksolc_latest_supported_version(); - if *version < min_supported_version { - return Err(SolcError::msg(format!( - "Specifying zksolc v{version} not supported. Minimum version supported is v{min_supported_version}" - ))); - } - if *version > latest_supported_version { - return Err(SolcError::msg(format!( - "Specifying zksolc v{version} not supported. Latest version supported is v{latest_supported_version}" - ))); - } let zksolc = Self::compiler_path(version)?; if !zksolc.is_file() { From 83777f7e05d7cfdffd04942ae83d547e36737ae2 Mon Sep 17 00:00:00 2001 From: elfedy Date: Thu, 30 Jan 2025 13:44:05 -0300 Subject: [PATCH 19/19] fix wrong solc major version --- crates/zksync/compilers/src/compilers/zksolc/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/zksync/compilers/src/compilers/zksolc/mod.rs b/crates/zksync/compilers/src/compilers/zksolc/mod.rs index 2a17c367d..01aba9eec 100644 --- a/crates/zksync/compilers/src/compilers/zksolc/mod.rs +++ b/crates/zksync/compilers/src/compilers/zksolc/mod.rs @@ -438,7 +438,7 @@ impl ZkSolc { pub fn solc_available_versions() -> Vec { let mut ret = vec![]; let version_ranges = - vec![(1, 4, 12..=26), (1, 5, 0..=17), (1, 6, 0..=12), (1, 7, 0..=6), (1, 8, 0..=28)]; + vec![(0, 4, 12..=26), (0, 5, 0..=17), (0, 6, 0..=12), (0, 7, 0..=6), (0, 8, 0..=28)]; for (major, minor, patch_range) in version_ranges { for patch in patch_range { ret.push(Version::new(major, minor, patch));