Skip to content

Commit 7738ed9

Browse files
committed
fix(test:zk): proper stripping during link
feat(link:script): register target & deps
1 parent 3c39167 commit 7738ed9

File tree

4 files changed

+37
-37
lines changed

4 files changed

+37
-37
lines changed

crates/forge/tests/it/zk/linking.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use crate::{
88
test_helpers::{deploy_zk_contract, run_zk_script_test, TEST_DATA_DEFAULT},
99
};
1010

11+
const ZKSOLC_MIN_LINKING_VERSION: Version = Version::new(1, 5, 9);
12+
1113
#[tokio::test(flavor = "multi_thread")]
1214
async fn test_zk_deploy_time_linking() {
1315
let runner = TEST_DATA_DEFAULT.runner_zksync();
@@ -20,7 +22,7 @@ forgetest_async!(
2022
#[should_panic = "no bytecode for contract; is it abstract or unlinked?"]
2123
script_zk_fails_indirect_reference_to_unlinked,
2224
|prj, cmd| {
23-
setup_libs_prj(&mut prj, &mut cmd, Some(Version::new(1, 5, 9)));
25+
setup_libs_prj(&mut prj, &mut cmd, Some(ZKSOLC_MIN_LINKING_VERSION));
2426
run_zk_script_test(
2527
prj.root(),
2628
&mut cmd,
@@ -35,7 +37,7 @@ forgetest_async!(
3537
);
3638

3739
forgetest_async!(script_zk_deploy_time_linking, |prj, cmd| {
38-
setup_libs_prj(&mut prj, &mut cmd, Some(Version::new(1, 5, 9)));
40+
setup_libs_prj(&mut prj, &mut cmd, Some(ZKSOLC_MIN_LINKING_VERSION));
3941
run_zk_script_test(
4042
prj.root(),
4143
&mut cmd,
@@ -54,7 +56,10 @@ forgetest_async!(
5456
#[should_panic = "deploy-time linking not supported"]
5557
script_zk_deploy_time_linking_fails_older_version,
5658
|prj, cmd| {
57-
setup_libs_prj(&mut prj, &mut cmd, Some(Version::new(1, 5, 8)));
59+
let mut version = ZKSOLC_MIN_LINKING_VERSION;
60+
version.patch -= 1;
61+
62+
setup_libs_prj(&mut prj, &mut cmd, Some(version));
5863
run_zk_script_test(
5964
prj.root(),
6065
&mut cmd,

crates/linking/src/zksync.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,11 @@ impl<'a> ZkLinker<'a> {
115115

116116
/// Performs DFS on the graph of link references, and populates `deps` with all found libraries,
117117
/// including ones of factory deps.
118-
fn zk_collect_dependencies(
118+
pub fn zk_collect_dependencies(
119119
&'a self,
120120
target: &'a ArtifactId,
121-
deps: &mut BTreeSet<&'a ArtifactId>,
121+
libraries: &mut BTreeSet<&'a ArtifactId>,
122+
factory_deps: Option<&mut BTreeSet<&'a ArtifactId>>,
122123
) -> Result<(), LinkerError> {
123124
let (_, artifact) = self
124125
.zk_artifacts()
@@ -131,10 +132,11 @@ impl<'a> ZkLinker<'a> {
131132
}
132133

133134
// find all nested factory deps's link references
134-
let mut factory_deps = BTreeSet::new();
135-
self.zk_collect_factory_deps(target, &mut factory_deps)?;
135+
let mut fdeps_default = BTreeSet::new();
136+
let factory_deps = factory_deps.unwrap_or(&mut fdeps_default);
137+
self.zk_collect_factory_deps(target, factory_deps)?;
136138

137-
for (_, fdep) in factory_deps.into_iter().filter_map(|target| {
139+
for (_, fdep) in factory_deps.iter().filter_map(|target| {
138140
self.zk_artifacts().find(|(id, _)| id.source == target.source && id.name == target.name)
139141
}) {
140142
if let Some(bytecode) = &fdep.bytecode {
@@ -151,8 +153,8 @@ impl<'a> ZkLinker<'a> {
151153
file: file.to_string(),
152154
name: contract.to_string(),
153155
})?;
154-
if deps.insert(id) {
155-
self.zk_collect_dependencies(id, deps)?;
156+
if libraries.insert(id) {
157+
self.zk_collect_dependencies(id, libraries, Some(factory_deps))?;
156158
}
157159
}
158160
}
@@ -182,7 +184,7 @@ impl<'a> ZkLinker<'a> {
182184

183185
let mut needed_libraries = BTreeSet::new();
184186
for target in targets {
185-
self.zk_collect_dependencies(target, &mut needed_libraries)?;
187+
self.zk_collect_dependencies(target, &mut needed_libraries, None)?;
186188
}
187189

188190
let mut libs_to_deploy = Vec::new();
@@ -225,7 +227,7 @@ impl<'a> ZkLinker<'a> {
225227
let mut contracts = self.linker.contracts.clone();
226228

227229
let mut needed_libraries = BTreeSet::new();
228-
self.zk_collect_dependencies(target, &mut needed_libraries)?;
230+
self.zk_collect_dependencies(target, &mut needed_libraries, None)?;
229231

230232
let attempt_link = |contracts: &mut ArtifactContracts<CompactContractBytecodeCow<'a>>,
231233
id,

crates/script/src/build.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -134,16 +134,14 @@ impl BuildData {
134134
output.libraries
135135
};
136136

137+
let mut factory_deps = Default::default();
138+
let mut libs = Default::default();
139+
linker.zk_collect_dependencies(target, &mut libs, Some(&mut factory_deps)).expect("able to enumerate all factory deps");
140+
137141
let linked_contracts = linker
138142
.zk_get_linked_artifacts(
139-
input
140-
.artifact_ids()
141-
.filter(|(_, artifact)| artifact.is_unlinked())
142-
// we can't use the `id` directly here
143-
// becuase we expect an iterator of references
144-
.map(|(id, _)| {
145-
linker.linker.contracts.get_key_value(&id).expect("id to be present").0
146-
}),
143+
// only retrieve target and its deps
144+
factory_deps.into_iter().chain(libs.into_iter()).chain([target]),
147145
&libraries,
148146
)
149147
.context("retrieving all fully linked contracts")?;

crates/strategy/zksync/src/executor/runner.rs

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ impl ExecutorStrategyRunner for ZksyncExecutorStrategyRunner {
144144
return Err(LinkerError::MissingTargetArtifact);
145145
};
146146

147+
// we don't strip here unlinke upstream due to
148+
// `input` being used later during linking
149+
// and that is unstripped
147150
let contracts: ArtifactContracts<CompactContractBytecodeCow<'_>> =
148151
input.artifact_ids().collect();
149152

@@ -194,33 +197,25 @@ impl ExecutorStrategyRunner for ZksyncExecutorStrategyRunner {
194197
.map_err(zk_linker_error_to_linker)?;
195198

196199
let linked_contracts = linker
197-
.zk_get_linked_artifacts(
198-
input
199-
.artifact_ids()
200-
.filter(|(_, artifact)| artifact.is_unlinked())
201-
// we can't use the `id` directly here
202-
// becuase we expect an iterator of references
203-
.map(|(id, _)| {
204-
linker.linker.contracts.get_key_value(&id).expect("id to be present").0
205-
}),
206-
&libraries,
207-
)
200+
.zk_get_linked_artifacts(linker.linker.contracts.keys(), &libraries)
208201
.map_err(zk_linker_error_to_linker)?;
209202

210203
let newly_linked_dual_compiled_contracts = linked_contracts
211204
.iter()
212205
.flat_map(|(needle, zk)| {
206+
// match EVM linking's prefix stripping
207+
let stripped = needle.clone().with_stripped_file_prefixes(&root);
213208
evm_link
214209
.linked_contracts
215210
.iter()
216-
.find(|(id, _)| id.source == needle.source && id.name == needle.name)
217-
.map(|(_, evm)| (needle, zk, evm))
211+
.find(|(id, _)| id.source == stripped.source && id.name == stripped.name)
212+
.map(|(_, evm)| (needle, stripped, zk, evm))
218213
})
219-
.filter(|(_, zk, evm)| zk.bytecode.is_some() && evm.bytecode.is_some())
220-
.map(|(id, linked_zk, evm)| {
214+
.filter(|(_, _, zk, evm)| zk.bytecode.is_some() && evm.bytecode.is_some())
215+
.map(|(unstripped_id, id, linked_zk, evm)| {
221216
let (_, unlinked_zk_artifact) = input
222217
.artifact_ids()
223-
.find(|(contract_id, _)| contract_id == id)
218+
.find(|(contract_id, _)| contract_id == unstripped_id)
224219
.expect("unable to find original (pre-linking) artifact");
225220
let zk_bytecode =
226221
linked_zk.get_bytecode_bytes().expect("no EraVM bytecode (or unlinked)");
@@ -363,7 +358,7 @@ impl ExecutorStrategyRunner for ZksyncExecutorStrategyRunner {
363358
// also mark this library as persistent, this will ensure that the state of the library is
364359
// persistent across fork swaps in forking mode
365360
executor.backend_mut().add_persistent_account(address);
366-
debug!(%address, "deployed contract with create2");
361+
debug!(%address, "deployed contract");
367362

368363
let mut request = TransactionMaybeSigned::new(Default::default());
369364
let unsigned = request.as_unsigned_mut().unwrap();

0 commit comments

Comments
 (0)