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

refactor: submit onchain improvements #453

Merged
merged 1 commit into from
Nov 8, 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
2 changes: 1 addition & 1 deletion packages/contracts/tasks/runner/initPoll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ interface IInitPollParams {
}

/**
* Command to merge signup and message queues of a MACI contract
* Command to initialize poll
*/
task("initPoll", "Initialize poll")
.addParam("poll", "The poll id", undefined, types.string)
Expand Down
102 changes: 56 additions & 46 deletions packages/contracts/tasks/runner/submitOnChain.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/* eslint-disable no-await-in-loop */
/* eslint-disable no-console */
import { BaseContract } from "ethers";
import { task, types } from "hardhat/config";
import { ContractStorage, Deployment, Proof, Prover, type TallyData } from "maci-contracts";

Expand All @@ -14,10 +13,35 @@ import {
type AccQueue,
type MessageProcessor,
type Tally,
type SimpleRegistry,
} from "../../typechain-types";
import { EContracts, ISubmitOnChainParams } from "../helpers/constants";

/**
* Interface that represents read proofs arguments
*/
interface IReadProofsArgs {
files: string[];
folder: string;
type: "tally" | "process";
}

/**
* Read and parse proofs
*
* @param args - read proofs arguments
* @returns proofs
*/
async function readProofs({ files, folder, type }: IReadProofsArgs): Promise<Proof[]> {
return Promise.all(
files
.filter((f) => f.startsWith(`${type}_`) && f.endsWith(".json"))
.sort()
.map(async (file) =>
fs.promises.readFile(`${folder}/${file}`, "utf8").then((result) => JSON.parse(result) as Proof),
),
);
}

/**
* Prove hardhat task for submitting proofs on-chain as well as uploading tally results
*/
Expand Down Expand Up @@ -57,13 +81,15 @@ task("submitOnChain", "Command to prove the result of a poll on-chain")
} = await import("../../typechain-types");

const maciContractAddress = storage.mustGetAddress(EContracts.MACI, network.name);
const maciContract = await deployment.getContract<MACI>({
name: EContracts.MACI,
address: maciContractAddress,
abi: MACIFactory.abi,
});
const vkRegistryContract = await deployment.getContract<VkRegistry>({ name: EContracts.VkRegistry });
const verifierContract = await deployment.getContract<Verifier>({ name: EContracts.Verifier });
const [maciContract, vkRegistryContract, verifierContract] = await Promise.all([
deployment.getContract<MACI>({
name: EContracts.MACI,
address: maciContractAddress,
abi: MACIFactory.abi,
}),
deployment.getContract<VkRegistry>({ name: EContracts.VkRegistry }),
deployment.getContract<Verifier>({ name: EContracts.Verifier }),
]);

const pollContracts = await maciContract.polls(poll);
const pollContract = await deployment.getContract<Poll>({
Expand All @@ -72,39 +98,38 @@ task("submitOnChain", "Command to prove the result of a poll on-chain")
abi: PollFactory.abi,
});

const [, messageAqContractAddress] = await pollContract.extContracts();
const [[, messageAqContractAddress], isStateAqMerged, messageTreeDepth, mpContract, tallyContract] =
await Promise.all([
pollContract.extContracts(),
pollContract.stateMerged(),
pollContract.treeDepths().then((depths) => Number(depths[2])),
deployment.getContract<MessageProcessor>({
name: EContracts.MessageProcessor,
address: pollContracts.messageProcessor,
}),
deployment.getContract<Tally>({
name: EContracts.Tally,
address: pollContracts.tally,
abi: TallyFactory.abi,
}),
]);
const messageAqContract = await deployment.getContract<AccQueue>({
name: EContracts.AccQueue,
address: messageAqContractAddress,
});
const isStateAqMerged = await pollContract.stateMerged();

// Check that the state and message trees have been merged for at least the first poll
if (!isStateAqMerged && poll.toString() === "0") {
throw new Error("The state tree has not been merged yet. Please use the mergeSignups subcommand to do so.");
}

const messageTreeDepth = await pollContract.treeDepths().then((depths) => Number(depths[2]));

// check that the main root is set
const mainRoot = await messageAqContract.getMainRoot(messageTreeDepth.toString());

if (mainRoot.toString() === "0") {
throw new Error("The message tree has not been merged yet. Please use the mergeMessages subcommand to do so.");
}

const mpContract = await deployment.getContract<MessageProcessor>({
name: EContracts.MessageProcessor,
address: pollContracts.messageProcessor,
});

// get the tally contract based on the useQuadraticVoting flag
const tallyContract = await deployment.getContract<Tally>({
name: EContracts.Tally,
address: pollContracts.tally,
abi: TallyFactory.abi,
});

const data = {
processProofs: [] as Proof[],
tallyProofs: [] as Proof[],
Expand All @@ -114,22 +139,9 @@ task("submitOnChain", "Command to prove the result of a poll on-chain")
const files = await fs.promises.readdir(outputDir);

// Read process proofs
const processProofFiles = files.filter((f) => f.startsWith("process_") && f.endsWith(".json"));
await Promise.all(
processProofFiles.sort().map(async (file) => {
const proofData = JSON.parse(await fs.promises.readFile(`${outputDir}/${file}`, "utf8")) as Proof;
data.processProofs.push(proofData);
}),
);

data.processProofs = await readProofs({ files, folder: outputDir, type: "process" });
// Read tally proofs
const tallyProofFiles = files.filter((f) => f.startsWith("tally_") && f.endsWith(".json"));
await Promise.all(
tallyProofFiles.sort().map(async (file) => {
const proofData = JSON.parse(await fs.promises.readFile(`${outputDir}/${file}`, "utf8")) as Proof;
data.tallyProofs.push(proofData);
}),
);
data.tallyProofs = await readProofs({ files, folder: outputDir, type: "tally" });

const prover = new Prover({
maciContract,
Expand All @@ -144,18 +156,16 @@ task("submitOnChain", "Command to prove the result of a poll on-chain")
await prover.proveMessageProcessing(data.processProofs);

// read tally data
const tallyData = JSON.parse(await fs.promises.readFile(tallyFile, "utf8")) as unknown as TallyData;
const tallyData = await fs.promises
.readFile(tallyFile, "utf8")
.then((result) => JSON.parse(result) as unknown as TallyData);

await prover.proveTally(data.tallyProofs);

// submit the results with number participants to be taken from the registry
const registryContractAddress = await pollContract.getRegistry();

const registryContract = new BaseContract(
registryContractAddress,
SimpleRegistryFactory.abi,
signer,
) as SimpleRegistry;
const registryContract = SimpleRegistryFactory.connect(registryContractAddress, signer);
const recipientCount = await registryContract.recipientCount();

await prover.submitResults(tallyData, Number.parseInt(recipientCount.toString(), 10));
Expand Down
Binary file removed packages/interface/metamask-chrome-11.15.1.zip
Binary file not shown.
Loading