Skip to content

Commit 1ca736a

Browse files
committed
chore: remove casts from block to checkpoint number
Cleans up some lingering `CheckpointNumber.fromBlockNumber` uses. In a few tests, keeps the assumption that we work with one block per slot.
1 parent 8e7e4a4 commit 1ca736a

File tree

16 files changed

+122
-105
lines changed

16 files changed

+122
-105
lines changed

yarn-project/archiver/src/l1/bin/retrieve-calldata.ts

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
#!/usr/bin/env node
22
import type { ViemPublicClient, ViemPublicDebugClient } from '@aztec/ethereum/types';
3-
import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
3+
import { CheckpointNumber } from '@aztec/foundation/branded-types';
44
import { EthAddress } from '@aztec/foundation/eth-address';
55
import { createLogger } from '@aztec/foundation/log';
6+
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
67

7-
import { type Hex, createPublicClient, http } from 'viem';
8+
import { type Hex, createPublicClient, getAbiItem, http, toEventSelector } from 'viem';
89
import { mainnet } from 'viem/chains';
910

1011
import { CalldataRetriever } from '../calldata_retriever.js';
@@ -111,43 +112,36 @@ async function main() {
111112
},
112113
);
113114

114-
// Extract L2 block number from transaction logs
115-
logger.info('Decoding transaction to extract L2 block number...');
115+
// Extract checkpoint number from transaction logs
116+
logger.info('Decoding transaction to extract checkpoint number...');
116117
const receipt = await publicClient.getTransactionReceipt({ hash: txHash });
117-
const l2BlockProposedEvent = receipt.logs.find(log => {
118+
119+
// Look for CheckpointProposed event (emitted when a checkpoint is proposed to the rollup)
120+
// Event signature: CheckpointProposed(uint256 indexed checkpointNumber, bytes32 indexed archive, bytes32[], bytes32, bytes32)
121+
// Hash: keccak256("CheckpointProposed(uint256,bytes32,bytes32[],bytes32,bytes32)")
122+
const checkpointProposedEvent = receipt.logs.find(log => {
118123
try {
119-
// Try to match the L2BlockProposed event
120124
return (
121125
log.address.toLowerCase() === rollupAddress.toString().toLowerCase() &&
122-
log.topics[0] === '0x2f1d0e696fa5186494a2f2f89a0e0bcbb15d607f6c5eac4637e07e1e5e7d3c00' // L2BlockProposed event signature
126+
log.topics[0] === toEventSelector(getAbiItem({ abi: RollupAbi, name: 'CheckpointProposed' }))
123127
);
124128
} catch {
125129
return false;
126130
}
127131
});
128132

129-
let l2BlockNumber: number;
130-
if (l2BlockProposedEvent && l2BlockProposedEvent.topics[1]) {
131-
// L2 block number is typically the first indexed parameter
132-
l2BlockNumber = Number(BigInt(l2BlockProposedEvent.topics[1]));
133-
logger.info(`L2 Block Number (from event): ${l2BlockNumber}`);
134-
} else {
135-
// Fallback: try to extract from transaction data or use a default
136-
logger.warn('Could not extract L2 block number from event, using block number as fallback');
137-
l2BlockNumber = Number(tx.blockNumber);
133+
if (!checkpointProposedEvent || checkpointProposedEvent.topics[1] === undefined) {
134+
throw new Error(`Checkpoint proposed event not found`);
138135
}
139136

137+
const checkpointNumber = CheckpointNumber.fromBigInt(BigInt(checkpointProposedEvent.topics[1]));
138+
140139
logger.info('');
141-
logger.info('Retrieving block header from rollup transaction...');
140+
logger.info('Retrieving checkpoint from rollup transaction...');
142141
logger.info('');
143142

144143
// For this script, we don't have blob hashes or expected hashes, so pass empty arrays/objects
145-
const result = await retriever.getCheckpointFromRollupTx(
146-
txHash,
147-
[],
148-
CheckpointNumber.fromBlockNumber(BlockNumber(l2BlockNumber)),
149-
{},
150-
);
144+
const result = await retriever.getCheckpointFromRollupTx(txHash, [], checkpointNumber, {});
151145

152146
logger.info(' Successfully retrieved block header!');
153147
logger.info('');

yarn-project/end-to-end/src/composed/e2e_token_bridge_tutorial_test.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import { createAztecNodeClient, waitForNode } from '@aztec/aztec.js/node';
99
import { createExtendedL1Client } from '@aztec/ethereum/client';
1010
import { RollupContract } from '@aztec/ethereum/contracts';
1111
import { deployL1Contract } from '@aztec/ethereum/deploy-l1-contract';
12-
import { CheckpointNumber } from '@aztec/foundation/branded-types';
1312
import {
1413
FeeAssetHandlerAbi,
1514
FeeAssetHandlerBytecode,
@@ -218,7 +217,8 @@ describe('e2e_cross_chain_messaging token_bridge_tutorial_test', () => {
218217

219218
// docs:start:l1-withdraw
220219
const rollup = new RollupContract(l1Client, l1ContractAddresses.rollupAddress.toString());
221-
const epoch = await rollup.getEpochNumberForCheckpoint(CheckpointNumber.fromBlockNumber(l2TxReceipt.blockNumber!));
220+
const block = await node.getBlock(l2TxReceipt.blockNumber!);
221+
const epoch = await rollup.getEpochNumberForCheckpoint(block!.checkpointNumber);
222222

223223
const result = await computeL2ToL1MembershipWitness(node, epoch, l2ToL1Message);
224224
if (!result) {

yarn-project/end-to-end/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import type {
1313
} from '@aztec/ethereum/deploy-aztec-l1-contracts';
1414
import { deployL1Contract } from '@aztec/ethereum/deploy-l1-contract';
1515
import type { ExtendedViemWalletClient } from '@aztec/ethereum/types';
16-
import { CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types';
16+
import { EpochNumber } from '@aztec/foundation/branded-types';
1717
import { sleep } from '@aztec/foundation/sleep';
1818
import { TestERC20Abi, TestERC20Bytecode } from '@aztec/l1-artifacts';
1919
import { TokenContract } from '@aztec/noir-contracts.js/Token';
@@ -86,9 +86,8 @@ export class CrossChainMessagingTest {
8686
}
8787

8888
async advanceToEpochProven(l2TxReceipt: TxReceipt): Promise<EpochNumber> {
89-
const epoch = await this.rollup.getEpochNumberForCheckpoint(
90-
CheckpointNumber.fromBlockNumber(l2TxReceipt.blockNumber!),
91-
);
89+
const block = await this.aztecNode.getBlock(l2TxReceipt.blockNumber!);
90+
const epoch = await this.rollup.getEpochNumberForCheckpoint(block!.checkpointNumber);
9291
// Warp to the next epoch.
9392
await this.cheatCodes.rollup.advanceToEpoch(EpochNumber(epoch + 1));
9493
// Wait for the tx to be proven.

yarn-project/end-to-end/src/e2e_epochs/epochs_invalidate_block.parallel.test.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { RollupContract } from '@aztec/ethereum/contracts';
77
import type { Operator } from '@aztec/ethereum/deploy-aztec-l1-contracts';
88
import type { ExtendedViemWalletClient } from '@aztec/ethereum/types';
99
import { asyncMap } from '@aztec/foundation/async-map';
10-
import { CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
10+
import { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
1111
import { times } from '@aztec/foundation/collection';
1212
import { SecretValue } from '@aztec/foundation/config';
1313
import { EthAddress } from '@aztec/foundation/eth-address';
@@ -455,7 +455,8 @@ describe('e2e_epochs/epochs_invalidate_block', () => {
455455
const [event] = checkpointInvalidatedEvents;
456456
logger.warn(`CheckpointInvalidated event emitted`, { event });
457457
expect(event.args.checkpointNumber).toBeGreaterThan(initialBlockNumber);
458-
expect(await test.rollup.getCheckpointNumber()).toEqual(CheckpointNumber.fromBlockNumber(initialBlockNumber));
458+
const initialCheckpointNumber = await getCheckpointNumberForBlock(nodes[0], initialBlockNumber);
459+
expect(await test.rollup.getCheckpointNumber()).toEqual(initialCheckpointNumber);
459460

460461
logger.warn(`Test succeeded '${expect.getState().currentTestName}'`);
461462
});
@@ -511,7 +512,8 @@ describe('e2e_epochs/epochs_invalidate_block', () => {
511512
const [event] = checkpointInvalidatedEvents;
512513
logger.warn(`CheckpointInvalidated event emitted`, { event });
513514
expect(event.args.checkpointNumber).toBeGreaterThan(initialBlockNumber);
514-
expect(await test.rollup.getCheckpointNumber()).toEqual(CheckpointNumber.fromBlockNumber(initialBlockNumber));
515+
const initialCheckpointNumber = await getCheckpointNumberForBlock(nodes[0], initialBlockNumber);
516+
expect(await test.rollup.getCheckpointNumber()).toEqual(initialCheckpointNumber);
515517

516518
logger.warn(`Test succeeded '${expect.getState().currentTestName}'`);
517519
});
@@ -586,3 +588,17 @@ describe('e2e_epochs/epochs_invalidate_block', () => {
586588
logger.warn(`Test succeeded '${expect.getState().currentTestName}'`);
587589
});
588590
});
591+
592+
async function getCheckpointNumberForBlock(
593+
node: AztecNodeService,
594+
blockNumber: BlockNumber,
595+
): Promise<CheckpointNumber> {
596+
if (blockNumber === 0) {
597+
return CheckpointNumber(0);
598+
}
599+
const block = await node.getBlock(blockNumber);
600+
if (!block) {
601+
throw new Error(`Block ${blockNumber} not found`);
602+
}
603+
return block.checkpointNumber;
604+
}

yarn-project/end-to-end/src/e2e_epochs/epochs_multiple.test.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { EpochsTestContext, WORLD_STATE_BLOCK_HISTORY } from './epochs_test.js';
99

1010
jest.setTimeout(1000 * 60 * 15);
1111

12+
// Assumes one block per checkpoint
1213
describe('e2e_epochs/epochs_multiple', () => {
1314
let context: EndToEndContext;
1415
let rollup: RollupContract;
@@ -42,13 +43,14 @@ describe('e2e_epochs/epochs_multiple', () => {
4243
logger.info(`Reached proven checkpoint number ${epochEndCheckpointNumber}, epoch ${epochNumber} is now proven`);
4344
epochNumber++;
4445

45-
// Verify the state syncs
46-
await test.waitForNodeToSync(BlockNumber.fromCheckpointNumber(epochEndCheckpointNumber), 'proven');
47-
await test.verifyHistoricBlock(BlockNumber.fromCheckpointNumber(epochEndCheckpointNumber), true);
46+
// Verify the state syncs. Assumes one block per checkpoint.
47+
const epochEndBlockNumber = BlockNumber.fromCheckpointNumber(epochEndCheckpointNumber);
48+
await test.waitForNodeToSync(epochEndBlockNumber, 'proven');
49+
await test.verifyHistoricBlock(epochEndBlockNumber, true);
4850

4951
// Check that finalized blocks are purged from world state
5052
// Right now finalization means a checkpoint is two L2 epochs deep. If this rule changes then this test needs to be updated.
51-
const provenBlockNumber = BlockNumber.fromCheckpointNumber(epochEndCheckpointNumber);
53+
const provenBlockNumber = epochEndBlockNumber;
5254
const finalizedBlockNumber = Math.max(provenBlockNumber - context.config.aztecEpochDuration * 2, 0);
5355
const expectedOldestHistoricBlock = Math.max(finalizedBlockNumber - WORLD_STATE_BLOCK_HISTORY + 1, 1);
5456
const expectedBlockRemoved = expectedOldestHistoricBlock - 1;

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ describe('L1Publisher integration', () => {
196196
slicedBlocks.map(
197197
async block =>
198198
new CheckpointedL2Block(
199+
// Test uses 1-block-per-checkpoint, so checkpoint number equals block number
199200
CheckpointNumber.fromBlockNumber(block.number),
200201
block,
201202
new L1PublishedData(BigInt(block.number), BigInt(block.number), (await block.hash()).toString()),
@@ -205,6 +206,7 @@ describe('L1Publisher integration', () => {
205206
);
206207
},
207208
async getCheckpoints(checkpointNumber, _limit) {
209+
// Test uses 1-block-per-checkpoint, so we find block by checkpoint number
208210
const block = blocks.find(b => Number(b.number) === Number(checkpointNumber));
209211
if (!block) {
210212
return Promise.resolve([]);
@@ -213,7 +215,7 @@ describe('L1Publisher integration', () => {
213215
block.archive,
214216
CheckpointHeader.random({ lastArchiveRoot: block.header.lastArchive.root }),
215217
[block],
216-
CheckpointNumber.fromBlockNumber(block.number),
218+
checkpointNumber,
217219
);
218220
return [
219221
new PublishedCheckpoint(
@@ -228,6 +230,7 @@ describe('L1Publisher integration', () => {
228230
const blockId = latestBlock
229231
? { number: latestBlock.number, hash: (await latestBlock.hash()).toString() }
230232
: { number: BlockNumber.ZERO, hash: GENESIS_BLOCK_HEADER_HASH.toString() };
233+
// Test uses 1-block-per-checkpoint, so checkpoint number equals block number
231234
const tipId = {
232235
block: blockId,
233236
checkpoint: { number: CheckpointNumber.fromBlockNumber(blockId.number), hash: blockId.hash },
@@ -352,6 +355,7 @@ describe('L1Publisher integration', () => {
352355
gasFees: globalVariables.gasFees,
353356
};
354357

358+
// Test uses 1-block-per-checkpoint
355359
const checkpointNumber = CheckpointNumber.fromBlockNumber(globalVariables.blockNumber);
356360
const builder = await LightweightCheckpointBuilder.startNewCheckpoint(
357361
checkpointNumber,
@@ -491,7 +495,7 @@ describe('L1Publisher integration', () => {
491495
});
492496
expect(logs).toHaveLength(i + 1);
493497
expect(logs[i].args.checkpointNumber).toEqual(BigInt(i + 1));
494-
const thisCheckpointNumber = CheckpointNumber.fromBlockNumber(block.header.globalVariables.blockNumber);
498+
const thisCheckpointNumber = checkpoint.number;
495499
const prevCheckpointNumber = CheckpointNumber(thisCheckpointNumber - 1);
496500
const isFirstCheckpointOfEpoch =
497501
thisCheckpointNumber == CheckpointNumber(1) ||
@@ -895,7 +899,6 @@ describe('L1Publisher integration', () => {
895899

896900
it(`speeds up block proposal if not mined`, async () => {
897901
const { checkpoint } = await buildSingleCheckpoint();
898-
const block = checkpoint.blocks[0];
899902
await enqueueProposeL2Checkpoint(checkpoint);
900903
await sendRequests();
901904

@@ -925,7 +928,7 @@ describe('L1Publisher integration', () => {
925928
expect(minedTx).toBeDefined();
926929
const minedTxReceipt = await l1Client.getTransactionReceipt({ hash: minedTx!.hash });
927930
expect(minedTxReceipt.status).toEqual('success');
928-
expect(await rollup.getCheckpointNumber()).toEqual(CheckpointNumber.fromBlockNumber(block.number));
931+
expect(await rollup.getCheckpointNumber()).toEqual(checkpoint.number);
929932
});
930933

931934
it(`can send two consecutive proposals if the first one times out`, async () => {
@@ -978,8 +981,8 @@ describe('L1Publisher integration', () => {
978981
expect(sendRequestsResult).not.toBeNull();
979982
expect(sendRequestsResult!.successfulActions).toEqual(['propose']);
980983
expect(sendRequestsResult!.failedActions).toEqual([]);
981-
expect(await rollup.getCheckpointNumber()).toEqual(CheckpointNumber.fromBlockNumber(block2.number));
982-
const rollupBlock = await rollup.getCheckpoint(CheckpointNumber.fromBlockNumber(block2.number));
984+
expect(await rollup.getCheckpointNumber()).toEqual(checkpoint2.number);
985+
const rollupBlock = await rollup.getCheckpoint(checkpoint2.number);
983986
expect(rollupBlock.slotNumber).toEqual(block2.slot);
984987
});
985988
});

yarn-project/end-to-end/src/e2e_multi_validator/e2e_multi_validator_node.test.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { createExtendedL1Client } from '@aztec/ethereum/client';
1212
import { getL1ContractsConfigEnvVars } from '@aztec/ethereum/config';
1313
import { RollupContract } from '@aztec/ethereum/contracts';
1414
import type { DeployAztecL1ContractsReturnType } from '@aztec/ethereum/deploy-aztec-l1-contracts';
15-
import { CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types';
15+
import { EpochNumber } from '@aztec/foundation/branded-types';
1616
import { SecretValue } from '@aztec/foundation/config';
1717
import { Signature } from '@aztec/foundation/eth-signature';
1818
import { retryUntil } from '@aztec/foundation/retry';
@@ -127,7 +127,8 @@ describe('e2e_multi_validator_node', () => {
127127
expect(tx.blockNumber).toBeDefined();
128128

129129
const dataStore = (aztecNode as AztecNodeService).getBlockSource() as Archiver;
130-
const [publishedCheckpoint] = await dataStore.getCheckpoints(CheckpointNumber.fromBlockNumber(tx.blockNumber!), 1);
130+
const checkpointedBlock = await dataStore.getCheckpointedBlock(tx.blockNumber!);
131+
const [publishedCheckpoint] = await dataStore.getCheckpoints(checkpointedBlock!.checkpointNumber, 1);
131132
const payload = ConsensusPayload.fromCheckpoint(publishedCheckpoint.checkpoint);
132133
const attestations = publishedCheckpoint.attestations
133134
.filter(a => !a.signature.isEmpty())
@@ -139,6 +140,7 @@ describe('e2e_multi_validator_node', () => {
139140

140141
expect(signers.every(s => validatorAddresses.includes(s))).toBe(true);
141142
});
143+
142144
it('should attest ONLY with the correct validator keys', async () => {
143145
const rollupContract1 = getContract({
144146
address: deployL1ContractsValues.l1ContractAddresses.rollupAddress.toString(),
@@ -188,7 +190,8 @@ describe('e2e_multi_validator_node', () => {
188190
expect(tx.blockNumber).toBeDefined();
189191

190192
const dataStore = (aztecNode as AztecNodeService).getBlockSource() as Archiver;
191-
const [publishedCheckpoint] = await dataStore.getCheckpoints(CheckpointNumber.fromBlockNumber(tx.blockNumber!), 1);
193+
const checkpointedBlock = await dataStore.getCheckpointedBlock(tx.blockNumber!);
194+
const [publishedCheckpoint] = await dataStore.getCheckpoints(checkpointedBlock!.checkpointNumber, 1);
192195
const payload = ConsensusPayload.fromCheckpoint(publishedCheckpoint.checkpoint);
193196
const attestations = publishedCheckpoint.attestations
194197
.filter(a => !a.signature.isEmpty())

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -350,9 +350,8 @@ describe('e2e_p2p_add_rollup', () => {
350350
});
351351

352352
const rollup = new RollupContract(l1Client, l1ContractAddresses.rollupAddress);
353-
const epoch = await rollup.getEpochNumberForCheckpoint(
354-
CheckpointNumber.fromBlockNumber(l2OutgoingReceipt.blockNumber!),
355-
);
353+
const block = await node.getBlock(l2OutgoingReceipt.blockNumber!);
354+
const epoch = await rollup.getEpochNumberForCheckpoint(block!.checkpointNumber);
356355

357356
const l2ToL1MessageResult = (await computeL2ToL1MembershipWitness(node, epoch, leaf))!;
358357
const leafId = getL2ToL1MessageLeafId(l2ToL1MessageResult);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import type { Archiver } from '@aztec/archiver';
22
import type { AztecNodeConfig, AztecNodeService } from '@aztec/aztec-node';
33
import { waitForTx } from '@aztec/aztec.js/node';
44
import { TxHash } from '@aztec/aztec.js/tx';
5-
import { CheckpointNumber } from '@aztec/foundation/branded-types';
65
import { Signature } from '@aztec/foundation/eth-signature';
76
import { retryUntil } from '@aztec/foundation/retry';
87
import { sleep } from '@aztec/foundation/sleep';
@@ -190,7 +189,8 @@ describe('e2e_p2p_network', () => {
190189
const receipt = await nodes[0].getTxReceipt(txsSentViaDifferentNodes[0][0]);
191190
const blockNumber = receipt.blockNumber!;
192191
const dataStore = (nodes[0] as AztecNodeService).getBlockSource() as Archiver;
193-
const [publishedCheckpoint] = await dataStore.getCheckpoints(CheckpointNumber.fromBlockNumber(blockNumber), 1);
192+
const checkpointedBlock = await dataStore.getCheckpointedBlock(blockNumber);
193+
const [publishedCheckpoint] = await dataStore.getCheckpoints(checkpointedBlock!.checkpointNumber, 1);
194194
const payload = ConsensusPayload.fromCheckpoint(publishedCheckpoint.checkpoint);
195195
const attestations = publishedCheckpoint.attestations
196196
.filter(a => !a.signature.isEmpty())

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { waitForTx } from '@aztec/aztec.js/node';
66
import { TxHash } from '@aztec/aztec.js/tx';
77
import { addL1Validator } from '@aztec/cli/l1/validators';
88
import { RollupContract } from '@aztec/ethereum/contracts';
9-
import { CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types';
9+
import { EpochNumber } from '@aztec/foundation/branded-types';
1010
import { Signature } from '@aztec/foundation/eth-signature';
1111
import { sleep } from '@aztec/foundation/sleep';
1212
import { MockZKPassportVerifierAbi } from '@aztec/l1-artifacts/MockZKPassportVerifierAbi';
@@ -224,7 +224,8 @@ describe('e2e_p2p_network', () => {
224224
// Gather signers from attestations downloaded from L1
225225
const blockNumber = await nodes[0].getTxReceipt(txsSentViaDifferentNodes[0][0]).then(r => r.blockNumber!);
226226
const dataStore = (nodes[0] as AztecNodeService).getBlockSource() as Archiver;
227-
const [publishedCheckpoint] = await dataStore.getCheckpoints(CheckpointNumber.fromBlockNumber(blockNumber), 1);
227+
const checkpointedBlock = await dataStore.getCheckpointedBlock(blockNumber);
228+
const [publishedCheckpoint] = await dataStore.getCheckpoints(checkpointedBlock!.checkpointNumber, 1);
228229
const payload = ConsensusPayload.fromCheckpoint(publishedCheckpoint.checkpoint);
229230
const attestations = publishedCheckpoint.attestations
230231
.filter(a => !a.signature.isEmpty())

0 commit comments

Comments
 (0)