Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(zk): zksolc linking #800

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 10 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion crates/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ workspace = true

[dependencies]
foundry-block-explorers = { workspace = true, features = ["foundry-compilers"] }
foundry-zksync-compiler.workspace = true
foundry-common-fmt.workspace = true
foundry-compilers.workspace = true
foundry-config.workspace = true
Expand Down
78 changes: 5 additions & 73 deletions crates/common/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@ use foundry_compilers::{
},
Artifact, Project, ProjectBuilder, ProjectCompileOutput, ProjectPathsConfig, SolcConfig,
};
use foundry_zksync_compiler::libraries::{self, ZkMissingLibrary};
use num_format::{Locale, ToFormattedString};
use std::{
collections::{BTreeMap, HashSet},
collections::BTreeMap,
fmt::Display,
io::IsTerminal,
path::{Path, PathBuf},
Expand Down Expand Up @@ -325,7 +324,7 @@ impl ProjectCompiler {
let zksolc_version = ZkSolc::get_version_for_path(&project.compiler.zksolc)?;
Report::new(SpinnerReporter::spawn_with(format!("Using zksolc-{zksolc_version}")));
}
self.zksync_compile_with(&project.paths.root, || {
self.zksync_compile_with(|| {
let files_to_compile =
if !files.is_empty() { files } else { project.paths.input_files() };
let sources = Source::read_all(files_to_compile)?;
Expand All @@ -338,11 +337,7 @@ impl ProjectCompiler {
}

#[instrument(target = "forge::compile", skip_all)]
fn zksync_compile_with<F>(
self,
root_path: impl AsRef<Path>,
f: F,
) -> Result<ZkProjectCompileOutput>
fn zksync_compile_with<F>(self, f: F) -> Result<ZkProjectCompileOutput>
where
F: FnOnce() -> Result<ZkProjectCompileOutput>,
{
Expand Down Expand Up @@ -385,80 +380,17 @@ impl ProjectCompiler {
sh_println!("{output}")?;
}

self.zksync_handle_output(root_path, &output)?;
self.zksync_handle_output(&output)?;
}

Ok(output)
}

/// If configured, this will print sizes or names
fn zksync_handle_output(
&self,
root_path: impl AsRef<Path>,
output: &ZkProjectCompileOutput,
) -> Result<()> {
fn zksync_handle_output(&self, output: &ZkProjectCompileOutput) -> Result<()> {
let print_names = self.print_names.unwrap_or(false);
let print_sizes = self.print_sizes.unwrap_or(false);

// Process missing libraries
// TODO: skip this if project was not compiled using --detect-missing-libraries
let mut missing_libs_unique: HashSet<String> = HashSet::new();
for (artifact_id, artifact) in output.artifact_ids() {
// TODO: when compiling specific files, the output might still add cached artifacts
// that are not part of the file list to the output, which may cause missing libraries
// error to trigger for files that were not intended to be compiled.
// This behaviour needs to be investigated better on the foundry-compilers side.
// For now we filter, checking only the files passed to compile.
let is_target_file =
self.files.is_empty() || self.files.iter().any(|f| artifact_id.path == *f);
if is_target_file {
if let Some(mls) = artifact.missing_libraries() {
missing_libs_unique.extend(mls.clone());
}
}
}

let missing_libs: Vec<ZkMissingLibrary> = missing_libs_unique
.into_iter()
.map(|ml| {
let mut split = ml.split(':');
let contract_path =
split.next().expect("Failed to extract contract path for missing library");
let contract_name =
split.next().expect("Failed to extract contract name for missing library");

let mut abs_path_buf = PathBuf::new();
abs_path_buf.push(root_path.as_ref());
abs_path_buf.push(contract_path);

let art = output.find(abs_path_buf.as_path(), contract_name).unwrap_or_else(|| {
panic!(
"Could not find contract {contract_name} at path {contract_path} for compilation output"
)
});

ZkMissingLibrary {
contract_path: contract_path.to_string(),
contract_name: contract_name.to_string(),
missing_libraries: art.missing_libraries().cloned().unwrap_or_default(),
}
})
.collect();

if !missing_libs.is_empty() {
libraries::add_dependencies_to_missing_libraries_cache(
root_path,
missing_libs.as_slice(),
)
.expect("Error while adding missing libraries");
let missing_libs_list = missing_libs
.iter()
.map(|ml| format!("{}:{}", ml.contract_path, ml.contract_name))
.collect::<Vec<String>>()
.join(", ");
eyre::bail!("Missing libraries detected: {missing_libs_list}\n\nRun the following command in order to deploy each missing library:\n\nforge create <LIBRARY> --private-key <PRIVATE_KEY> --rpc-url <RPC_URL> --chain <CHAIN_ID> --zksync\n\nThen pass the library addresses using the --libraries option");
}

// print any sizes or names
if print_names {
let mut artifacts: BTreeMap<_, Vec<_>> = BTreeMap::new();
Expand Down
12 changes: 6 additions & 6 deletions crates/forge/bin/cmd/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,10 @@ impl CreateArgs {
let (artifact, id) =
remove_zk_contract(&mut zk_output, &target_path, &self.contract.name)?;

let ZkContractArtifact { bytecode, factory_dependencies, abi, .. } = artifact;
let ZkContractArtifact { bytecode, abi, factory_dependencies, .. } = &artifact;

let abi = abi.expect("Abi not found");
let bin = bytecode.expect("Bytecode not found");
let abi = abi.clone().expect("Abi not found");
let bin = bytecode.as_ref().expect("Bytecode not found");

let bytecode = match bin.object() {
BytecodeObject::Bytecode(bytes) => bytes.to_vec(),
Expand Down Expand Up @@ -206,7 +206,7 @@ impl CreateArgs {

let factory_deps: Vec<Vec<u8>> = {
let factory_dependencies_map =
factory_dependencies.expect("factory deps not found");
factory_dependencies.as_ref().expect("factory deps not found");
let mut visited_paths = HashSet::new();
let mut visited_bytecodes = HashSet::new();
let mut queue = VecDeque::new();
Expand Down Expand Up @@ -234,12 +234,12 @@ impl CreateArgs {
)
});
let fdep_fdeps_map =
fdep_art.factory_dependencies.clone().expect("factory deps not found");
fdep_art.factory_dependencies.as_ref().expect("factory deps not found");
for dep in fdep_fdeps_map.values() {
queue.push_back(dep.clone())
}

// TODO(zk): ensure factory deps are also linked
// NOTE(zk): unlinked factory deps don't show up in `factory_dependencies`
let fdep_bytecode = fdep_art
.bytecode
.clone()
Expand Down
Loading
Loading