Skip to content

Commit

Permalink
chore: run smart contract verification integration tests inside hardh…
Browse files Browse the repository at this point in the history
…at (#2957)
  • Loading branch information
TomAFrench authored Oct 3, 2023
1 parent 0764cf4 commit 2cb4749
Show file tree
Hide file tree
Showing 13 changed files with 2,219 additions and 105 deletions.
12 changes: 0 additions & 12 deletions .github/workflows/test-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ on:
schedule:
- cron: "0 2 * * *" # Run nightly at 2 AM UTC

env:
CI: true

jobs:
build-nargo:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -208,15 +205,6 @@ jobs:
run: |
npm i wasm-opt -g
- name: Install Foundry
uses: onbjerg/foundry-toolchain@v1
with:
version: nightly

- name: Deploy verifier contracts to Anvil
working-directory: compiler/integration-tests
run: bash ./scripts/setup-project.sh

- name: Setup `integration-tests`
run: |
yarn workspace @noir-lang/source-resolver build
Expand Down
15 changes: 14 additions & 1 deletion compiler/integration-tests/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
foundry-project
contracts
crs

node_modules
.env
coverage
coverage.json
typechain
typechain-types

# Hardhat files
cache
artifacts

17 changes: 17 additions & 0 deletions compiler/integration-tests/hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { HardhatUserConfig } from 'hardhat/config';
import '@nomicfoundation/hardhat-chai-matchers';
import '@nomicfoundation/hardhat-ethers';

const config: HardhatUserConfig = {
solidity: {
version: '0.8.19',
settings: {
optimizer: {
enabled: true,
runs: 200,
},
},
},
};

export default config;
7 changes: 6 additions & 1 deletion compiler/integration-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"private": true,
"scripts": {
"build": "echo Integration Test build step",
"test": "yarn test:browser",
"test": "bash ./scripts/codegen-verifiers.sh && yarn test:browser && yarn test:node",
"test:node": "hardhat test test/node/**/*",
"test:browser": "web-test-runner",
"test:integration:browser": "web-test-runner test/browser/**/*.test.ts",
"test:integration:browser:watch": "web-test-runner test/browser/**/*.test.ts --watch",
Expand All @@ -17,15 +18,19 @@
"@noir-lang/noir_js": "workspace:*",
"@noir-lang/noir_wasm": "workspace:*",
"@noir-lang/source-resolver": "workspace:*",
"@nomicfoundation/hardhat-chai-matchers": "^2.0.0",
"@nomicfoundation/hardhat-ethers": "^3.0.0",
"@web/dev-server-esbuild": "^0.3.6",
"@web/test-runner": "^0.15.3",
"@web/test-runner-webdriver": "^0.7.0",
"eslint": "^8.50.0",
"eslint-plugin-prettier": "^5.0.0",
"ethers": "^6.7.1",
"fflate": "^0.8.0",
"hardhat": "^2.17.4",
"prettier": "3.0.3",
"smol-toml": "^1.1.2",
"toml": "^3.0.0",
"tslog": "^4.9.2"
}
}
8 changes: 5 additions & 3 deletions compiler/integration-tests/scripts/codegen-verifiers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ main_dir=$repo_root/compiler/integration-tests/circuits/main
nargo --program-dir $main_dir codegen-verifier

# Copy compiled contracts from the root of compiler/integration-tests
src_dir=$self_path/../foundry-project/src
cp $mul_dir/contract/1_mul/plonk_vk.sol $src_dir/1_mul.sol
cp $main_dir/contract/main/plonk_vk.sol $src_dir/main.sol
contracts_dir=$self_path/../contracts
mkdir $contracts_dir

cp $mul_dir/contract/1_mul/plonk_vk.sol $contracts_dir/1_mul.sol
cp $main_dir/contract/main/plonk_vk.sol $contracts_dir/main.sol
23 changes: 0 additions & 23 deletions compiler/integration-tests/scripts/deploy-verifiers.sh

This file was deleted.

13 changes: 0 additions & 13 deletions compiler/integration-tests/scripts/forge-init.sh

This file was deleted.

7 changes: 0 additions & 7 deletions compiler/integration-tests/scripts/setup-project.sh

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { expect } from '@esm-bundle/chai';
import { TEST_LOG_LEVEL } from '../environment.js';
import { Logger } from 'tslog';
import * as TOML from 'smol-toml';

import { initializeResolver } from '@noir-lang/source-resolver';
import newCompiler, { compile, init_log_level as compilerLogLevel } from '@noir-lang/noir_wasm';
import { Noir } from '@noir-lang/noir_js';
import { BarretenbergBackend } from '@noir-lang/backend_barretenberg';
import { ethers } from 'ethers';
import * as TOML from 'smol-toml';

