Skip to content

Commit

Permalink
fix: contract tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kittybest committed Jan 9, 2024
1 parent b9fee47 commit b6c9701
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 47 deletions.
3 changes: 2 additions & 1 deletion contracts/contracts/Subsidy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IPoll } from "./interfaces/IPoll.sol";
import { SnarkCommon } from "./crypto/SnarkCommon.sol";
import { Hasher } from "./crypto/Hasher.sol";
import { CommonUtilities } from "./utilities/CommonUtilities.sol";
import { IVerifier } from "./interfaces/IVerifier.sol";
import { IVkRegistry } from "./interfaces/IVkRegistry.sol";

/// @title Subsidy
/// @notice This contract is used to verify that the subsidy calculations
/// are correct. It is also used to update the subsidy commitment if the
/// proof is valid.
contract Subsidy is Ownable, Hasher, SnarkCommon {
contract Subsidy is Ownable, CommonUtilities, Hasher, SnarkCommon {
uint256 public rbi; // row batch index
uint256 public cbi; // column batch index
// The final commitment to the state and ballot roots
Expand Down
3 changes: 2 additions & 1 deletion contracts/contracts/SubsidyFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ contract SubsidyFactory {
/// @param _vkRegistry VkRegistry contract
/// @param _poll Poll contract
/// @param _messageProcessor MessageProcessor contract
/// @param _owner Owner of the Subsidy contract
/// @return subsidyAddr The deployed Subsidy contract
function deploy(
address _verifier,
Expand All @@ -19,7 +20,7 @@ contract SubsidyFactory {
address _messageProcessor,
address _owner
) public returns (address subsidyAddr) {
/// @notice deploy Tally for this Poll
/// @notice deploy Subsidy for this Poll
Subsidy subsidy = new Subsidy(_verifier, _vkRegistry, _poll, _messageProcessor);
subsidy.transferOwnership(_owner);
subsidyAddr = address(subsidy);
Expand Down
3 changes: 2 additions & 1 deletion contracts/contracts/Tally.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ import { IMessageProcessor } from "./interfaces/IMessageProcessor.sol";
import { SnarkCommon } from "./crypto/SnarkCommon.sol";
import { IVerifier } from "./interfaces/IVerifier.sol";
import { IVkRegistry } from "./interfaces/IVkRegistry.sol";
import { CommonUtilities } from "./utilities/CommonUtilities.sol";

/// @title Tally
/// @notice The Tally contract is used during votes tallying
/// and by users to verify the tally results.
contract Tally is Ownable, SnarkCommon, Hasher {
contract Tally is Ownable, SnarkCommon, CommonUtilities, Hasher {
// custom errors
error ProcessingNotComplete();
error InvalidTallyVotesProof();
Expand Down
23 changes: 23 additions & 0 deletions contracts/contracts/utilities/CommonUtilities.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import { Poll } from "../Poll.sol";

/// @title CommonUtilities
/// @notice A contract that holds common utilities
/// which are to be used by multiple contracts
/// namely Subsidy, Tally and MessageProcessor
contract CommonUtilities {
error VotingPeriodNotPassed();

/// @notice common function for MessageProcessor, Tally and Subsidy
/// @param _poll the poll to be checked
function _votingPeriodOver(Poll _poll) internal view {
(uint256 deployTime, uint256 duration) = _poll.getDeployTimeAndDuration();
// Require that the voting period is over
uint256 secondsPassed = block.timestamp - deployTime;
if (secondsPassed <= duration) {
revert VotingPeriodNotPassed();
}
}
}
8 changes: 5 additions & 3 deletions contracts/tests/Poll.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,14 @@ describe("Poll", () => {
signer = await getDefaultSigner();
const r = await deployTestContracts(initialVoiceCreditBalance, STATE_TREE_DEPTH, signer, true);
maciContract = r.maciContract;
verifierContract = r.mockVerifierContract;
vkRegistryContract = r.vkRegistryContract;

// deploy on chain poll
const tx = await maciContract.deployPoll(
duration,
maxValues,
treeDepths,
duration,
maxValues,
treeDepths,
coordinator.pubKey.asContractParam(),
verifierContract,
vkRegistryContract,
Expand Down
84 changes: 45 additions & 39 deletions contracts/tests/Subsidy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { Keypair, Message, PubKey } from "maci-domainobjs";
import { parseArtifact } from "../ts/abi";
import { IVerifyingKeyStruct } from "../ts/types";
import { getDefaultSigner } from "../ts/utils";
import { MACI, Poll as PollContract, MessageProcessor, Subsidy } from "../typechain-types";
import { MACI, Poll as PollContract, MessageProcessor, Subsidy, Verifier, VkRegistry } from "../typechain-types";

import {
STATE_TREE_DEPTH,
Expand All @@ -28,11 +28,15 @@ describe("Subsidy", () => {
let pollContract: PollContract;
let subsidyContract: Subsidy;
let mpContract: MessageProcessor;
let verifierContract: Verifier;
let vkRegistryContract: VkRegistry;

const coordinator = new Keypair();
const maciState = new MaciState(STATE_TREE_DEPTH);

const [pollAbi] = parseArtifact("Poll");
const [mpAbi] = parseArtifact("MessageProcessor");
const [subsidyAbi] = parseArtifact("Subsidy");

let pollId: number;
let poll: Poll;
Expand All @@ -44,29 +48,46 @@ describe("Subsidy", () => {

const r = await deployTestContracts(100, STATE_TREE_DEPTH, signer, true);
maciContract = r.maciContract;
mpContract = r.mpContract;
subsidyContract = r.subsidyContract!;
verifierContract = r.mockVerifierContract;
vkRegistryContract = r.vkRegistryContract;

// deploy a poll
// deploy on chain poll
const tx = await maciContract.deployPoll(duration, maxValues, treeDepths, coordinator.pubKey.asContractParam(), {
gasLimit: 8000000,
});
const tx = await maciContract.deployPoll(
duration,
maxValues,
treeDepths,
coordinator.pubKey.asContractParam(),
verifierContract,
vkRegistryContract,
true,
{
gasLimit: 10000000,
},
);
const 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 };
const logSubsidy = receipt!.logs[receipt!.logs.length - 2];
const subsidyEvent = iface.parseLog(logSubsidy as unknown as { topics: string[]; data: string }) as unknown as {
args: { _subsidyAddr: string };
};
pollId = event.args._pollId;
const logMPTally = receipt!.logs[receipt!.logs.length - 1];
const MPTallyevent = iface.parseLog(logMPTally as unknown as { topics: string[]; data: string }) as unknown as {
args: { _pollId: number; _mpAddr: string };
};
pollId = MPTallyevent.args._pollId;

const pollContractAddress = await maciContract.getPoll(pollId);
pollContract = new BaseContract(pollContractAddress, pollAbi, signer) as PollContract;
const mpContractAddress = MPTallyevent.args._mpAddr;
mpContract = new BaseContract(mpContractAddress, mpAbi, signer) as MessageProcessor;
const subsidyContractAddress = subsidyEvent.args._subsidyAddr;
subsidyContract = new BaseContract(subsidyContractAddress, subsidyAbi, signer) as Subsidy;

// deploy local poll
const p = maciState.deployPoll(BigInt(deployTime + duration), maxValues, treeDepths, messageBatchSize, coordinator);
Expand All @@ -90,8 +111,8 @@ describe("Subsidy", () => {
generatedInputs = poll.processMessages(pollId) as typeof generatedInputs;

// set the verification keys on the vk smart contract
const vkContract = r.vkRegistryContract;
await vkContract.setVerifyingKeys(
vkRegistryContract = r.vkRegistryContract;
await vkRegistryContract.setVerifyingKeys(
STATE_TREE_DEPTH,
treeDepths.intStateTreeDepth,
treeDepths.messageTreeDepth,
Expand All @@ -101,7 +122,7 @@ describe("Subsidy", () => {
testTallyVk.asContractParam() as IVerifyingKeyStruct,
{ gasLimit: 1000000 },
);
await vkContract.setSubsidyKeys(
await vkRegistryContract.setSubsidyKeys(
STATE_TREE_DEPTH,
treeDepths.intStateTreeDepth,
treeDepths.voteOptionTreeDepth,
Expand All @@ -111,14 +132,10 @@ describe("Subsidy", () => {
});

it("should not be possible to tally votes before the poll has ended", async () => {
await expect(
subsidyContract.updateSubsidy(
await pollContract.getAddress(),
await mpContract.getAddress(),
0,
[0, 0, 0, 0, 0, 0, 0, 0],
),
).to.be.revertedWithCustomError(subsidyContract, "VOTING_PERIOD_NOT_PASSED");
await expect(subsidyContract.updateSubsidy(0, [0, 0, 0, 0, 0, 0, 0, 0])).to.be.revertedWithCustomError(
subsidyContract,
"ProcessingNotComplete",
);
});

it("genSubsidyPackedVals() should generate the correct value", async () => {
Expand All @@ -131,17 +148,17 @@ describe("Subsidy", () => {
// go forward in time
await timeTravel(signer.provider! as unknown as EthereumProvider, duration + 1);

await expect(subsidyContract.updateSbCommitment(await mpContract.getAddress())).to.be.revertedWithCustomError(
await expect(subsidyContract.updateSbCommitment()).to.be.revertedWithCustomError(
subsidyContract,
"ProcessingNotComplete",
);
});

it("updateSubsidy() should fail as the messages have not been processed yet", async () => {
const pollContractAddress = await maciContract.getPoll(pollId);
await expect(
subsidyContract.updateSubsidy(pollContractAddress, await mpContract.getAddress(), 0, [0, 0, 0, 0, 0, 0, 0, 0]),
).to.be.revertedWithCustomError(subsidyContract, "ProcessingNotComplete");
await expect(subsidyContract.updateSubsidy(0, [0, 0, 0, 0, 0, 0, 0, 0])).to.be.revertedWithCustomError(
subsidyContract,
"ProcessingNotComplete",
);
});

describe("after merging acc queues", () => {
Expand All @@ -156,15 +173,9 @@ describe("Subsidy", () => {
});
it("updateSubsidy() 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],
);
await mpContract.processMessages(generatedInputs.newSbCommitment, [0, 0, 0, 0, 0, 0, 0, 0]);

const tx = await subsidyContract.updateSubsidy(
await pollContract.getAddress(),
await mpContract.getAddress(),
subsidyGeneratedInputs.newSubsidyCommitment,
[0, 0, 0, 0, 0, 0, 0, 0],
);
Expand All @@ -178,12 +189,7 @@ describe("Subsidy", () => {
});
it("updateSubsidy() should revert when votes have already been tallied", async () => {
await expect(
subsidyContract.updateSubsidy(
await pollContract.getAddress(),
await mpContract.getAddress(),
subsidyGeneratedInputs.newSubsidyCommitment,
[0, 0, 0, 0, 0, 0, 0, 0],
),
subsidyContract.updateSubsidy(subsidyGeneratedInputs.newSubsidyCommitment, [0, 0, 0, 0, 0, 0, 0, 0]),
).to.be.revertedWithCustomError(subsidyContract, "AllSubsidyCalculated");
});
});
Expand Down
4 changes: 2 additions & 2 deletions contracts/tests/Tally.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ describe("TallyVotes", () => {
gasLimit: 8000000,
},
);
let receipt = await tx.wait();
const receipt = await tx.wait();

const block = await signer.provider!.getBlock(receipt!.blockHash);
const deployTime = block!.timestamp;
Expand Down Expand Up @@ -123,7 +123,7 @@ describe("TallyVotes", () => {
it("should not be possible to tally votes before the poll has ended", async () => {
await expect(tallyContract.tallyVotes(0, [0, 0, 0, 0, 0, 0, 0, 0])).to.be.revertedWithCustomError(
tallyContract,
"VOTING_PERIOD_NOT_PASSED",
"ProcessingNotComplete",
);
});

Expand Down

0 comments on commit b6c9701

Please sign in to comment.