diff --git a/.github/workflows/e2e_test.yaml b/.github/workflows/e2e_test.yaml index 7012b01c..ca65f707 100644 --- a/.github/workflows/e2e_test.yaml +++ b/.github/workflows/e2e_test.yaml @@ -64,12 +64,13 @@ jobs: - name: Generate Proofs run: | export PATH="$HOME/.bb:$PATH" - bb prove -b ./target/get_header.json -w ./target/get_header.gz --write_vk -o ./target/get_header - bb prove -b ./target/get_account.json -w ./target/get_account.gz --write_vk -o ./target/get_account - bb prove -b ./target/get_storage.json -w ./target/get_storage.gz --write_vk -o ./target/get_storage - bb prove -b ./target/get_receipt.json -w ./target/get_receipt.gz --write_vk -o ./target/get_receipt - bb prove -b ./target/get_transaction.json -w ./target/get_transaction.gz --write_vk -o ./target/get_transaction - bb prove -b ./target/get_log.json -w ./target/get_log.gz --write_vk -o ./target/get_log + mkdir -p proofs + bb prove -b ./target/get_header.json -w ./target/get_header.gz --write_vk -o ./proofs/get_header.proof + bb prove -b ./target/get_account.json -w ./target/get_account.gz --write_vk -o ./proofs/get_account.proof + bb prove -b ./target/get_storage.json -w ./target/get_storage.gz --write_vk -o ./proofs/get_storage.proof + bb prove -b ./target/get_receipt.json -w ./target/get_receipt.gz --write_vk -o ./proofs/get_receipt.proof + bb prove -b ./target/get_transaction.json -w ./target/get_transaction.gz --write_vk -o ./proofs/get_transaction.proof + bb prove -b ./target/get_log.json -w ./target/get_log.gz --write_vk -o ./proofs/get_log.proof # Note: Solidity verifiers are pre-generated and committed to ethereum/contracts/src/generated-verifier/ # Generating them in CI causes OOM errors due to high memory requirements @@ -92,9 +93,9 @@ jobs: working-directory: ethereum/oracles run: yarn test:unit - # - name: Run e2e Tests - # working-directory: ethereum/tests - # run: yarn test:e2e + - name: Run e2e Tests + working-directory: ethereum/tests + run: yarn test:e2e - name: Stop Oracle Server if: always() diff --git a/ethereum/tests/src/solidityVerifier.ts b/ethereum/tests/src/solidityVerifier.ts index 60986526..302e9fe5 100644 --- a/ethereum/tests/src/solidityVerifier.ts +++ b/ethereum/tests/src/solidityVerifier.ts @@ -17,14 +17,93 @@ export interface FoundryArtefact { abi: Abi; bytecode: { object: Hex; + linkReferences?: Record>>; }; } +// Cache deployed libraries to avoid redeploying +const deployedLibraries = new Map(); + +async function deployLibrary(libraryName: string, libraryPath: string): Promise
{ + // Check if already deployed + const cacheKey = `${libraryPath}:${libraryName}`; + if (deployedLibraries.has(cacheKey)) { + return deployedLibraries.get(cacheKey)!; + } + + // Import and deploy the library + const libraryArtifact = await import(`../../contracts/out/${libraryPath}/${libraryName}.json`, { + with: { type: 'json' } + }); + + const hash = await client.deployContract({ + abi: libraryArtifact.default.abi, + account, + bytecode: libraryArtifact.default.bytecode.object as Hex, + chain: client.chain + }); + + const receipt = await client.waitForTransactionReceipt({ hash }); + assert(receipt.status === 'success', 'Library deployment failed'); + assert(!!receipt.contractAddress, 'Library address should not be empty'); + + deployedLibraries.set(cacheKey, receipt.contractAddress); + return receipt.contractAddress; +} + +function linkLibraries( + bytecode: Hex, + linkReferences: Record>>, + libraryAddresses: Map +): Hex { + let linkedBytecode = bytecode; + + for (const [filePath, libraries] of Object.entries(linkReferences)) { + for (const [libraryName, references] of Object.entries(libraries)) { + const libraryAddress = libraryAddresses.get(`${filePath}:${libraryName}`); + assert(!!libraryAddress, `Library ${libraryName} not deployed`); + + const addressHex = libraryAddress.slice(2).toLowerCase(); + + // Replace all occurrences of the library placeholder + for (const ref of references) { + // Each reference has a start position (in bytes, so multiply by 2 for hex string) + // Add 2 to skip '0x' prefix + const startPos = ref.start * 2 + 2; + const endPos = startPos + ref.length * 2; + + linkedBytecode = (linkedBytecode.slice(0, startPos) + addressHex + linkedBytecode.slice(endPos)) as Hex; + } + } + } + + return linkedBytecode; +} + export async function deploySolidityProofVerifier(artefact: FoundryArtefact): Promise { + let bytecode = artefact.bytecode.object; + + // Deploy and link libraries if needed + if (artefact.bytecode.linkReferences && Object.keys(artefact.bytecode.linkReferences).length > 0) { + const libraryAddresses = new Map(); + + for (const [filePath, libraries] of Object.entries(artefact.bytecode.linkReferences)) { + for (const libraryName of Object.keys(libraries)) { + const address = await deployLibrary( + libraryName, + filePath.replace('src/generated-verifier/', '') + ); + libraryAddresses.set(`${filePath}:${libraryName}`, address); + } + } + + bytecode = linkLibraries(bytecode, artefact.bytecode.linkReferences, libraryAddresses); + } + const hash = await client.deployContract({ abi: artefact.abi, account, - bytecode: artefact.bytecode.object, + bytecode, chain: client.chain });