@aztec/archiver 3.0.0-nightly.20251127 → 3.0.0-nightly.20251201.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dest/archiver/archiver.d.ts +25 -18
  2. package/dest/archiver/archiver.d.ts.map +1 -1
  3. package/dest/archiver/archiver.js +221 -163
  4. package/dest/archiver/archiver_store.d.ts +1 -1
  5. package/dest/archiver/archiver_store_test_suite.d.ts +1 -1
  6. package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
  7. package/dest/archiver/archiver_store_test_suite.js +5 -4
  8. package/dest/archiver/config.d.ts +1 -1
  9. package/dest/archiver/data_retrieval.d.ts +15 -15
  10. package/dest/archiver/data_retrieval.d.ts.map +1 -1
  11. package/dest/archiver/data_retrieval.js +56 -61
  12. package/dest/archiver/errors.d.ts +1 -1
  13. package/dest/archiver/errors.d.ts.map +1 -1
  14. package/dest/archiver/index.d.ts +1 -1
  15. package/dest/archiver/instrumentation.d.ts +3 -3
  16. package/dest/archiver/instrumentation.d.ts.map +1 -1
  17. package/dest/archiver/kv_archiver_store/block_store.d.ts +1 -1
  18. package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
  19. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +1 -1
  20. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +1 -1
  21. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +1 -1
  22. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +1 -1
  23. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +2 -2
  24. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
  25. package/dest/archiver/kv_archiver_store/log_store.d.ts +1 -1
  26. package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
  27. package/dest/archiver/kv_archiver_store/message_store.d.ts +1 -1
  28. package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
  29. package/dest/archiver/structs/data_retrieval.d.ts +1 -1
  30. package/dest/archiver/structs/inbox_message.d.ts +1 -1
  31. package/dest/archiver/structs/published.d.ts +3 -2
  32. package/dest/archiver/structs/published.d.ts.map +1 -1
  33. package/dest/archiver/validation.d.ts +10 -4
  34. package/dest/archiver/validation.d.ts.map +1 -1
  35. package/dest/archiver/validation.js +25 -17
  36. package/dest/factory.d.ts +1 -1
  37. package/dest/index.d.ts +2 -2
  38. package/dest/index.d.ts.map +1 -1
  39. package/dest/index.js +1 -1
  40. package/dest/rpc/index.d.ts +2 -2
  41. package/dest/test/index.d.ts +1 -1
  42. package/dest/test/mock_archiver.d.ts +1 -1
  43. package/dest/test/mock_archiver.d.ts.map +1 -1
  44. package/dest/test/mock_l1_to_l2_message_source.d.ts +1 -1
  45. package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
  46. package/dest/test/mock_l2_block_source.d.ts +7 -6
  47. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  48. package/dest/test/mock_l2_block_source.js +1 -1
  49. package/dest/test/mock_structs.d.ts +1 -1
  50. package/package.json +16 -16
  51. package/src/archiver/archiver.ts +294 -196
  52. package/src/archiver/archiver_store_test_suite.ts +5 -4
  53. package/src/archiver/data_retrieval.ts +70 -81
  54. package/src/archiver/instrumentation.ts +2 -2
  55. package/src/archiver/structs/published.ts +2 -1
  56. package/src/archiver/validation.ts +40 -19
  57. package/src/index.ts +1 -1
  58. package/src/test/mock_l2_block_source.ts +7 -6
@@ -4,6 +4,7 @@ import {
4
4
  PRIVATE_LOG_SIZE_IN_FIELDS,
5
5
  } from '@aztec/constants';
6
6
  import { makeTuple } from '@aztec/foundation/array';
7
+ import { EpochNumber } from '@aztec/foundation/branded-types';
7
8
  import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
8
9
  import { times, timesParallel } from '@aztec/foundation/collection';
9
10
  import { randomInt } from '@aztec/foundation/crypto';