import { getFile } from './utils.js';
import { separatePublicInputsFromProof } from '../shared/proof.js';
import { TEST_LOG_LEVEL } from '../environment.js';

const provider = new ethers.JsonRpcProvider('http://localhost:8545');
const logger = new Logger({ name: 'test', minLevel: TEST_LOG_LEVEL });

await newCompiler();
Expand All @@ -20,14 +19,10 @@ compilerLogLevel('INFO');
const test_cases = [
{
case: 'tooling/nargo_cli/tests/execution_success/1_mul',
compiled: 'compiler/integration-tests/foundry-project/out/1_mul.sol/UltraVerifier.json',
deployInformation: 'compiler/integration-tests/foundry-project/mul_output.json',
numPublicInputs: 0,
},
{
case: 'compiler/integration-tests/circuits/main',
compiled: 'compiler/integration-tests/foundry-project/out/main.sol/UltraVerifier.json',
deployInformation: 'compiler/integration-tests/foundry-project/main_output.json',
numPublicInputs: 1,
},
];
Expand Down Expand Up @@ -79,20 +74,6 @@ test_cases.forEach((testInfo) => {

const verified = await program.verifyFinalProof(proofWithPublicInputs);
expect(verified, 'Proof fails verification in JS').to.be.true;

// Smart contract verification

const compiled_contract = await getFile(`${base_relative_path}/${testInfo.compiled}`);
const deploy_information = await getFile(`${base_relative_path}/${testInfo.deployInformation}`);

const { abi } = JSON.parse(compiled_contract);
const { deployedTo } = JSON.parse(deploy_information);
const contract = new ethers.Contract(deployedTo, abi, provider);

const { proof, publicInputs } = separatePublicInputsFromProof(proofWithPublicInputs, testInfo.numPublicInputs);
const result = await contract.verify(proof, publicInputs);

expect(result).to.be.true;
});

suite.addTest(mochaTest);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { expect } from 'chai';
import { ethers } from 'hardhat';

import { readFileSync } from 'node:fs';
import { resolve } from 'path';
import toml from 'toml';

import { compile, init_log_level as compilerLogLevel } from '@noir-lang/noir_wasm';
import { Noir } from '@noir-lang/noir_js';
import { BarretenbergBackend } from '@noir-lang/backend_barretenberg';
import { separatePublicInputsFromProof } from '../shared/proof';

compilerLogLevel('INFO');

const test_cases = [
{
case: 'tooling/nargo_cli/tests/execution_success/1_mul',
compiled: 'contracts/1_mul.sol:UltraVerifier',
numPublicInputs: 0,
},
{
case: 'compiler/integration-tests/circuits/main',
compiled: 'contracts/main.sol:UltraVerifier',
numPublicInputs: 1,
},
];

async function getCircuit(entry_point: string) {
return compile({ entry_point });
}

test_cases.forEach((testInfo) => {
const test_name = testInfo.case.split('/').pop();

it(`${test_name} (smart contract verifier)`, async () => {
const base_relative_path = '../..';
const test_case = testInfo.case;

const noir_source_path = resolve(`${base_relative_path}/${test_case}/src/main.nr`);

let compile_output;
try {
compile_output = await getCircuit(noir_source_path);

expect(await compile_output, 'Compile output ').to.be.an('object');
} catch (e) {
expect(e, 'Compilation Step').to.not.be.an('error');
throw e;
}

const noir_program = { bytecode: compile_output.circuit, abi: compile_output.abi };
const backend = new BarretenbergBackend(noir_program);
const program = new Noir(noir_program, backend);

// JS Proving

const prover_toml = readFileSync(resolve(`${base_relative_path}/${test_case}/Prover.toml`)).toString();
const inputs = toml.parse(prover_toml);

const proofWithPublicInputs = await program.generateFinalProof(inputs);

// JS verification

const verified = await program.verifyFinalProof(proofWithPublicInputs);
expect(verified, 'Proof fails verification in JS').to.be.true;

// Smart contract verification

const contract = await ethers.deployContract(testInfo.compiled, [], {});

const { proof, publicInputs } = separatePublicInputsFromProof(proofWithPublicInputs, testInfo.numPublicInputs);
const result = await contract.verify(proof, publicInputs);

expect(result).to.be.true;
});
});
12 changes: 12 additions & 0 deletions compiler/integration-tests/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"resolveJsonModule": true
},
"include": ["test/integration/node/**/*"]
}
2 changes: 1 addition & 1 deletion tooling/noir_js_backend_barretenberg/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@
"prettier": "3.0.3",
"typescript": "5.1.5"
}
}
}
Loading

0 comments on commit 2cb4749

Please sign in to comment.