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(coordinator): add coordinator controller #1433

Merged
merged 1 commit into from
May 7, 2024
Merged
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
72 changes: 69 additions & 3 deletions .github/workflows/coordinator-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ on:
pull_request:

env:
COORDINATOR_RPC_URL: "http://localhost:8545"
COORDINATOR_PUBLIC_KEY_PATH: "./pub.key"
COORDINATOR_PRIVATE_KEY_PATH: "./priv.key"
COORDINATOR_TALLY_ZKEY_NAME: "TallyVotes"
COORDINATOR_MESSAGE_PROCESS_ZKEY_NAME: "ProcessMessages"
COORDINATOR_TALLY_ZKEY_NAME: "TallyVotes_10-1-2_test"
COORDINATOR_MESSAGE_PROCESS_ZKEY_NAME: "ProcessMessages_10-2-1-2_test"
COORDINATOR_ZKEY_PATH: "./zkeys"
COORDINATOR_RAPIDSNARK_EXE: ""
COORDINATOR_RAPIDSNARK_EXE: "~/rapidsnark/build/prover"
COORDINATOR_MNEMONIC: ${{ secrets.COORDINATOR_MNEMONIC }}

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
Expand All @@ -33,6 +35,35 @@ jobs:
node-version: 20
cache: "pnpm"

# Check for changes in the 'circuit' folder
- name: Get changed files
id: get-changed-files
uses: jitterbit/get-changed-files@v1
with:
format: "csv"

- name: Check for changes in 'circuit' folder
id: check_changes
run: |
CHANGED_FILES=${{ steps.get-changed-files.outputs.all }}
if echo "$CHANGED_FILES" | grep -q "\.circom"; then
echo "CHANGED=true" >> $GITHUB_ENV
echo "Circuits have changes."
else
echo "CHANGED=false" >> $GITHUB_ENV
echo "No changes on circuits."
fi

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install --yes \
build-essential \
libgmp-dev \
libsodium-dev \
nasm \
nlohmann-json3-dev

- name: Install
run: |
pnpm install --frozen-lockfile --prefer-offline
Expand All @@ -41,6 +72,41 @@ jobs:
run: |
pnpm run build

- name: Run hardhat
run: |
pnpm run hardhat &
sleep 5
working-directory: coordinator

- name: Download rapidsnark (1c137)
run: |
mkdir -p ~/rapidsnark/build
wget -qO ~/rapidsnark/build/prover https://maci-devops-zkeys.s3.ap-northeast-2.amazonaws.com/rapidsnark-linux-amd64-1c137
chmod +x ~/rapidsnark/build/prover

- name: Download circom Binary v2.1.6
run: |
wget -qO ${{ github.workspace }}/circom https://github.com/iden3/circom/releases/download/v2.1.6/circom-linux-amd64
chmod +x ${{ github.workspace }}/circom
sudo mv ${{ github.workspace }}/circom /bin/circom

- name: Compile Circuits And Generate zkeys
if: ${{ env.CHANGED == 'true' }}
run: |
pnpm build:circuits-c --outPath ../coordinator/zkeys
pnpm setup:zkeys --outPath ../coordinator/zkeys

- name: Download zkeys
if: ${{ env.CHANGED == 'false' }}
run: |
pnpm download-zkeys:test
working-directory: coordinator

- name: Generate keypair
run: |
pnpm generate-keypair
working-directory: coordinator

- name: Test
run: pnpm run test
working-directory: coordinator
4 changes: 2 additions & 2 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ jobs:

- name: Compile Circuits And Generate zkeys
run: |
pnpm build:circuits-c
pnpm setup:zkeys
pnpm build:circuits-c -- --outPath ../cli/zkeys
pnpm setup:zkeys -- --outPath ../cli/zkeys