@@ -1189,7 +1190,7 @@ export function describeArchiverDataStore(
1189
1190
  valid: false,
1190
1191
  block: randomBlockInfo(1),
1191
1192
  committee: [EthAddress.random(), EthAddress.random()],
1192
- epoch: 123n,
1193
+ epoch: EpochNumber(123),
1193
1194
  seed: 456n,
1194
1195
  attestors: [EthAddress.random()],
1195
1196
  attestations: [CommitteeAttestation.random()],
@@ -1208,7 +1209,7 @@ export function describeArchiverDataStore(
1208
1209
  block: randomBlockInfo(2),
1209
1210
  committee: [EthAddress.random()],
1210
1211
  attestors: [EthAddress.random()],
1211
- epoch: 789n,
1212
+ epoch: EpochNumber(789),
1212
1213
  seed: 101n,
1213
1214
  attestations: [CommitteeAttestation.random()],
1214
1215
  reason: 'invalid-attestation',
@@ -1227,7 +1228,7 @@ export function describeArchiverDataStore(
1227
1228
  valid: false,
1228
1229
  block: randomBlockInfo(3),
1229
1230
  committee: [EthAddress.random()],
1230
- epoch: 999n,
1231
+ epoch: EpochNumber(999),
1231
1232
  seed: 888n,
1232
1233
  attestors: [EthAddress.random()],
1233
1234
  attestations: [CommitteeAttestation.random()],
@@ -1246,7 +1247,7 @@ export function describeArchiverDataStore(
1246
1247
  valid: false,
1247
1248
  block: randomBlockInfo(4),
1248
1249
  committee: [],
1249
- epoch: 0n,
1250
+ epoch: EpochNumber(0),
1250
1251
  seed: 0n,
1251
1252
  attestors: [],
1252
1253
  attestations: [],
@@ -12,7 +12,6 @@ import type {
12
12
  ViemCommitteeAttestations,
13
13
  ViemHeader,
14
14
  ViemPublicClient,
15
- ViemStateReference,
16
15
  } from '@aztec/ethereum';
17
16
  import { asyncPool } from '@aztec/foundation/async-pool';
18
17
  import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
@@ -21,7 +20,8 @@ import type { ViemSignature } from '@aztec/foundation/eth-signature';
21
20
  import { Fr } from '@aztec/foundation/fields';
22
21
  import { type Logger, createLogger } from '@aztec/foundation/log';
23
22
  import { type InboxAbi, RollupAbi } from '@aztec/l1-artifacts';
24
- import { Body, CommitteeAttestation, L2Block, L2BlockHeader, PublishedL2Block } from '@aztec/stdlib/block';
23
+ import { Body, CommitteeAttestation, L2BlockNew } from '@aztec/stdlib/block';
24
+ import { Checkpoint, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
25
25
  import { Proof } from '@aztec/stdlib/proofs';
26
26
  import { CheckpointHeader } from '@aztec/stdlib/rollup';
27
27
  import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
@@ -42,9 +42,9 @@ import type { DataRetrieval } from './structs/data_retrieval.js';
42
42
  import type { InboxMessage } from './structs/inbox_message.js';
43
43
  import type { L1PublishedData } from './structs/published.js';
44
44
 
45
- export type RetrievedL2Block = {
45
+ export type RetrievedCheckpoint = {
46
+ checkpointNumber: number;
46
47
  archiveRoot: Fr;
47
- stateReference: StateReference;
48
48
  header: CheckpointHeader;
49
49
  checkpointBlobData: CheckpointBlobData;
50
50
  l1: L1PublishedData;
@@ -53,16 +53,16 @@ export type RetrievedL2Block = {
53
53
  attestations: CommitteeAttestation[];
54
54
  };
55
55
 
56
- export async function retrievedBlockToPublishedL2Block({
56
+ export async function retrievedToPublishedCheckpoint({
57
+ checkpointNumber,
57
58
  archiveRoot,
58
- stateReference,
59
59
  header: checkpointHeader,
60
60
  checkpointBlobData,
61
61
  l1,
62
62
  chainId,
63
63
  version,
64
64
  attestations,
65
- }: RetrievedL2Block): Promise<PublishedL2Block> {
65
+ }: RetrievedCheckpoint): Promise<PublishedCheckpoint> {
66
66
  const { blocks: blocksBlobData } = checkpointBlobData;
67
67
 
68
68
  // The lastArchiveRoot of a block is the new archive for the previous block.
@@ -76,7 +76,7 @@ export async function retrievedBlockToPublishedL2Block({
76
76
  const l1toL2MessageTreeRoot = blocksBlobData[0].l1ToL2MessageRoot!;
77
77
 
78
78
  const spongeBlob = SpongeBlob.init();
79
- const l2Blocks: L2Block[] = [];
79
+ const l2Blocks: L2BlockNew[] = [];
80
80
  for (let i = 0; i < blocksBlobData.length; i++) {
81
81
  const blockBlobData = blocksBlobData[i];
82
82
  const { blockEndMarker, blockEndStateField, lastArchiveRoot, noteHashRoot, nullifierRoot, publicDataRoot } =
@@ -115,7 +115,7 @@ export async function retrievedBlockToPublishedL2Block({
115
115
  const clonedSpongeBlob = spongeBlob.clone();
116
116
  const spongeBlobHash = await clonedSpongeBlob.squeeze();
117
117
 
118
- const blockHeader = BlockHeader.from({
118
+ const header = BlockHeader.from({
119
119
  lastArchive: new AppendOnlyTreeSnapshot(lastArchiveRoot, l2BlockNumber),
120
120
  state,
121
121
  spongeBlobHash,
@@ -124,31 +124,24 @@ export async function retrievedBlockToPublishedL2Block({
124
124
  totalManaUsed: new Fr(blockEndStateField.totalManaUsed),
125
125
  });
126
126
 
127
- const header = L2BlockHeader.from({
128
- ...blockHeader,
129
- blockHeadersHash: checkpointHeader.blockHeadersHash,
130
- contentCommitment: checkpointHeader.contentCommitment,
131
- });
132
-
133
127
  const newArchive = new AppendOnlyTreeSnapshot(newArchiveRoots[i], l2BlockNumber + 1);
134
128
 
135
- l2Blocks.push(new L2Block(newArchive, header, body));
129
+ l2Blocks.push(new L2BlockNew(newArchive, header, body));
136
130
  }
137
131
 
138
- const lastBlock = l2Blocks[l2Blocks.length - 1];
139
- if (!lastBlock.header.state.equals(stateReference)) {
140
- throw new Error(
141
- 'The claimed state reference submitted to L1 does not match the state reference of the last block.',
142
- );
143
- }
132
+ const lastBlock = l2Blocks.at(-1)!;
133
+ const checkpoint = Checkpoint.from({
134
+ archive: new AppendOnlyTreeSnapshot(archiveRoot, lastBlock.number + 1),
135
+ header: checkpointHeader,
136
+ blocks: l2Blocks,
137
+ number: checkpointNumber,
138
+ });
144
139
 
145
- // TODO(#17027)
146
- // There's only one block per checkpoint at the moment.
147
- return PublishedL2Block.fromFields({ block: l2Blocks[0], l1, attestations });
140
+ return PublishedCheckpoint.from({ checkpoint, l1, attestations });
148
141
  }
149
142
 
150
143
  /**
151
- * Fetches new L2 blocks.
144
+ * Fetches new checkpoints.
152
145
  * @param publicClient - The viem public client to use for transaction retrieval.
153
146
  * @param rollupAddress - The address of the rollup contract.
154
147
  * @param searchStartBlock - The block number to use for starting the search.
@@ -156,15 +149,15 @@ export async function retrievedBlockToPublishedL2Block({
156
149
  * @param expectedNextL2BlockNum - The next L2 block number that we expect to find.
157
150
  * @returns An array of block; as well as the next eth block to search from.
158
151
  */
159
- export async function retrieveBlocksFromRollup(
152
+ export async function retrieveCheckpointsFromRollup(
160
153
  rollup: GetContractReturnType<typeof RollupAbi, ViemPublicClient>,
161
154
  publicClient: ViemPublicClient,
162
155
  blobSinkClient: BlobSinkClientInterface,
163
156
  searchStartBlock: bigint,
164
157
  searchEndBlock: bigint,
165
158
  logger: Logger = createLogger('archiver'),
166
- ): Promise<RetrievedL2Block[]> {
167
- const retrievedBlocks: RetrievedL2Block[] = [];
159
+ ): Promise<RetrievedCheckpoint[]> {
160
+ const retrievedCheckpoints: RetrievedCheckpoint[] = [];
168
161
 
169
162
  let rollupConstants: { chainId: Fr; version: Fr; targetCommitteeSize: number } | undefined;
170
163
 
@@ -172,7 +165,7 @@ export async function retrieveBlocksFromRollup(
172
165
  if (searchStartBlock > searchEndBlock) {
173
166
  break;
174
167
  }
175
- const l2BlockProposedLogs = (
168
+ const checkpointProposedLogs = (
176
169
  await rollup.getEvents.CheckpointProposed(
177
170
  {},
178
171
  {
@@ -182,13 +175,13 @@ export async function retrieveBlocksFromRollup(
182
175
  )
183
176
  ).filter(log => log.blockNumber! >= searchStartBlock && log.blockNumber! <= searchEndBlock);
184
177
 
185
- if (l2BlockProposedLogs.length === 0) {
178
+ if (checkpointProposedLogs.length === 0) {
186
179
  break;
187
180
  }
188
181
 
189
- const lastLog = l2BlockProposedLogs[l2BlockProposedLogs.length - 1];
182
+ const lastLog = checkpointProposedLogs.at(-1)!;
190
183
  logger.debug(
191
- `Got ${l2BlockProposedLogs.length} L2 block processed logs for L2 blocks ${l2BlockProposedLogs[0].args.checkpointNumber}-${lastLog.args.checkpointNumber} between L1 blocks ${searchStartBlock}-${searchEndBlock}`,
184
+ `Got ${checkpointProposedLogs.length} processed logs for checkpoints ${checkpointProposedLogs[0].args.checkpointNumber}-${lastLog.args.checkpointNumber} between L1 blocks ${searchStartBlock}-${searchEndBlock}`,
192
185
  );
193
186
 
194
187
  if (rollupConstants === undefined) {
@@ -204,52 +197,52 @@ export async function retrieveBlocksFromRollup(
204
197
  };
205
198
  }
206
199
 
207
- const newBlocks = await processL2BlockProposedLogs(
200
+ const newCheckpoints = await processCheckpointProposedLogs(
208
201
  rollup,
209
202
  publicClient,
210
203
  blobSinkClient,
211
- l2BlockProposedLogs,
204
+ checkpointProposedLogs,
212
205
  rollupConstants,
213
206
  logger,
214
207
  );
215
- retrievedBlocks.push(...newBlocks);
208
+ retrievedCheckpoints.push(...newCheckpoints);
216
209
  searchStartBlock = lastLog.blockNumber! + 1n;
217
210
  } while (searchStartBlock <= searchEndBlock);
218
211
 
219
- // The asyncpool from processL2BlockProposedLogs will not necessarily return the blocks in order, so we sort them before returning.
220
- return retrievedBlocks.sort((a, b) => Number(a.l1.blockNumber - b.l1.blockNumber));
212
+ // The asyncPool from processCheckpointProposedLogs will not necessarily return the checkpoints in order, so we sort them before returning.
213
+ return retrievedCheckpoints.sort((a, b) => Number(a.l1.blockNumber - b.l1.blockNumber));
221
214
  }
222
215
 
223
216
  /**
224
- * Processes newly received L2BlockProposed logs.
217
+ * Processes newly received CheckpointProposed logs.
225
218
  * @param rollup - The rollup contract
226
219
  * @param publicClient - The viem public client to use for transaction retrieval.
227
- * @param logs - L2BlockProposed logs.
228
- * @returns - An array blocks.
220
+ * @param logs - CheckpointProposed logs.
221
+ * @returns - An array of checkpoints.
229
222
  */
230
- async function processL2BlockProposedLogs(
223
+ async function processCheckpointProposedLogs(
231
224
  rollup: GetContractReturnType<typeof RollupAbi, ViemPublicClient>,
232
225
  publicClient: ViemPublicClient,
233
226
  blobSinkClient: BlobSinkClientInterface,
234
227
  logs: GetContractEventsReturnType<typeof RollupAbi, 'CheckpointProposed'>,
235
228
  { chainId, version, targetCommitteeSize }: { chainId: Fr; version: Fr; targetCommitteeSize: number },
236
229
  logger: Logger,
237
- ): Promise<RetrievedL2Block[]> {
238
- const retrievedBlocks: RetrievedL2Block[] = [];
230
+ ): Promise<RetrievedCheckpoint[]> {
231
+ const retrievedCheckpoints: RetrievedCheckpoint[] = [];
239
232
  await asyncPool(10, logs, async log => {
240
- const l2BlockNumber = Number(log.args.checkpointNumber!);
233
+ const checkpointNumber = Number(log.args.checkpointNumber!);
241
234
  const archive = log.args.archive!;
242
- const archiveFromChain = await rollup.read.archiveAt([BigInt(l2BlockNumber)]);
235
+ const archiveFromChain = await rollup.read.archiveAt([BigInt(checkpointNumber)]);
243
236
  const blobHashes = log.args.versionedBlobHashes!.map(blobHash => Buffer.from(blobHash.slice(2), 'hex'));
244
237
 
245
- // The value from the event and contract will match only if the block is in the chain.
238
+ // The value from the event and contract will match only if the checkpoint is in the chain.
246
239
  if (archive === archiveFromChain) {
247
- const block = await getBlockFromRollupTx(
240
+ const checkpoint = await getCheckpointFromRollupTx(
248
241
  publicClient,
249
242
  blobSinkClient,
250
243
  log.transactionHash!,
251
244
  blobHashes,
252
- l2BlockNumber,
245
+ checkpointNumber,
253
246
  rollup.address,
254
247
  targetCommitteeSize,
255
248
  logger,
@@ -261,22 +254,22 @@ async function processL2BlockProposedLogs(
261
254
  timestamp: await getL1BlockTime(publicClient, log.blockNumber),
262
255
  };
263
256
 
264
- retrievedBlocks.push({ ...block, l1, chainId, version });
265
- logger.trace(`Retrieved L2 block ${l2BlockNumber} from L1 tx ${log.transactionHash}`, {
257
+ retrievedCheckpoints.push({ ...checkpoint, l1, chainId, version });
258
+ logger.trace(`Retrieved checkpoint ${checkpointNumber} from L1 tx ${log.transactionHash}`, {
266
259
  l1BlockNumber: log.blockNumber,
267
- l2BlockNumber,
260
+ checkpointNumber,
268
261
  archive: archive.toString(),
269
- attestations: block.attestations,
262
+ attestations: checkpoint.attestations,
270
263
  });
271
264
  } else {
272
- logger.warn(`Ignoring L2 block ${l2BlockNumber} due to archive root mismatch`, {
265
+ logger.warn(`Ignoring checkpoint ${checkpointNumber} due to archive root mismatch`, {
273
266
  actual: archive,
274
267
  expected: archiveFromChain,
275
268
  });
276
269
  }
277
270
  });
278
271
 
279
- return retrievedBlocks;
272
+ return retrievedCheckpoints;
280
273
  }
281
274
 
282
275
  export async function getL1BlockTime(publicClient: ViemPublicClient, blockNumber: bigint): Promise<bigint> {
@@ -335,25 +328,25 @@ function extractRollupProposeCalldata(multicall3Data: Hex, rollupAddress: Hex):
335
328
  }
336
329
 
337
330
  /**
338
- * Gets block from the calldata of an L1 transaction.
339
- * Assumes that the block was published from an EOA.
331
+ * Gets checkpoint from the calldata of an L1 transaction.
332
+ * Assumes that the checkpoint was published from an EOA.
340
333
  * TODO: Add retries and error management.
341
334
  * @param publicClient - The viem public client to use for transaction retrieval.
342
335
  * @param txHash - Hash of the tx that published it.
343
- * @param l2BlockNumber - L2 block number.
344
- * @returns L2 block from the calldata, deserialized
336
+ * @param checkpointNumber - Checkpoint number.
337
+ * @returns Checkpoint from the calldata, deserialized
345
338
  */
346
- async function getBlockFromRollupTx(
339
+ async function getCheckpointFromRollupTx(
347
340
  publicClient: ViemPublicClient,
348
341
  blobSinkClient: BlobSinkClientInterface,
349
342
  txHash: `0x${string}`,
350
343
  blobHashes: Buffer[], // TODO(md): buffer32?
351
- l2BlockNumber: number,
344
+ checkpointNumber: number,
352
345
  rollupAddress: Hex,
353
346
  targetCommitteeSize: number,
354
347
  logger: Logger,
355
- ): Promise<Omit<RetrievedL2Block, 'l1' | 'chainId' | 'version'>> {
356
- logger.trace(`Fetching L2 block ${l2BlockNumber} from rollup tx ${txHash}`);
348
+ ): Promise<Omit<RetrievedCheckpoint, 'l1' | 'chainId' | 'version'>> {
349
+ logger.trace(`Fetching checkpoint ${checkpointNumber} from rollup tx ${txHash}`);
357
350
  const { input: forwarderData, blockHash } = await publicClient.getTransaction({ hash: txHash });
358
351
 
359
352
  const rollupData = extractRollupProposeCalldata(forwarderData, rollupAddress);
@@ -369,7 +362,6 @@ async function getBlockFromRollupTx(
369
362
  const [decodedArgs, packedAttestations, _signers, _blobInput] = rollupArgs! as readonly [
370
363
  {
371
364
  archive: Hex;
372
- stateReference: ViemStateReference;
373
365
  oracleInput: {
374
366
  feeAssetPriceModifier: bigint;
375
367
  };
@@ -385,9 +377,8 @@ async function getBlockFromRollupTx(
385
377
  const attestations = CommitteeAttestation.fromPacked(packedAttestations, targetCommitteeSize);
386
378
 
387
379
  logger.trace(`Recovered propose calldata from tx ${txHash}`, {
388
- l2BlockNumber,
380
+ checkpointNumber,
389
381
  archive: decodedArgs.archive,
390
- stateReference: decodedArgs.stateReference,
391
382
  header: decodedArgs.header,
392
383
  l1BlockHash: blockHash,
393
384
  blobHashes,
@@ -399,7 +390,7 @@ async function getBlockFromRollupTx(
399
390
  const header = CheckpointHeader.fromViem(decodedArgs.header);
400
391
  const blobBodies = await blobSinkClient.getBlobSidecar(blockHash, blobHashes);
401
392
  if (blobBodies.length === 0) {
402
- throw new NoBlobBodiesFoundError(l2BlockNumber);
393
+ throw new NoBlobBodiesFoundError(checkpointNumber);
403
394
  }
404
395
 
405
396
  let checkpointBlobData: CheckpointBlobData;
@@ -417,11 +408,9 @@ async function getBlockFromRollupTx(
417
408
 
418
409
  const archiveRoot = new Fr(Buffer.from(hexToBytes(decodedArgs.archive)));
419
410
 
420
- const stateReference = StateReference.fromViem(decodedArgs.stateReference);
421
-
422
411
  return {
412
+ checkpointNumber,
423
413
  archiveRoot,
424
- stateReference,
425
414
  header,
426
415
  checkpointBlobData,
427
416
  attestations,
@@ -492,7 +481,7 @@ export async function retrieveL2ProofVerifiedEvents(
492
481
  rollupAddress: EthAddress,
493
482
  searchStartBlock: bigint,
494
483
  searchEndBlock?: bigint,
495
- ): Promise<{ l1BlockNumber: bigint; l2BlockNumber: number; proverId: Fr; txHash: Hex }[]> {
484
+ ): Promise<{ l1BlockNumber: bigint; checkpointNumber: number; proverId: Fr; txHash: Hex }[]> {
496
485
  const logs = await publicClient.getLogs({
497
486
  address: rollupAddress.toString(),
498
487
  fromBlock: searchStartBlock,
@@ -503,7 +492,7 @@ export async function retrieveL2ProofVerifiedEvents(
503
492
 
504
493
  return logs.map(log => ({
505
494
  l1BlockNumber: log.blockNumber,
506
- l2BlockNumber: Number(log.args.checkpointNumber),
495
+ checkpointNumber: Number(log.args.checkpointNumber),
507
496
  proverId: Fr.fromHexString(log.args.proverId),
508
497
  txHash: log.transactionHash,
509
498
  }));
@@ -515,14 +504,14 @@ export async function retrieveL2ProofsFromRollup(
515
504
  rollupAddress: EthAddress,
516
505
  searchStartBlock: bigint,
517
506
  searchEndBlock?: bigint,
518
- ): Promise<DataRetrieval<{ proof: Proof; proverId: Fr; l2BlockNumber: number; txHash: `0x${string}` }>> {
507
+ ): Promise<DataRetrieval<{ proof: Proof; proverId: Fr; checkpointNumber: number; txHash: `0x${string}` }>> {
519
508
  const logs = await retrieveL2ProofVerifiedEvents(publicClient, rollupAddress, searchStartBlock, searchEndBlock);
520
- const retrievedData: { proof: Proof; proverId: Fr; l2BlockNumber: number; txHash: `0x${string}` }[] = [];
509
+ const retrievedData: { proof: Proof; proverId: Fr; checkpointNumber: number; txHash: `0x${string}` }[] = [];
521
510
  const lastProcessedL1BlockNumber = logs.length > 0 ? logs.at(-1)!.l1BlockNumber : searchStartBlock - 1n;
522
511
 
523
- for (const { txHash, proverId, l2BlockNumber } of logs) {
512
+ for (const { txHash, proverId, checkpointNumber } of logs) {
524
513
  const proofData = await getProofFromSubmitProofTx(publicClient, txHash, proverId);
525
- retrievedData.push({ proof: proofData.proof, proverId: proofData.proverId, l2BlockNumber, txHash });
514
+ retrievedData.push({ proof: proofData.proof, proverId: proofData.proverId, checkpointNumber, txHash });
526
515
  }
527
516
  return {
528
517
  retrievedData,
@@ -530,26 +519,26 @@ export async function retrieveL2ProofsFromRollup(
530
519
  };
531
520
  }
532
521
 
533
- export type SubmitBlockProof = {
522
+ export type SubmitEpochProof = {
534
523
  archiveRoot: Fr;
535
524
  proverId: Fr;
536
525
  proof: Proof;
537
526
  };
538
527
 
539
528
  /**
540
- * Gets block metadata (header and archive snapshot) from the calldata of an L1 transaction.
529
+ * Gets epoch proof metadata (archive root and proof) from the calldata of an L1 transaction.
541
530
  * Assumes that the block was published from an EOA.
542
531
  * TODO: Add retries and error management.
543
532
  * @param publicClient - The viem public client to use for transaction retrieval.
544
533
  * @param txHash - Hash of the tx that published it.
545
- * @param l2BlockNum - L2 block number.
546
- * @returns L2 block metadata (header and archive) from the calldata, deserialized
534
+ * @param expectedProverId - Expected prover ID.
535
+ * @returns Epoch proof metadata from the calldata, deserialized.
547
536
  */
548
537
  export async function getProofFromSubmitProofTx(
549
538
  publicClient: ViemPublicClient,
550
539
  txHash: `0x${string}`,
551
540
  expectedProverId: Fr,
552
- ): Promise<SubmitBlockProof> {
541
+ ): Promise<SubmitEpochProof> {
553
542
  const { input: data } = await publicClient.getTransaction({ hash: txHash });
554
543
  const { functionName, args } = decodeFunctionData({ abi: RollupAbi, data });
555
544
 
@@ -1,5 +1,5 @@
1
1
  import { createLogger } from '@aztec/foundation/log';
2
- import type { L2Block } from '@aztec/stdlib/block';
2
+ import type { L2BlockNew } from '@aztec/stdlib/block';
3
3
  import {
4
4
  Attributes,
5
5
  type Gauge,
@@ -139,7 +139,7 @@ export class ArchiverInstrumentation {
139
139
  return this.telemetry.isEnabled();
140
140
  }
141
141
 
142
- public processNewBlocks(syncTimePerBlock: number, blocks: L2Block[]) {
142
+ public processNewBlocks(syncTimePerBlock: number, blocks: L2BlockNew[]) {
143
143
  this.syncDurationPerBlock.record(Math.ceil(syncTimePerBlock));
144
144
  this.blockHeight.record(Math.max(...blocks.map(b => b.number)));
145
145
  this.syncBlockCount.add(blocks.length);
@@ -1 +1,2 @@
1
- export type { PublishedL2Block, L1PublishedData } from '@aztec/stdlib/block';
1
+ export type { PublishedL2Block } from '@aztec/stdlib/block';
2
+ export type { L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
@@ -1,45 +1,63 @@
1
1
  import type { EpochCache } from '@aztec/epoch-cache';
2
+ import { EpochNumber } from '@aztec/foundation/branded-types';
2
3
  import { compactArray } from '@aztec/foundation/collection';
3
4
  import type { Logger } from '@aztec/foundation/log';
4
5
  import {
5
- type PublishedL2Block,
6
+ type AttestationInfo,
6
7
  type ValidateBlockNegativeResult,
7
8
  type ValidateBlockResult,
8
- getAttestationInfoFromPublishedL2Block,
9
+ getAttestationInfoFromPayload,
9
10
  } from '@aztec/stdlib/block';
11
+ import type { PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
10
12
  import { type L1RollupConstants, getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
13
+ import { ConsensusPayload } from '@aztec/stdlib/p2p';
11
14
 
12
15
  export type { ValidateBlockResult };
13
16
 
14
17
  /**
15
- * Validates the attestations submitted for the given block.
18
+ * Extracts attestation information from a published checkpoint.
19
+ * Returns info for each attestation, preserving array indices.
20
+ */
21
+ export function getAttestationInfoFromPublishedCheckpoint({
22
+ checkpoint,
23
+ attestations,
24
+ }: PublishedCheckpoint): AttestationInfo[] {
25
+ const payload = ConsensusPayload.fromCheckpoint(checkpoint);
26
+ return getAttestationInfoFromPayload(payload, attestations);
27
+ }
28
+
29
+ /**
30
+ * Validates the attestations submitted for the given checkpoint.
16
31
  * Returns true if the attestations are valid and sufficient, false otherwise.
17
32
  */
18
- export async function validateBlockAttestations(
19
- publishedBlock: PublishedL2Block,
33
+ export async function validateCheckpointAttestations(
34
+ publishedCheckpoint: PublishedCheckpoint,
20
35
  epochCache: EpochCache,
21
36
  constants: Pick<L1RollupConstants, 'epochDuration'>,
22
37
  logger?: Logger,
23
38
  ): Promise<ValidateBlockResult> {
24
- const attestorInfos = getAttestationInfoFromPublishedL2Block(publishedBlock);
39
+ const attestorInfos = getAttestationInfoFromPublishedCheckpoint(publishedCheckpoint);
25
40
  const attestors = compactArray(attestorInfos.map(info => ('address' in info ? info.address : undefined)));
26
- const { block } = publishedBlock;
27
- const blockHash = await block.hash().then(hash => hash.toString());
28
- const archiveRoot = block.archive.root.toString();
29
- const slot = block.header.getSlot();
30
- const epoch = getEpochAtSlot(slot, constants);
41
+ const { checkpoint, attestations } = publishedCheckpoint;
42
+ const headerHash = checkpoint.header.hash();
43
+ const archiveRoot = checkpoint.archive.root.toString();
44
+ const slot = checkpoint.header.slotNumber;
45
+ const epoch: EpochNumber = getEpochAtSlot(slot, constants);
31
46
  const { committee, seed } = await epochCache.getCommitteeForEpoch(epoch);
32
- const logData = { blockNumber: block.number, slot, epoch, blockHash, archiveRoot };
47
+ const logData = { checkpointNumber: checkpoint.number, slot, epoch, headerHash, archiveRoot };
33
48
 
34
- logger?.debug(`Validating attestations for block ${block.number} at slot ${slot} in epoch ${epoch}`, {
49
+ logger?.debug(`Validating attestations for checkpoint ${checkpoint.number} at slot ${slot} in epoch ${epoch}`, {
35
50
  committee: (committee ?? []).map(member => member.toString()),
36
51
  recoveredAttestors: attestorInfos,
37
- postedAttestations: publishedBlock.attestations.map(a => (a.address.isZero() ? a.signature : a.address).toString()),
52
+ postedAttestations: attestations.map(a => (a.address.isZero() ? a.signature : a.address).toString()),
38
53
  ...logData,
39
54
  });
40
55
 
41
56
  if (!committee || committee.length === 0) {
42
- logger?.warn(`No committee found for epoch ${epoch} at slot ${slot}. Accepting block without validation.`, logData);
57
+ logger?.warn(
58
+ `No committee found for epoch ${epoch} at slot ${slot}. Accepting checkpoint without validation.`,
59
+ logData,
60
+ );
43
61
  return { valid: true };
44
62
  }
45
63
 
@@ -48,12 +66,12 @@ export async function validateBlockAttestations(
48
66
  const failedValidationResult = <TReason extends ValidateBlockNegativeResult['reason']>(reason: TReason) => ({
49
67
  valid: false as const,
50
68
  reason,
51
- block: publishedBlock.block.toBlockInfo(),
69
+ block: checkpoint.blocks[0].toBlockInfo(),
52
70
  committee,
53
71
  seed,
54
72
  epoch,
55
73
  attestors,
56
- attestations: publishedBlock.attestations,
74
+ attestations,
57
75
  });
58
76
 
59
77
  for (let i = 0; i < attestorInfos.length; i++) {
@@ -90,7 +108,7 @@ export async function validateBlockAttestations(
90
108
 
91
109
  const validAttestationCount = attestorInfos.filter(info => info.status === 'recovered-from-signature').length;
92
110
  if (validAttestationCount < requiredAttestationCount) {
93
- logger?.warn(`Insufficient attestations for block at slot ${slot}`, {
111
+ logger?.warn(`Insufficient attestations for checkpoint at slot ${slot}`, {
94
112
  requiredAttestations: requiredAttestationCount,
95
113
  actualAttestations: validAttestationCount,
96
114
  ...logData,
@@ -98,6 +116,9 @@ export async function validateBlockAttestations(
98
116
  return failedValidationResult('insufficient-attestations');
99
117
  }
100
118
 
101
- logger?.debug(`Block attestations validated successfully for block ${block.number} at slot ${slot}`, logData);
119
+ logger?.debug(
120
+ `Checkpoint attestations validated successfully for checkpoint ${checkpoint.number} at slot ${slot}`,
121
+ logData,
122
+ );
102
123
  return { valid: true };
103
124
  }
package/src/index.ts CHANGED
@@ -2,4 +2,4 @@ export * from './archiver/index.js';
2
2
  export * from './factory.js';
3
3
  export * from './rpc/index.js';
4
4
 
5
- export { retrieveBlocksFromRollup, retrieveL2ProofVerifiedEvents } from './archiver/data_retrieval.js';
5
+ export { retrieveL2ProofVerifiedEvents } from './archiver/data_retrieval.js';
@@ -1,5 +1,6 @@
1
1
  import { GENESIS_ARCHIVE_ROOT } from '@aztec/constants';
2
2
  import { DefaultL1ContractsConfig } from '@aztec/ethereum';
3
+ import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
3
4
  import { Buffer32 } from '@aztec/foundation/buffer';
4
5
  import { EthAddress } from '@aztec/foundation/eth-address';
5
6
  import { Fr } from '@aztec/foundation/fields';
@@ -182,17 +183,17 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
182
183
  return Promise.resolve(this.l2Blocks.at(typeof number === 'number' ? number - 1 : -1)?.getBlockHeader());
183
184
  }
184
185
 
185
- getBlocksForEpoch(epochNumber: bigint): Promise<L2Block[]> {
186
+ getBlocksForEpoch(epochNumber: EpochNumber): Promise<L2Block[]> {
186
187
  const epochDuration = DefaultL1ContractsConfig.aztecEpochDuration;
187
188
  const [start, end] = getSlotRangeForEpoch(epochNumber, { epochDuration });
188
189
  const blocks = this.l2Blocks.filter(b => {
189
- const slot = b.header.globalVariables.slotNumber.toBigInt();
190
+ const slot = b.header.globalVariables.slotNumber;
190
191
  return slot >= start && slot <= end;
191
192
  });
192
193
  return Promise.resolve(blocks);
193
194
  }
194
195
 
195
- async getBlockHeadersForEpoch(epochNumber: bigint): Promise<BlockHeader[]> {
196
+ async getBlockHeadersForEpoch(epochNumber: EpochNumber): Promise<BlockHeader[]> {
196
197
  const blocks = await this.getBlocksForEpoch(epochNumber);
197
198
  return blocks.map(b => b.getBlockHeader());
198
199
  }
@@ -268,15 +269,15 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
268
269
  };
269
270
  }
270
271
 
271
- getL2EpochNumber(): Promise<bigint> {
272
+ getL2EpochNumber(): Promise<EpochNumber> {
272
273
  throw new Error('Method not implemented.');
273
274
  }
274
275
 
275
- getL2SlotNumber(): Promise<bigint> {
276
+ getL2SlotNumber(): Promise<SlotNumber> {
276
277
  throw new Error('Method not implemented.');
277
278
  }
278
279
 
279
- isEpochComplete(_epochNumber: bigint): Promise<boolean> {
280
+ isEpochComplete(_epochNumber: EpochNumber): Promise<boolean> {
280
281
  throw new Error('Method not implemented.');
281
282
  }
282
283