From e3322727e48d185ee812c402002c640bf7550f28 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Tue, 7 Feb 2023 17:41:47 +0700 Subject: [PATCH 1/6] test: hashConsesus quroum setter,getter,events --- .../0.8.9/oracle/hash-consensus-set-quorum.js | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 test/0.8.9/oracle/hash-consensus-set-quorum.js diff --git a/test/0.8.9/oracle/hash-consensus-set-quorum.js b/test/0.8.9/oracle/hash-consensus-set-quorum.js new file mode 100644 index 000000000..8e1e1bf5d --- /dev/null +++ b/test/0.8.9/oracle/hash-consensus-set-quorum.js @@ -0,0 +1,72 @@ +const { assert } = require('chai') +const { assertEvent, assertAmountOfEvents } = require('@aragon/contract-helpers-test/src/asserts') +const { assertRevert } = require('../../helpers/assertThrow') + +const { + SLOTS_PER_EPOCH, + SECONDS_PER_SLOT, + SLOTS_PER_FRAME, + computeEpochFirstSlot, + computeTimestampAtEpoch, + ZERO_HASH, + HASH_1, + CONSENSUS_VERSION, + deployHashConsensus +} = require('./hash-consensus-deploy.test') + +contract('HashConsensus', ([admin, member1, member2, member3]) => { + context('setQuorum', () => { + let consensus + + beforeEach(async () => { + const deployed = await deployHashConsensus(admin, { initialEpoch: 1 }) + consensus = deployed.consensus + }) + + it('at deploy quorum is zero and can be set to any number while event is fired on every changes', async () => { + assert.equal(+(await consensus.getQuorum()), 0) + + const tx1 = await consensus.setQuorum(1) + assert.equal(+(await consensus.getQuorum()), 1) + assertEvent(tx1, 'QuorumSet', { expectedArgs: { newQuorum: 1, totalMembers: 0, prevQuorum: 0 } }) + + // dry run + const tx2 = await consensus.setQuorum(1) + assert.equal(+(await consensus.getQuorum()), 1) + assertAmountOfEvents(tx2, 'QuorumSet', { expectedAmount: 0 }) + + const tx3 = await consensus.setQuorum(10) + assert.equal(+(await consensus.getQuorum()), 10) + assertEvent(tx3, 'QuorumSet', { expectedArgs: { newQuorum: 10, totalMembers: 0, prevQuorum: 1 } }) + + const tx4 = await consensus.setQuorum(5) + assert.equal(+(await consensus.getQuorum()), 5) + assertEvent(tx4, 'QuorumSet', { expectedArgs: { newQuorum: 5, totalMembers: 0, prevQuorum: 10 } }) + }) + + it('as new members are added quorum is updated and cannot be set lower than members/2', async () => { + assert.equal(+(await consensus.getQuorum()), 0) + + await consensus.addMember(member1, 1, { from: admin }) + assert.equal(+(await consensus.getQuorum()), 1) + + await assertRevert(consensus.setQuorum(0), 'QuorumTooSmall(1, 0)') + + await consensus.addMember(member2, 2, { from: admin }) + assert.equal(+(await consensus.getQuorum()), 2) + + await assertRevert(consensus.setQuorum(1), 'QuorumTooSmall(2, 1)') + + await consensus.addMember(member3, 2, { from: admin }) + assert.equal(+(await consensus.getQuorum()), 2) + + await consensus.setQuorum(3) + assert.equal(+(await consensus.getQuorum()), 3) + + await assertRevert(consensus.setQuorum(1), 'QuorumTooSmall(2, 1)') + + await consensus.setQuorum(2) + assert.equal(+(await consensus.getQuorum()), 2) + }) + }) +}) From 1780f4bb1ad50363efe60309224b68da6a85ac42 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Tue, 7 Feb 2023 20:49:48 +0700 Subject: [PATCH 2/6] feat: setQuorum advanced tests --- .../0.8.9/oracle/hash-consensus-set-quorum.js | 88 ++++++++++++++++++- 1 file changed, 86 insertions(+), 2 deletions(-) diff --git a/test/0.8.9/oracle/hash-consensus-set-quorum.js b/test/0.8.9/oracle/hash-consensus-set-quorum.js index 8e1e1bf5d..022f24d65 100644 --- a/test/0.8.9/oracle/hash-consensus-set-quorum.js +++ b/test/0.8.9/oracle/hash-consensus-set-quorum.js @@ -5,17 +5,19 @@ const { assertRevert } = require('../../helpers/assertThrow') const { SLOTS_PER_EPOCH, SECONDS_PER_SLOT, - SLOTS_PER_FRAME, + SECONDS_PER_EPOCH, + SECONDS_PER_FRAME, computeEpochFirstSlot, computeTimestampAtEpoch, ZERO_HASH, HASH_1, + HASH_3, CONSENSUS_VERSION, deployHashConsensus } = require('./hash-consensus-deploy.test') contract('HashConsensus', ([admin, member1, member2, member3]) => { - context('setQuorum', () => { + context('setQuorum changes getQuorum', () => { let consensus beforeEach(async () => { @@ -69,4 +71,86 @@ contract('HashConsensus', ([admin, member1, member2, member3]) => { assert.equal(+(await consensus.getQuorum()), 2) }) }) + + context('setQuorum changes the effective quorum', () => { + let consensus + let frame + + beforeEach(async () => { + const deployed = await deployHashConsensus(admin, { initialEpoch: 1 }) + consensus = deployed.consensus + + await consensus.addMember(member1, 1, { from: admin }) + await consensus.addMember(member2, 2, { from: admin }) + await consensus.addMember(member3, 3, { from: admin }) + frame = await consensus.getCurrentFrame() + }) + + it('setQuorum increases and cancels current consensus', async () => { + await consensus.setQuorum(2) + + const tx1 = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, { from: member1 }) + assertEvent(tx1, 'ReportReceived', { expectedArgs: { refSlot: frame.refSlot, member: member1, report: HASH_1 } }) + assertAmountOfEvents(tx1, 'ConsensusReached', { expectedAmount: 0 }) + + const tx2 = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, { from: member2 }) + assertEvent(tx2, 'ReportReceived', { + expectedArgs: { refSlot: frame.refSlot, member: member2, report: HASH_1 } + }) + assertAmountOfEvents(tx2, 'ConsensusReached', { expectedAmount: 1 }) + + const tx3 = await consensus.setQuorum(3) + assertAmountOfEvents(tx3, 'ConsensusReached', { expectedAmount: 0 }) + const consensusState = await consensus.getConsensusState() + assert.equal(consensusState.consensusReport, ZERO_HASH) + assert.isFalse(consensusState.isReportProcessing) + }) + + it('setQuorum decreases, triggers quorum once and goes up/down again', async () => { + await consensus.setQuorum(3) + + const tx1 = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, { from: member1 }) + assertEvent(tx1, 'ReportReceived', { expectedArgs: { refSlot: frame.refSlot, member: member1, report: HASH_1 } }) + assertAmountOfEvents(tx1, 'ConsensusReached', { expectedAmount: 0 }) + + const tx2 = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, { from: member2 }) + assertEvent(tx2, 'ReportReceived', { + expectedArgs: { refSlot: frame.refSlot, member: member2, report: HASH_1 } + }) + assertAmountOfEvents(tx2, 'ConsensusReached', { expectedAmount: 0 }) + + const tx3 = await consensus.setQuorum(2) + assertAmountOfEvents(tx3, 'ConsensusReached', { expectedAmount: 1 }) + let consensusState = await consensus.getConsensusState() + assert.equal(consensusState.consensusReport, HASH_1) + + const tx4 = await consensus.setQuorum(3) + assertAmountOfEvents(tx4, 'ConsensusReached', { expectedAmount: 0 }) + consensusState = await consensus.getConsensusState() + assert.equal(consensusState.consensusReport, ZERO_HASH) + + const tx5 = await consensus.setQuorum(2) + assertAmountOfEvents(tx5, 'ConsensusReached', { expectedAmount: 0 }) + }) + + it('setQuorum does not re-trigger consensus if hash is already being processed', async () => { + await consensus.setQuorum(3) + const tx1 = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, { from: member1 }) + assertEvent(tx1, 'ReportReceived', { + expectedArgs: { refSlot: frame.refSlot, member: member1, report: HASH_1 } + }) + assertAmountOfEvents(tx1, 'ConsensusReached', { expectedAmount: 0 }) + + const tx2 = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, { from: member2 }) + assertEvent(tx2, 'ReportReceived', { + expectedArgs: { refSlot: frame.refSlot, member: member2, report: HASH_1 } + }) + assertAmountOfEvents(tx2, 'ConsensusReached', { expectedAmount: 0 }) + + await consensus.advanceTimeBy(SECONDS_PER_FRAME) + + const tx3 = await consensus.setQuorum(2) + assertAmountOfEvents(tx3, 'ConsensusReached', { expectedAmount: 0 }) + }) + }) }) From 057ce176f8d3525942d772ee6dec5686031b52de Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Wed, 8 Feb 2023 19:54:38 +0700 Subject: [PATCH 3/6] feat: rework set-quorum test structure and update consensus (re)trigger tests --- .../0.8.9/oracle/hash-consensus-set-quorum.js | 248 ++++++++++++------ 1 file changed, 164 insertions(+), 84 deletions(-) diff --git a/test/0.8.9/oracle/hash-consensus-set-quorum.js b/test/0.8.9/oracle/hash-consensus-set-quorum.js index 022f24d65..753b18554 100644 --- a/test/0.8.9/oracle/hash-consensus-set-quorum.js +++ b/test/0.8.9/oracle/hash-consensus-set-quorum.js @@ -17,140 +17,220 @@ const { } = require('./hash-consensus-deploy.test') contract('HashConsensus', ([admin, member1, member2, member3]) => { - context('setQuorum changes getQuorum', () => { + describe('setQuorum and addMember changes getQuorum', () => { let consensus - beforeEach(async () => { + const deployContract = async () => { const deployed = await deployHashConsensus(admin, { initialEpoch: 1 }) consensus = deployed.consensus - }) + } + + context('at deploy quorum is zero and can be set to any number while event is fired on every change', () => { + before(deployContract) - it('at deploy quorum is zero and can be set to any number while event is fired on every changes', async () => { - assert.equal(+(await consensus.getQuorum()), 0) + it('quorum is zero at deploy', async () => { + assert.equal(+(await consensus.getQuorum()), 0) + }) - const tx1 = await consensus.setQuorum(1) - assert.equal(+(await consensus.getQuorum()), 1) - assertEvent(tx1, 'QuorumSet', { expectedArgs: { newQuorum: 1, totalMembers: 0, prevQuorum: 0 } }) + it('quorum is changed, event is fired and getter returns new value', async () => { + const tx1 = await consensus.setQuorum(1) + assert.equal(+(await consensus.getQuorum()), 1) + assertEvent(tx1, 'QuorumSet', { expectedArgs: { newQuorum: 1, totalMembers: 0, prevQuorum: 0 } }) + }) - // dry run - const tx2 = await consensus.setQuorum(1) - assert.equal(+(await consensus.getQuorum()), 1) - assertAmountOfEvents(tx2, 'QuorumSet', { expectedAmount: 0 }) + it('change to same value does not emit event and value is the same', async () => { + const tx2 = await consensus.setQuorum(1) + assert.equal(+(await consensus.getQuorum()), 1) + assertAmountOfEvents(tx2, 'QuorumSet', { expectedAmount: 0 }) + }) - const tx3 = await consensus.setQuorum(10) - assert.equal(+(await consensus.getQuorum()), 10) - assertEvent(tx3, 'QuorumSet', { expectedArgs: { newQuorum: 10, totalMembers: 0, prevQuorum: 1 } }) + it('quorum value changes up and down', async () => { + const tx3 = await consensus.setQuorum(10) + assert.equal(+(await consensus.getQuorum()), 10) + assertEvent(tx3, 'QuorumSet', { expectedArgs: { newQuorum: 10, totalMembers: 0, prevQuorum: 1 } }) - const tx4 = await consensus.setQuorum(5) - assert.equal(+(await consensus.getQuorum()), 5) - assertEvent(tx4, 'QuorumSet', { expectedArgs: { newQuorum: 5, totalMembers: 0, prevQuorum: 10 } }) + const tx4 = await consensus.setQuorum(5) + assert.equal(+(await consensus.getQuorum()), 5) + assertEvent(tx4, 'QuorumSet', { expectedArgs: { newQuorum: 5, totalMembers: 0, prevQuorum: 10 } }) + }) }) - it('as new members are added quorum is updated and cannot be set lower than members/2', async () => { - assert.equal(+(await consensus.getQuorum()), 0) + context('as new members are added quorum is updated and cannot be set lower than members/2', () => { + before(deployContract) - await consensus.addMember(member1, 1, { from: admin }) - assert.equal(+(await consensus.getQuorum()), 1) + it('addMember adds member and updates quorum', async () => { + assert.equal(+(await consensus.getQuorum()), 0) - await assertRevert(consensus.setQuorum(0), 'QuorumTooSmall(1, 0)') + const tx1 = await consensus.addMember(member1, 1, { from: admin }) + assert.equal(+(await consensus.getQuorum()), 1) + assertEvent(tx1, 'QuorumSet', { expectedArgs: { newQuorum: 1, totalMembers: 1, prevQuorum: 0 } }) + }) - await consensus.addMember(member2, 2, { from: admin }) - assert.equal(+(await consensus.getQuorum()), 2) + it('setQuorum reverts on value less than members/2', async () => { + await assertRevert(consensus.setQuorum(0), 'QuorumTooSmall(1, 0)') - await assertRevert(consensus.setQuorum(1), 'QuorumTooSmall(2, 1)') + await consensus.addMember(member2, 2, { from: admin }) + assert.equal(+(await consensus.getQuorum()), 2) - await consensus.addMember(member3, 2, { from: admin }) - assert.equal(+(await consensus.getQuorum()), 2) + await assertRevert(consensus.setQuorum(1), 'QuorumTooSmall(2, 1)') + }) + + it('addMember sets any valid quorum value', async () => { + await consensus.addMember(member3, 2, { from: admin }) + assert.equal(+(await consensus.getQuorum()), 2) - await consensus.setQuorum(3) - assert.equal(+(await consensus.getQuorum()), 3) + await consensus.setQuorum(3) + assert.equal(+(await consensus.getQuorum()), 3) - await assertRevert(consensus.setQuorum(1), 'QuorumTooSmall(2, 1)') + await assertRevert(consensus.setQuorum(1), 'QuorumTooSmall(2, 1)') - await consensus.setQuorum(2) - assert.equal(+(await consensus.getQuorum()), 2) + await consensus.setQuorum(2) + assert.equal(+(await consensus.getQuorum()), 2) + }) }) }) - context('setQuorum changes the effective quorum', () => { + describe('setQuorum changes the effective quorum', () => { let consensus + let reportProcessor let frame - beforeEach(async () => { + const deployContractWithMembers = async () => { const deployed = await deployHashConsensus(admin, { initialEpoch: 1 }) consensus = deployed.consensus + reportProcessor = deployed.reportProcessor await consensus.addMember(member1, 1, { from: admin }) await consensus.addMember(member2, 2, { from: admin }) await consensus.addMember(member3, 3, { from: admin }) frame = await consensus.getCurrentFrame() - }) - - it('setQuorum increases and cancels current consensus', async () => { - await consensus.setQuorum(2) + } + + context('quorum increases and cancels current unprocessed consensus', () => { + before(deployContractWithMembers) + + it('consensus is reached at 2/3 for quorum of 2', async () => { + await consensus.setQuorum(2) + const tx1 = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, { from: member1 }) + assertEvent(tx1, 'ReportReceived', { + expectedArgs: { refSlot: frame.refSlot, member: member1, report: HASH_1 } + }) + assertAmountOfEvents(tx1, 'ConsensusReached', { expectedAmount: 0 }) + const tx2 = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, { from: member2 }) + assertEvent(tx2, 'ReportReceived', { + expectedArgs: { refSlot: frame.refSlot, member: member2, report: HASH_1 } + }) + assertAmountOfEvents(tx2, 'ConsensusReached', { expectedAmount: 1 }) + }) - const tx1 = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, { from: member1 }) - assertEvent(tx1, 'ReportReceived', { expectedArgs: { refSlot: frame.refSlot, member: member1, report: HASH_1 } }) - assertAmountOfEvents(tx1, 'ConsensusReached', { expectedAmount: 0 }) + it('quorum increases but current report is not cancelled', async () => { + const tx3 = await consensus.setQuorum(3) + assertAmountOfEvents(tx3, 'ConsensusReached', { expectedAmount: 0 }) + const consensusState = await consensus.getConsensusState() + assert.equal(consensusState.consensusReport, ZERO_HASH) + assert.isFalse(consensusState.isReportProcessing) + }) + }) - const tx2 = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, { from: member2 }) - assertEvent(tx2, 'ReportReceived', { - expectedArgs: { refSlot: frame.refSlot, member: member2, report: HASH_1 } + context('setQuorum triggers consensus on decrease', () => { + before(deployContractWithMembers) + + it('2/3 reports come in', async () => { + const tx1 = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, { from: member1 }) + assertEvent(tx1, 'ReportReceived', { + expectedArgs: { refSlot: frame.refSlot, member: member1, report: HASH_1 } + }) + assertAmountOfEvents(tx1, 'ConsensusReached', { expectedAmount: 0 }) + + const tx2 = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, { from: member2 }) + assertEvent(tx2, 'ReportReceived', { + expectedArgs: { refSlot: frame.refSlot, member: member2, report: HASH_1 } + }) + assertAmountOfEvents(tx2, 'ConsensusReached', { expectedAmount: 0 }) }) - assertAmountOfEvents(tx2, 'ConsensusReached', { expectedAmount: 1 }) - const tx3 = await consensus.setQuorum(3) - assertAmountOfEvents(tx3, 'ConsensusReached', { expectedAmount: 0 }) - const consensusState = await consensus.getConsensusState() - assert.equal(consensusState.consensusReport, ZERO_HASH) - assert.isFalse(consensusState.isReportProcessing) + it('quorum decreases and consensus is reached', async () => { + const tx3 = await consensus.setQuorum(2) + assertAmountOfEvents(tx3, 'ConsensusReached', { expectedAmount: 1 }) + const consensusState = await consensus.getConsensusState() + assert.equal(consensusState.consensusReport, HASH_1) + }) }) - it('setQuorum decreases, triggers quorum once and goes up/down again', async () => { - await consensus.setQuorum(3) - - const tx1 = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, { from: member1 }) - assertEvent(tx1, 'ReportReceived', { expectedArgs: { refSlot: frame.refSlot, member: member1, report: HASH_1 } }) - assertAmountOfEvents(tx1, 'ConsensusReached', { expectedAmount: 0 }) + context('setQuorum does not re-trigger same consensus', () => { + before(deployContractWithMembers) + + it('2/3 members reach consensus with quorum of 2', async () => { + await consensus.setQuorum(2) + const tx1 = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, { from: member1 }) + assertEvent(tx1, 'ReportReceived', { + expectedArgs: { refSlot: frame.refSlot, member: member1, report: HASH_1 } + }) + assertAmountOfEvents(tx1, 'ConsensusReached', { expectedAmount: 0 }) + + const tx2 = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, { from: member2 }) + assertEvent(tx2, 'ReportReceived', { + expectedArgs: { refSlot: frame.refSlot, member: member2, report: HASH_1 } + }) + assertAmountOfEvents(tx2, 'ConsensusReached', { expectedAmount: 1 }) + assert.equal(+(await reportProcessor.getLastCall_submitReport()).callCount, 1) + }) - const tx2 = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, { from: member2 }) - assertEvent(tx2, 'ReportReceived', { - expectedArgs: { refSlot: frame.refSlot, member: member2, report: HASH_1 } + it('quorum goes up and effective consensus changes to none', async () => { + await consensus.setQuorum(3) + const consensusState = await consensus.getConsensusState() + assert.equal(consensusState.consensusReport, ZERO_HASH) + assert.isFalse(consensusState.isReportProcessing) }) - assertAmountOfEvents(tx2, 'ConsensusReached', { expectedAmount: 0 }) - const tx3 = await consensus.setQuorum(2) - assertAmountOfEvents(tx3, 'ConsensusReached', { expectedAmount: 1 }) - let consensusState = await consensus.getConsensusState() - assert.equal(consensusState.consensusReport, HASH_1) + it('quorum goes down but same consensus is not triggered and report is not submitted', async () => { + const tx = await consensus.setQuorum(2) + assertAmountOfEvents(tx, 'ConsensusReached', { expectedAmount: 0 }) - const tx4 = await consensus.setQuorum(3) - assertAmountOfEvents(tx4, 'ConsensusReached', { expectedAmount: 0 }) - consensusState = await consensus.getConsensusState() - assert.equal(consensusState.consensusReport, ZERO_HASH) + const consensusState = await consensus.getConsensusState() + assert.equal(consensusState.consensusReport, HASH_1) + assert.isFalse(consensusState.isReportProcessing) - const tx5 = await consensus.setQuorum(2) - assertAmountOfEvents(tx5, 'ConsensusReached', { expectedAmount: 0 }) + assert.equal(+(await reportProcessor.getLastCall_submitReport()).callCount, 1) + }) }) - it('setQuorum does not re-trigger consensus if hash is already being processed', async () => { - await consensus.setQuorum(3) - const tx1 = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, { from: member1 }) - assertEvent(tx1, 'ReportReceived', { - expectedArgs: { refSlot: frame.refSlot, member: member1, report: HASH_1 } + context('setQuorum does not re-trigger consensus if hash is already being processed', () => { + before(deployContractWithMembers) + + it('2/3 members reach consensus with Quorum of 2', async () => { + await consensus.setQuorum(2) + const tx1 = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, { from: member1 }) + assertEvent(tx1, 'ReportReceived', { + expectedArgs: { refSlot: frame.refSlot, member: member1, report: HASH_1 } + }) + assertAmountOfEvents(tx1, 'ConsensusReached', { expectedAmount: 0 }) + + const tx2 = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, { from: member2 }) + assertEvent(tx2, 'ReportReceived', { + expectedArgs: { refSlot: frame.refSlot, member: member2, report: HASH_1 } + }) + assertAmountOfEvents(tx2, 'ConsensusReached', { expectedAmount: 1 }) }) - assertAmountOfEvents(tx1, 'ConsensusReached', { expectedAmount: 0 }) - const tx2 = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, { from: member2 }) - assertEvent(tx2, 'ReportReceived', { - expectedArgs: { refSlot: frame.refSlot, member: member2, report: HASH_1 } + it('reportProcessor starts processing', async () => { + await reportProcessor.startReportProcessing() + const consensusState = await consensus.getConsensusState() + assert.equal(consensusState.consensusReport, HASH_1) + assert.isTrue(consensusState.isReportProcessing) }) - assertAmountOfEvents(tx2, 'ConsensusReached', { expectedAmount: 0 }) - await consensus.advanceTimeBy(SECONDS_PER_FRAME) + it('quorum increases while report is processing', async () => { + await consensus.setQuorum(3) + const consensusState = await consensus.getConsensusState() + assert.isTrue(consensusState.isReportProcessing) + }) - const tx3 = await consensus.setQuorum(2) - assertAmountOfEvents(tx3, 'ConsensusReached', { expectedAmount: 0 }) + it('quorum decreases but no consensus is triggered', async () => { + const tx = await consensus.setQuorum(2) + assertAmountOfEvents(tx, 'ConsensusReached', { expectedAmount: 0 }) + assert.equal(+(await reportProcessor.getLastCall_submitReport()).callCount, 1) + }) }) }) }) From a105086feaafb6f7253d37c3a5244db6924e45a8 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Thu, 9 Feb 2023 14:05:35 +0700 Subject: [PATCH 4/6] fix: correct description and add final step to test --- test/0.8.9/oracle/hash-consensus-set-quorum.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/0.8.9/oracle/hash-consensus-set-quorum.js b/test/0.8.9/oracle/hash-consensus-set-quorum.js index 753b18554..89cefa9b9 100644 --- a/test/0.8.9/oracle/hash-consensus-set-quorum.js +++ b/test/0.8.9/oracle/hash-consensus-set-quorum.js @@ -106,7 +106,7 @@ contract('HashConsensus', ([admin, member1, member2, member3]) => { frame = await consensus.getCurrentFrame() } - context('quorum increases and cancels current unprocessed consensus', () => { + context('quorum increases and changes effective consensus', () => { before(deployContractWithMembers) it('consensus is reached at 2/3 for quorum of 2', async () => { @@ -121,15 +121,23 @@ contract('HashConsensus', ([admin, member1, member2, member3]) => { expectedArgs: { refSlot: frame.refSlot, member: member2, report: HASH_1 } }) assertAmountOfEvents(tx2, 'ConsensusReached', { expectedAmount: 1 }) + assert.equal(+(await reportProcessor.getLastCall_submitReport()).callCount, 1) }) - it('quorum increases but current report is not cancelled', async () => { + it('quorum increases and effective consensus is changed to none', async () => { const tx3 = await consensus.setQuorum(3) assertAmountOfEvents(tx3, 'ConsensusReached', { expectedAmount: 0 }) const consensusState = await consensus.getConsensusState() assert.equal(consensusState.consensusReport, ZERO_HASH) assert.isFalse(consensusState.isReportProcessing) }) + + it('report starts processing and it is reflected in getConsensusState', async () => { + await reportProcessor.startReportProcessing() + const consensusState = await consensus.getConsensusState() + assert.equal(consensusState.consensusReport, ZERO_HASH) + assert.isTrue(consensusState.isReportProcessing) + }) }) context('setQuorum triggers consensus on decrease', () => { From 79d2ac4e748689b55f5e848c293cedd2c0f5cfae Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Thu, 9 Feb 2023 15:49:52 +0700 Subject: [PATCH 5/6] feat: add UNREACHABLE_QUORUM to export and prettify file --- .../oracle/hash-consensus-deploy.test.js | 66 ++++++++++++------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/test/0.8.9/oracle/hash-consensus-deploy.test.js b/test/0.8.9/oracle/hash-consensus-deploy.test.js index a9c66f89b..8b3b524fa 100644 --- a/test/0.8.9/oracle/hash-consensus-deploy.test.js +++ b/test/0.8.9/oracle/hash-consensus-deploy.test.js @@ -1,7 +1,5 @@ const { assert } = require('chai') -const { assertBn, assertEvent, assertAmountOfEvents } = require('@aragon/contract-helpers-test/src/asserts') -const { assertRevert } = require('../../helpers/assertThrow') -const { ZERO_ADDRESS, bn } = require('@aragon/contract-helpers-test') +const { bn } = require('@aragon/contract-helpers-test') const HashConsensus = artifacts.require('HashConsensusTimeTravellable') const MockReportProcessor = artifacts.require('MockReportProcessor') @@ -15,12 +13,12 @@ const SECONDS_PER_EPOCH = SLOTS_PER_EPOCH * SECONDS_PER_SLOT const SECONDS_PER_FRAME = SECONDS_PER_EPOCH * EPOCHS_PER_FRAME const SLOTS_PER_FRAME = EPOCHS_PER_FRAME * SLOTS_PER_EPOCH -const computeSlotAt = time => Math.floor((time - GENESIS_TIME) / SECONDS_PER_SLOT) -const computeEpochAt = time => Math.floor(computeSlotAt(time) / SLOTS_PER_EPOCH) -const computeEpochFirstSlot = epoch => epoch * SLOTS_PER_EPOCH -const computeEpochFirstSlotAt = time => computeEpochFirstSlot(computeEpochAt(time)) -const computeTimestampAtEpoch = epoch => GENESIS_TIME + epoch * SECONDS_PER_EPOCH -const computeTimestampAtSlot = slot => GENESIS_TIME + slot * SECONDS_PER_SLOT +const computeSlotAt = (time) => Math.floor((time - GENESIS_TIME) / SECONDS_PER_SLOT) +const computeEpochAt = (time) => Math.floor(computeSlotAt(time) / SLOTS_PER_EPOCH) +const computeEpochFirstSlot = (epoch) => epoch * SLOTS_PER_EPOCH +const computeEpochFirstSlotAt = (time) => computeEpochFirstSlot(computeEpochAt(time)) +const computeTimestampAtEpoch = (epoch) => GENESIS_TIME + epoch * SECONDS_PER_EPOCH +const computeTimestampAtSlot = (slot) => GENESIS_TIME + slot * SECONDS_PER_SLOT const ZERO_HASH = '0x0000000000000000000000000000000000000000000000000000000000000000' @@ -30,17 +28,22 @@ const HASH_3 = '0x33333333333333333333333333333333333333333333333333333333333333 const HASH_4 = '0x4444444444444444444444444444444444444444444444444444444444444444' const HASH_5 = '0x5555555555555555555555555555555555555555555555555555555555555555' +const UNREACHABLE_QUORUM = bn('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') + const CONSENSUS_VERSION = 1 -async function deployHashConsensus(admin, { - reportProcessor = null, - slotsPerEpoch = SLOTS_PER_EPOCH, - secondsPerSlot = SECONDS_PER_SLOT, - genesisTime = GENESIS_TIME, - epochsPerFrame = EPOCHS_PER_FRAME, - fastLaneLengthSlots = 0, - initialEpoch = 1 -} = {}) { +async function deployHashConsensus( + admin, + { + reportProcessor = null, + slotsPerEpoch = SLOTS_PER_EPOCH, + secondsPerSlot = SECONDS_PER_SLOT, + genesisTime = GENESIS_TIME, + epochsPerFrame = EPOCHS_PER_FRAME, + fastLaneLengthSlots = 0, + initialEpoch = 1 + } = {} +) { if (!reportProcessor) { reportProcessor = await MockReportProcessor.new(CONSENSUS_VERSION, { from: admin }) } @@ -69,11 +72,26 @@ async function deployHashConsensus(admin, { } module.exports = { - SLOTS_PER_EPOCH, SECONDS_PER_SLOT, GENESIS_TIME, EPOCHS_PER_FRAME, - SECONDS_PER_EPOCH, SECONDS_PER_FRAME, SLOTS_PER_FRAME, - computeSlotAt, computeEpochAt, computeEpochFirstSlot, computeEpochFirstSlotAt, - computeTimestampAtSlot, computeTimestampAtEpoch, - ZERO_HASH, HASH_1, HASH_2, HASH_3, HASH_4, HASH_5, + SLOTS_PER_EPOCH, + SECONDS_PER_SLOT, + GENESIS_TIME, + EPOCHS_PER_FRAME, + SECONDS_PER_EPOCH, + SECONDS_PER_FRAME, + SLOTS_PER_FRAME, + computeSlotAt, + computeEpochAt, + computeEpochFirstSlot, + computeEpochFirstSlotAt, + computeTimestampAtSlot, + computeTimestampAtEpoch, + ZERO_HASH, + HASH_1, + HASH_2, + HASH_3, + HASH_4, + HASH_5, + UNREACHABLE_QUORUM, CONSENSUS_VERSION, deployHashConsensus } @@ -86,7 +104,7 @@ contract('HashConsensus', ([admin, member1]) => { let reportProcessor it('deploying hash consensus', async () => { - const deployed = await deployHashConsensus(admin, {initialEpoch: INITIAL_EPOCH}) + const deployed = await deployHashConsensus(admin, { initialEpoch: INITIAL_EPOCH }) consensus = deployed.consensus reportProcessor = deployed.reportProcessor }) From c262289fa0c4eac6de2a8badff2c0e4d9dce66d9 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Thu, 9 Feb 2023 15:50:30 +0700 Subject: [PATCH 6/6] feat: add disableConsensus tests --- test/0.8.9/oracle/hash-consensus-set-quorum.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/test/0.8.9/oracle/hash-consensus-set-quorum.js b/test/0.8.9/oracle/hash-consensus-set-quorum.js index 89cefa9b9..2a14c2d05 100644 --- a/test/0.8.9/oracle/hash-consensus-set-quorum.js +++ b/test/0.8.9/oracle/hash-consensus-set-quorum.js @@ -1,5 +1,5 @@ const { assert } = require('chai') -const { assertEvent, assertAmountOfEvents } = require('@aragon/contract-helpers-test/src/asserts') +const { assertEvent, assertAmountOfEvents, assertBn } = require('@aragon/contract-helpers-test/src/asserts') const { assertRevert } = require('../../helpers/assertThrow') const { @@ -10,6 +10,7 @@ const { computeEpochFirstSlot, computeTimestampAtEpoch, ZERO_HASH, + UNREACHABLE_QUORUM, HASH_1, HASH_3, CONSENSUS_VERSION, @@ -88,6 +89,18 @@ contract('HashConsensus', ([admin, member1, member2, member3]) => { assert.equal(+(await consensus.getQuorum()), 2) }) }) + + context('disableConsensus sets unreachable quorum value', () => { + before(deployContract) + + it('disableConsensus updated quorum value and emits events', async () => { + const tx = await consensus.disableConsensus() + assertEvent(tx, 'QuorumSet', { + expectedArgs: { newQuorum: UNREACHABLE_QUORUM.toString(10), totalMembers: 0, prevQuorum: 0 } + }) + assertBn(await consensus.getQuorum(), UNREACHABLE_QUORUM) + }) + }) }) describe('setQuorum changes the effective quorum', () => {