Skip to content

Commit 9120621

Browse files
authored
feat: dynamic ZKsync/LLVM solc revision selection (#1055)
1 parent 4bcedfb commit 9120621

File tree

7 files changed

+98
-40
lines changed

7 files changed

+98
-40
lines changed

crates/config/src/zksync.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use foundry_zksync_compilers::{
1515
ZkSolcSettings,
1616
},
1717
ErrorType, WarningType, ZkSettings, ZkSolc, ZkSolcCompiler,
18+
ZKSOLC_FIRST_VERSION_SUPPORTS_CBOR, ZKSYNC_SOLC_REVISIONS,
1819
},
1920
},
2021
};
@@ -254,12 +255,30 @@ fn config_solc_compiler(config: &Config) -> Result<SolcCompiler, SolcError> {
254255
SolcReq::Version(version) => {
255256
let solc_version_without_metadata =
256257
format!("{}.{}.{}", version.major, version.minor, version.patch);
257-
let maybe_solc =
258-
ZkSolc::find_solc_installed_version(&solc_version_without_metadata)?;
258+
let solc_revision = match config
259+
.zksync
260+
.zksolc
261+
.as_ref()
262+
.and_then(|zksolc| zksolc.try_version().ok())
263+
{
264+
Some(ref zksolc_version)
265+
if zksolc_version >= &ZKSOLC_FIRST_VERSION_SUPPORTS_CBOR =>
266+
{
267+
&ZKSYNC_SOLC_REVISIONS[1]
268+
}
269+
_ => &ZKSYNC_SOLC_REVISIONS[0],
270+
};
271+
let maybe_solc = ZkSolc::find_solc_installed_version(
272+
&solc_version_without_metadata,
273+
&solc_revision.to_string(),
274+
)?;
259275
let path = if let Some(solc) = maybe_solc {
260276
solc
261277
} else {
262-
ZkSolc::solc_blocking_install(&solc_version_without_metadata)?
278+
ZkSolc::solc_blocking_install(
279+
&solc_version_without_metadata,
280+
&solc_revision.to_string(),
281+
)?
263282
};
264283
Solc::new_with_version(
265284
path,

crates/verify/src/etherscan/flatten/zksync.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ impl EtherscanFlattenedSource {
9999
},
100100
solc_version: solc_version.clone(),
101101
cli_settings: CliSettings::default(),
102+
zksolc_version,
102103
zksolc_path,
103104
};
104105

crates/verify/src/verify.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ impl VerifyArgs {
231231
.create_verify_request(&self, &context)
232232
.await?;
233233
sh_println!("{}", args.source)?;
234-
return Ok(())
234+
return Ok(());
235235
}
236236

237237
let verifier_url = self.verifier.verifier_url.clone();

crates/verify/src/zk_provider.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ use foundry_compilers::{
1313
use foundry_config::Config;
1414
use foundry_zksync_compilers::compilers::{
1515
artifact_output::zk::ZkArtifactOutput,
16-
zksolc::{self, ZkSolc, ZkSolcCompiler},
16+
zksolc::{
17+
self, ZkSolc, ZkSolcCompiler, ZKSOLC_FIRST_VERSION_SUPPORTS_CBOR, ZKSYNC_SOLC_REVISIONS,
18+
},
1719
};
1820
use revm_primitives::Bytes;
1921
use semver::Version;
@@ -47,19 +49,29 @@ impl ZkVerificationContext {
4749
foundry_config::zksync::config_create_project(&config, config.cache, false)?;
4850
project.no_artifacts = true;
4951
let zksolc_version = project.settings.zksolc_version_ref();
52+
let solc_revision = if zksolc_version >= &ZKSOLC_FIRST_VERSION_SUPPORTS_CBOR {
53+
&ZKSYNC_SOLC_REVISIONS[1]
54+
} else {
55+
&ZKSYNC_SOLC_REVISIONS[0]
56+
};
5057

5158
let (solc_version, is_zksync_solc) = if let Some(solc) = &config.zksync.solc_path {
5259
let solc_type_and_version = zksolc::get_solc_version_info(solc)?;
5360
(solc_type_and_version.version, solc_type_and_version.zksync_version.is_some())
5461
} else {
55-
//if there's no `solc_path` specified then we use the same
62+
// if there's no `solc_path` specified then we use the same
5663
// as the project version
57-
let maybe_solc_path =
58-
ZkSolc::find_solc_installed_version(&context_solc_version.to_string())?;
64+
let maybe_solc_path = ZkSolc::find_solc_installed_version(
65+
&context_solc_version.to_string(),
66+
&solc_revision.to_string(),
67+
)?;
5968
let solc_path = if let Some(p) = maybe_solc_path {
6069
p
6170
} else {
62-
ZkSolc::solc_blocking_install(&context_solc_version.to_string())?
71+
ZkSolc::solc_blocking_install(
72+
&context_solc_version.to_string(),
73+
&solc_revision.to_string(),
74+
)?
6375
};
6476

6577
let solc = Solc::new_with_version(solc_path, context_solc_version.clone());

crates/verify/src/zksync/mod.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ use alloy_primitives::hex;
55
use eyre::{eyre, Result};
66
use foundry_cli::opts::EtherscanOpts;
77
use foundry_common::{abi::encode_function_args, retry::Retry};
8-
use foundry_zksync_compilers::compilers::zksolc::input::StandardJsonCompilerInput;
8+
use foundry_zksync_compilers::compilers::zksolc::{
9+
input::StandardJsonCompilerInput, ZKSOLC_FIRST_VERSION_SUPPORTS_CBOR, ZKSYNC_SOLC_REVISIONS,
10+
};
911
use futures::FutureExt;
1012
use serde::{Deserialize, Serialize};
1113
use std::{fmt::Debug, thread::sleep, time::Duration};
@@ -175,8 +177,15 @@ impl ZkVerificationProvider {
175177

176178
let (solc_version, zk_compiler_version) = match context {
177179
CompilerVerificationContext::ZkSolc(zk_context) => {
178-
// Format solc_version as "zkVM-{compiler_version}-1.0.1"
179-
let solc_version = format!("zkVM-{}-1.0.1", zk_context.compiler_version.solc);
180+
// Format solc_version as "zkVM-{compiler_version}-1.0.2"
181+
let solc_revision =
182+
if zk_context.compiler_version.zksolc >= ZKSOLC_FIRST_VERSION_SUPPORTS_CBOR {
183+
&ZKSYNC_SOLC_REVISIONS[1]
184+
} else {
185+
&ZKSYNC_SOLC_REVISIONS[0]
186+
};
187+
let solc_version =
188+
format!("zkVM-{}-{solc_revision}", zk_context.compiler_version.solc);
180189
let zk_compiler_version = format!("v{}", zk_context.compiler_version.zksolc);
181190
(solc_version, zk_compiler_version)
182191
}

crates/zksync/compilers/src/compilers/zksolc/input.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ pub struct ZkSolcVersionedInput {
2929
pub solc_version: Version,
3030
/// zksolc cli settings
3131
pub cli_settings: solc::CliSettings,
32+
/// zksolc version
33+
pub zksolc_version: Version,
3234
/// zksolc binary path
3335
pub zksolc_path: PathBuf,
3436
}
@@ -52,7 +54,7 @@ impl CompilerInput for ZkSolcVersionedInput {
5254
let input =
5355
ZkSolcInput::new(language, sources, settings, &zksolc_version).sanitized(&version);
5456

55-
Self { solc_version: version, input, cli_settings, zksolc_path }
57+
Self { solc_version: version, input, cli_settings, zksolc_version, zksolc_path }
5658
}
5759

5860
fn language(&self) -> Self::Language {

crates/zksync/compilers/src/compilers/zksolc/mod.rs

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,15 @@ mod types;
3737
pub use settings::{ZkSettings, ZkSolcSettings};
3838
pub use types::{ErrorType, WarningType};
3939

40-
/// ZKsync solc release used for all ZKsync solc versions
41-
pub const ZKSYNC_SOLC_RELEASE: Version = Version::new(1, 0, 1);
40+
/// ZKsync solc revisions used for all ZKsync solc versions
41+
pub const ZKSYNC_SOLC_REVISIONS: [Version; 2] = [Version::new(1, 0, 1), Version::new(1, 0, 2)];
4242

4343
/// Get zksolc versions that are specifically not supported
4444
pub const ZKSOLC_UNSUPPORTED_VERSIONS: [Version; 1] = [Version::new(1, 5, 9)];
4545

46+
/// The first zksolc version where CBOR-encoded metadata is supported
47+
pub const ZKSOLC_FIRST_VERSION_SUPPORTS_CBOR: Version = Version::new(1, 5, 13);
48+
4649
#[cfg(test)]
4750
macro_rules! take_solc_installer_lock {
4851
($lock:ident) => {
@@ -214,14 +217,23 @@ impl ZkSolcCompiler {
214217
"{}.{}.{}",
215218
input.solc_version.major, input.solc_version.minor, input.solc_version.patch
216219
);
217-
let maybe_solc =
218-
ZkSolc::find_solc_installed_version(&solc_version_without_metadata)?;
220+
let solc_revision = if input.zksolc_version >= ZKSOLC_FIRST_VERSION_SUPPORTS_CBOR {
221+
&ZKSYNC_SOLC_REVISIONS[1]
222+
} else {
223+
&ZKSYNC_SOLC_REVISIONS[0]
224+
};
225+
let maybe_solc = ZkSolc::find_solc_installed_version(
226+
&solc_version_without_metadata,
227+
&solc_revision.to_string(),
228+
)?;
219229
if let Some(solc) = maybe_solc {
220230
Some(solc)
221231
} else {
222232
{
223-
let installed_solc_path =
224-
ZkSolc::solc_blocking_install(&solc_version_without_metadata)?;
233+
let installed_solc_path = ZkSolc::solc_blocking_install(
234+
&solc_version_without_metadata,
235+
&solc_revision.to_string(),
236+
)?;
225237
Some(installed_solc_path)
226238
}
227239
}
@@ -241,9 +253,9 @@ impl ZkSolcCompiler {
241253
/// Version metadata. Will include `zksync_version` if compiler is zksync solc.
242254
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
243255
pub struct SolcVersionInfo {
244-
/// The solc compiler version (e.g: 0.8.20)
256+
/// The solc compiler version (e.g: 0.8.30)
245257
pub version: Version,
246-
/// The full zksync solc compiler version (e.g: 0.8.20-1.0.1)
258+
/// The full zksync solc compiler version (e.g: 0.8.30-1.0.2)
247259
pub zksync_version: Option<Version>,
248260
}
249261

@@ -395,7 +407,9 @@ impl ZkSolc {
395407
.filter_map(std::result::Result::ok)
396408
.filter(|e| e.file_type().is_file())
397409
.filter_map(|e| e.file_name().to_str().map(|s| s.to_string()))
398-
.filter(|e| e.ends_with(&ZKSYNC_SOLC_RELEASE.to_string()))
410+
.filter(|e| {
411+
ZKSYNC_SOLC_REVISIONS.iter().any(|v| e.ends_with(v.to_string().as_str()))
412+
})
399413
.filter_map(|e| {
400414
e.strip_prefix(solc_prefix)
401415
.and_then(|s| s.split('-').next())
@@ -412,7 +426,7 @@ impl ZkSolc {
412426
/// Get supported zksolc versions
413427
pub fn zksolc_supported_versions() -> Vec<Version> {
414428
let mut ret = vec![];
415-
let version_ranges = vec![(1, 5, 6..=12)];
429+
let version_ranges = vec![(1, 5, 6..=15)];
416430

417431
for (major, minor, patch_range) in version_ranges {
418432
for patch in patch_range {
@@ -440,7 +454,7 @@ impl ZkSolc {
440454
pub fn solc_available_versions() -> Vec<Version> {
441455
let mut ret = vec![];
442456
let version_ranges =
443-
vec![(0, 4, 12..=26), (0, 5, 0..=17), (0, 6, 0..=12), (0, 7, 0..=6), (0, 8, 0..=29)];
457+
vec![(0, 4, 12..=26), (0, 5, 0..=17), (0, 6, 0..=12), (0, 7, 0..=6), (0, 8, 0..=30)];
444458
for (major, minor, patch_range) in version_ranges {
445459
for patch in patch_range {
446460
ret.push(Version::new(major, minor, patch));
@@ -508,14 +522,10 @@ impl ZkSolc {
508522
Ok(Self::compilers_dir()?.join(format!("{}v{}", os.get_zksolc_prefix(), version)))
509523
}
510524

511-
fn solc_path(version_str: &str) -> Result<PathBuf> {
525+
fn solc_path(version_str: &str, revision_str: &str) -> Result<PathBuf> {
512526
let os = get_operating_system()?;
513-
Ok(Self::compilers_dir()?.join(format!(
514-
"{}{}-{}",
515-
os.get_solc_prefix(),
516-
version_str,
517-
ZKSYNC_SOLC_RELEASE
518-
)))
527+
Ok(Self::compilers_dir()?
528+
.join(format!("{}{version_str}-{revision_str}", os.get_solc_prefix(),)))
519529
}
520530

521531
/// Install zksolc version and block the thread
@@ -560,19 +570,19 @@ impl ZkSolc {
560570
}
561571

562572
/// Install zksync solc version and block the thread
563-
pub fn solc_blocking_install(version_str: &str) -> Result<PathBuf> {
573+
pub fn solc_blocking_install(version_str: &str, revision_str: &str) -> Result<PathBuf> {
564574
let os = get_operating_system()?;
565575
let solc_os_namespace = os.get_solc_prefix();
566576
let download_url = format!(
567-
"https://github.com/matter-labs/era-solidity/releases/download/{version_str}-{ZKSYNC_SOLC_RELEASE}/{solc_os_namespace}{version_str}-{ZKSYNC_SOLC_RELEASE}",
577+
"https://github.com/matter-labs/era-solidity/releases/download/{version_str}-{revision_str}/{solc_os_namespace}{version_str}-{revision_str}",
568578
);
569579

570580
let compilers_dir = Self::compilers_dir()?;
571581
if !compilers_dir.exists() {
572582
create_dir_all(compilers_dir)
573583
.map_err(|e| SolcError::msg(format!("Could not create compilers path: {e}")))?;
574584
}
575-
let solc_path = Self::solc_path(version_str)?;
585+
let solc_path = Self::solc_path(version_str, revision_str)?;
576586
let lock_path = lock_file_path("solc", version_str);
577587

578588
let label = format!("solc-{version_str}");
@@ -590,8 +600,11 @@ impl ZkSolc {
590600
}
591601

592602
/// Get path for installed ZKsync solc version. Returns `Ok(None)` if not installed
593-
pub fn find_solc_installed_version(version_str: &str) -> Result<Option<PathBuf>> {
594-
let solc = Self::solc_path(version_str)?;
603+
pub fn find_solc_installed_version(
604+
version_str: &str,
605+
revision_str: &str,
606+
) -> Result<Option<PathBuf>> {
607+
let solc = Self::solc_path(version_str, revision_str)?;
595608

596609
if !solc.is_file() {
597610
return Ok(None);
@@ -768,14 +781,16 @@ mod tests {
768781
fn zksolc() -> ZkSolc {
769782
let zksolc_path =
770783
ZkSolc::get_path_for_version(&ZkSolc::zksolc_latest_supported_version()).unwrap();
771-
let solc_version = "0.8.27";
784+
let solc_version = "0.8.30";
785+
let solc_revision = ZKSYNC_SOLC_REVISIONS.last().unwrap().to_string();
772786

773787
take_solc_installer_lock!(_lock);
774-
let maybe_solc = ZkSolc::find_solc_installed_version(solc_version).unwrap();
788+
let maybe_solc =
789+
ZkSolc::find_solc_installed_version(solc_version, solc_revision.as_str()).unwrap();
775790
let solc_path = if let Some(solc) = maybe_solc {
776791
solc
777792
} else {
778-
ZkSolc::solc_blocking_install(solc_version).unwrap()
793+
ZkSolc::solc_blocking_install(solc_version, solc_revision.as_str()).unwrap()
779794
};
780795
ZkSolc::new(zksolc_path, Some(solc_path)).unwrap()
781796
}
@@ -801,7 +816,7 @@ mod tests {
801816
let zksync_v = solc_v.zksync_version.unwrap();
802817
let prerelease = Version::parse(zksync_v.pre.as_str()).unwrap();
803818
assert_eq!(solc_v.version.minor, 8);
804-
assert_eq!(prerelease, ZKSYNC_SOLC_RELEASE);
819+
assert!(ZKSYNC_SOLC_REVISIONS.contains(&prerelease));
805820
}
806821

807822
#[test]

0 commit comments

Comments
 (0)