Skip to content

Commit 89ad4cc

Browse files
authored
Merge pull request #615 from lidofinance/feature/shapella-upgrade-tests-accounting-oracle
Feature/shapella upgrade tests accounting oracle
2 parents 4786bea + 53be633 commit 89ad4cc

File tree

2 files changed

+148
-42
lines changed

2 files changed

+148
-42
lines changed

contracts/0.8.9/test_helpers/oracle/AccountingOracleTimeTravellable.sol

+4
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,8 @@ contract AccountingOracleTimeTravellable is AccountingOracle, ITimeProvider {
3030
address consensus = CONSENSUS_CONTRACT_POSITION.getStorageAddress();
3131
return ITimeProvider(consensus).getTime();
3232
}
33+
34+
function getExtraDataProcessingState() external view returns (ExtraDataProcessingState memory) {
35+
return _storageExtraDataProcessingState().value;
36+
}
3337
}

test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js

+144-42
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
const { assert } = require('../../helpers/assert')
2-
const { assertEvent } = require('@aragon/contract-helpers-test/src/asserts')
32
const { e9, e18, e27 } = require('../../helpers/utils')
43

54
const {
@@ -13,7 +12,8 @@ const {
1312
EXTRA_DATA_FORMAT_LIST,
1413
SLOTS_PER_FRAME,
1514
SECONDS_PER_SLOT,
16-
GENESIS_TIME
15+
GENESIS_TIME,
16+
ZERO_HASH
1717
} = require('./accounting-oracle-deploy.test')
1818

1919
contract('AccountingOracle', ([admin, account1, account2, member1, member2, stranger]) => {
@@ -94,7 +94,20 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra
9494
await consensus.advanceTimeToNextFrameStart()
9595
await consensus.submitReport(newReportFields.refSlot, reportHash, CONSENSUS_VERSION, { from: member1 })
9696

97-
return newReportItems
97+
return {
98+
newReportFields,
99+
newReportItems,
100+
reportHash
101+
}
102+
}
103+
104+
async function prepareNextReportInNextFrame(newReportFields) {
105+
const { refSlot } = await consensus.getCurrentFrame()
106+
const next = await prepareNextReport({
107+
...newReportFields,
108+
refSlot: +refSlot + SLOTS_PER_FRAME
109+
})
110+
return next
98111
}
99112

100113
context('deploying', () => {
@@ -140,7 +153,7 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra
140153
await consensus.setTime(deadline)
141154

142155
const tx = await oracle.submitReportData(reportItems, oracleVersion, { from: member1 })
143-
assertEvent(tx, 'ProcessingStarted', { expectedArgs: { refSlot: reportFields.refSlot } })
156+
assert.emits(tx, 'ProcessingStarted', { refSlot: reportFields.refSlot })
144157
})
145158
})
146159

@@ -165,22 +178,9 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra
165178

166179
it('should should allow calling if correct ref slot', async () => {
167180
await consensus.setTime(deadline)
168-
const { refSlot } = await consensus.getCurrentFrame()
169-
170-
const nextRefSlot = +refSlot + SLOTS_PER_FRAME
171-
172-
const newReportFields = {
173-
...reportFields,
174-
refSlot: nextRefSlot
175-
}
176-
const reportItems = getReportDataItems(newReportFields)
177-
178-
const reportHash = calcReportDataHash(reportItems)
179-
await consensus.advanceTimeToNextFrameStart()
180-
await consensus.submitReport(nextRefSlot, reportHash, CONSENSUS_VERSION, { from: member1 })
181-
182-
const tx = await oracle.submitReportData(reportItems, oracleVersion, { from: member1 })
183-
assertEvent(tx, 'ProcessingStarted', { expectedArgs: { refSlot: newReportFields.refSlot } })
181+
const { newReportFields, newReportItems } = await prepareNextReportInNextFrame({ ...reportFields })
182+
const tx = await oracle.submitReportData(newReportItems, oracleVersion, { from: member1 })
183+
assert.emits(tx, 'ProcessingStarted', { refSlot: newReportFields.refSlot })
184184
})
185185
})
186186

