Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor network:info for L2 epochs #348

Merged
merged 7 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/dull-kangaroos-reply.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@celo/celocli': patch
---

Adds support for L2 epoch data for network:info command
shazarre marked this conversation as resolved.
Show resolved Hide resolved
5 changes: 5 additions & 0 deletions .changeset/twenty-fans-listen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@celo/contractkit': minor
---

Adds support for firstKnownEpoch, getFirstBlockAtEpoch, getLastBlockAtEpoch on EpochManager wrapper
83 changes: 81 additions & 2 deletions packages/cli/src/commands/network/info-l2.test.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,95 @@
import { newKitFromWeb3 } from '@celo/contractkit'
import { testWithAnvilL2 } from '@celo/dev-utils/lib/anvil-test'
import { timeTravel } from '@celo/dev-utils/lib/ganache-test'
import { stripAnsiCodesFromNestedArray, testLocallyWithWeb3Node } from '../../test-utils/cliUtils'
import EpochsSwitch from '../epochs/switch'
import Info from './info'
process.env.NO_SYNCCHECK = 'true'

testWithAnvilL2('network:info', (web3) => {
test('runs', async () => {
beforeAll(async () => {
const kit = newKitFromWeb3(web3)
const epochManager = await kit.contracts.getEpochManager()
const epochDuration = await epochManager.epochDuration()
const accounts = await web3.eth.getAccounts()

// Switch epochs 3 times
for (let i = 0; i < 3; i++) {
await timeTravel(epochDuration + 1, web3)
await testLocallyWithWeb3Node(EpochsSwitch, ['--from', accounts[0]], web3)
}
})

it('runs for latest epoch', async () => {
const spy = jest.spyOn(console, 'log')
await testLocallyWithWeb3Node(Info, [], web3)

expect(stripAnsiCodesFromNestedArray(spy.mock.calls)).toMatchInlineSnapshot(`
[
[
"blockNumber: 359
epochs:
number: 7
start: 359
epochSize: 86400",
],
]
`)
})

it('runs for last 3 epochs', async () => {
const spy = jest.spyOn(console, 'log')

await testLocallyWithWeb3Node(Info, ['--lastN', '3'], web3)

expect(stripAnsiCodesFromNestedArray(spy.mock.calls)).toMatchInlineSnapshot(`
[
[
"blockNumber: 359
epochs:
0:
number: 7
start: 359
1:
end: 358
number: 6
start: 356
2:
end: 355
number: 5
start: 353
epochSize: 86400",
],
]
`)
})

it('runs for last 100 epochs, but displays only epoch that exist', async () => {
const spy = jest.spyOn(console, 'log')

await testLocallyWithWeb3Node(Info, ['--lastN', '100'], web3)

expect(stripAnsiCodesFromNestedArray(spy.mock.calls)).toMatchInlineSnapshot(`
[
[
"blockNumber: 350",
"blockNumber: 359
epochs:
0:
number: 7
start: 359
1:
end: 358
number: 6
start: 356
2:
end: 355
number: 5
start: 353
3:
end: 352
number: 4
start: 300
epochSize: 86400",
],
]
`)
Expand Down
84 changes: 84 additions & 0 deletions packages/cli/src/commands/network/info.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { testWithAnvilL1 } from '@celo/dev-utils/lib/anvil-test'
import { stripAnsiCodesFromNestedArray, testLocallyWithWeb3Node } from '../../test-utils/cliUtils'
import Info from './info'
process.env.NO_SYNCCHECK = 'true'

testWithAnvilL1('network:info', (web3) => {
it('runs for latest epoch', async () => {
const spy = jest.spyOn(console, 'log')
await testLocallyWithWeb3Node(Info, [], web3)

expect(stripAnsiCodesFromNestedArray(spy.mock.calls)).toMatchInlineSnapshot(`
[
[
"blockNumber: 349
epochs:
end: 400
number: 4
start: 301
epochSize: 100",
],
]
`)
})

it('runs for last 3 epochs', async () => {
const spy = jest.spyOn(console, 'log')

await testLocallyWithWeb3Node(Info, ['--lastN', '3'], web3)

expect(stripAnsiCodesFromNestedArray(spy.mock.calls)).toMatchInlineSnapshot(`
[
[
"blockNumber: 349
epochs:
0:
end: 400
number: 4
start: 301
1:
end: 300
number: 3
start: 201
2:
end: 200
number: 2
start: 101
epochSize: 100",
],
]
`)
})

it('runs for last 100 epochs, but displays only epoch that exist', async () => {
const spy = jest.spyOn(console, 'log')

await testLocallyWithWeb3Node(Info, ['--lastN', '100'], web3)

expect(stripAnsiCodesFromNestedArray(spy.mock.calls)).toMatchInlineSnapshot(`
[
[
"blockNumber: 349
epochs:
0:
end: 400
number: 4
start: 301
1:
end: 300
number: 3
start: 201
2:
end: 200
number: 2
start: 101
3:
end: 100
number: 1
start: 1
epochSize: 100",
],
]
`)
})
})
50 changes: 35 additions & 15 deletions packages/cli/src/commands/network/info.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { isCel2 } from '@celo/connect'
import { Flags, ux } from '@oclif/core'
import { Flags } from '@oclif/core'
import { BaseCommand } from '../../base'
import { printValueMapRecursive } from '../../utils/cli'

Expand All @@ -9,7 +9,7 @@ export default class Info extends BaseCommand {
static flags = {
...BaseCommand.flags,
lastN: Flags.integer({
char: 'n',
// We cannot use char: 'n' here because it conflicts with the node flag
shazarre marked this conversation as resolved.
Show resolved Hide resolved
description: 'Fetch info about the last n epochs',
required: false,
default: 1,
Expand All @@ -20,29 +20,49 @@ export default class Info extends BaseCommand {
const kit = await this.getKit()
const res = await this.parse(Info)
const isL2 = await isCel2(kit.connection.web3)
let latestEpochNumber: number
let epochSize: number

const blockNumber = await kit.connection.getBlockNumber()

if (isL2) {
ux.info('Celo no longer has epochs')
printValueMapRecursive({
blockNumber,
})
return
const epochManagerWrapper = await kit.contracts.getEpochManager()

latestEpochNumber = await epochManagerWrapper.getCurrentEpochNumber()
epochSize = await epochManagerWrapper.epochDuration()
} else {
latestEpochNumber = await kit.getEpochNumberOfBlock(blockNumber)
epochSize = await kit.getEpochSize()
}

const latestEpochNumber = await kit.getEpochNumberOfBlock(blockNumber)
const epochSize = await kit.getEpochSize()
const fetchEpochInfo = async (epochNumber: number) => {
if (isL2) {
const epochManagerWrapper = await kit.contracts.getEpochManager()

const fetchEpochInfo = async (epochNumber: number) => ({
number: epochNumber,
start: await kit.getFirstBlockNumberForEpoch(epochNumber),
end: await kit.getLastBlockNumberForEpoch(epochNumber),
})
const epochData: Record<string, number> = {
number: epochNumber,
start: await epochManagerWrapper.getFirstBlockAtEpoch(epochNumber),
}

// for L2 we cannot fetch the end block of the current epoch
if (epochNumber < latestEpochNumber) {
epochData.end = await epochManagerWrapper.getLastBlockAtEpoch(epochNumber)
}

return epochData
}

return {
number: epochNumber,
start: await kit.getFirstBlockNumberForEpoch(epochNumber),
end: await kit.getLastBlockNumberForEpoch(epochNumber),
}
}

const n = res.flags.lastN
const minEpoch = isL2 ? await (await kit.contracts.getEpochManager()).firstKnownEpoch() : 1
const epochs = []
for (let i = latestEpochNumber; i > latestEpochNumber - n; i--) {
for (let i = latestEpochNumber; i > latestEpochNumber - n && i >= minEpoch; i--) {
epochs.push(await fetchEpochInfo(i))
}

Expand Down
30 changes: 30 additions & 0 deletions packages/sdk/contractkit/src/wrappers/EpochManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,36 @@ testWithAnvilL2('EpochManagerWrapper', (web3: Web3) => {
expect((await epochManagerWrapper.getEpochProcessingStatus()).status).toEqual(1)
})

it('gets first known epoch number', async () => {
const epochManagerWrapper = await kit.contracts.getEpochManager()

expect(await epochManagerWrapper.firstKnownEpoch()).toEqual(4)
})

it('gets block numbers for an epoch', async () => {
const epochManagerWrapper = await kit.contracts.getEpochManager()
const currentEpochNumber = await epochManagerWrapper.getCurrentEpochNumber()
const accounts = await web3.eth.getAccounts()

expect(await epochManagerWrapper.getFirstBlockAtEpoch(currentEpochNumber)).toEqual(300)
await expect(
epochManagerWrapper.getLastBlockAtEpoch(currentEpochNumber)
).rejects.toMatchInlineSnapshot(`[Error: execution reverted: revert: Epoch not finished yet]`)

// Let the epoch pass and start another one
await timeTravel(EPOCH_DURATION + 1, web3)
await epochManagerWrapper.startNextEpochProcess().sendAndWaitForReceipt({
from: accounts[0],
})
await (
await epochManagerWrapper.finishNextEpochProcessTx()
).sendAndWaitForReceipt({
from: accounts[0],
})

expect(await epochManagerWrapper.getLastBlockAtEpoch(currentEpochNumber)).toEqual(352)
})

async function activateValidators() {
const validatorsContract = await kit.contracts.getValidators()
const electionWrapper = await kit.contracts.getElection()
Expand Down
7 changes: 7 additions & 0 deletions packages/sdk/contractkit/src/wrappers/EpochManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,18 @@ export interface EpochManagerConfig {
*/
export class EpochManagerWrapper extends BaseWrapperForGoverning<EpochManager> {
epochDuration = proxyCall(this.contract.methods.epochDuration, undefined, valueToInt)
firstKnownEpoch = proxyCall(this.contract.methods.firstKnownEpoch, undefined, valueToInt)
getCurrentEpochNumber = proxyCall(
this.contract.methods.getCurrentEpochNumber,
undefined,
valueToInt
)
getFirstBlockAtEpoch = proxyCall(
this.contract.methods.getFirstBlockAtEpoch,
undefined,
valueToInt
)
getLastBlockAtEpoch = proxyCall(this.contract.methods.getLastBlockAtEpoch, undefined, valueToInt)
isOnEpochProcess = proxyCall(this.contract.methods.isOnEpochProcess)
isTimeForNextEpoch = proxyCall(this.contract.methods.isTimeForNextEpoch)
getElected = proxyCall(this.contract.methods.getElected)
Expand Down
Loading