diff --git a/hardhat/contracts/v2_contracts/transactions/Voting.sol b/hardhat/contracts/v2_contracts/transactions/Voting.sol index c4f91a37d..798bdec7a 100644 --- a/hardhat/contracts/v2_contracts/transactions/Voting.sol +++ b/hardhat/contracts/v2_contracts/transactions/Voting.sol @@ -27,6 +27,12 @@ contract Voting { if (maxVotes == validatorCount) { if (majorityVote == ITransactions.VoteType.Agree) { result = ITransactions.ResultType.MajorityAgree; + } else if (majorityVote == ITransactions.VoteType.Timeout) { + result = ITransactions.ResultType.Timeout; + } else if ( + majorityVote == ITransactions.VoteType.DeterministicViolation + ) { + result = ITransactions.ResultType.DeterministicViolation; } else { result = ITransactions.ResultType.MajorityDisagree; } diff --git a/hardhat/test/voting/001_voting_majority_vote.test.js b/hardhat/test/voting/001_voting_majority_vote.test.js new file mode 100644 index 000000000..51005240c --- /dev/null +++ b/hardhat/test/voting/001_voting_majority_vote.test.js @@ -0,0 +1,116 @@ +const { expect } = require("chai"); +const { ethers } = require("hardhat"); + +const VoteType = { + NotVoted: 0, + Agree: 1, + Disagree: 2, + Timeout: 3, + DeterministicViolation: 4, +}; + +const ResultType = { + Idle: 0, + Agree: 1, + Disagree: 2, + Timeout: 3, + DeterministicViolation: 4, + NoMajority: 5, + MajorityAgree: 6, + MajorityDisagree: 7, +}; + +const resultNames = Object.fromEntries( + Object.entries(ResultType).map(([name, value]) => [value, name]) +); + +function roundData(votes) { + return { + round: 1, + leaderIndex: 0, + votesCommitted: votes.length, + votesRevealed: votes.length, + appealBond: 0, + rotationsLeft: 0, + result: ResultType.Idle, + roundValidators: votes.map(() => ethers.ZeroAddress), + validatorVotesHash: votes.map(() => ethers.ZeroHash), + validatorVotes: votes, + }; +} + +describe("Voting.getMajorityVote", function () { + let voting; + + before(async function () { + const factory = await ethers.getContractFactory("Voting"); + voting = await factory.deploy(); + await voting.waitForDeployment(); + }); + + it("returns Timeout for a unanimous timeout vote", async function () { + const votes = Array(5).fill(VoteType.Timeout); + const result = await voting.getMajorityVote(roundData(votes)); + expect(resultNames[Number(result)]).to.equal("Timeout"); + }); + + it("returns DeterministicViolation for a unanimous violation vote", async function () { + const votes = Array(5).fill(VoteType.DeterministicViolation); + const result = await voting.getMajorityVote(roundData(votes)); + expect(resultNames[Number(result)]).to.equal("DeterministicViolation"); + }); + + it("still returns MajorityAgree for a unanimous agree vote", async function () { + const votes = Array(5).fill(VoteType.Agree); + const result = await voting.getMajorityVote(roundData(votes)); + expect(resultNames[Number(result)]).to.equal("MajorityAgree"); + }); + + it("still returns MajorityDisagree for a unanimous disagree vote", async function () { + const votes = Array(5).fill(VoteType.Disagree); + const result = await voting.getMajorityVote(roundData(votes)); + expect(resultNames[Number(result)]).to.equal("MajorityDisagree"); + }); + + it("still returns MajorityDisagree for a unanimous not-voted vote", async function () { + const votes = Array(5).fill(VoteType.NotVoted); + const result = await voting.getMajorityVote(roundData(votes)); + expect(resultNames[Number(result)]).to.equal("MajorityDisagree"); + }); + + it("returns Timeout for a non-unanimous majority timeout vote", async function () { + const votes = [ + VoteType.Timeout, + VoteType.Timeout, + VoteType.Timeout, + VoteType.Agree, + VoteType.Disagree, + ]; + const result = await voting.getMajorityVote(roundData(votes)); + expect(resultNames[Number(result)]).to.equal("Timeout"); + }); + + it("returns DeterministicViolation for a non-unanimous majority violation vote", async function () { + const votes = [ + VoteType.DeterministicViolation, + VoteType.DeterministicViolation, + VoteType.DeterministicViolation, + VoteType.Agree, + VoteType.Disagree, + ]; + const result = await voting.getMajorityVote(roundData(votes)); + expect(resultNames[Number(result)]).to.equal("DeterministicViolation"); + }); + + it("returns NoMajority when no vote type reaches a majority", async function () { + const votes = [ + VoteType.Agree, + VoteType.Agree, + VoteType.Disagree, + VoteType.Disagree, + VoteType.Timeout, + ]; + const result = await voting.getMajorityVote(roundData(votes)); + expect(resultNames[Number(result)]).to.equal("NoMajority"); + }); +});