@@ -216,7 +216,7 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra
216216
const { refSlot } = await consensus.getCurrentFrame()
217217

218218
const tx = await oracle.submitReportData(reportItems, oracleVersion, { from: member1 })
219-
assertEvent(tx, 'ProcessingStarted', { expectedArgs: { refSlot: reportFields.refSlot } })
219+
assert.emits(tx, 'ProcessingStarted', { refSlot: reportFields.refSlot })
220220

221221
const newConsensusVersion = CONSENSUS_VERSION + 1
222222
const nextRefSlot = +refSlot + SLOTS_PER_FRAME
@@ -233,46 +233,48 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra
233233
await consensus.submitReport(newReportFields.refSlot, newReportHash, newConsensusVersion, { from: member1 })
234234

235235
const txNewVersion = await oracle.submitReportData(newReportItems, oracleVersion, { from: member1 })
236-
assertEvent(txNewVersion, 'ProcessingStarted', { expectedArgs: { refSlot: newReportFields.refSlot } })
236+
assert.emits(txNewVersion, 'ProcessingStarted', { refSlot: newReportFields.refSlot })
237237
})
238238
})
239239

240240
context('enforces module ids sorting order', () => {
241241
beforeEach(deploy)
242242

243-
it('should revert if incorrect stakingModuleIdsWithNewlyExitedValidators order', async () => {
244-
const { refSlot } = await consensus.getCurrentFrame()
245-
246-
const nextRefSlot = +refSlot + SLOTS_PER_FRAME
247-
const newReportFields = {
243+
it('should revert if incorrect stakingModuleIdsWithNewlyExitedValidators order (when next number in list is less than previous)', async () => {
244+
const { newReportItems } = await prepareNextReportInNextFrame({
248245
...reportFields,
249-
refSlot: nextRefSlot,
250246
stakingModuleIdsWithNewlyExitedValidators: [2, 1],
251247
numExitedValidatorsByStakingModule: [3, 4]
252-
}
253-
const newReportItems = await prepareNextReport(newReportFields)
248+
})
254249

255250
await assert.reverts(
256251
oracle.submitReportData(newReportItems, oracleVersion, { from: member1 }),
257252
'InvalidExitedValidatorsData()'
258253
)
259254
})
260255

261-
it('should should allow calling if correct extra data list moduleId', async () => {
262-
const { refSlot } = await consensus.getCurrentFrame()
256+
it('should revert if incorrect stakingModuleIdsWithNewlyExitedValidators order (when next number in list is less than previous)', async () => {
257+
const { newReportItems } = await prepareNextReportInNextFrame({
258+
...reportFields,
259+
stakingModuleIdsWithNewlyExitedValidators: [1, 1],
260+
numExitedValidatorsByStakingModule: [3, 4]
261+
})
263262

264-
const nextRefSlot = +refSlot + SLOTS_PER_FRAME
263+
await assert.reverts(
264+
oracle.submitReportData(newReportItems, oracleVersion, { from: member1 }),
265+
'InvalidExitedValidatorsData()'
266+
)
267+
})
265268

266-
const newReportFields = {
269+
it('should should allow calling if correct extra data list moduleId', async () => {
270+
const { newReportFields, newReportItems } = await prepareNextReportInNextFrame({
267271
...reportFields,
268-
refSlot: nextRefSlot,
269272
stakingModuleIdsWithNewlyExitedValidators: [1, 2],
270273
numExitedValidatorsByStakingModule: [3, 4]
271-
}
272-
const newReportItems = await prepareNextReport(newReportFields)
274+
})
273275

274276
const tx = await oracle.submitReportData(newReportItems, oracleVersion, { from: member1 })
275-
assertEvent(tx, 'ProcessingStarted', { expectedArgs: { refSlot: newReportFields.refSlot } })
277+
assert.emits(tx, 'ProcessingStarted', { refSlot: newReportFields.refSlot })
276278
})
277279
})
278280

@@ -294,7 +296,7 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra
294296

295297
it('submits if data successfully pass hash validation', async () => {
296298
const tx = await oracle.submitReportData(reportItems, oracleVersion, { from: member1 })
297-
assertEvent(tx, 'ProcessingStarted', { expectedArgs: { refSlot: reportFields.refSlot } })
299+
assert.emits(tx, 'ProcessingStarted', { refSlot: reportFields.refSlot })
298300
})
299301
})
300302

@@ -330,14 +332,79 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra
330332

331333
await oracle.submitReportData(reportItems, oracleVersion, { from: member1 })
332334
})
335+
336+
it('reverts with InvalidExitedValidatorsData if counts of stakingModuleIds and numExitedValidatorsByStakingModule does not match', async () => {
337+
const { newReportItems } = await prepareNextReportInNextFrame({
338+
...reportFields,
339+
stakingModuleIdsWithNewlyExitedValidators: [1, 2],
340+
numExitedValidatorsByStakingModule: [3]
341+
})
342+
await assert.reverts(
343+
oracle.submitReportData(newReportItems, oracleVersion, { from: member1 }),
344+
'InvalidExitedValidatorsData()'
345+
)
346+
})
347+
348+
it('reverts with InvalidExitedValidatorsData if any record for number of exited validators equals 0', async () => {
349+
const { newReportItems } = await prepareNextReportInNextFrame({
350+
...reportFields,
351+
stakingModuleIdsWithNewlyExitedValidators: [1, 2],
352+
numExitedValidatorsByStakingModule: [3, 0]
353+
})
354+
await assert.reverts(
355+
oracle.submitReportData(newReportItems, oracleVersion, { from: member1 }),
356+
'InvalidExitedValidatorsData()'
357+
)
358+
})
359+
360+
it('reverts with NumExitedValidatorsCannotDecrease if total count of exited validators less then previous exited number', async () => {
361+
const totalExitedValidators = reportFields.numExitedValidatorsByStakingModule.reduce(
362+
(sum, curr) => sum + curr,
363+
0
364+
)
365+
await mockStakingRouter.setExitedKeysCountAcrossAllModules(totalExitedValidators + 1)
366+
await assert.reverts(
367+
oracle.submitReportData(reportItems, oracleVersion, { from: member1 }),
368+
'NumExitedValidatorsCannotDecrease()'
369+
)
370+
})
371+
372+
it('does not reverts with NumExitedValidatorsCannotDecrease if total count of exited validators equals to previous exited number', async () => {
373+
const totalExitedValidators = reportFields.numExitedValidatorsByStakingModule.reduce(
374+
(sum, curr) => sum + curr,
375+
0
376+
)
377+
await mockStakingRouter.setExitedKeysCountAcrossAllModules(totalExitedValidators)
378+
await oracle.submitReportData(reportItems, oracleVersion, { from: member1 })
379+
})
380+
381+
it('reverts with ExitedValidatorsLimitExceeded if exited validators rate limit will be reached', async () => {
382+
// Really simple test here for now
383+
// TODO: Come up with more tests for better coverage of edge-case scenarios that can be accrued
384+
// during calculation `exitedValidatorsPerDay` rate in AccountingOracle:612
385+
const totalExitedValidators = reportFields.numExitedValidatorsByStakingModule.reduce(
386+
(sum, curr) => sum + curr,
387+
0
388+
)
389+
const exitingRateLimit = totalExitedValidators - 1
390+
await oracleReportSanityChecker.setChurnValidatorsPerDayLimit(exitingRateLimit)
391+
assert.equals(
392+
(await oracleReportSanityChecker.getOracleReportLimits()).churnValidatorsPerDayLimit,
393+
exitingRateLimit
394+
)
395+
await assert.reverts(
396+
oracle.submitReportData(reportItems, oracleVersion, { from: member1 }),
397+
`ExitedValidatorsLimitExceeded(${exitingRateLimit}, ${totalExitedValidators})`
398+
)
399+
})
333400
})
334401

