Skip to content

Commit 6dd5c6a

Browse files
committed
link libraries
1 parent 3f14875 commit 6dd5c6a

File tree

2 files changed

+87
-7
lines changed

2 files changed

+87
-7
lines changed

.github/workflows/e2e_test.yaml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,13 @@ jobs:
6464
- name: Generate Proofs
6565
run: |
6666
export PATH="$HOME/.bb:$PATH"
67-
bb prove -b ./target/get_header.json -w ./target/get_header.gz --write_vk -o ./target/get_header
68-
bb prove -b ./target/get_account.json -w ./target/get_account.gz --write_vk -o ./target/get_account
69-
bb prove -b ./target/get_storage.json -w ./target/get_storage.gz --write_vk -o ./target/get_storage
70-
bb prove -b ./target/get_receipt.json -w ./target/get_receipt.gz --write_vk -o ./target/get_receipt
71-
bb prove -b ./target/get_transaction.json -w ./target/get_transaction.gz --write_vk -o ./target/get_transaction
72-
bb prove -b ./target/get_log.json -w ./target/get_log.gz --write_vk -o ./target/get_log
67+
mkdir -p proofs
68+
bb prove -b ./target/get_header.json -w ./target/get_header.gz --write_vk -o ./proofs/get_header
69+
bb prove -b ./target/get_account.json -w ./target/get_account.gz --write_vk -o ./proofs/get_account
70+
bb prove -b ./target/get_storage.json -w ./target/get_storage.gz --write_vk -o ./proofs/get_storage
71+
bb prove -b ./target/get_receipt.json -w ./target/get_receipt.gz --write_vk -o ./proofs/get_receipt
72+
bb prove -b ./target/get_transaction.json -w ./target/get_transaction.gz --write_vk -o ./proofs/get_transaction
73+
bb prove -b ./target/get_log.json -w ./target/get_log.gz --write_vk -o ./proofs/get_log
7374
7475
# Note: Solidity verifiers are pre-generated and committed to ethereum/contracts/src/generated-verifier/
7576
# Generating them in CI causes OOM errors due to high memory requirements

ethereum/tests/src/solidityVerifier.ts

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,93 @@ export interface FoundryArtefact {
1717
abi: Abi;
1818
bytecode: {
1919
object: Hex;
20+
linkReferences?: Record<string, Record<string, Array<{ start: number; length: number }>>>;
2021
};
2122
}
2223

24+
// Cache deployed libraries to avoid redeploying
25+
const deployedLibraries = new Map<string, Address>();
26+
27+
async function deployLibrary(libraryName: string, libraryPath: string): Promise<Address> {
28+
// Check if already deployed
29+
const cacheKey = `${libraryPath}:${libraryName}`;
30+
if (deployedLibraries.has(cacheKey)) {
31+
return deployedLibraries.get(cacheKey)!;
32+
}
33+
34+
// Import and deploy the library
35+
const libraryArtifact = await import(`../../contracts/out/${libraryPath}/${libraryName}.json`, {
36+
with: { type: 'json' }
37+
});
38+
39+
const hash = await client.deployContract({
40+
abi: libraryArtifact.default.abi,
41+
account,
42+
bytecode: libraryArtifact.default.bytecode.object as Hex,
43+
chain: client.chain
44+
});
45+
46+
const receipt = await client.waitForTransactionReceipt({ hash });
47+
assert(receipt.status === 'success', 'Library deployment failed');
48+
assert(!!receipt.contractAddress, 'Library address should not be empty');
49+
50+
deployedLibraries.set(cacheKey, receipt.contractAddress);
51+
return receipt.contractAddress;
52+
}
53+
54+
function linkLibraries(
55+
bytecode: Hex,
56+
linkReferences: Record<string, Record<string, Array<{ start: number; length: number }>>>,
57+
libraryAddresses: Map<string, Address>
58+
): Hex {
59+
let linkedBytecode = bytecode;
60+
61+
for (const [filePath, libraries] of Object.entries(linkReferences)) {
62+
for (const [libraryName, references] of Object.entries(libraries)) {
63+
const libraryAddress = libraryAddresses.get(`${filePath}:${libraryName}`);
64+
assert(!!libraryAddress, `Library ${libraryName} not deployed`);
65+
66+
const addressHex = libraryAddress.slice(2).toLowerCase();
67+
68+
// Replace all occurrences of the library placeholder
69+
for (const ref of references) {
70+
// Each reference has a start position (in bytes, so multiply by 2 for hex string)
71+
// Add 2 to skip '0x' prefix
72+
const startPos = ref.start * 2 + 2;
73+
const endPos = startPos + ref.length * 2;
74+
75+
linkedBytecode = (linkedBytecode.slice(0, startPos) + addressHex + linkedBytecode.slice(endPos)) as Hex;
76+
}
77+
}
78+
}
79+
80+
return linkedBytecode;
81+
}
82+
2383
export async function deploySolidityProofVerifier(artefact: FoundryArtefact): Promise<SolidityProofVerifier> {
84+
let bytecode = artefact.bytecode.object;
85+
86+
// Deploy and link libraries if needed
87+
if (artefact.bytecode.linkReferences && Object.keys(artefact.bytecode.linkReferences).length > 0) {
88+
const libraryAddresses = new Map<string, Address>();
89+
90+
for (const [filePath, libraries] of Object.entries(artefact.bytecode.linkReferences)) {
91+
for (const libraryName of Object.keys(libraries)) {
92+
const address = await deployLibrary(
93+
libraryName,
94+
filePath.replace('src/generated-verifier/', '')
95+
);
96+
libraryAddresses.set(`${filePath}:${libraryName}`, address);
97+
}
98+
}
99+
100+
bytecode = linkLibraries(bytecode, artefact.bytecode.linkReferences, libraryAddresses);
101+
}
102+
24103
const hash = await client.deployContract({
25104
abi: artefact.abi,
26105
account,
27-
bytecode: artefact.bytecode.object,
106+
bytecode,
28107
chain: client.chain
29108
});
30109

0 commit comments

Comments
 (0)