Skip to content

Commit cab0c0d

Browse files
committed
fix: Wait for flushable epoch using actual current epoch
Turns out the rollup contract method `getEpochNumber` did NOT return the current epoch number: it retutned the epoch number for the latest pending block, so if there was no block production, this number would not increase. This is now fixed by removing that method in favor of a `getEpochNumberForBlock` and `getCurrentEpochNumber`, and using the latter in the queue flush. Also fixed the deploy-l1-contracts test to handle this and artificially bump the epoch when testing the flush.
1 parent 08cc68b commit cab0c0d

File tree

10 files changed

+77
-30
lines changed

10 files changed

+77
-30
lines changed

.test_patterns.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,6 @@ tests:
273273
error_regex: "Failed to fetch dynamically imported module"
274274
owners:
275275
- *alex
276-
- regex: "ethereum/src/deploy_l1_contracts.test.ts"
277-
owners:
278-
- *palla
279276
- regex: "ethereum/src/test/tx_delayer.test.ts"
280277
error_regex: "delays a transaction until a given L1 timestamp"
281278
owners:

yarn-project/cli/src/cmds/l1/update_l1_validators.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ export async function debugRollup({ rpcUrls, chainId, rollupAddress, log }: Roll
308308
log(`Committee: ${committee?.map(v => v.toString()).join(', ')}`);
309309
const archive = await rollup.archive();
310310
log(`Archive: ${archive}`);
311-
const epochNum = await rollup.getEpochNumber();
311+
const epochNum = await rollup.getCurrentEpochNumber();
312312
log(`Current epoch: ${epochNum}`);
313313
const slot = await rollup.getSlotNumber();
314314
log(`Current slot: ${slot}`);

yarn-project/end-to-end/src/e2e_l1_publisher/e2e_l1_publisher.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,8 @@ describe('L1Publisher integration', () => {
444444
const thisBlockNumber = BigInt(block.header.globalVariables.blockNumber);
445445
const isFirstBlockOfEpoch =
446446
thisBlockNumber == 1n ||
447-
(await rollup.getEpochNumber(thisBlockNumber)) > (await rollup.getEpochNumber(thisBlockNumber - 1n));
447+
(await rollup.getEpochNumberForBlock(thisBlockNumber)) >
448+
(await rollup.getEpochNumberForBlock(thisBlockNumber - 1n));
448449
// If we are at the first blob of the epoch, we must initialize the hash:
449450
prevBlobAccumulatorHash = isFirstBlockOfEpoch ? Buffer.alloc(0) : prevBlobAccumulatorHash;
450451
const currentBlobAccumulatorHash = hexToBuffer(await rollup.getCurrentBlobCommitmentsHash());

yarn-project/end-to-end/src/e2e_p2p/add_rollup.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ describe('e2e_p2p_add_rollup', () => {
474474

475475
// With all down, we make a time jump such that we ensure that we will be at a point where epochs are non-empty
476476
// This is to avoid conflicts when the checkpoints are looking further back.
477-
const futureEpoch = 500n + (await newRollup.getEpochNumber());
477+
const futureEpoch = 500n + (await newRollup.getCurrentEpochNumber());
478478
const time = await newRollup.getTimestampForSlot(futureEpoch * BigInt(t.ctx.aztecNodeConfig.aztecEpochDuration));
479479
if (time > BigInt(await t.ctx.cheatCodes.eth.timestamp())) {
480480
await t.ctx.cheatCodes.eth.warp(Number(time));

yarn-project/epoch-cache/src/epoch_cache.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ export class EpochCache implements EpochCacheInterface {
116116
rollup.getL1GenesisTime(),
117117
rollup.getCurrentEpochCommittee(),
118118
rollup.getCurrentSampleSeed(),
119-
rollup.getEpochNumber(),
119+
rollup.getCurrentEpochNumber(),
120120
rollup.getProofSubmissionEpochs(),
121121
rollup.getSlotDuration(),
122122
rollup.getEpochDuration(),

yarn-project/ethereum/src/contracts/rollup.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -446,8 +446,11 @@ export class RollupContract {
446446
return this.rollup.read.getNextFlushableEpoch();
447447
}
448448

449-
async getEpochNumber(blockNumber?: bigint) {
450-
blockNumber ??= await this.getBlockNumber();
449+
getCurrentEpochNumber(): Promise<bigint> {
450+
return this.rollup.read.getCurrentEpoch();
451+
}
452+
453+
getEpochNumberForBlock(blockNumber: bigint) {
451454
return this.rollup.read.getEpochForBlock([BigInt(blockNumber)]);
452455
}
453456

yarn-project/ethereum/src/deploy_l1_contracts.test.ts

Lines changed: 60 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { GSEContract } from './contracts/gse.js';
1515
import { RegistryContract } from './contracts/registry.js';
1616
import { RollupContract } from './contracts/rollup.js';
1717
import { type DeployL1ContractsArgs, type Operator, deployL1Contracts } from './deploy_l1_contracts.js';
18+
import { EthCheatCodes } from './test/eth_cheat_codes.js';
1819
import { startAnvil } from './test/start_anvil.js';
1920
import type { ExtendedViemWalletClient } from './types.js';
2021

@@ -26,13 +27,16 @@ describe('deploy_l1_contracts', () => {
2627
let protocolContractTreeRoot: Fr;
2728
let genesisArchiveRoot: Fr;
2829
let initialValidators: Operator[];
30+
let timeout: NodeJS.Timeout;
2931

3032
// Use these environment variables to run against a live node. Eg to test against spartan's eth-devnet:
3133
// BLOCK_TIME=1 spartan/aztec-network/eth-devnet/run-locally.sh
3234
// LOG_LEVEL=verbose L1_RPC_URL=http://localhost:8545 L1_CHAIN_ID=1337 yarn test deploy_l1_contracts
3335
const chainId = process.env.L1_CHAIN_ID ? parseInt(process.env.L1_CHAIN_ID, 10) : 31337;
36+
3437
let rpcUrl = process.env.L1_RPC_URL;
3538
let client: ExtendedViemWalletClient;
39+
let cheat: EthCheatCodes;
3640
let stop: () => Promise<void> = () => Promise.resolve();
3741

3842
beforeAll(async () => {
@@ -53,9 +57,14 @@ describe('deploy_l1_contracts', () => {
5357
}
5458

5559
client = createExtendedL1Client([rpcUrl], privateKey, createEthereumChain([rpcUrl], chainId).chainInfo);
60+
cheat = new EthCheatCodes([rpcUrl]);
5661
});
5762

5863
afterAll(async () => {
64+
if (timeout) {
65+
clearTimeout(timeout);
66+
}
67+
5968
if (stop) {
6069
try {
6170
await stop();
@@ -65,17 +74,26 @@ describe('deploy_l1_contracts', () => {
6574
}
6675
});
6776

68-
const deploy = (args: Partial<DeployL1ContractsArgs> = {}) =>
69-
deployL1Contracts([rpcUrl!], privateKey, createEthereumChain([rpcUrl!], chainId).chainInfo, logger, {
70-
...DefaultL1ContractsConfig,
71-
salt: undefined,
72-
vkTreeRoot,
73-
protocolContractTreeRoot,
74-
genesisArchiveRoot,
75-
l1TxConfig: { checkIntervalMs: 100 },
76-
realVerifier: false,
77-
...args,
78-
});
77+
const deploy = (args: Partial<DeployL1ContractsArgs> & { flushEntryQueue?: boolean } = {}) =>
78+
deployL1Contracts(
79+
[rpcUrl!],
80+
privateKey,
81+
createEthereumChain([rpcUrl!], chainId).chainInfo,
82+
logger,
83+
{
84+
...DefaultL1ContractsConfig,
85+
salt: undefined,
86+
vkTreeRoot,
87+
protocolContractTreeRoot,
88+
genesisArchiveRoot,
89+
l1TxConfig: { checkIntervalMs: 100 },
90+
realVerifier: false,
91+
...args,
92+
},
93+
undefined,
94+
false,
95+
args.flushEntryQueue ?? true,
96+
);
7997

8098
const getRollup = (deployed: Awaited<ReturnType<typeof deploy>>) =>
8199
new RollupContract(deployed.l1Client, deployed.l1ContractAddresses.rollupAddress);
@@ -147,22 +165,48 @@ describe('deploy_l1_contracts', () => {
147165
});
148166

149167
it('deploys and adds 48 initialValidators', async () => {
150-
// Adds 48 validators.
151-
// Note, that not all 48 validators is necessarily added in the active set, some might be in the entry queue
152-
168+
// Adds 48 validators. Note, that not all 48 validators is necessarily added in the active set, some might be in the entry queue
153169
const initialValidators = times(48, () => {
154170
const addr = EthAddress.random();
155171
const bn254SecretKey = new SecretValue(Fr.random().toBigInt());
156172
return { attester: addr, withdrawer: addr, bn254SecretKey };
157173
});
158-
const info = await deploy({ initialValidators, aztecTargetCommitteeSize: initialValidators.length });
159-
const rollup = new RollupContract(client, info.l1ContractAddresses.rollupAddress);
160174

175+
const info = await deploy({
176+
initialValidators,
177+
aztecTargetCommitteeSize: initialValidators.length,
178+
flushEntryQueue: false,
179+
});
180+
181+
const rollup = new RollupContract(client, info.l1ContractAddresses.rollupAddress);
161182
expect((await rollup.getActiveAttesterCount()) + (await rollup.getEntryQueueLength())).toEqual(
162183
BigInt(initialValidators.length),
163184
);
164185
});
165186

187+
it('deploys and flushes 48 initialValidators', async () => {
188+
// Adds 48 validators. This time we flush the entry queue so we can verify that the flushing logic works as expected.
189+
const initialValidators = times(48, () => {
190+
const addr = EthAddress.random();
191+
const bn254SecretKey = new SecretValue(Fr.random().toBigInt());
192+
return { attester: addr, withdrawer: addr, bn254SecretKey };
193+
});
194+
195+
// Set an interval to advance the chain, otherwise we get stuck in "Waiting for next flushable epoch"
196+
let timestamp = await client.getBlock({ includeTransactions: false }).then(b => b.timestamp);
197+
timeout = setInterval(() => void cheat.warp((timestamp += 60n * 60n)), 1000);
198+
199+
const info = await deploy({
200+
initialValidators,
201+
aztecTargetCommitteeSize: initialValidators.length,
202+
flushEntryQueue: true,
203+
});
204+
const rollup = new RollupContract(client, info.l1ContractAddresses.rollupAddress);
205+
206+
expect(await rollup.getEntryQueueLength()).toEqual(0n);
207+
expect(await rollup.getActiveAttesterCount()).toEqual(BigInt(initialValidators.length));
208+
});
209+
166210
it('ensure governance is the owner', async () => {
167211
// Runs the deployment script and checks if we have handed over things correctly to the governance.
168212

yarn-project/ethereum/src/deploy_l1_contracts.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -939,7 +939,7 @@ export const addMultipleValidators = async (
939939

940940
let queueLength = await rollup.getEntryQueueLength();
941941
while (flushEntryQueue && queueLength > 0n) {
942-
logger.info(`Flushing entry queue`);
942+
logger.info(`Flushing entry queue with ${queueLength} entries`);
943943

944944
try {
945945
await deployer.l1TxUtils.sendAndMonitorTransaction(
@@ -965,12 +965,14 @@ export const addMultipleValidators = async (
965965
break;
966966
}
967967

968+
logger.info(`Waiting for next flushable epoch to flush remaining ${queueLength} entries`);
968969
await retryUntil(
969970
async () => {
970971
const [currentEpoch, flushableEpoch] = await Promise.all([
971-
rollup.getEpochNumber(),
972+
rollup.getCurrentEpochNumber(),
972973
rollup.getNextFlushableEpoch(),
973974
]);
975+
logger.debug(`Next flushable epoch is ${flushableEpoch} (current epoch is ${currentEpoch})`);
974976
return currentEpoch >= flushableEpoch;
975977
},
976978
'wait for next flushable epoch',

yarn-project/ethereum/src/test/chain_monitor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ export class ChainMonitor extends EventEmitter<ChainMonitorEventMap> {
116116

117117
const newL2BlockNumber = Number(await this.rollup.getBlockNumber());
118118
if (this.l2BlockNumber !== newL2BlockNumber) {
119-
const epochNumber = await this.rollup.getEpochNumber(BigInt(newL2BlockNumber));
119+
const epochNumber = await this.rollup.getEpochNumberForBlock(BigInt(newL2BlockNumber));
120120
msg += ` with new L2 block ${newL2BlockNumber} for epoch ${epochNumber}`;
121121
this.l2BlockNumber = newL2BlockNumber;
122122
this.l2BlockTimestamp = timestamp;
@@ -130,7 +130,7 @@ export class ChainMonitor extends EventEmitter<ChainMonitorEventMap> {
130130

131131
const newL2ProvenBlockNumber = Number(await this.rollup.getProvenBlockNumber());
132132
if (this.l2ProvenBlockNumber !== newL2ProvenBlockNumber) {
133-
const epochNumber = await this.rollup.getEpochNumber(BigInt(newL2ProvenBlockNumber));
133+
const epochNumber = await this.rollup.getEpochNumberForBlock(BigInt(newL2ProvenBlockNumber));
134134
msg += ` with proof up to L2 block ${newL2ProvenBlockNumber} for epoch ${epochNumber}`;
135135
this.l2ProvenBlockNumber = newL2ProvenBlockNumber;
136136
this.l2ProvenBlockTimestamp = timestamp;

yarn-project/prover-node/src/metrics.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export class ProverNodeRewardsMetrics {
9191
}
9292

9393
private observe = async (observer: BatchObservableResult): Promise<void> => {
94-
const epoch = await this.rollup.getEpochNumber();
94+
const epoch = await this.rollup.getCurrentEpochNumber();
9595

9696
if (epoch > this.proofSubmissionEpochs) {
9797
// look at the prev epoch so that we get an accurate value, after proof submission window has closed

0 commit comments

Comments
 (0)