335402
context('delivers the data to corresponded contracts', () => {
336403
it('should call handleOracleReport on Lido', async () => {
337404
assert.equals((await mockLido.getLastCall_handleOracleReport()).callCount, 0)
338405
await consensus.setTime(deadline)
339406
const tx = await oracle.submitReportData(reportItems, oracleVersion, { from: member1 })
340-
assertEvent(tx, 'ProcessingStarted', { expectedArgs: { refSlot: reportFields.refSlot } })
407+
assert.emits(tx, 'ProcessingStarted', { refSlot: reportFields.refSlot })
341408

342409
const lastOracleReportToLido = await mockLido.getLastCall_handleOracleReport()
343410

@@ -357,11 +424,11 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra
357424
assert.equals(lastOracleReportToLido.finalizationShareRate, reportFields.finalizationShareRate)
358425
})
359426

360-
it('should call updateExitedValidatorsCountByStakingModule on stakingRouter', async () => {
427+
it('should call updateExitedValidatorsCountByStakingModule on StakingRouter', async () => {
361428
assert.equals((await mockStakingRouter.lastCall_updateExitedKeysByModule()).callCount, 0)
362429
await consensus.setTime(deadline)
363430
const tx = await oracle.submitReportData(reportItems, oracleVersion, { from: member1 })
364-
assertEvent(tx, 'ProcessingStarted', { expectedArgs: { refSlot: reportFields.refSlot } })
431+
assert.emits(tx, 'ProcessingStarted', { refSlot: reportFields.refSlot })
365432

366433
const lastOracleReportToStakingRouter = await mockStakingRouter.lastCall_updateExitedKeysByModule()
367434

@@ -370,6 +437,18 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra
370437
assert.equals(lastOracleReportToStakingRouter.exitedKeysCounts, reportFields.numExitedValidatorsByStakingModule)
371438
})
372439

440+
it('does not calling StakingRouter.updateExitedKeysByModule if lists of exited validators is empty', async () => {
441+
const { newReportItems, newReportFields } = await prepareNextReportInNextFrame({
442+
...reportFields,
443+
stakingModuleIdsWithNewlyExitedValidators: [],
444+
numExitedValidatorsByStakingModule: []
445+
})
446+
const tx = await oracle.submitReportData(newReportItems, oracleVersion, { from: member1 })
447+
assert.emits(tx, 'ProcessingStarted', { refSlot: newReportFields.refSlot })
448+
const lastOracleReportToStakingRouter = await mockStakingRouter.lastCall_updateExitedKeysByModule()
449+
assert.equals(lastOracleReportToStakingRouter.callCount, 0)
450+
})
451+
373452
it('should call handleConsensusLayerReport on legacyOracle', async () => {
374453
await oracle.submitReportData(reportItems, oracleVersion, { from: member1 })
375454
const lastCall = await mockLegacyOracle.lastCall__handleConsensusLayerReport()
@@ -413,5 +492,28 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra
413492
)
414493
})
415494
})
495+
496+
context('ExtraDataProcessingState', () => {
497+
it('should be empty from start', async () => {
498+
const data = await oracle.getExtraDataProcessingState()
499+
assert.equals(data.refSlot, '0')
500+
assert.equals(data.dataFormat, '0')
501+
assert.equals(data.itemsCount, '0')
502+
assert.equals(data.itemsProcessed, '0')
503+
assert.equals(data.lastSortingKey, '0')
504+
assert.equals(data.dataHash, ZERO_HASH)
505+
})
506+
507+
it('should be filled with report data after submitting', async () => {
508+
await oracle.submitReportData(reportItems, oracleVersion, { from: member1 })
509+
const data = await oracle.getExtraDataProcessingState()
510+
assert.equals(data.refSlot, reportFields.refSlot)
511+
assert.equals(data.dataFormat, reportFields.extraDataFormat)
512+
assert.equals(data.itemsCount, reportFields.extraDataItemsCount)
513+
assert.equals(data.itemsProcessed, '0')
514+
assert.equals(data.lastSortingKey, '0')
515+
assert.equals(data.dataHash, reportFields.extraDataHash)
516+
})
517+
})
416518
})
417519
})

0 commit comments

Comments
 (0)