Skip to content

Commit

Permalink
Merge pull request #1172 from privacy-scaling-explorations/chore/gene…
Browse files Browse the repository at this point in the history
…rate-proof

chore(contracts): add proof generation for task coordinator
  • Loading branch information
0xmad authored Feb 12, 2024
2 parents 4eef63f + c145883 commit 6d15f08
Show file tree
Hide file tree
Showing 20 changed files with 1,661 additions and 284 deletions.
1 change: 1 addition & 0 deletions circuits/ts/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { genProof, verifyProof, extractVk } from "./proofs";
export { cleanThreads } from "./utils";
export type { ISnarkJSVerificationKey } from "./types";
3 changes: 3 additions & 0 deletions circuits/ts/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { CircuitConfig } from "circomkit";
import type { CircuitInputs } from "maci-core";
import type { ISnarkJSVerificationKey } from "snarkjs";

/**
* Parameters for the genProof function
Expand Down Expand Up @@ -73,3 +74,5 @@ export interface ITallyVotesInputs {
export interface CircuitConfigWithName extends CircuitConfig {
name: string;
}

export type { ISnarkJSVerificationKey };
1 change: 1 addition & 0 deletions contracts/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { EChainId, ESupportedChains, NETWORKS_DEFAULT_GAS, getNetworkRpcUrls } f
import "./tasks/runner/deployFull";
import "./tasks/runner/deployPoll";
import "./tasks/runner/merge";
import "./tasks/runner/prove";
import "./tasks/runner/verifyFull";

dotenv.config();
Expand Down
35 changes: 19 additions & 16 deletions contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,32 +19,35 @@
"postbuild": "cp -r ./artifacts ./build",
"types": "tsc -p tsconfig.json --noEmit",
"docs": "hardhat docgen",
"test": "hardhat test",
"test:maci": "hardhat test ./tests/MACI.test.ts",
"test:poll": "hardhat test ./tests/Poll.test.ts",
"test:messageProcessor": "hardhat test ./tests/MessageProcessor.test.ts",
"test:tally": "hardhat test ./tests/Tally.test.ts",
"test:hasher": "hardhat test ./tests/Hasher.test.ts",
"test:utilities": "hardhat test ./tests/Utilities.test.ts",
"test:signupGatekeeper": "hardhat test ./tests/SignUpGatekeeper.test.ts",
"test:verifier": "hardhat test ./tests/Verifier.test.ts",
"test:accQueue": "hardhat test ./tests/AccQueue.test.ts",
"test:accQueueBenchmark": "hardhat test ./tests/AccQueueBenchmark.test.ts",
"test:hasherBenchmarks": "hardhat test ./tests/HasherBenchmarks.test.ts",
"test:vkRegistry": "hardhat test ./tests/VkRegistry.test.ts",
"test:pollFactory": "hardhat test ./tests/PollFactory.test.ts",
"test:subsidy": "hardhat test ./tests/Subsidy.test.ts",
"test:eas_gatekeeper": "hardhat test ./tests/EASGatekeeper.test.ts",
"test": "hardhat test --network hardhat",
"test:maci": "pnpm run test ./tests/MACI.test.ts",
"test:poll": "pnpm run test ./tests/Poll.test.ts",
"test:messageProcessor": "pnpm run test ./tests/MessageProcessor.test.ts",
"test:tally": "pnpm run test ./tests/Tally.test.ts",
"test:hasher": "pnpm run test ./tests/Hasher.test.ts",
"test:utilities": "pnpm run test ./tests/Utilities.test.ts",
"test:signupGatekeeper": "pnpm run test ./tests/SignUpGatekeeper.test.ts",
"test:verifier": "pnpm run test ./tests/Verifier.test.ts",
"test:accQueue": "pnpm run test ./tests/AccQueue.test.ts",
"test:accQueueBenchmark": "pnpm run test ./tests/AccQueueBenchmark.test.ts",
"test:hasherBenchmarks": "pnpm run test ./tests/HasherBenchmarks.test.ts",
"test:vkRegistry": "pnpm run test ./tests/VkRegistry.test.ts",
"test:pollFactory": "pnpm run test ./tests/PollFactory.test.ts",
"test:subsidy": "pnpm run test ./tests/Subsidy.test.ts",
"test:eas_gatekeeper": "pnpm run test ./tests/EASGatekeeper.test.ts",
"deploy": "hardhat deploy-full",
"deploy-poll": "hardhat deploy-poll",
"verify": "hardhat verify-full",
"merge": "hardhat merge",
"prove": "hardhat prove",
"deploy:localhost": "pnpm run deploy",
"deploy:sepolia": "pnpm run deploy --network sepolia",
"deploy-poll:localhost": "pnpm run deploy-poll",
"deploy-poll:sepolia": "pnpm run deploy-poll --network sepolia",
"merge:localhost": "pnpm run merge",
"merge:sepolia": "pnpm run merge --network sepolia",
"prove:localhost": "pnpm run prove",
"prove:sepolia": "pnpm run prove",
"verify:sepolia": "pnpm run verify --network sepolia"
},
"dependencies": {
Expand Down
3 changes: 2 additions & 1 deletion contracts/scripts/compileSol.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ cd ..
# Delete old files
rm -rf ./artifacts/*
rm -rf ./cache/*
rm -rf ./typechain-types/*

echo 'Writing Merkle zeros contracts'
./scripts/writeMerkleZeroesContracts.sh
Expand All @@ -15,7 +16,7 @@ echo 'Writing empty ballot tree root contract'
pnpm exec ts-node ts/genEmptyBallotRootsContract.ts

echo 'Building contracts with Hardhat'
pnpm exec hardhat compile
TS_NODE_TRANSPILE_ONLY=1 pnpm exec hardhat compile

echo 'Building Poseidon libraries from bytecode'
pnpm exec ts-node ts/buildPoseidon.ts
12 changes: 12 additions & 0 deletions contracts/tasks/deploy/maci/10-maci.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { EASGatekeeper } from "../../../typechain-types";

import { ContractStorage } from "../../helpers/ContractStorage";
import { Deployment } from "../../helpers/Deployment";
import { EContracts, IDeployParams } from "../../helpers/types";
Expand Down Expand Up @@ -67,6 +69,16 @@ deployment
stateTreeDepth,
);

if (gatekeeper === EContracts.EASGatekeeper) {
const gatekeeperContract = await deployment.getContract<EASGatekeeper>({
name: EContracts.EASGatekeeper,
address: gatekeeperContractAddress,
});
const maciInstanceAddress = await maciContract.getAddress();

await gatekeeperContract.setMaciInstance(maciInstanceAddress).then((tx) => tx.wait());
}

await storage.register({
id: EContracts.MACI,
contract: maciContract,
Expand Down
5 changes: 3 additions & 2 deletions contracts/tasks/deploy/maci/11-vkRegistry.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { extractVk } from "maci-circuits";
import { VerifyingKey } from "maci-domainobjs";

import type { IVerifyingKeyStruct } from "../../../ts";
import type { IVerifyingKeyStruct } from "../../../ts/types";
import type { VkRegistry } from "../../../typechain-types";

import { ContractStorage } from "../../helpers/ContractStorage";
import { Deployment } from "../../helpers/Deployment";
import { EContracts, type IDeployParams, type VkRegistry } from "../../helpers/types";
import { EContracts, type IDeployParams } from "../../helpers/types";

const deployment = Deployment.getInstance();
const storage = ContractStorage.getInstance();
Expand Down
117 changes: 86 additions & 31 deletions contracts/tasks/deploy/poll/01-poll.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/* eslint-disable no-console */
import { BaseContract } from "ethers";
import { ZeroAddress } from "ethers";
import { PubKey } from "maci-domainobjs";

