Skip to content

Commit

Permalink
feat: Cache invalidation on zksolc version change (#871)
Browse files Browse the repository at this point in the history
---------

Co-authored-by: elfedy <federico@moonsonglabs.com>
Co-authored-by: Jrigada <jrigada@frba.utn.edu.ar>
  • Loading branch information
3 people authored Jan 29, 2025
1 parent 43c6159 commit 60a8f35
Show file tree
Hide file tree
Showing 13 changed files with 183 additions and 104 deletions.
6 changes: 3 additions & 3 deletions crates/common/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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(|| {
Expand Down
51 changes: 21 additions & 30 deletions crates/config/src/zksync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ impl ZkSyncConfig {
libraries: Libraries,
evm_version: EvmVersion,
via_ir: bool,
) -> ZkSolcSettings {
offline: bool,
) -> Result<ZkSolcSettings, SolcError> {
let optimizer = Optimizer {
enabled: Some(self.optimizer),
mode: Some(self.optimizer_mode),
Expand All @@ -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),
Expand All @@ -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)
}
}

Expand All @@ -163,34 +178,10 @@ pub fn config_zksolc_settings(config: &Config) -> Result<ZkSolcSettings, SolcErr
Err(e) => 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<ZkSolcCompiler, SolcError> {
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,
Expand All @@ -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)?;

Expand Down
8 changes: 4 additions & 4 deletions crates/linking/src/zksync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ZkSolcCompiler, ZkArtifactOutput>,
}

Expand All @@ -57,7 +57,7 @@ impl<'a> ZkLinker<'a> {
pub fn new(
root: impl Into<PathBuf>,
contracts: ArtifactContracts<CompactContractBytecodeCow<'a>>,
compiler: ZkSolcCompiler,
compiler: PathBuf,
compiler_output: &'a ProjectCompileOutput<ZkSolcCompiler, ZkArtifactOutput>,
) -> Self {
Self { linker: Linker::new(root, contracts), compiler, compiler_output }
Expand Down Expand Up @@ -299,7 +299,7 @@ impl<'a> ZkLinker<'a> {
contracts: &ArtifactContracts<CompactContractBytecodeCow<'a>>,
target: &ArtifactId,
libraries: &Libraries,
zksolc: &ZkSolcCompiler,
zksolc_path: &Path,
) -> Result<CompactContractBytecodeCow<'a>, ZkLinkerError> {
let artifact_to_link_id = |id: &ArtifactId| format!("{}:{}", id.source.display(), id.name);

Expand Down Expand Up @@ -336,7 +336,7 @@ impl<'a> ZkLinker<'a> {
.collect::<HashSet<_>>();

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);
Expand Down
14 changes: 9 additions & 5 deletions crates/script/src/build/zksync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,27 @@ use super::BuildData;

impl BuildData {
fn get_zk_linker(&self, script_config: &ScriptConfig) -> Result<ZkLinker<'_>> {
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,
Expand Down
8 changes: 4 additions & 4 deletions crates/strategy/zksync/src/executor/runner/libraries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,14 @@ impl ZksyncExecutorStrategyRunner {
let contracts: ArtifactContracts<CompactContractBytecodeCow<'_>> =
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,
Expand Down Expand Up @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion crates/verify/src/etherscan/flatten.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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()) {
Expand Down
4 changes: 2 additions & 2 deletions crates/verify/src/zk_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;
Expand All @@ -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 })
}
Expand Down
1 change: 1 addition & 0 deletions crates/zksync/compilers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ similar-asserts.workspace = true
fd-lock = "4.0.2"
tempfile.workspace = true
foundry-test-utils.workspace = true

7 changes: 5 additions & 2 deletions crates/zksync/compilers/src/compilers/zksolc/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down
20 changes: 3 additions & 17 deletions crates/zksync/compilers/src/compilers/zksolc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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());
Expand Down Expand Up @@ -236,19 +227,14 @@ 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);
zksolc.include_paths.clone_from(&input.cli_settings.include_paths);

Ok(zksolc)
}

/// Retrieve the version of the specified `zksolc`
pub fn version(&self) -> Result<Version> {
ZkSolc::get_version_for_path(self.zksolc.as_ref())
}
}

/// Version metadata. Will include `zksync_version` if compiler is zksync solc.
Expand Down
Loading

0 comments on commit 60a8f35

Please sign in to comment.