- name: ${{ matrix.command }}
run: pnpm run ${{ matrix.command }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/reusable-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ jobs:
- name: Compile Circuits And Generate zkeys
if: ${{ env.CHANGED == 'true' }}
run: |
pnpm build:circuits-c
pnpm setup:zkeys
pnpm build:circuits-c -- --outPath ../cli/zkeys
pnpm setup:zkeys -- --outPath ../cli/zkeys

- name: Download zkeys
if: ${{ env.CHANGED == 'false' }}
Expand Down
1 change: 0 additions & 1 deletion contracts/scripts/compileSol.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env node
import hre from "hardhat";

import fs from "fs";
Expand Down
13 changes: 10 additions & 3 deletions contracts/tasks/helpers/ProofGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ export class ProofGenerator {
* @param network - current network
* @returns tally proofs
*/
async generateTallyProofs(network: Network): Promise<Proof[]> {
async generateTallyProofs(network: Network): Promise<{ proofs: Proof[]; tallyData: TallyData }> {
performance.mark("tally-proofs-start");

console.log(`Generating proofs of vote tallying...`);
Expand Down Expand Up @@ -316,7 +316,7 @@ export class ProofGenerator {
performance.mark("tally-proofs-end");
performance.measure("Generate tally proofs", "tally-proofs-start", "tally-proofs-end");

return proofs;
return { proofs, tallyData: tallyFileData };
}

/**
Expand Down Expand Up @@ -359,7 +359,14 @@ export class ProofGenerator {
publicInputs: publicSignals,
});

fs.writeFileSync(path.resolve(this.outputDir, outputFile), JSON.stringify(proofs[proofs.length - 1], null, 4));
if (!fs.existsSync(path.resolve(this.outputDir))) {
await fs.promises.mkdir(path.resolve(this.outputDir));
}

await fs.promises.writeFile(
path.resolve(this.outputDir, outputFile),
JSON.stringify(proofs[proofs.length - 1], null, 4),
);

return proofs;
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/tasks/runner/prove.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ task("prove", "Command to generate proof and prove the result of a poll on-chain
data.processProofs = await proofGenerator.generateMpProofs();
await prover.proveMessageProcessing(data.processProofs);

data.tallyProofs = await proofGenerator.generateTallyProofs(network);
data.tallyProofs = await proofGenerator.generateTallyProofs(network).then(({ proofs }) => proofs);
await prover.proveTally(data.tallyProofs);

const endBalance = await signer.provider.getBalance(signer);
Expand Down
16 changes: 10 additions & 6 deletions coordinator/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,23 @@ LIMIT=10
COORDINATOR_PUBLIC_KEY_PATH="./pub.key"
COORDINATOR_PRIVATE_KEY_PATH="./priv.key"

# Make sure you have TallyVotesQv.zkey, TallyVotesQv.wasm
# and TallyVotesNonQv.zkey, TallyVotesNonQv.wasm inside COORDINATOR_ZKEY_PATH folder
# Make sure you have zkeys folder
# https://maci.pse.dev/docs/trusted-setup
COORDINATOR_TALLY_ZKEY_NAME=TallyVotes
COORDINATOR_TALLY_ZKEY_NAME=TallyVotes_10-1-2_test

# Make sure you have ProcessMessagesQv.zkey, ProcessMessagesQv.wasm
# and ProcessMessagesNonQv.zkey, ProcessMessagesNonQv.wasm inside COORDINATOR_ZKEY_PATH folder
# Make sure you have zkeys folder
# https://maci.pse.dev/docs/trusted-setup
COORDINATOR_MESSAGE_PROCESS_ZKEY_NAME=ProcessMessages
COORDINATOR_MESSAGE_PROCESS_ZKEY_NAME=ProcessMessages_10-2-1-2_test

# Rapidsnark executable path
COORDINATOR_RAPIDSNARK_EXE=

# Location of zkey, wasm files
COORDINATOR_ZKEY_PATH="./zkeys"

# Coordinator mnemonic phrase
COORDINATOR_MNEMONIC=

# Coordinator RPC url
COORDINATOR_RPC_URL=http://localhost:8545

2 changes: 2 additions & 0 deletions coordinator/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
*.key
*.key
zkeys/
proofs/
tally.json

22 changes: 18 additions & 4 deletions coordinator/hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,35 @@
import "@nomicfoundation/hardhat-toolbox";
import { config as envConfig } from "dotenv";
import dotenv from "dotenv";

import path from "path";

import type { HardhatUserConfig } from "hardhat/config";

envConfig();
dotenv.config();

const parentDir = __dirname.includes("build") ? ".." : "";

const config: HardhatUserConfig = {
defaultNetwork: "localhost",
networks: {
localhost: {
url: process.env.ETH_PROVIDER,
accounts: [process.env.ETH_SK!],
url: process.env.COORDINATOR_RPC_URL,
loggingEnabled: false,
accounts: {
mnemonic: process.env.COORDINATOR_MNEMONIC,
path: "m/44'/60'/0'/0",
initialIndex: 0,
count: 20,
},
},
hardhat: {
loggingEnabled: false,
accounts: {
mnemonic: process.env.COORDINATOR_MNEMONIC,
path: "m/44'/60'/0'/0",
initialIndex: 0,
count: 20,
},
},
},
paths: {
Expand Down
10 changes: 8 additions & 2 deletions coordinator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"README.md"
],
"scripts": {
"hardhat": "hardhat node",
"prebuild": "pnpm run generate-keypair",
"build": "nest build",
"start": "nest start",
Expand All @@ -17,6 +18,7 @@
"test": "jest",
"test:coverage": "jest --coverage",
"types": "tsc -p tsconfig.json --noEmit",
"download-zkeys:test": "ts-node ./scripts/downloadZkeys.ts test",
"generate-keypair": "ts-node ./scripts/generateKeypair.ts"
},
"dependencies": {
Expand All @@ -34,7 +36,8 @@
"maci-contracts": "^1.2.0",
"maci-domainobjs": "^1.2.0",
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1"
"rxjs": "^7.8.1",
"tar": "^7.1.0"
},
"devDependencies": {
"@nestjs/cli": "^10.3.2",
Expand All @@ -52,6 +55,7 @@
"typescript": "^5.4.5"
},
"jest": {
"testTimeout": 900000,
"moduleFileExtensions": [
"js",
"json",
Expand All @@ -64,11 +68,13 @@
],
"testRegex": ".*\\.test\\.ts$",
"transform": {
"^.+\\.js$": "<rootDir>/ts/jest/transform.js",
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s",
"!<rootDir>/ts/main.ts"
"!<rootDir>/ts/main.ts",
"!<rootDir>/hardhat.config.ts"
],
"coverageDirectory": "<rootDir>/coverage",
"testEnvironment": "node"
Expand Down
44 changes: 44 additions & 0 deletions coordinator/scripts/downloadZkeys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import dotenv from "dotenv";
import * as tar from "tar";

import fs from "fs";
import https from "https";
import path from "path";

dotenv.config({ path: [path.resolve(__dirname, "../.env"), path.resolve(__dirname, "../.env.example")] });
0xmad marked this conversation as resolved.
Show resolved Hide resolved

const ZKEY_PATH = path.resolve(process.env.COORDINATOR_ZKEY_PATH!);
const ZKEYS_URLS = {
test: "https://maci-develop-fra.s3.eu-central-1.amazonaws.com/v1.3.0/maci_artifacts_10-2-1-2_test.tar.gz",
};
const ARCHIVE_NAME = path.resolve(ZKEY_PATH, "maci_keys.tar.gz");

export async function downloadZkeys(): Promise<void> {
const [type] = process.argv.slice(2).map((arg) => arg.trim() as keyof typeof ZKEYS_URLS);

if (!Object.keys(ZKEYS_URLS).includes(type)) {
throw new Error(`${type} doesn't exist`);
}

if (!fs.existsSync(ZKEY_PATH)) {
await fs.promises.mkdir(ZKEY_PATH);
}

const file = fs.createWriteStream(ARCHIVE_NAME);

https
.get(ZKEYS_URLS[type], (response) => {
response.pipe(file);

file
.on("finish", () => {
file.close();

tar.x({ f: ARCHIVE_NAME }).then(() => fs.promises.rm(ARCHIVE_NAME));
})
.on("error", () => fs.promises.unlink(ARCHIVE_NAME));
})
.on("error", () => fs.promises.unlink(ARCHIVE_NAME));
}

downloadZkeys();
Loading
Loading