import { parseArtifact } from "../../../ts/abi";
import { AccQueueBinary, MACI, Poll } from "../../../typechain-types";
import { ContractStorage } from "../../helpers/ContractStorage";
import { Deployment } from "../../helpers/Deployment";
import { EContracts, type MACI, type Poll, type StateAq, type TDeployPollParams } from "../../helpers/types";
import { EContracts } from "../../helpers/types";

const deployment = Deployment.getInstance();
const storage = ContractStorage.getInstance();
Expand All @@ -15,7 +15,6 @@ const storage = ContractStorage.getInstance();
*/
deployment.deployTask("poll:deploy-poll", "Deploy poll").setAction(async (_, hre) => {
deployment.setHre(hre);
const deployer = await deployment.getDeployer();

const maciContractAddress = storage.getAddress(EContracts.MACI, hre.network.name);
const verifierContractAddress = storage.getAddress(EContracts.Verifier, hre.network.name);
Expand All @@ -33,13 +32,14 @@ deployment.deployTask("poll:deploy-poll", "Deploy poll").setAction(async (_, hre
throw new Error("Need to deploy VkRegistry contract first");
}

const [maciAbi] = parseArtifact("MACI");
const maciContract = new BaseContract(maciContractAddress, maciAbi, deployer) as MACI;
const maciContract = await deployment.getContract<MACI>({ name: EContracts.MACI });
const pollId = await maciContract.nextPollId();
const stateAqContractAddress = await maciContract.stateAq();

const [stateAqAbi] = parseArtifact("AccQueue");
const stateAq = new BaseContract(stateAqContractAddress, stateAqAbi, deployer) as StateAq;
const stateAq = await deployment.getContract<AccQueueBinary>({
name: EContracts.AccQueue,
address: stateAqContractAddress,
});
const isTreeMerged = await stateAq.treeMerged();

if (pollId > 0n && !isTreeMerged) {
Expand All @@ -56,7 +56,22 @@ deployment.deployTask("poll:deploy-poll", "Deploy poll").setAction(async (_, hre
const subsidyEnabled = deployment.getDeployConfigField<boolean | null>(EContracts.Poll, "subsidyEnabled") ?? false;
const unserializedKey = PubKey.deserialize(coordinatorPubkey);

const deployPollParams: TDeployPollParams = [
const [pollContractAddress, messageProcessorContractAddress, tallyContractAddress, subsidyContractAddress] =
await maciContract.deployPoll.staticCall(
pollDuration,
{
intStateTreeDepth,
messageTreeSubDepth,
messageTreeDepth,
voteOptionTreeDepth,
},
unserializedKey.asContractParam(),
verifierContractAddress,
vkRegistryContractAddress,
subsidyEnabled,
);

const tx = await maciContract.deployPoll(
pollDuration,
{
intStateTreeDepth,
Expand All @@ -68,36 +83,76 @@ deployment.deployTask("poll:deploy-poll", "Deploy poll").setAction(async (_, hre
verifierContractAddress,
vkRegistryContractAddress,
subsidyEnabled,
];
);

const [pollAddress] = await maciContract.deployPoll.staticCall(...deployPollParams);
const tx = await maciContract.deployPoll(...deployPollParams);
const receipt = await tx.wait();

if (receipt?.status !== 1) {
throw new Error("Deploy poll transaction is failed");
}

const [pollAbi] = parseArtifact("Poll");
const pollContract = new BaseContract(pollAddress, pollAbi, deployer) as Poll;
const pollContract = await deployment.getContract<Poll>({ name: EContracts.Poll, address: pollContractAddress });
const [maxValues, extContracts] = await Promise.all([pollContract.maxValues(), pollContract.extContracts()]);

await storage.register({
id: EContracts.Poll,
key: pollId,
contract: pollContract,
args: [
pollDuration,
maxValues.map((value) => value.toString()),
{
intStateTreeDepth,
messageTreeSubDepth,
messageTreeDepth,
voteOptionTreeDepth,
},
unserializedKey.asContractParam(),
extContracts,
],
network: hre.network.name,
const messageProcessorContract = await deployment.getContract({
name: EContracts.MessageProcessor,
address: messageProcessorContractAddress,
});

const tallyContract = await deployment.getContract({
name: EContracts.Tally,
address: tallyContractAddress,
});

await Promise.all([
storage.register({
id: EContracts.Poll,
key: `poll-${pollId}`,
contract: pollContract,
args: [
pollDuration,
maxValues.map((value) => value.toString()),
{
intStateTreeDepth,
messageTreeSubDepth,
messageTreeDepth,
voteOptionTreeDepth,
},
unserializedKey.asContractParam(),
extContracts,
],
network: hre.network.name,
}),

storage.register({
id: EContracts.MessageProcessor,
key: `poll-${pollId}`,
contract: messageProcessorContract,
args: [verifierContractAddress, vkRegistryContractAddress, pollContractAddress],
network: hre.network.name,
}),

storage.register({
id: EContracts.Tally,
key: `poll-${pollId}`,
contract: tallyContract,
args: [verifierContractAddress, vkRegistryContractAddress, pollContractAddress, messageProcessorContractAddress],
network: hre.network.name,
}),
]);

if (subsidyContractAddress && subsidyContractAddress !== ZeroAddress) {
const subsidyContract = await deployment.getContract({
name: EContracts.Subsidy,
address: subsidyContractAddress,
});

await storage.register({
id: EContracts.Subsidy,
key: `poll-${pollId}`,
contract: subsidyContract,
args: [verifierContractAddress, vkRegistryContractAddress, pollContractAddress, messageProcessorContractAddress],
network: hre.network.name,
});
}
});
12 changes: 6 additions & 6 deletions contracts/tasks/helpers/ContractStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,12 @@ export class ContractStorage {

this.db.set(`${network}.instance.${contractAddress}`, logEntry).write();

const namedEntry = this.db.get(`${network}.named.${id}${key !== undefined ? `.poll-${key}` : ""}`).value() as
const namedEntry = this.db.get(`${network}.named.${id}${key !== undefined ? `.${key}` : ""}`).value() as
| IStorageNamedEntry
| undefined;
const count = namedEntry?.count ?? 0;
this.db
.set(`${network}.named.${id}${key !== undefined ? `.poll-${key}` : ""}`, {
.set(`${network}.named.${id}${key !== undefined ? `.${key}` : ""}`, {
address: contractAddress,
count: count + 1,
})
Expand Down Expand Up @@ -145,7 +145,7 @@ export class ContractStorage {
* @returns contract address
*/
getAddress(id: EContracts, network: string, key?: string): string | undefined {
const collection = this.db.get(`${network}.named.${id}${key !== undefined ? `.poll-${key}` : ""}`);
const collection = this.db.get(`${network}.named.${id}${key !== undefined ? `.${key}` : ""}`);
const namedEntry = collection.value() as IStorageNamedEntry | undefined;

return namedEntry?.address;
Expand All @@ -159,8 +159,8 @@ export class ContractStorage {
* @throws {Error} if there is no address the error will be thrown
* @returns contract address
*/
mustGetAddress(id: EContracts, network: string): string {
const address = this.getAddress(id, network);
mustGetAddress(id: EContracts, network: string, key?: string): string {
const address = this.getAddress(id, network, key);

if (!address) {
throw new Error(`Contract ${id} is not saved`);
Expand Down Expand Up @@ -209,7 +209,7 @@ export class ContractStorage {
multiCount += 1;
} else {
console.log(`\t${key}-${id}: ${nested.address}`);
entryMap.set(id, nested.address);
entryMap.set(key, nested.address);
}
});
}
Expand Down
19 changes: 18 additions & 1 deletion contracts/tasks/helpers/Deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import FileSync from "lowdb/adapters/FileSync";

import { exit } from "process";

import type { EContracts, IDeployParams, IDeployStep, IDeployStepCatalog } from "./types";
import type { EContracts, IDeployParams, IDeployStep, IDeployStepCatalog, IGetContractParams } from "./types";
import type { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
import type { ConfigurableTaskDefinition, HardhatRuntimeEnvironment, TaskArguments } from "hardhat/types";

import { parseArtifact } from "../../ts/abi";

import { ContractStorage } from "./ContractStorage";

/**
Expand Down Expand Up @@ -396,4 +398,19 @@ export class Deployment {

return value;
}

/**
* Get contract by name and group key
*
* @param {IGetContractParams} params - params
* @returns contract wrapper
*/
async getContract<T extends BaseContract>({ name, key, address, signer }: IGetContractParams): Promise<T> {
const deployer = signer || (await this.getDeployer());
const contractAddress = address || this.storage.mustGetAddress(name, this.hre!.network.name, key);

const [abi] = parseArtifact(name.toString());

return new BaseContract(contractAddress, abi, deployer) as T;
}
}
Loading

0 comments on commit 6d15f08

Please sign in to comment.