From 70e328a633b0e1c45e2c4a1650295728e5925f5e Mon Sep 17 00:00:00 2001 From: ctrlc03 <93448202+ctrlc03@users.noreply.github.com> Date: Mon, 11 Dec 2023 10:56:04 +0000 Subject: [PATCH] test(contracts): re-organize smart contract tests in separate files Currently all tests related to a Poll were inside one file (MACI.test) - these tests have been moved into their respective files, re organized and cleaned up, and a small number of test cases were added which were missing. --- contracts/contracts/Poll.sol | 2 +- contracts/package.json | 3 + contracts/tests/Hasher.test.ts | 2 - contracts/tests/MACI.test.ts | 380 +++++------------------ contracts/tests/MaciOverflow.test.ts | 28 +- contracts/tests/MessageProcessor.test.ts | 168 ++++++++++ contracts/tests/Poll.test.ts | 172 ++++++++++ contracts/tests/Tally.test.ts | 192 ++++++++++++ contracts/tests/Verifier.test.ts | 112 +++---- contracts/tests/constants.ts | 42 +++ contracts/tests/utils.ts | 36 +++ 11 files changed, 746 insertions(+), 391 deletions(-) create mode 100644 contracts/tests/MessageProcessor.test.ts create mode 100644 contracts/tests/Poll.test.ts create mode 100644 contracts/tests/Tally.test.ts create mode 100644 contracts/tests/constants.ts diff --git a/contracts/contracts/Poll.sol b/contracts/contracts/Poll.sol index 150f5888ac..9e71921e3a 100644 --- a/contracts/contracts/Poll.sol +++ b/contracts/contracts/Poll.sol @@ -98,7 +98,7 @@ contract PollFactory is Params, IPubKey, Ownable, PollDeploymentParams { contract Poll is Params, Utilities, SnarkCommon, Ownable, PollDeploymentParams, EmptyBallotRoots { using SafeERC20 for ERC20; - bool internal isInit = false; + bool public isInit; // The coordinator's public key PubKey public coordinatorPubKey; diff --git a/contracts/package.json b/contracts/package.json index c325901803..91e54b4818 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -13,6 +13,9 @@ "postbuild": "cp -r ./artifacts ./build", "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-domainObjs": "hardhat test ./tests/DomainObjs.test.ts", "test-signupGatekeeper": "hardhat test ./tests/SignUpGatekeeper.test.ts", diff --git a/contracts/tests/Hasher.test.ts b/contracts/tests/Hasher.test.ts index bcb5d7af8e..b16a48dbad 100644 --- a/contracts/tests/Hasher.test.ts +++ b/contracts/tests/Hasher.test.ts @@ -5,8 +5,6 @@ import { sha256Hash, hashLeftRight, hash3, hash4, hash5, genRandomSalt } from "m import { deployPoseidonContracts, linkPoseidonLibraries } from "../ts/deploy"; import { Hasher } from "../typechain-types"; -require("module-alias/register"); - describe("Hasher", () => { let hasherContract: Hasher; diff --git a/contracts/tests/MACI.test.ts b/contracts/tests/MACI.test.ts index d37b043ce3..c210aa792f 100644 --- a/contracts/tests/MACI.test.ts +++ b/contracts/tests/MACI.test.ts @@ -1,116 +1,45 @@ /* eslint-disable no-underscore-dangle */ import { expect } from "chai"; -import { AbiCoder, BaseContract, BigNumberish, Signer } from "ethers"; -import { - MaciState, - genProcessVkSig, - MaxValues, - TreeDepths, - packProcessMessageSmallVals, - packTallyVotesSmallVals, - Poll, -} from "maci-core"; -import { G1Point, G2Point, NOTHING_UP_MY_SLEEVE } from "maci-crypto"; -import { PCommand, VerifyingKey, Keypair, PubKey, Message } from "maci-domainobjs"; +import { AbiCoder, BaseContract, BigNumberish, Signer, ZeroAddress } from "ethers"; +import { EthereumProvider } from "hardhat/types"; +import { MaciState, genProcessVkSig, STATE_TREE_DEPTH } from "maci-core"; +import { NOTHING_UP_MY_SLEEVE } from "maci-crypto"; +import { VerifyingKey, Keypair, PubKey, Message } from "maci-domainobjs"; import type { IVerifyingKeyStruct } from "../ts/types"; -import type { EthereumProvider } from "hardhat/types"; import { parseArtifact, getDefaultSigner } from "../ts/deploy"; import { deployTestContracts } from "../ts/utils"; +import { AccQueueQuinaryMaci, MACI, VkRegistry, Poll as PollContract } from "../typechain-types"; + import { - AccQueueQuinaryMaci, - AccQueue, - MACI, - MessageProcessor, - Tally, - VkRegistry, - Poll as PollContract, -} from "../typechain-types"; - -import { timeTravel } from "./utils"; - -const STATE_TREE_DEPTH = 10; -const STATE_TREE_ARITY = 5; -const MESSAGE_TREE_DEPTH = 4; -const MESSAGE_TREE_SUBDEPTH = 2; + duration, + initialVoiceCreditBalance, + maxValues, + messageBatchSize, + tallyBatchSize, + testProcessVk, + testTallyVk, + treeDepths, +} from "./constants"; +import { compareVks, timeTravel } from "./utils"; const coordinator = new Keypair(); const [pollAbi] = parseArtifact("Poll"); -const [accQueueQuinaryMaciAbi] = parseArtifact("AccQueueQuinaryMaci"); - -const testProcessVk = new VerifyingKey( - new G1Point(BigInt(0), BigInt(1)), - new G2Point([BigInt(2), BigInt(3)], [BigInt(4), BigInt(5)]), - new G2Point([BigInt(6), BigInt(7)], [BigInt(8), BigInt(9)]), - new G2Point([BigInt(10), BigInt(11)], [BigInt(12), BigInt(13)]), - [new G1Point(BigInt(14), BigInt(15)), new G1Point(BigInt(16), BigInt(17))], -); - -const testTallyVk = new VerifyingKey( - new G1Point(BigInt(0), BigInt(1)), - new G2Point([BigInt(2), BigInt(3)], [BigInt(4), BigInt(5)]), - new G2Point([BigInt(6), BigInt(7)], [BigInt(8), BigInt(9)]), - new G2Point([BigInt(10), BigInt(11)], [BigInt(12), BigInt(13)]), - [new G1Point(BigInt(14), BigInt(15)), new G1Point(BigInt(16), BigInt(17))], -); - -const compareVks = (vk: VerifyingKey, vkOnChain: VerifyingKey) => { - expect(vk.ic.length).to.eq(vkOnChain.ic.length); - for (let i = 0; i < vk.ic.length; i += 1) { - expect(vk.ic[i].x.toString()).to.eq(vkOnChain.ic[i].x.toString()); - expect(vk.ic[i].y.toString()).to.eq(vkOnChain.ic[i].y.toString()); - } - expect(vk.alpha1.x.toString()).to.eq(vkOnChain.alpha1.x.toString()); - expect(vk.alpha1.y.toString()).to.eq(vkOnChain.alpha1.y.toString()); - expect(vk.beta2.x[0].toString()).to.eq(vkOnChain.beta2.x[0].toString()); - expect(vk.beta2.x[1].toString()).to.eq(vkOnChain.beta2.x[1].toString()); - expect(vk.beta2.y[0].toString()).to.eq(vkOnChain.beta2.y[0].toString()); - expect(vk.beta2.y[1].toString()).to.eq(vkOnChain.beta2.y[1].toString()); - expect(vk.delta2.x[0].toString()).to.eq(vkOnChain.delta2.x[0].toString()); - expect(vk.delta2.x[1].toString()).to.eq(vkOnChain.delta2.x[1].toString()); - expect(vk.delta2.y[0].toString()).to.eq(vkOnChain.delta2.y[0].toString()); - expect(vk.delta2.y[1].toString()).to.eq(vkOnChain.delta2.y[1].toString()); - expect(vk.gamma2.x[0].toString()).to.eq(vkOnChain.gamma2.x[0].toString()); - expect(vk.gamma2.x[1].toString()).to.eq(vkOnChain.gamma2.x[1].toString()); - expect(vk.gamma2.y[0].toString()).to.eq(vkOnChain.gamma2.y[0].toString()); - expect(vk.gamma2.y[1].toString()).to.eq(vkOnChain.gamma2.y[1].toString()); -}; - -const users = [new Keypair(), new Keypair(), new Keypair()]; - -const signUpTxOpts = { gasLimit: 300000 }; - -const maciState = new MaciState(STATE_TREE_DEPTH); - -// Poll parameters -const duration = 15; -const maxValues: MaxValues = { - maxMessages: 25, - maxVoteOptions: 25, -}; - -const treeDepths: TreeDepths = { - intStateTreeDepth: 1, - messageTreeDepth: MESSAGE_TREE_DEPTH, - messageTreeSubDepth: MESSAGE_TREE_SUBDEPTH, - voteOptionTreeDepth: 2, -}; - -const messageBatchSize = 25; -const tallyBatchSize = STATE_TREE_ARITY ** treeDepths.intStateTreeDepth; - -const initialVoiceCreditBalance = 100; -let signer: Signer; describe("MACI", () => { let maciContract: MACI; let stateAqContract: AccQueueQuinaryMaci; let vkRegistryContract: VkRegistry; - let mpContract: MessageProcessor; - let tallyContract: Tally; let pollId: number; + const users = [new Keypair(), new Keypair(), new Keypair()]; + + let signer: Signer; + + const maciState = new MaciState(STATE_TREE_DEPTH); + const signUpTxOpts = { gasLimit: 300000 }; + describe("Deployment", () => { before(async () => { signer = await getDefaultSigner(); @@ -119,14 +48,19 @@ describe("MACI", () => { maciContract = r.maciContract; stateAqContract = r.stateAqContract; vkRegistryContract = r.vkRegistryContract; - mpContract = r.mpContract; - tallyContract = r.tallyContract; }); it("MACI.stateTreeDepth should be correct", async () => { const std = await maciContract.stateTreeDepth(); expect(std.toString()).to.eq(STATE_TREE_DEPTH.toString()); }); + + it("should not be possible to initialize the contract twice", async () => { + await expect(maciContract.init(ZeroAddress, ZeroAddress)).to.be.revertedWithCustomError( + maciContract, + "AlreadyInitialized", + ); + }); }); describe("Signups", () => { @@ -178,19 +112,29 @@ describe("MACI", () => { ), ).to.be.revertedWithCustomError(maciContract, "MaciPubKeyLargerThanSnarkFieldSize"); }); - }); - describe("Merging sign-ups should fail because of onlyPoll", () => { - it("coordinator should not be able to merge the signUp AccQueue", async () => { - await expect(maciContract.mergeStateAqSubRoots(0, 0, { gasLimit: 3000000 })).to.be.revertedWithCustomError( - maciContract, - "CallerMustBePoll", - ); + it("should not allow to sign up more than the supported amount of users (5 ** stateTreeDepth)", async () => { + const stateTreeDepthTest = 1; + const maxUsers = 5 ** stateTreeDepthTest; + const maci = (await deployTestContracts(initialVoiceCreditBalance, stateTreeDepthTest, true)).maciContract; + const keypair = new Keypair(); + for (let i = 0; i < maxUsers; i += 1) { + // eslint-disable-next-line no-await-in-loop + await maci.signUp( + keypair.pubKey.asContractParam(), + AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), + AbiCoder.defaultAbiCoder().encode(["uint256"], [0]), + ); + } - await expect(maciContract.mergeStateAq(0, { gasLimit: 3000000 })).to.be.revertedWithCustomError( - maciContract, - "CallerMustBePoll", - ); + // the next signup should fail + await expect( + maci.signUp( + keypair.pubKey.asContractParam(), + AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), + AbiCoder.defaultAbiCoder().encode(["uint256"], [0]), + ), + ).to.be.revertedWithCustomError(maci, "TooManySignups"); }); }); @@ -347,140 +291,40 @@ describe("MACI", () => { expect(Number(onChainBatchSizes.messageBatchSize)).to.eq(messageBatchSize); expect(Number(onChainBatchSizes.tallyBatchSize)).to.eq(tallyBatchSize); }); - }); - - describe("Publish messages (vote + key-change)", () => { - let pollContract: PollContract; - - before(async () => { - const pollContractAddress = await maciContract.getPoll(pollId); - pollContract = new BaseContract(pollContractAddress, pollAbi, signer) as PollContract; - }); - - it("should publish a message to the Poll contract", async () => { - const keypair = new Keypair(); - - const command = new PCommand( - BigInt(1), - keypair.pubKey, - BigInt(0), - BigInt(9), - BigInt(1), - BigInt(pollId), - BigInt(0), - ); - - const signature = command.sign(keypair.privKey); - const sharedKey = Keypair.genEcdhSharedKey(keypair.privKey, coordinator.pubKey); - const message = command.encrypt(signature, sharedKey); - const tx = await pollContract.publishMessage( - message.asContractParam(), - keypair.pubKey.asContractParam() as { x: BigNumberish; y: BigNumberish }, - ); - const receipt = await tx.wait(); - expect(receipt?.status).to.eq(1); - - maciState.polls[pollId].publishMessage(message, keypair.pubKey); - }); - - it("shold not publish a message after the voting period", async () => { - const dd = await pollContract.getDeployTimeAndDuration(); - await timeTravel(signer.provider as unknown as EthereumProvider, Number(dd[0]) + 1); - - const keypair = new Keypair(); - const command = new PCommand( - BigInt(0), - keypair.pubKey, - BigInt(0), - BigInt(0), - BigInt(0), - BigInt(pollId), - BigInt(0), - ); - - const signature = command.sign(keypair.privKey); - const sharedKey = Keypair.genEcdhSharedKey(keypair.privKey, coordinator.pubKey); - const message = command.encrypt(signature, sharedKey); + it("should prevent deploying a second poll before the first has finished", async () => { await expect( - pollContract.publishMessage( - message.asContractParam(), - keypair.pubKey.asContractParam() as { x: BigNumberish; y: BigNumberish }, - { gasLimit: 300000 }, - ), - ).to.be.revertedWithCustomError(pollContract, "VotingPeriodOver"); + maciContract.deployPoll(duration, maxValues, treeDepths, coordinator.pubKey.asContractParam(), { + gasLimit: 8000000, + }), + ) + .to.be.revertedWithCustomError(maciContract, "PreviousPollNotCompleted") + .withArgs(1); }); }); - describe("Merge messages", () => { + describe("Merge sign-ups", () => { let pollContract: PollContract; - let messageAqContract: AccQueue; - beforeEach(async () => { + before(async () => { const pollContractAddress = await maciContract.getPoll(pollId); pollContract = new BaseContract(pollContractAddress, pollAbi, signer) as PollContract; - - const extContracts = await pollContract.extContracts(); - - const messageAqAddress = extContracts.messageAq; - messageAqContract = new BaseContract(messageAqAddress, accQueueQuinaryMaciAbi, signer) as AccQueue; }); - it("should revert if subtrees are not merged for StateAq", async () => { - await expect(pollContract.mergeMaciStateAq(0, { gasLimit: 4000000 })).to.be.revertedWithCustomError( - pollContract, - "StateAqSubtreesNeedMerge", + it("coordinator should not be able to merge the signUp AccQueue", async () => { + await expect(maciContract.mergeStateAqSubRoots(0, 0, { gasLimit: 3000000 })).to.be.revertedWithCustomError( + maciContract, + "CallerMustBePoll", ); - }); - - it("coordinator should be able to merge the message AccQueue", async () => { - let tx = await pollContract.mergeMessageAqSubRoots(0, { - gasLimit: 3000000, - }); - let receipt = await tx.wait(); - expect(receipt?.status).to.eq(1); - tx = await pollContract.mergeMessageAq({ gasLimit: 4000000 }); - receipt = await tx.wait(); - expect(receipt?.status).to.eq(1); - }); - - it("the message root must be correct", async () => { - const onChainMessageRoot = await messageAqContract.getMainRoot(MESSAGE_TREE_DEPTH); - const offChainMessageRoot = maciState.polls[pollId].messageTree.root; - - expect(onChainMessageRoot.toString()).to.eq(offChainMessageRoot.toString()); - }); - }); - - describe("Tally votes (negative test)", () => { - it("tallyVotes() should fail as the messages have not been processed yet", async () => { - const pollContractAddress = await maciContract.getPoll(pollId); - await expect( - tallyContract.tallyVotes(pollContractAddress, await mpContract.getAddress(), 0, [0, 0, 0, 0, 0, 0, 0, 0]), - ).to.be.revertedWithCustomError(tallyContract, "ProcessingNotComplete"); - }); - }); - - describe("Process messages (negative test)", () => { - it("processMessages() should fail if the state AQ has not been merged", async () => { - const pollContractAddress = await maciContract.getPoll(pollId); - - await expect( - mpContract.processMessages(pollContractAddress, 0, [0, 0, 0, 0, 0, 0, 0, 0]), - ).to.be.revertedWithCustomError(mpContract, "StateAqNotMerged"); - }); - }); - - describe("Merge sign-ups as the Poll", () => { - let pollContract: PollContract; - - before(async () => { - const pollContractAddress = await maciContract.getPoll(pollId); - pollContract = new BaseContract(pollContractAddress, pollAbi, signer) as PollContract; + await expect(maciContract.mergeStateAq(0, { gasLimit: 3000000 })).to.be.revertedWithCustomError( + maciContract, + "CallerMustBePoll", + ); }); it("The Poll should be able to merge the signUp AccQueue", async () => { + await timeTravel(signer.provider as unknown as EthereumProvider, Number(duration) + 1); let tx = await pollContract.mergeMaciStateAqSubRoots(0, pollId, { gasLimit: 3000000, }); @@ -499,88 +343,4 @@ describe("MACI", () => { expect(onChainStateRoot.toString()).to.eq(maciState.stateTree.root.toString()); }); }); - - describe("Process messages", () => { - let pollContract: PollContract; - let poll: Poll; - let generatedInputs: { newSbCommitment: bigint }; - - before(async () => { - const pollContractAddress = await maciContract.getPoll(pollId); - pollContract = new BaseContract(pollContractAddress, pollAbi, signer) as PollContract; - - poll = maciState.polls[pollId]; - generatedInputs = poll.processMessages(pollId) as typeof generatedInputs; - }); - - it("genProcessMessagesPackedVals() should generate the correct value", async () => { - const packedVals = packProcessMessageSmallVals( - BigInt(maxValues.maxVoteOptions), - BigInt(users.length), - 0, - poll.messages.length, - ); - const onChainPackedVals = BigInt( - await mpContract.genProcessMessagesPackedVals(await pollContract.getAddress(), 0, users.length), - ); - expect(packedVals.toString(16)).to.eq(onChainPackedVals.toString(16)); - }); - - it("processMessages() should update the state and ballot root commitment", async () => { - const pollContractAddress = await maciContract.getPoll(pollId); - - // Submit the proof - const tx = await mpContract.processMessages( - pollContractAddress, - generatedInputs.newSbCommitment, - [0, 0, 0, 0, 0, 0, 0, 0], - ); - - const receipt = await tx.wait(); - expect(receipt?.status).to.eq(1); - - const processingComplete = await mpContract.processingComplete(); - expect(processingComplete).to.eq(true); - - const onChainNewSbCommitment = await mpContract.sbCommitment(); - expect(generatedInputs.newSbCommitment).to.eq(onChainNewSbCommitment.toString()); - }); - }); - - describe("Tally votes", () => { - it("genTallyVotesPackedVals() should generate the correct value", async () => { - const onChainPackedVals = BigInt(await tallyContract.genTallyVotesPackedVals(users.length, 0, tallyBatchSize)); - const packedVals = packTallyVotesSmallVals(0, tallyBatchSize, users.length); - expect(onChainPackedVals.toString()).to.eq(packedVals.toString()); - }); - - it("tallyVotes() should update the tally commitment", async () => { - const poll = maciState.polls[pollId]; - const generatedInputs = poll.tallyVotes() as { newTallyCommitment: bigint }; - - const pollContractAddress = await maciContract.getPoll(pollId); - const tx = await tallyContract.tallyVotes( - pollContractAddress, - await mpContract.getAddress(), - generatedInputs.newTallyCommitment, - [0, 0, 0, 0, 0, 0, 0, 0], - ); - - const receipt = await tx.wait(); - expect(receipt?.status).to.eq(1); - - const onChainNewTallyCommitment = await tallyContract.tallyCommitment(); - - expect(generatedInputs.newTallyCommitment).to.eq(onChainNewTallyCommitment.toString()); - - await expect( - tallyContract.tallyVotes( - pollContractAddress, - await mpContract.getAddress(), - generatedInputs.newTallyCommitment, - [0, 0, 0, 0, 0, 0, 0, 0], - ), - ).to.be.revertedWithCustomError(tallyContract, "AllBallotsTallied"); - }); - }); }); diff --git a/contracts/tests/MaciOverflow.test.ts b/contracts/tests/MaciOverflow.test.ts index 3944de5703..3a9ccb6a17 100644 --- a/contracts/tests/MaciOverflow.test.ts +++ b/contracts/tests/MaciOverflow.test.ts @@ -1,37 +1,19 @@ import { expect } from "chai"; import { AbiCoder, BigNumberish } from "ethers"; -import { MaxValues, TreeDepths } from "maci-core"; +import { MaxValues, STATE_TREE_DEPTH, TreeDepths } from "maci-core"; import { Keypair } from "maci-domainobjs"; import { deployTestContracts } from "../ts/utils"; import { MACI } from "../typechain-types"; -const coordinator = new Keypair(); -const users = [new Keypair(), new Keypair(), new Keypair()]; - -const STATE_TREE_DEPTH = 10; -const MESSAGE_TREE_DEPTH = 4; -const MESSAGE_TREE_SUBDEPTH = 2; - -// Poll parameters -const duration = 15; -const maxValues: MaxValues = { - maxMessages: 25, - maxVoteOptions: 25, -}; - -const treeDepths: TreeDepths = { - intStateTreeDepth: 1, - messageTreeDepth: MESSAGE_TREE_DEPTH, - messageTreeSubDepth: MESSAGE_TREE_SUBDEPTH, - voteOptionTreeDepth: 2, -}; - -const initialVoiceCreditBalance = 100; +import { duration, initialVoiceCreditBalance, maxValues, treeDepths } from "./constants"; describe("Overflow testing", () => { let maciContract: MACI; + const coordinator = new Keypair(); + const users = [new Keypair(), new Keypair(), new Keypair()]; + beforeEach(async () => { const r = await deployTestContracts(initialVoiceCreditBalance, STATE_TREE_DEPTH, true); maciContract = r.maciContract; diff --git a/contracts/tests/MessageProcessor.test.ts b/contracts/tests/MessageProcessor.test.ts new file mode 100644 index 0000000000..086cd34ff7 --- /dev/null +++ b/contracts/tests/MessageProcessor.test.ts @@ -0,0 +1,168 @@ +/* eslint-disable no-underscore-dangle */ +import { expect } from "chai"; +import { BaseContract, Signer } from "ethers"; +import { EthereumProvider } from "hardhat/types"; +import { MaciState, Poll, STATE_TREE_DEPTH, packProcessMessageSmallVals } from "maci-core"; +import { NOTHING_UP_MY_SLEEVE } from "maci-crypto"; +import { Keypair, Message, PubKey } from "maci-domainobjs"; + +import { IVerifyingKeyStruct, deployTestContracts, getDefaultSigner, parseArtifact } from "../ts"; +import { MACI, MessageProcessor, Poll as PollContract } from "../typechain-types"; + +import { + duration, + initialVoiceCreditBalance, + maxValues, + messageBatchSize, + testProcessVk, + testTallyVk, + treeDepths, +} from "./constants"; +import { timeTravel } from "./utils"; + +describe("MessageProcessor", () => { + // contracts + let maciContract: MACI; + let pollContract: PollContract; + let mpContract: MessageProcessor; + const [pollAbi] = parseArtifact("Poll"); + + let pollId: number; + + // local poll and maci state + let poll: Poll; + const maciState = new MaciState(STATE_TREE_DEPTH); + + let signer: Signer; + let generatedInputs: { newSbCommitment: bigint }; + const coordinator = new Keypair(); + + const users = [new Keypair(), new Keypair()]; + + before(async () => { + // deploy test contracts + const r = await deployTestContracts(initialVoiceCreditBalance, STATE_TREE_DEPTH, true); + maciContract = r.maciContract; + signer = await getDefaultSigner(); + mpContract = r.mpContract; + + // deploy on chain poll + const tx = await maciContract.deployPoll(duration, maxValues, treeDepths, coordinator.pubKey.asContractParam(), { + gasLimit: 8000000, + }); + let receipt = await tx.wait(); + + // extract poll id + expect(receipt?.status).to.eq(1); + const iface = maciContract.interface; + const logs = receipt!.logs[receipt!.logs.length - 1]; + const event = iface.parseLog(logs as unknown as { topics: string[]; data: string }) as unknown as { + args: { _pollId: number }; + }; + pollId = event.args._pollId; + + const pollContractAddress = await maciContract.getPoll(pollId); + pollContract = new BaseContract(pollContractAddress, pollAbi, signer) as PollContract; + + const block = await signer.provider!.getBlock(receipt!.blockHash); + const deployTime = block!.timestamp; + + // deploy local poll + const p = maciState.deployPoll( + duration, + BigInt(deployTime + duration), + maxValues, + treeDepths, + messageBatchSize, + coordinator, + ); + expect(p.toString()).to.eq(pollId.toString()); + + // publish the NOTHING_UP_MY_SLEEVE message + const messageData = [NOTHING_UP_MY_SLEEVE, BigInt(0)]; + for (let i = 2; i < 10; i += 1) { + messageData.push(BigInt(0)); + } + const message = new Message(BigInt(1), messageData); + const padKey = new PubKey([ + BigInt("10457101036533406547632367118273992217979173478358440826365724437999023779287"), + BigInt("19824078218392094440610104313265183977899662750282163392862422243483260492317"), + ]); + maciState.polls[pollId].publishMessage(message, padKey); + + poll = maciState.polls[pollId]; + generatedInputs = poll.processMessages(pollId) as typeof generatedInputs; + + // set the verification keys on the vk smart contract + const vkContract = r.vkRegistryContract; + await vkContract.setVerifyingKeys( + STATE_TREE_DEPTH, + treeDepths.intStateTreeDepth, + treeDepths.messageTreeDepth, + treeDepths.voteOptionTreeDepth, + messageBatchSize, + testProcessVk.asContractParam() as IVerifyingKeyStruct, + testTallyVk.asContractParam() as IVerifyingKeyStruct, + { gasLimit: 1000000 }, + ); + receipt = await tx.wait(); + expect(receipt?.status).to.eq(1); + }); + + describe("before merging acc queues", () => { + before(async () => { + await timeTravel(signer.provider! as unknown as EthereumProvider, duration + 1); + }); + + it("processMessages() should fail if the state AQ has not been merged", async () => { + const pollContractAddress = await maciContract.getPoll(pollId); + + await expect( + mpContract.processMessages(pollContractAddress, 0, [0, 0, 0, 0, 0, 0, 0, 0]), + ).to.be.revertedWithCustomError(mpContract, "StateAqNotMerged"); + }); + }); + + describe("after merging acc queues", () => { + before(async () => { + await pollContract.mergeMaciStateAqSubRoots(0, pollId); + await pollContract.mergeMaciStateAq(0); + + await pollContract.mergeMessageAqSubRoots(0); + await pollContract.mergeMessageAq(); + }); + + it("genProcessMessagesPackedVals() should generate the correct value", async () => { + const packedVals = packProcessMessageSmallVals( + BigInt(maxValues.maxVoteOptions), + BigInt(users.length), + 0, + poll.messages.length, + ); + const onChainPackedVals = BigInt( + await mpContract.genProcessMessagesPackedVals(await pollContract.getAddress(), 0, users.length), + ); + expect(packedVals.toString(16)).to.eq(onChainPackedVals.toString(16)); + }); + + it("processMessages() should update the state and ballot root commitment", async () => { + const pollContractAddress = await maciContract.getPoll(pollId); + + // Submit the proof + const tx = await mpContract.processMessages( + pollContractAddress, + generatedInputs.newSbCommitment, + [0, 0, 0, 0, 0, 0, 0, 0], + ); + + const receipt = await tx.wait(); + expect(receipt?.status).to.eq(1); + + const processingComplete = await mpContract.processingComplete(); + expect(processingComplete).to.eq(true); + + const onChainNewSbCommitment = await mpContract.sbCommitment(); + expect(generatedInputs.newSbCommitment).to.eq(onChainNewSbCommitment.toString()); + }); + }); +}); diff --git a/contracts/tests/Poll.test.ts b/contracts/tests/Poll.test.ts new file mode 100644 index 0000000000..13b71ccada --- /dev/null +++ b/contracts/tests/Poll.test.ts @@ -0,0 +1,172 @@ +/* eslint-disable no-underscore-dangle */ +import { expect } from "chai"; +import { BaseContract, Signer } from "ethers"; +import { EthereumProvider } from "hardhat/types"; +import { MaciState } from "maci-core"; +import { NOTHING_UP_MY_SLEEVE } from "maci-crypto"; +import { Keypair, Message, PCommand, PubKey } from "maci-domainobjs"; + +import { deployTestContracts, getDefaultSigner, parseArtifact } from "../ts"; +import { AccQueue, MACI, Poll as PollContract } from "../typechain-types"; + +import { + MESSAGE_TREE_DEPTH, + STATE_TREE_DEPTH, + duration, + initialVoiceCreditBalance, + maxValues, + messageBatchSize, + treeDepths, +} from "./constants"; +import { timeTravel } from "./utils"; + +describe("Poll", () => { + let maciContract: MACI; + let pollId: number; + let pollContract: PollContract; + let signer: Signer; + let deployTime: number; + const coordinator = new Keypair(); + const [pollAbi] = parseArtifact("Poll"); + const [accQueueQuinaryMaciAbi] = parseArtifact("AccQueueQuinaryMaci"); + + const maciState = new MaciState(STATE_TREE_DEPTH); + + before(async () => { + signer = await getDefaultSigner(); + const r = await deployTestContracts(initialVoiceCreditBalance, STATE_TREE_DEPTH, true); + maciContract = r.maciContract; + + // deploy on chain poll + const tx = await maciContract.deployPoll(duration, maxValues, treeDepths, coordinator.pubKey.asContractParam(), { + gasLimit: 8000000, + }); + const receipt = await tx.wait(); + + const block = await signer.provider!.getBlock(receipt!.blockHash); + deployTime = block!.timestamp; + + expect(receipt?.status).to.eq(1); + const iface = maciContract.interface; + const logs = receipt!.logs[receipt!.logs.length - 1]; + const event = iface.parseLog(logs as unknown as { topics: string[]; data: string }) as unknown as { + args: { _pollId: number }; + }; + pollId = event.args._pollId; + + const pollContractAddress = await maciContract.getPoll(pollId); + pollContract = new BaseContract(pollContractAddress, pollAbi, signer) as PollContract; + + // deploy local poll + const p = maciState.deployPoll( + duration, + BigInt(deployTime + duration), + maxValues, + treeDepths, + messageBatchSize, + coordinator, + ); + expect(p.toString()).to.eq(pollId.toString()); + // publish the NOTHING_UP_MY_SLEEVE message + const messageData = [NOTHING_UP_MY_SLEEVE, BigInt(0)]; + for (let i = 2; i < 10; i += 1) { + messageData.push(BigInt(0)); + } + const message = new Message(BigInt(1), messageData); + const padKey = new PubKey([ + BigInt("10457101036533406547632367118273992217979173478358440826365724437999023779287"), + BigInt("19824078218392094440610104313265183977899662750282163392862422243483260492317"), + ]); + maciState.polls[pollId].publishMessage(message, padKey); + }); + + it("should not be possible to init the Poll contract twice", async () => { + await expect(pollContract.init()).to.be.revertedWithCustomError(pollContract, "PollAlreadyInit"); + }); + + describe("Publish messages (vote + key-change)", () => { + it("should publish a message to the Poll contract", async () => { + const keypair = new Keypair(); + + const command = new PCommand( + BigInt(1), + keypair.pubKey, + BigInt(0), + BigInt(9), + BigInt(1), + BigInt(pollId), + BigInt(0), + ); + + const signature = command.sign(keypair.privKey); + const sharedKey = Keypair.genEcdhSharedKey(keypair.privKey, coordinator.pubKey); + const message = command.encrypt(signature, sharedKey); + const tx = await pollContract.publishMessage(message.asContractParam(), keypair.pubKey.asContractParam()); + const receipt = await tx.wait(); + expect(receipt?.status).to.eq(1); + + maciState.polls[pollId].publishMessage(message, keypair.pubKey); + }); + + it("shold not publish a message after the voting period", async () => { + const dd = await pollContract.getDeployTimeAndDuration(); + await timeTravel(signer.provider as unknown as EthereumProvider, Number(dd[0]) + 1); + + const keypair = new Keypair(); + const command = new PCommand( + BigInt(0), + keypair.pubKey, + BigInt(0), + BigInt(0), + BigInt(0), + BigInt(pollId), + BigInt(0), + ); + + const signature = command.sign(keypair.privKey); + const sharedKey = Keypair.genEcdhSharedKey(keypair.privKey, coordinator.pubKey); + const message = command.encrypt(signature, sharedKey); + + await expect( + pollContract.publishMessage(message.asContractParam(), keypair.pubKey.asContractParam(), { gasLimit: 300000 }), + ).to.be.revertedWithCustomError(pollContract, "VotingPeriodOver"); + }); + }); + + describe("Merge messages", () => { + let messageAqContract: AccQueue; + + beforeEach(async () => { + const extContracts = await pollContract.extContracts(); + + const messageAqAddress = extContracts.messageAq; + messageAqContract = new BaseContract(messageAqAddress, accQueueQuinaryMaciAbi, signer) as AccQueue; + }); + + it("should revert if subtrees are not merged for StateAq", async () => { + await expect(pollContract.mergeMaciStateAq(0, { gasLimit: 4000000 })).to.be.revertedWithCustomError( + pollContract, + "StateAqSubtreesNeedMerge", + ); + }); + + it("coordinator should be able to merge the message AccQueue", async () => { + let tx = await pollContract.mergeMessageAqSubRoots(0, { + gasLimit: 3000000, + }); + let receipt = await tx.wait(); + expect(receipt?.status).to.eq(1); + + tx = await pollContract.mergeMessageAq({ gasLimit: 4000000 }); + receipt = await tx.wait(); + expect(receipt?.status).to.eq(1); + }); + + it("the message root must be correct", async () => { + const onChainMessageRoot = await messageAqContract.getMainRoot(MESSAGE_TREE_DEPTH); + const offChainMessageRoot = maciState.polls[pollId].messageTree.root; + + expect(onChainMessageRoot.toString()).to.eq(offChainMessageRoot.toString()); + }); + }); +}); diff --git a/contracts/tests/Tally.test.ts b/contracts/tests/Tally.test.ts new file mode 100644 index 0000000000..d4b4611f8a --- /dev/null +++ b/contracts/tests/Tally.test.ts @@ -0,0 +1,192 @@ +/* eslint-disable no-underscore-dangle */ +import { expect } from "chai"; +import { BaseContract, Signer } from "ethers"; +import { EthereumProvider } from "hardhat/types"; +import { MaciState, Poll, packTallyVotesSmallVals } from "maci-core"; +import { NOTHING_UP_MY_SLEEVE } from "maci-crypto"; +import { Keypair, Message, PubKey } from "maci-domainobjs"; + +import { IVerifyingKeyStruct, deployTestContracts, getDefaultSigner, parseArtifact } from "../ts"; +import { Tally, MACI, Poll as PollContract, MessageProcessor } from "../typechain-types"; + +import { + STATE_TREE_DEPTH, + duration, + maxValues, + messageBatchSize, + tallyBatchSize, + testProcessVk, + testTallyVk, + treeDepths, +} from "./constants"; +import { timeTravel } from "./utils"; + +describe("TallyVotes", () => { + let signer: Signer; + let maciContract: MACI; + let pollContract: PollContract; + let tallyContract: Tally; + let mpContract: MessageProcessor; + + const coordinator = new Keypair(); + const users = [new Keypair(), new Keypair()]; + const maciState = new MaciState(STATE_TREE_DEPTH); + + const [pollAbi] = parseArtifact("Poll"); + + let pollId: number; + let poll: Poll; + + let generatedInputs: { newSbCommitment: bigint }; + + before(async () => { + signer = await getDefaultSigner(); + + const r = await deployTestContracts(100, STATE_TREE_DEPTH, true); + maciContract = r.maciContract; + mpContract = r.mpContract; + tallyContract = r.tallyContract; + + // deploy a poll + // deploy on chain poll + const tx = await maciContract.deployPoll(duration, maxValues, treeDepths, coordinator.pubKey.asContractParam(), { + gasLimit: 8000000, + }); + let receipt = await tx.wait(); + + const block = await signer.provider!.getBlock(receipt!.blockHash); + const deployTime = block!.timestamp; + + expect(receipt?.status).to.eq(1); + const iface = maciContract.interface; + const logs = receipt!.logs[receipt!.logs.length - 1]; + const event = iface.parseLog(logs as unknown as { topics: string[]; data: string }) as unknown as { + args: { _pollId: number }; + }; + pollId = event.args._pollId; + + const pollContractAddress = await maciContract.getPoll(pollId); + pollContract = new BaseContract(pollContractAddress, pollAbi, signer) as PollContract; + + // deploy local poll + const p = maciState.deployPoll( + duration, + BigInt(deployTime + duration), + maxValues, + treeDepths, + messageBatchSize, + coordinator, + ); + expect(p.toString()).to.eq(pollId.toString()); + // publish the NOTHING_UP_MY_SLEEVE message + const messageData = [NOTHING_UP_MY_SLEEVE, BigInt(0)]; + for (let i = 2; i < 10; i += 1) { + messageData.push(BigInt(0)); + } + const message = new Message(BigInt(1), messageData); + const padKey = new PubKey([ + BigInt("10457101036533406547632367118273992217979173478358440826365724437999023779287"), + BigInt("19824078218392094440610104313265183977899662750282163392862422243483260492317"), + ]); + maciState.polls[pollId].publishMessage(message, padKey); + + // save the poll + poll = maciState.polls[pollId]; + + // process messages locally + generatedInputs = poll.processMessages(pollId) as typeof generatedInputs; + + // set the verification keys on the vk smart contract + const vkContract = r.vkRegistryContract; + await vkContract.setVerifyingKeys( + STATE_TREE_DEPTH, + treeDepths.intStateTreeDepth, + treeDepths.messageTreeDepth, + treeDepths.voteOptionTreeDepth, + messageBatchSize, + testProcessVk.asContractParam() as IVerifyingKeyStruct, + testTallyVk.asContractParam() as IVerifyingKeyStruct, + { gasLimit: 1000000 }, + ); + receipt = await tx.wait(); + expect(receipt?.status).to.eq(1); + }); + + it("should not be possible to tally votes before the poll has ended", async () => { + await expect( + tallyContract.tallyVotes( + await pollContract.getAddress(), + await mpContract.getAddress(), + 0, + [0, 0, 0, 0, 0, 0, 0, 0], + ), + ).to.be.revertedWithCustomError(tallyContract, "VOTING_PERIOD_NOT_PASSED"); + }); + + it("genTallyVotesPackedVals() should generate the correct value", async () => { + const onChainPackedVals = BigInt(await tallyContract.genTallyVotesPackedVals(users.length, 0, tallyBatchSize)); + const packedVals = packTallyVotesSmallVals(0, tallyBatchSize, users.length); + expect(onChainPackedVals.toString()).to.eq(packedVals.toString()); + }); + + it("updateSbCommitment() should revert when the messages have not been processed yet", async () => { + // go forward in time + await timeTravel(signer.provider! as unknown as EthereumProvider, duration + 1); + + await expect(tallyContract.updateSbCommitment(await mpContract.getAddress())).to.be.revertedWithCustomError( + tallyContract, + "ProcessingNotComplete", + ); + }); + + it("tallyVotes() should fail as the messages have not been processed yet", async () => { + const pollContractAddress = await maciContract.getPoll(pollId); + await expect( + tallyContract.tallyVotes(pollContractAddress, await mpContract.getAddress(), 0, [0, 0, 0, 0, 0, 0, 0, 0]), + ).to.be.revertedWithCustomError(tallyContract, "ProcessingNotComplete"); + }); + + describe("after merging acc queues", () => { + let tallyGeneratedInputs: { newTallyCommitment: bigint }; + before(async () => { + await pollContract.mergeMaciStateAqSubRoots(0, pollId); + await pollContract.mergeMaciStateAq(0); + + await pollContract.mergeMessageAqSubRoots(0); + await pollContract.mergeMessageAq(); + tallyGeneratedInputs = poll.tallyVotes() as { newTallyCommitment: bigint }; + }); + it("tallyVotes() should update the tally commitment", async () => { + // do the processing on the message processor contract + await mpContract.processMessages( + await pollContract.getAddress(), + generatedInputs.newSbCommitment, + [0, 0, 0, 0, 0, 0, 0, 0], + ); + + const tx = await tallyContract.tallyVotes( + await pollContract.getAddress(), + await mpContract.getAddress(), + tallyGeneratedInputs.newTallyCommitment, + [0, 0, 0, 0, 0, 0, 0, 0], + ); + + const receipt = await tx.wait(); + expect(receipt?.status).to.eq(1); + + const onChainNewTallyCommitment = await tallyContract.tallyCommitment(); + + expect(tallyGeneratedInputs.newTallyCommitment).to.eq(onChainNewTallyCommitment.toString()); + }); + it("tallyVotes() shuold revert when votes have already been tallied", async () => { + await expect( + tallyContract.tallyVotes( + await pollContract.getAddress(), + await mpContract.getAddress(), + tallyGeneratedInputs.newTallyCommitment, + [0, 0, 0, 0, 0, 0, 0, 0], + ), + ).to.be.revertedWithCustomError(tallyContract, "AllBallotsTallied"); + }); + }); +}); diff --git a/contracts/tests/Verifier.test.ts b/contracts/tests/Verifier.test.ts index 6268ac2de3..e3d064238a 100644 --- a/contracts/tests/Verifier.test.ts +++ b/contracts/tests/Verifier.test.ts @@ -8,70 +8,72 @@ import type { BigNumberish } from "ethers"; import { deployVerifier } from "../ts/deploy"; import { Verifier } from "../typechain-types"; -const vk = new VerifyingKey( - new G1Point( - BigInt("20491192805390485299153009773594534940189261866228447918068658471970481763042"), - BigInt("9383485363053290200918347156157836566562967994039712273449902621266178545958"), - ), - new G2Point( - [ - BigInt("4252822878758300859123897981450591353533073413197771768651442665752259397132"), - BigInt("6375614351688725206403948262868962793625744043794305715222011528459656738731"), - ], - [ - BigInt("21847035105528745403288232691147584728191162732299865338377159692350059136679"), - BigInt("10505242626370262277552901082094356697409835680220590971873171140371331206856"), - ], - ), - new G2Point( - [ - BigInt("11559732032986387107991004021392285783925812861821192530917403151452391805634"), - BigInt("10857046999023057135944570762232829481370756359578518086990519993285655852781"), - ], - [ - BigInt("4082367875863433681332203403145435568316851327593401208105741076214120093531"), - BigInt("8495653923123431417604973247489272438418190587263600148770280649306958101930"), - ], - ), - new G2Point( - [ - BigInt("11700261708411360112482712242528551130212577267248363110777096731569359533937"), - BigInt("19316071393769631071739466808924557575370046223156790236472688098546713485164"), - ], - [ - BigInt("8314809347259847850803251217663255270167988731493310587391546796826904220459"), - BigInt("19027224119116513453619472056165183919393637553270616301189593772848351986009"), - ], - ), - [ +describe("DomainObjs", () => { + const vk = new VerifyingKey( new G1Point( - BigInt("8475939680648083280638846051497134319487781451783634569144849229381887869470"), - BigInt("15777387922383777864128245075158682837173769163333646572506201314277694741524"), + BigInt("20491192805390485299153009773594534940189261866228447918068658471970481763042"), + BigInt("9383485363053290200918347156157836566562967994039712273449902621266178545958"), ), - new G1Point( - BigInt("6307974476057044946223853054915497058693993784049217695740696374670315278450"), - BigInt("19541766564091333476121980691242907000813131822237920987048117031710761017707"), + new G2Point( + [ + BigInt("4252822878758300859123897981450591353533073413197771768651442665752259397132"), + BigInt("6375614351688725206403948262868962793625744043794305715222011528459656738731"), + ], + [ + BigInt("21847035105528745403288232691147584728191162732299865338377159692350059136679"), + BigInt("10505242626370262277552901082094356697409835680220590971873171140371331206856"), + ], + ), + new G2Point( + [ + BigInt("11559732032986387107991004021392285783925812861821192530917403151452391805634"), + BigInt("10857046999023057135944570762232829481370756359578518086990519993285655852781"), + ], + [ + BigInt("4082367875863433681332203403145435568316851327593401208105741076214120093531"), + BigInt("8495653923123431417604973247489272438418190587263600148770280649306958101930"), + ], ), - ], -); + new G2Point( + [ + BigInt("11700261708411360112482712242528551130212577267248363110777096731569359533937"), + BigInt("19316071393769631071739466808924557575370046223156790236472688098546713485164"), + ], + [ + BigInt("8314809347259847850803251217663255270167988731493310587391546796826904220459"), + BigInt("19027224119116513453619472056165183919393637553270616301189593772848351986009"), + ], + ), + [ + new G1Point( + BigInt("8475939680648083280638846051497134319487781451783634569144849229381887869470"), + BigInt("15777387922383777864128245075158682837173769163333646572506201314277694741524"), + ), + new G1Point( + BigInt("6307974476057044946223853054915497058693993784049217695740696374670315278450"), + BigInt("19541766564091333476121980691242907000813131822237920987048117031710761017707"), + ), + ], + ); -const proof: BigNumberish[] = [ - "1165825367733124312792381812275119057681245770152620921258630875255505370924", - "1326527658843314194011957286833609405197138989276710702270523657454496479584", + const proof: BigNumberish[] = [ + "1165825367733124312792381812275119057681245770152620921258630875255505370924", + "1326527658843314194011957286833609405197138989276710702270523657454496479584", - "7737027768984365020868604289323857674854735856726312758475237268839850113180", - "20950373595246980797046559551868305313847958836379415962375381761472018077992", + "7737027768984365020868604289323857674854735856726312758475237268839850113180", + "20950373595246980797046559551868305313847958836379415962375381761472018077992", - "13877265106716680864869634040774025553232681727839817029074568384172308524666", - "15414074355891062201145392604892692653071670599659589357921635169192446560614", + "13877265106716680864869634040774025553232681727839817029074568384172308524666", + "15414074355891062201145392604892692653071670599659589357921635169192446560614", - "18990315920454525475289309807669145530304447815324475374776788804237092237703", - "14054172703456858179866637245926478995167764402990898943219235085496257747260", -]; + "18990315920454525475289309807669145530304447815324475374776788804237092237703", + "14054172703456858179866637245926478995167764402990898943219235085496257747260", + ]; -const publicInputs: BigNumberish[] = ["17771946183498688010237928397719449956849198402702324449167227661291280245514"]; + const publicInputs: BigNumberish[] = [ + "17771946183498688010237928397719449956849198402702324449167227661291280245514", + ]; -describe("DomainObjs", () => { let verifierContract: Verifier; describe("Deployment", () => { diff --git a/contracts/tests/constants.ts b/contracts/tests/constants.ts new file mode 100644 index 0000000000..f2fcc4ce81 --- /dev/null +++ b/contracts/tests/constants.ts @@ -0,0 +1,42 @@ +import { MaxValues, TreeDepths } from "maci-core"; +import { G1Point, G2Point } from "maci-crypto"; +import { VerifyingKey } from "maci-domainobjs"; + +export const duration = 15; + +export const messageBatchSize = 25; +export const STATE_TREE_DEPTH = 10; +export const STATE_TREE_ARITY = 5; +export const MESSAGE_TREE_DEPTH = 4; +export const MESSAGE_TREE_SUBDEPTH = 2; + +export const testProcessVk = new VerifyingKey( + new G1Point(BigInt(0), BigInt(1)), + new G2Point([BigInt(2), BigInt(3)], [BigInt(4), BigInt(5)]), + new G2Point([BigInt(6), BigInt(7)], [BigInt(8), BigInt(9)]), + new G2Point([BigInt(10), BigInt(11)], [BigInt(12), BigInt(13)]), + [new G1Point(BigInt(14), BigInt(15)), new G1Point(BigInt(16), BigInt(17))], +); + +export const testTallyVk = new VerifyingKey( + new G1Point(BigInt(0), BigInt(1)), + new G2Point([BigInt(2), BigInt(3)], [BigInt(4), BigInt(5)]), + new G2Point([BigInt(6), BigInt(7)], [BigInt(8), BigInt(9)]), + new G2Point([BigInt(10), BigInt(11)], [BigInt(12), BigInt(13)]), + [new G1Point(BigInt(14), BigInt(15)), new G1Point(BigInt(16), BigInt(17))], +); + +export const initialVoiceCreditBalance = 100; +export const maxValues: MaxValues = { + maxMessages: 25, + maxVoteOptions: 25, +}; + +export const treeDepths: TreeDepths = { + intStateTreeDepth: 1, + messageTreeDepth: MESSAGE_TREE_DEPTH, + messageTreeSubDepth: MESSAGE_TREE_SUBDEPTH, + voteOptionTreeDepth: 2, +}; + +export const tallyBatchSize = STATE_TREE_ARITY ** treeDepths.intStateTreeDepth; diff --git a/contracts/tests/utils.ts b/contracts/tests/utils.ts index a17b33efe3..6d152a43b2 100644 --- a/contracts/tests/utils.ts +++ b/contracts/tests/utils.ts @@ -1,6 +1,42 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import { expect } from "chai"; +import { VerifyingKey } from "maci-domainobjs"; + import type { EthereumProvider } from "hardhat/types"; +/** + * Travel in time in a local blockchain node + * @param provider the provider to use + * @param seconds the number of seconds to travel for + */ export async function timeTravel(provider: EthereumProvider, seconds: number): Promise { await provider.send("evm_increaseTime", [Number(seconds)]); await provider.send("evm_mine", []); } + +/** + * Compare two verifying keys + * @param vk - the off chain vk + * @param vkOnChain - the on chain vk + */ +export const compareVks = (vk: VerifyingKey, vkOnChain: VerifyingKey): void => { + expect(vk.ic.length).to.eq(vkOnChain.ic.length); + for (let i = 0; i < vk.ic.length; i += 1) { + expect(vk.ic[i].x.toString()).to.eq(vkOnChain.ic[i].x.toString()); + expect(vk.ic[i].y.toString()).to.eq(vkOnChain.ic[i].y.toString()); + } + expect(vk.alpha1.x.toString()).to.eq(vkOnChain.alpha1.x.toString()); + expect(vk.alpha1.y.toString()).to.eq(vkOnChain.alpha1.y.toString()); + expect(vk.beta2.x[0].toString()).to.eq(vkOnChain.beta2.x[0].toString()); + expect(vk.beta2.x[1].toString()).to.eq(vkOnChain.beta2.x[1].toString()); + expect(vk.beta2.y[0].toString()).to.eq(vkOnChain.beta2.y[0].toString()); + expect(vk.beta2.y[1].toString()).to.eq(vkOnChain.beta2.y[1].toString()); + expect(vk.delta2.x[0].toString()).to.eq(vkOnChain.delta2.x[0].toString()); + expect(vk.delta2.x[1].toString()).to.eq(vkOnChain.delta2.x[1].toString()); + expect(vk.delta2.y[0].toString()).to.eq(vkOnChain.delta2.y[0].toString()); + expect(vk.delta2.y[1].toString()).to.eq(vkOnChain.delta2.y[1].toString()); + expect(vk.gamma2.x[0].toString()).to.eq(vkOnChain.gamma2.x[0].toString()); + expect(vk.gamma2.x[1].toString()).to.eq(vkOnChain.gamma2.x[1].toString()); + expect(vk.gamma2.y[0].toString()).to.eq(vkOnChain.gamma2.y[0].toString()); + expect(vk.gamma2.y[1].toString()).to.eq(vkOnChain.gamma2.y[1].toString()); +};