From 983a4d7fd41e251f1a76e4cb53cc5dc0f2e6f763 Mon Sep 17 00:00:00 2001 From: Andrei Date: Wed, 8 Feb 2023 21:35:09 +0700 Subject: [PATCH 1/4] test: hash consensus: add more frames tests --- .../oracle/HashConsensusTimeTravellable.sol | 8 + .../hash-consensus-access-control.test.js | 110 ++++++--- .../oracle/hash-consensus-deploy.test.js | 61 +++-- test/0.8.9/oracle/hash-consensus-frames.js | 214 ++++++++++++------ 4 files changed, 267 insertions(+), 126 deletions(-) diff --git a/contracts/0.8.9/test_helpers/oracle/HashConsensusTimeTravellable.sol b/contracts/0.8.9/test_helpers/oracle/HashConsensusTimeTravellable.sol index cb7cda2f5..ff223f717 100644 --- a/contracts/0.8.9/test_helpers/oracle/HashConsensusTimeTravellable.sol +++ b/contracts/0.8.9/test_helpers/oracle/HashConsensusTimeTravellable.sol @@ -72,4 +72,12 @@ contract HashConsensusTimeTravellable is HashConsensus { function advanceTimeByEpochs(uint256 numEpochs) external { _time += SECONDS_PER_SLOT * SLOTS_PER_EPOCH * numEpochs; } + + function getFrameConfigFastLaneLengthSlots() external view returns (uint256 fastLaneLengthSlots) { + return (_frameConfig.fastLaneLengthSlots); + } + + function getReportProcessor() external view returns (address) { + return _reportProcessor; + } } diff --git a/test/0.8.9/oracle/hash-consensus-access-control.test.js b/test/0.8.9/oracle/hash-consensus-access-control.test.js index eea0884ab..b63c42df9 100644 --- a/test/0.8.9/oracle/hash-consensus-access-control.test.js +++ b/test/0.8.9/oracle/hash-consensus-access-control.test.js @@ -28,18 +28,20 @@ contract('HashConsensus', ([admin, account1, account2, member1, member2, strange }) context('MANAGE_MEMBERS_AND_QUORUM_ROLE', () => { - const errorMessage = `AccessControl: account ${account1.toLowerCase()} is missing role ${manageMembersAndQuorumRoleKeccak156}` - beforeEach(deploy) context('addMember', () => { - it('should revert without manage members and qourum role', async () => { - await assert.reverts(consensus.addMember(member1, 2, { from: account1 }), errorMessage) + it('should revert without MANAGE_MEMBERS_AND_QUORUM_ROLE role', async () => { + await assert.revertsOZAccessControl( + consensus.addMember(member1, 2, { from: account1 }), + account1, + 'MANAGE_MEMBERS_AND_QUORUM_ROLE' + ) assert.equal(await consensus.getIsMember(member1), false) assert.equal(+(await consensus.getQuorum()), 0) }) - it('should check manage members and qourum role', async () => { + it('should allow calling from a possessor of MANAGE_MEMBERS_AND_QUORUM_ROLE role', async () => { await consensus.grantRole(manageMembersAndQuorumRoleKeccak156, account2) await consensus.addMember(member2, 1, { from: account2 }) @@ -49,13 +51,17 @@ contract('HashConsensus', ([admin, account1, account2, member1, member2, strange }) context('removeMember', () => { - it('should revert without manage members and qourum role', async () => { - await assert.reverts(consensus.removeMember(member1, 2, { from: account1 }), errorMessage) + it('should revert without MANAGE_MEMBERS_AND_QUORUM_ROLE role', async () => { + await assert.revertsOZAccessControl( + consensus.removeMember(member1, 2, { from: account1 }), + account1, + 'MANAGE_MEMBERS_AND_QUORUM_ROLE' + ) assert.equal(await consensus.getIsMember(member1), false) assert.equal(+(await consensus.getQuorum()), 0) }) - it('should check manage members and qourum role', async () => { + it('should allow calling from a possessor of MANAGE_MEMBERS_AND_QUORUM_ROLE role', async () => { await consensus.grantRole(manageMembersAndQuorumRoleKeccak156, account2) await consensus.addMember(member2, 1, { from: account2 }) assert.equal(await consensus.getIsMember(member2), true) @@ -68,12 +74,16 @@ contract('HashConsensus', ([admin, account1, account2, member1, member2, strange }) context('setQuorum', () => { - it('should revert without manage members and qourum role', async () => { - await assert.reverts(consensus.setQuorum(1, { from: account1 }), errorMessage) + it('should revert without MANAGE_MEMBERS_AND_QUORUM_ROLE role', async () => { + await assert.revertsOZAccessControl( + consensus.setQuorum(1, { from: account1 }), + account1, + 'MANAGE_MEMBERS_AND_QUORUM_ROLE' + ) assert.equal(+(await consensus.getQuorum()), 0) }) - it('should check manage members and qourum role', async () => { + it('should allow calling from a possessor of MANAGE_MEMBERS_AND_QUORUM_ROLE role', async () => { await consensus.grantRole(manageMembersAndQuorumRoleKeccak156, account2) await consensus.setQuorum(1, { from: account2 }) @@ -82,27 +92,31 @@ contract('HashConsensus', ([admin, account1, account2, member1, member2, strange }) context('disableConsensus', () => { - it('should revert without manage members and qourum role', async () => { - const errorMessage = `AccessControl: account ${account1.toLowerCase()} is missing role ${disableConsensusRoleKeccak156}` - - await assert.reverts(consensus.disableConsensus({ from: account1 }), errorMessage) + it('should revert without MANAGE_MEMBERS_AND_QUORUM_ROLE role', async () => { + await assert.revertsOZAccessControl( + consensus.disableConsensus({ from: account1 }), + account1, + 'DISABLE_CONSENSUS_ROLE' + ) assert.equal(+(await consensus.getQuorum()), 0) }) }) }) context('DISABLE_CONSENSUS_ROLE', () => { - const errorMessage = `AccessControl: account ${account1.toLowerCase()} is missing role ${disableConsensusRoleKeccak156}` - beforeEach(deploy) context('setQuorum', () => { - it('should revert without disable consensus role', async () => { - await assert.reverts(consensus.setQuorum(MaxUint256, { from: account1 }), errorMessage) + it('should revert without DISABLE_CONSENSUS_ROLE role', async () => { + await assert.revertsOZAccessControl( + consensus.setQuorum(MaxUint256, { from: account1 }), + account1, + 'DISABLE_CONSENSUS_ROLE' + ) assert.equal(+(await consensus.getQuorum()), 0) }) - it('should check disable consensus role', async () => { + it('should allow calling from a possessor of DISABLE_CONSENSUS_ROLE role', async () => { await consensus.grantRole(disableConsensusRoleKeccak156, account2) await consensus.setQuorum(MaxUint256, { from: account2 }) @@ -111,12 +125,16 @@ contract('HashConsensus', ([admin, account1, account2, member1, member2, strange }) context('disableConsensus', () => { - it('should revert without disable consensus role', async () => { - await assert.reverts(consensus.disableConsensus({ from: account1 }), errorMessage) + it('should revert without DISABLE_CONSENSUS_ROLE role', async () => { + await assert.revertsOZAccessControl( + consensus.disableConsensus({ from: account1 }), + account1, + 'DISABLE_CONSENSUS_ROLE' + ) assert.equal(+(await consensus.getQuorum()), 0) }) - it('should check disable consensus role', async () => { + it('should allow calling from a possessor of DISABLE_CONSENSUS_ROLE role', async () => { await consensus.grantRole(disableConsensusRoleKeccak156, account2) await consensus.disableConsensus({ from: account2 }) @@ -126,17 +144,19 @@ contract('HashConsensus', ([admin, account1, account2, member1, member2, strange }) context('MANAGE_FRAME_CONFIG_ROLE', () => { - const errorMessage = `AccessControl: account ${account1.toLowerCase()} is missing role ${manageFrameConfigRoleKeccak156}` - beforeEach(deploy) context('setFrameConfig', () => { - it('should revert without manage frame config role', async () => { - await assert.reverts(consensus.setFrameConfig(5, 0, { from: account1 }), errorMessage) + it('should revert without MANAGE_FRAME_CONFIG_ROLE role', async () => { + await assert.revertsOZAccessControl( + consensus.setFrameConfig(5, 0, { from: account1 }), + account1, + 'MANAGE_FRAME_CONFIG_ROLE' + ) assert.equal(+(await consensus.getFrameConfig()).epochsPerFrame, EPOCHS_PER_FRAME) }) - it('should check manage frame config role', async () => { + it('should allow calling from a possessor of MANAGE_FRAME_CONFIG_ROLE role', async () => { await consensus.grantRole(manageFrameConfigRoleKeccak156, account2) await consensus.setFrameConfig(5, 0, { from: account2 }) @@ -146,25 +166,43 @@ contract('HashConsensus', ([admin, account1, account2, member1, member2, strange }) context('MANAGE_REPORT_PROCESSOR_ROLE', () => { - const errorMessage = `AccessControl: account ${account1.toLowerCase()} is missing role ${manageReportProcessorRoleKeccak156}` - beforeEach(deploy) context('setReportProcessor', () => { - it('should revert without manage report processor role', async () => { - await assert.reverts(consensus.setReportProcessor(member1, { from: account1 }), errorMessage) + it('should revert without MANAGE_REPORT_PROCESSOR_ROLE role', async () => { + await assert.revertsOZAccessControl( + consensus.setReportProcessor(member1, { from: account1 }), + account1, + 'MANAGE_REPORT_PROCESSOR_ROLE' + ) + }) + + it('should allow calling from a possessor of MANAGE_REPORT_PROCESSOR_ROLE role', async () => { + await consensus.grantRole(manageReportProcessorRoleKeccak156, account2) + await consensus.setReportProcessor(member1, { from: account2 }) + + assert.equal(+(await consensus.getReportProcessor()), member1) }) }) }) context('MANAGE_FAST_LANE_CONFIG_ROLE', () => { - const errorMessage = `AccessControl: account ${account1.toLowerCase()} is missing role ${manageFastLineConfigRoleKeccak156}` - beforeEach(deploy) context('setFastLaneLengthSlots', () => { - it('should revert without manage fast lane config role', async () => { - await assert.reverts(consensus.setFastLaneLengthSlots(member1, { from: account1 }), errorMessage) + it('should revert without MANAGE_FAST_LANE_CONFIG_ROLE role', async () => { + await assert.revertsOZAccessControl( + consensus.setFastLaneLengthSlots(5, { from: account1 }), + account1, + 'MANAGE_FAST_LANE_CONFIG_ROLE' + ) + }) + + it('should allow calling from a possessor of MANAGE_FAST_LANE_CONFIG_ROLE role', async () => { + await consensus.grantRole(manageFastLineConfigRoleKeccak156, account2) + await consensus.setFastLaneLengthSlots(64, { from: account2 }) + + assert.equal(+(await consensus.getFrameConfigFastLaneLengthSlots()), 64) }) }) }) 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..9747c3da7 100644 --- a/test/0.8.9/oracle/hash-consensus-deploy.test.js +++ b/test/0.8.9/oracle/hash-consensus-deploy.test.js @@ -10,17 +10,18 @@ const SLOTS_PER_EPOCH = 32 const SECONDS_PER_SLOT = 12 const GENESIS_TIME = 100 const EPOCHS_PER_FRAME = 225 // one day +const INITIAL_EPOCH = 1 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' @@ -32,15 +33,18 @@ const HASH_5 = '0x55555555555555555555555555555555555555555555555555555555555555 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 = INITIAL_EPOCH + } = {} +) { if (!reportProcessor) { reportProcessor = await MockReportProcessor.new(CONSENSUS_VERSION, { from: admin }) } @@ -69,11 +73,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, + INITIAL_EPOCH, + 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, CONSENSUS_VERSION, deployHashConsensus } @@ -86,7 +105,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 }) diff --git a/test/0.8.9/oracle/hash-consensus-frames.js b/test/0.8.9/oracle/hash-consensus-frames.js index bcf22a1be..b2dca0b78 100644 --- a/test/0.8.9/oracle/hash-consensus-frames.js +++ b/test/0.8.9/oracle/hash-consensus-frames.js @@ -1,18 +1,22 @@ -const { assert } = require('chai') -const { assertBn, assertEvent, assertAmountOfEvents } = require('@aragon/contract-helpers-test/src/asserts') +const { assert } = require('../../helpers/assert') +const { assertEvent } = require('@aragon/contract-helpers-test/src/asserts') const { assertRevert } = require('../../helpers/assertThrow') -const { ZERO_ADDRESS, bn } = require('@aragon/contract-helpers-test') const { - SLOTS_PER_EPOCH, SECONDS_PER_SLOT, GENESIS_TIME, SECONDS_PER_EPOCH, SLOTS_PER_FRAME, - computeSlotAt, computeEpochAt, computeEpochFirstSlotAt, - computeEpochFirstSlot, computeTimestampAtSlot, computeTimestampAtEpoch, - ZERO_HASH, HASH_1, HASH_2, HASH_3, HASH_4, HASH_5, CONSENSUS_VERSION, - deployHashConsensus } = require('./hash-consensus-deploy.test') - -const HashConsensus = artifacts.require('HashConsensusTimeTravellable') -const MockReportProcessor = artifacts.require('MockReportProcessor') - + INITIAL_EPOCH, + EPOCHS_PER_FRAME, + SLOTS_PER_EPOCH, + SECONDS_PER_SLOT, + SLOTS_PER_FRAME, + computeEpochAt, + computeEpochFirstSlot, + computeTimestampAtSlot, + computeTimestampAtEpoch, + ZERO_HASH, + HASH_1, + CONSENSUS_VERSION, + deployHashConsensus +} = require('./hash-consensus-deploy.test') const getFrameIndex = (time, epochsPerFrame, initialEpoch) => Math.floor((computeEpochAt(time) - initialEpoch) / epochsPerFrame) @@ -26,36 +30,109 @@ const computeIthFrameStartTime = (frameIndex, epochsPerFrame, initialEpoch) => const computeNextFrameStartSlot = (time, epochsPerFrame, initialEpoch) => computeIthFrameStartSlot(getFrameIndex(time, epochsPerFrame, initialEpoch), epochsPerFrame, initialEpoch) - contract('HashConsensus', ([admin, member1, member2]) => { - const INITIAL_EPOCH = 3 + const TEST_INITIAL_EPOCH = 3 + + context('Frame methods', () => { + let consensus = null + const deploy = async (options = undefined) => { + const deployed = await deployHashConsensus(admin, options) + consensus = deployed.consensus + } + + context('getFrameConfig', () => { + before(deploy) + + it('should return initial data', async () => { + assert.equal(+(await consensus.getFrameConfig()).epochsPerFrame, EPOCHS_PER_FRAME) + assert.equal(+(await consensus.getFrameConfig()).initialEpoch, INITIAL_EPOCH) + }) + + it('should return new data', async () => { + await consensus.setFrameConfig(100, 50) + + assert.equal(+(await consensus.getFrameConfig()).epochsPerFrame, 100) + assert.equal(+(await consensus.getFrameConfigFastLaneLengthSlots()), 50) + assert.equal(+(await consensus.getFrameConfig()).initialEpoch, INITIAL_EPOCH) + }) + }) + context('setFrameConfig', () => { + beforeEach(deploy) + + it('should set data', async () => { + await consensus.setFrameConfig(100, 50) + + assert.equal(+(await consensus.getFrameConfig()).epochsPerFrame, 100) + assert.equal(+(await consensus.getFrameConfigFastLaneLengthSlots()), 50) + assert.equal(+(await consensus.getFrameConfig()).initialEpoch, INITIAL_EPOCH) + }) + + it('should set first epoch in next frame', async () => { + await consensus.setTimeInEpochs(INITIAL_EPOCH + EPOCHS_PER_FRAME) + await consensus.setFrameConfig(100, 50) + + assert.equal(+(await consensus.getFrameConfig()).epochsPerFrame, 100) + assert.equal(+(await consensus.getFrameConfigFastLaneLengthSlots()), 50) + assert.equal(+(await consensus.getFrameConfig()).initialEpoch, EPOCHS_PER_FRAME + 1) + }) + + it('should revert if epochsPerFrame == 0', async () => { + await assert.revertsWithCustomError(consensus.setFrameConfig(0, 50), 'EpochsPerFrameCannotBeZero()') + }) + + it('should revert if fastLaneLengthSlots > epochsPerFrame * SLOTS_PER_EPOCH', async () => { + await assert.revertsWithCustomError(consensus.setFrameConfig(1, 50), 'FastLanePeriodCannotBeLongerThanFrame()') + }) + + it('should revert if epoch < config.initialEpoc', async () => { + await consensus.setTimeInEpochs(INITIAL_EPOCH - 1) + + await assert.revertsWithCustomError(consensus.setFrameConfig(1, 50), 'InitialEpochIsYetToArrive()') + }) + + it('should emit FrameConfigSet & FastLaneConfigSet event', async () => { + const tx = await consensus.setFrameConfig(100, 50) + + assertEvent(tx, 'FrameConfigSet') + assertEvent(tx, 'FastLaneConfigSet') + }) + + it('should not emit FrameConfigSet & FastLaneConfigSet event', async () => { + const tx = await consensus.setFrameConfig(EPOCHS_PER_FRAME, 0) + + assert.notEmits(tx, 'FrameConfigSet') + assert.notEmits(tx, 'FastLaneConfigSet') + }) + }) + }) context('State before initial epoch', () => { let consensus before(async () => { - const deployed = await deployHashConsensus(admin, {initialEpoch: INITIAL_EPOCH}) + const deployed = await deployHashConsensus(admin, { initialEpoch: TEST_INITIAL_EPOCH }) consensus = deployed.consensus }) - it('before the initial epoch arrives, members can be added and queried, and quorum increased', - async () => - { - await consensus.setTimeInEpochs(INITIAL_EPOCH - 1) + it('before the initial epoch arrives, members can be added and queried, and quorum increased', async () => { + await consensus.setTimeInEpochs(TEST_INITIAL_EPOCH - 1) - await consensus.addMember(member1, 1, {from: admin}) - await consensus.addMember(member2, 2, {from: admin}) - await consensus.setQuorum(3, {from: admin}) + await consensus.addMember(member1, 1, { from: admin }) + await consensus.addMember(member2, 2, { from: admin }) + await consensus.setQuorum(3, { from: admin }) - assert.equal(+await consensus.getQuorum(), 3) + assert.equal(+(await consensus.getQuorum()), 3) assert.isTrue(await consensus.getIsMember(member1)) assert.isTrue(await consensus.getIsMember(member2)) assert.isFalse(await consensus.getIsMember(admin)) - const {addresses, lastReportedRefSlots} = await consensus.getMembers() + const { addresses, lastReportedRefSlots } = await consensus.getMembers() assert.sameOrderedMembers(addresses, [member1, member2]) - assert.sameOrderedMembers(lastReportedRefSlots.map(x => +x), [0, 0]) + assert.sameOrderedMembers( + lastReportedRefSlots.map((x) => +x), + [0, 0] + ) }) it('but otherwise, the contract is dysfunctional', async () => { @@ -67,7 +144,7 @@ contract('HashConsensus', ([admin, member1, member2]) => { await assertRevert(consensus.getConsensusState(), 'InitialEpochIsYetToArrive()') await assertRevert(consensus.getMemberInfo(member1), 'InitialEpochIsYetToArrive()') - const firstRefSlot = INITIAL_EPOCH * SLOTS_PER_EPOCH - 1 + const firstRefSlot = TEST_INITIAL_EPOCH * SLOTS_PER_EPOCH - 1 await assertRevert( consensus.submitReport(firstRefSlot, HASH_1, CONSENSUS_VERSION, { from: member1 }), 'InitialEpochIsYetToArrive()' @@ -75,14 +152,14 @@ contract('HashConsensus', ([admin, member1, member2]) => { }) it('after the initial epoch comes, the consensus contract becomes functional', async () => { - await consensus.setTimeInEpochs(INITIAL_EPOCH) + await consensus.setTimeInEpochs(TEST_INITIAL_EPOCH) - await consensus.setQuorum(2, {from: admin}) - assert.equal(+await consensus.getQuorum(), 2) + await consensus.setQuorum(2, { from: admin }) + assert.equal(+(await consensus.getQuorum()), 2) const frame = await consensus.getCurrentFrame() - assert.equal(+frame.refSlot, computeEpochFirstSlot(INITIAL_EPOCH) - 1) - assert.equal(+frame.reportProcessingDeadlineSlot, computeEpochFirstSlot(INITIAL_EPOCH) + SLOTS_PER_FRAME - 1) + assert.equal(+frame.refSlot, computeEpochFirstSlot(TEST_INITIAL_EPOCH) - 1) + assert.equal(+frame.reportProcessingDeadlineSlot, computeEpochFirstSlot(TEST_INITIAL_EPOCH) + SLOTS_PER_FRAME - 1) const consensusState = await consensus.getConsensusState() assert.equal(consensusState.consensusReport, ZERO_HASH) @@ -92,8 +169,8 @@ contract('HashConsensus', ([admin, member1, member2]) => { assert.equal(+memberInfo.currentRefSlot, +frame.refSlot) assert.equal(+memberInfo.lastReportRefSlot, 0) - const tx = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, {from: member1}) - assertEvent(tx, 'ReportReceived', {expectedArgs: {refSlot: frame.refSlot, member: member1, report: HASH_1}}) + const tx = await consensus.submitReport(frame.refSlot, HASH_1, CONSENSUS_VERSION, { from: member1 }) + assertEvent(tx, 'ReportReceived', { expectedArgs: { refSlot: frame.refSlot, member: member1, report: HASH_1 } }) }) }) @@ -101,15 +178,13 @@ contract('HashConsensus', ([admin, member1, member2]) => { let consensus beforeEach(async () => { - const deployed = await deployHashConsensus(admin, {initialEpoch: 1}) + const deployed = await deployHashConsensus(admin, { initialEpoch: 1 }) consensus = deployed.consensus - await consensus.addMember(member1, 1, {from: admin}) + await consensus.addMember(member1, 1, { from: admin }) }) - it(`crossing frame boundary time advances reference and deadline slots by the frame size`, - async () => - { - assert.equal(+await consensus.getTime(), computeTimestampAtEpoch(1)) + it(`crossing frame boundary time advances reference and deadline slots by the frame size`, async () => { + assert.equal(+(await consensus.getTime()), computeTimestampAtEpoch(1)) await consensus.setFrameConfig(5, 0) assert.equal(+(await consensus.getFrameConfig()).initialEpoch, 1) @@ -134,7 +209,7 @@ contract('HashConsensus', ([admin, member1, member2]) => { }) it('increasing frame size always keeps the current start slot', async () => { - assert.equal(+await consensus.getTime(), computeTimestampAtEpoch(1)) + assert.equal(+(await consensus.getTime()), computeTimestampAtEpoch(1)) await consensus.setFrameConfig(5, 0) assert.equal(+(await consensus.getFrameConfig()).initialEpoch, 1) @@ -161,7 +236,7 @@ contract('HashConsensus', ([admin, member1, member2]) => { }) it(`decreasing the frame size cannot decrease the current reference slot`, async () => { - assert.equal(+await consensus.getTime(), computeTimestampAtEpoch(1)) + assert.equal(+(await consensus.getTime()), computeTimestampAtEpoch(1)) await consensus.setFrameConfig(5, 0) assert.equal(+(await consensus.getFrameConfig()).initialEpoch, 1) @@ -187,33 +262,34 @@ contract('HashConsensus', ([admin, member1, member2]) => { assert.equal(+newFrame.reportProcessingDeadlineSlot, computeEpochFirstSlot(10) - 1) }) - it(`decreasing the frame size may advance the current reference slot, ` + - `but at least by the new frame size`, async () => - { - assert.equal(+await consensus.getTime(), computeTimestampAtEpoch(1)) - - await consensus.setFrameConfig(5, 0) - assert.equal(+(await consensus.getFrameConfig()).initialEpoch, 1) - - /// we're at the end of the frame 1 spanning epochs 6-10 - /// - /// epochs 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 - /// frames before |-------------r|------------^-|--------------|--------------| - /// frames after |--------------|----------r|^----------|-----------|--------- - /// | - /// NOT like this |-----------|----------r|---^-------|-----------|-----------| - /// - await consensus.setTime(computeTimestampAtEpoch(10)) - - const frame = await consensus.getCurrentFrame() - assert.equal(+frame.refSlot, computeEpochFirstSlot(6) - 1) - assert.equal(+frame.reportProcessingDeadlineSlot, computeEpochFirstSlot(11) - 1) - - await consensus.setFrameConfig(4, 0) - - const newFrame = await consensus.getCurrentFrame() - assert.equal(+newFrame.refSlot, computeEpochFirstSlot(10) - 1) - assert.equal(+newFrame.reportProcessingDeadlineSlot, computeEpochFirstSlot(14) - 1) - }) + it( + `decreasing the frame size may advance the current reference slot, ` + `but at least by the new frame size`, + async () => { + assert.equal(+(await consensus.getTime()), computeTimestampAtEpoch(1)) + + await consensus.setFrameConfig(5, 0) + assert.equal(+(await consensus.getFrameConfig()).initialEpoch, 1) + + /// we're at the end of the frame 1 spanning epochs 6-10 + /// + /// epochs 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 + /// frames before |-------------r|------------^-|--------------|--------------| + /// frames after |--------------|----------r|^----------|-----------|--------- + /// | + /// NOT like this |-----------|----------r|---^-------|-----------|-----------| + /// + await consensus.setTime(computeTimestampAtEpoch(10)) + + const frame = await consensus.getCurrentFrame() + assert.equal(+frame.refSlot, computeEpochFirstSlot(6) - 1) + assert.equal(+frame.reportProcessingDeadlineSlot, computeEpochFirstSlot(11) - 1) + + await consensus.setFrameConfig(4, 0) + + const newFrame = await consensus.getCurrentFrame() + assert.equal(+newFrame.refSlot, computeEpochFirstSlot(10) - 1) + assert.equal(+newFrame.reportProcessingDeadlineSlot, computeEpochFirstSlot(14) - 1) + } + ) }) }) From a06a02baab3ed4ca150993d85f34064ed5758c5f Mon Sep 17 00:00:00 2001 From: Andrei Date: Thu, 9 Feb 2023 14:11:38 +0700 Subject: [PATCH 2/4] test: hash consensus: fix report processor tests --- .../hash-consensus-report-processor.test.js | 66 +++++-------------- 1 file changed, 15 insertions(+), 51 deletions(-) diff --git a/test/0.8.9/oracle/hash-consensus-report-processor.test.js b/test/0.8.9/oracle/hash-consensus-report-processor.test.js index 25790e55b..2ba105fde 100644 --- a/test/0.8.9/oracle/hash-consensus-report-processor.test.js +++ b/test/0.8.9/oracle/hash-consensus-report-processor.test.js @@ -1,23 +1,16 @@ const { assert, getAccessControlMessage } = require('../../helpers/assert') -const { toNum } = require('../../helpers/utils') -const { assertBn, assertEvent, assertAmountOfEvents } = require('@aragon/contract-helpers-test/src/asserts') +const { assertEvent } = require('@aragon/contract-helpers-test/src/asserts') const { assertRevert } = require('../../helpers/assertThrow') -const { ZERO_ADDRESS, bn } = require('@aragon/contract-helpers-test') +const { ZERO_ADDRESS } = require('@aragon/contract-helpers-test') -const { - 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, - CONSENSUS_VERSION, deployHashConsensus} = require('./hash-consensus-deploy.test') +const { CONSENSUS_VERSION, deployHashConsensus } = require('./hash-consensus-deploy.test') const CONSENSUS_VERSION_2 = 2 const HashConsensus = artifacts.require('HashConsensusTimeTravellable') const MockReportProcessor = artifacts.require('MockReportProcessor') -contract('HashConsensus', ([admin, member1, member2, member3, member4, member5, stranger]) => { +contract('HashConsensus', ([admin, stranger]) => { let consensus let reportProcessor @@ -33,26 +26,11 @@ contract('HashConsensus', ([admin, member1, member2, member3, member4, member5, reportProcessor2 = await MockReportProcessor.new(CONSENSUS_VERSION_2, { from: admin }) } - const deployProcessorZero = async () => { - await deploy({ reportProcessorAddress: ZERO_ADDRESS }) - } - context('without initial processor', () => { - before(deployProcessorZero) - - it('has no initial processor', async () => { - assert.addressEqual( - await consensus.getReportProcessor(), - ZERO_ADDRESS, - 'there should be zero address for processor', - ) - }) + before(deploy) it('consensus version equals zero', async () => { - assert.equal( - await consensus.getConsensusVersion(), - 0, - ) + assert.equal(+(await consensus.getConsensusVersion()), CONSENSUS_VERSION) }) }) @@ -60,40 +38,32 @@ contract('HashConsensus', ([admin, member1, member2, member3, member4, member5, before(deploy) it('properly set initial report processor', async () => { - assert.addressEqual( - await consensus.getReportProcessor(), - reportProcessor1.address, - 'processor address differs', - ) + assert.addressEqual(await consensus.getReportProcessor(), reportProcessor1.address, 'processor address differs') }) context('method setReportProcessor', () => { before(deploy) it('checks next processor is not zero', async () => { - await assertRevert( - consensus.setReportProcessor(ZERO_ADDRESS), - 'AddressCannotBeZero()', - ) + await assertRevert(consensus.setReportProcessor(ZERO_ADDRESS), 'ReportProcessorCannotBeZero()') }) it('checks next processor is not the same as previous', async () => { - await assertRevert( - consensus.setReportProcessor(reportProcessor1.address), - 'NewProcessorCannotBeTheSame()', - ) + await assertRevert(consensus.setReportProcessor(reportProcessor1.address), 'NewProcessorCannotBeTheSame()') }) it('checks tx sender for MANAGE_REPORT_PROCESSOR_ROLE', async () => { await assertRevert( - consensus.setReportProcessor(reportProcessor2.address, {from: stranger}), + consensus.setReportProcessor(reportProcessor2.address, { from: stranger }), getAccessControlMessage(stranger.toLowerCase(), await consensus.MANAGE_REPORT_PROCESSOR_ROLE()) ) }) it('emits ReportProcessorSet event', async () => { const tx = await consensus.setReportProcessor(reportProcessor2.address) - assertEvent(tx, 'ReportProcessorSet', {expectedArgs: {processor: reportProcessor2.address, prevProcessor: reportProcessor1.address}}) + assertEvent(tx, 'ReportProcessorSet', { + expectedArgs: { processor: reportProcessor2.address, prevProcessor: reportProcessor1.address } + }) }) }) @@ -101,18 +71,12 @@ contract('HashConsensus', ([admin, member1, member2, member3, member4, member5, beforeEach(deploy) it('equals to version of initial processor', async () => { - assert.equal( - await consensus.getConsensusVersion(), - CONSENSUS_VERSION, - ) + assert.equal(await consensus.getConsensusVersion(), CONSENSUS_VERSION) }) it('equals to new processor version after it was changed', async () => { await consensus.setReportProcessor(reportProcessor2.address) - assert.equal( - await consensus.getConsensusVersion(), - CONSENSUS_VERSION_2, - ) + assert.equal(await consensus.getConsensusVersion(), CONSENSUS_VERSION_2) }) }) }) From 913fd374f9b30d48f58ce53de4b727fbf6ea6cec Mon Sep 17 00:00:00 2001 From: Andrei Date: Thu, 9 Feb 2023 14:26:48 +0700 Subject: [PATCH 3/4] test: hash consensus: update tests, update getFrameConfig method --- contracts/0.8.9/oracle/HashConsensus.sol | 4 +- .../oracle/HashConsensusTimeTravellable.sol | 4 -- .../hash-consensus-access-control.test.js | 2 +- test/0.8.9/oracle/hash-consensus-frames.js | 65 +++++++++---------- 4 files changed, 34 insertions(+), 41 deletions(-) diff --git a/contracts/0.8.9/oracle/HashConsensus.sol b/contracts/0.8.9/oracle/HashConsensus.sol index d7c79268a..113061122 100644 --- a/contracts/0.8.9/oracle/HashConsensus.sol +++ b/contracts/0.8.9/oracle/HashConsensus.sol @@ -222,8 +222,8 @@ contract HashConsensus is AccessControlEnumerable { /// @notice Returns the parameters required to calculate reporting frame given an epoch. /// - function getFrameConfig() external view returns (uint256 initialEpoch, uint256 epochsPerFrame) { - return (_frameConfig.initialEpoch, _frameConfig.epochsPerFrame); + function getFrameConfig() external view returns (uint256 initialEpoch, uint256 epochsPerFrame, uint256 fastLaneLengthSlots) { + return (_frameConfig.initialEpoch, _frameConfig.epochsPerFrame, _frameConfig.fastLaneLengthSlots); } /// @notice Returns the current reporting frame. diff --git a/contracts/0.8.9/test_helpers/oracle/HashConsensusTimeTravellable.sol b/contracts/0.8.9/test_helpers/oracle/HashConsensusTimeTravellable.sol index fd5409a60..238cc9506 100644 --- a/contracts/0.8.9/test_helpers/oracle/HashConsensusTimeTravellable.sol +++ b/contracts/0.8.9/test_helpers/oracle/HashConsensusTimeTravellable.sol @@ -73,10 +73,6 @@ contract HashConsensusTimeTravellable is HashConsensus { _time += SECONDS_PER_SLOT * SLOTS_PER_EPOCH * numEpochs; } - function getFrameConfigFastLaneLengthSlots() external view returns (uint256 fastLaneLengthSlots) { - return (_frameConfig.fastLaneLengthSlots); - } - function getReportProcessor() external view returns (address) { return _reportProcessor; } diff --git a/test/0.8.9/oracle/hash-consensus-access-control.test.js b/test/0.8.9/oracle/hash-consensus-access-control.test.js index b63c42df9..1f831602d 100644 --- a/test/0.8.9/oracle/hash-consensus-access-control.test.js +++ b/test/0.8.9/oracle/hash-consensus-access-control.test.js @@ -202,7 +202,7 @@ contract('HashConsensus', ([admin, account1, account2, member1, member2, strange await consensus.grantRole(manageFastLineConfigRoleKeccak156, account2) await consensus.setFastLaneLengthSlots(64, { from: account2 }) - assert.equal(+(await consensus.getFrameConfigFastLaneLengthSlots()), 64) + assert.equal(+(await consensus.getFrameConfig()).fastLaneLengthSlots, 64) }) }) }) diff --git a/test/0.8.9/oracle/hash-consensus-frames.js b/test/0.8.9/oracle/hash-consensus-frames.js index 5910f53c1..578b433a7 100644 --- a/test/0.8.9/oracle/hash-consensus-frames.js +++ b/test/0.8.9/oracle/hash-consensus-frames.js @@ -52,7 +52,7 @@ contract('HashConsensus', ([admin, member1, member2]) => { await consensus.setFrameConfig(100, 50) assert.equal(+(await consensus.getFrameConfig()).epochsPerFrame, 100) - assert.equal(+(await consensus.getFrameConfigFastLaneLengthSlots()), 50) + assert.equal(+(await consensus.getFrameConfig()).fastLaneLengthSlots, 50) assert.equal(+(await consensus.getFrameConfig()).initialEpoch, INITIAL_EPOCH) }) }) @@ -63,7 +63,7 @@ contract('HashConsensus', ([admin, member1, member2]) => { await consensus.setFrameConfig(100, 50) assert.equal(+(await consensus.getFrameConfig()).epochsPerFrame, 100) - assert.equal(+(await consensus.getFrameConfigFastLaneLengthSlots()), 50) + assert.equal(+(await consensus.getFrameConfig()).fastLaneLengthSlots, 50) assert.equal(+(await consensus.getFrameConfig()).initialEpoch, INITIAL_EPOCH) }) @@ -72,7 +72,7 @@ contract('HashConsensus', ([admin, member1, member2]) => { await consensus.setFrameConfig(100, 50) assert.equal(+(await consensus.getFrameConfig()).epochsPerFrame, 100) - assert.equal(+(await consensus.getFrameConfigFastLaneLengthSlots()), 50) + assert.equal(+(await consensus.getFrameConfig()).fastLaneLengthSlots, 50) assert.equal(+(await consensus.getFrameConfig()).initialEpoch, EPOCHS_PER_FRAME + 1) }) @@ -93,8 +93,8 @@ contract('HashConsensus', ([admin, member1, member2]) => { it('should emit FrameConfigSet & FastLaneConfigSet event', async () => { const tx = await consensus.setFrameConfig(100, 50) - assertEvent(tx, 'FrameConfigSet') - assertEvent(tx, 'FastLaneConfigSet') + assertEvent(tx, 'FrameConfigSet', { expectedArgs: { newInitialEpoch: 1, newEpochsPerFrame: 100 } }) + assertEvent(tx, 'FastLaneConfigSet', { expectedArgs: { fastLaneLengthSlots: 50 } }) }) it('should not emit FrameConfigSet & FastLaneConfigSet event', async () => { @@ -262,34 +262,31 @@ contract('HashConsensus', ([admin, member1, member2]) => { assert.equal(+newFrame.reportProcessingDeadlineSlot, computeEpochFirstSlot(10) - 1) }) - it( - `decreasing the frame size may advance the current reference slot, ` + `but at least by the new frame size`, - async () => { - assert.equal(+(await consensus.getTime()), computeTimestampAtEpoch(1)) - - await consensus.setFrameConfig(5, 0) - assert.equal(+(await consensus.getFrameConfig()).initialEpoch, 1) - - /// we're at the end of the frame 1 spanning epochs 6-10 - /// - /// epochs 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 - /// frames before |-------------r|------------^-|--------------|--------------| - /// frames after |--------------|----------r|^----------|-----------|--------- - /// | - /// NOT like this |-----------|----------r|---^-------|-----------|-----------| - /// - await consensus.setTime(computeTimestampAtEpoch(10)) - - const frame = await consensus.getCurrentFrame() - assert.equal(+frame.refSlot, computeEpochFirstSlot(6) - 1) - assert.equal(+frame.reportProcessingDeadlineSlot, computeEpochFirstSlot(11) - 1) - - await consensus.setFrameConfig(4, 0) - - const newFrame = await consensus.getCurrentFrame() - assert.equal(+newFrame.refSlot, computeEpochFirstSlot(10) - 1) - assert.equal(+newFrame.reportProcessingDeadlineSlot, computeEpochFirstSlot(14) - 1) - } - ) + it('decreasing the frame size may advance the current reference slot, but at least by the new frame size', async () => { + assert.equal(+(await consensus.getTime()), computeTimestampAtEpoch(1)) + + await consensus.setFrameConfig(5, 0) + assert.equal(+(await consensus.getFrameConfig()).initialEpoch, 1) + + /// we're at the end of the frame 1 spanning epochs 6-10 + /// + /// epochs 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 + /// frames before |-------------r|------------^-|--------------|--------------| + /// frames after |--------------|----------r|^----------|-----------|--------- + /// | + /// NOT like this |-----------|----------r|---^-------|-----------|-----------| + /// + await consensus.setTime(computeTimestampAtEpoch(10)) + + const frame = await consensus.getCurrentFrame() + assert.equal(+frame.refSlot, computeEpochFirstSlot(6) - 1) + assert.equal(+frame.reportProcessingDeadlineSlot, computeEpochFirstSlot(11) - 1) + + await consensus.setFrameConfig(4, 0) + + const newFrame = await consensus.getCurrentFrame() + assert.equal(+newFrame.refSlot, computeEpochFirstSlot(10) - 1) + assert.equal(+newFrame.reportProcessingDeadlineSlot, computeEpochFirstSlot(14) - 1) + }) }) }) From 57459d517aa17f0a03deaafe34094d6a50706d92 Mon Sep 17 00:00:00 2001 From: Andrei Date: Thu, 9 Feb 2023 14:32:55 +0700 Subject: [PATCH 4/4] test: hash consensus: update getFrameConfig test --- test/0.8.9/oracle/hash-consensus-deploy.test.js | 4 +++- test/0.8.9/oracle/hash-consensus-frames.js | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) 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 b03a168ad..b2bcaf4de 100644 --- a/test/0.8.9/oracle/hash-consensus-deploy.test.js +++ b/test/0.8.9/oracle/hash-consensus-deploy.test.js @@ -11,6 +11,7 @@ const SECONDS_PER_SLOT = 12 const GENESIS_TIME = 100 const EPOCHS_PER_FRAME = 225 // one day const INITIAL_EPOCH = 1 +const INITIAL_FAST_LANE_LENGHT_SLOTS = 0 const SECONDS_PER_EPOCH = SLOTS_PER_EPOCH * SECONDS_PER_SLOT const SECONDS_PER_FRAME = SECONDS_PER_EPOCH * EPOCHS_PER_FRAME @@ -42,7 +43,7 @@ async function deployHashConsensus( secondsPerSlot = SECONDS_PER_SLOT, genesisTime = GENESIS_TIME, epochsPerFrame = EPOCHS_PER_FRAME, - fastLaneLengthSlots = 0, + fastLaneLengthSlots = INITIAL_FAST_LANE_LENGHT_SLOTS, initialEpoch = INITIAL_EPOCH } = {} ) { @@ -74,6 +75,7 @@ async function deployHashConsensus( } module.exports = { + INITIAL_FAST_LANE_LENGHT_SLOTS, INITIAL_EPOCH, SLOTS_PER_EPOCH, SECONDS_PER_SLOT, diff --git a/test/0.8.9/oracle/hash-consensus-frames.js b/test/0.8.9/oracle/hash-consensus-frames.js index 578b433a7..a7347f137 100644 --- a/test/0.8.9/oracle/hash-consensus-frames.js +++ b/test/0.8.9/oracle/hash-consensus-frames.js @@ -3,6 +3,7 @@ const { assertEvent } = require('@aragon/contract-helpers-test/src/asserts') const { assertRevert } = require('../../helpers/assertThrow') const { + INITIAL_FAST_LANE_LENGHT_SLOTS, INITIAL_EPOCH, EPOCHS_PER_FRAME, SLOTS_PER_EPOCH, @@ -46,6 +47,7 @@ contract('HashConsensus', ([admin, member1, member2]) => { it('should return initial data', async () => { assert.equal(+(await consensus.getFrameConfig()).epochsPerFrame, EPOCHS_PER_FRAME) assert.equal(+(await consensus.getFrameConfig()).initialEpoch, INITIAL_EPOCH) + assert.equal(+(await consensus.getFrameConfig()).fastLaneLengthSlots, INITIAL_FAST_LANE_LENGHT_SLOTS) }) it('should return new data', async () => {