@aztec/archiver 4.0.0-nightly.20260121 → 4.0.0-nightly.20260123

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 (47) hide show
  1. package/README.md +9 -0
  2. package/dest/archiver.d.ts +3 -3
  3. package/dest/archiver.d.ts.map +1 -1
  4. package/dest/archiver.js +12 -12
  5. package/dest/factory.d.ts +3 -2
  6. package/dest/factory.d.ts.map +1 -1
  7. package/dest/factory.js +5 -3
  8. package/dest/l1/bin/retrieve-calldata.js +2 -2
  9. package/dest/l1/data_retrieval.d.ts +1 -1
  10. package/dest/l1/data_retrieval.d.ts.map +1 -1
  11. package/dest/l1/data_retrieval.js +2 -2
  12. package/dest/modules/data_source_base.d.ts +18 -19
  13. package/dest/modules/data_source_base.d.ts.map +1 -1
  14. package/dest/modules/data_source_base.js +25 -56
  15. package/dest/modules/data_store_updater.d.ts +5 -5
  16. package/dest/modules/data_store_updater.d.ts.map +1 -1
  17. package/dest/modules/instrumentation.d.ts +3 -3
  18. package/dest/modules/instrumentation.d.ts.map +1 -1
  19. package/dest/store/block_store.d.ts +21 -11
  20. package/dest/store/block_store.d.ts.map +1 -1
  21. package/dest/store/block_store.js +34 -5
  22. package/dest/store/kv_archiver_store.d.ts +25 -17
  23. package/dest/store/kv_archiver_store.d.ts.map +1 -1
  24. package/dest/store/kv_archiver_store.js +16 -8
  25. package/dest/store/log_store.d.ts +17 -8
  26. package/dest/store/log_store.d.ts.map +1 -1
  27. package/dest/store/log_store.js +20 -6
  28. package/dest/test/fake_l1_state.d.ts +4 -4
  29. package/dest/test/fake_l1_state.d.ts.map +1 -1
  30. package/dest/test/mock_l2_block_source.d.ts +18 -18
  31. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  32. package/dest/test/mock_l2_block_source.js +37 -38
  33. package/dest/test/mock_structs.js +4 -4
  34. package/package.json +13 -13
  35. package/src/archiver.ts +15 -18
  36. package/src/factory.ts +4 -2
  37. package/src/l1/bin/retrieve-calldata.ts +7 -2
  38. package/src/l1/data_retrieval.ts +3 -3
  39. package/src/modules/data_source_base.ts +33 -80
  40. package/src/modules/data_store_updater.ts +7 -7
  41. package/src/modules/instrumentation.ts +2 -2
  42. package/src/store/block_store.ts +59 -21
  43. package/src/store/kv_archiver_store.ts +35 -19
  44. package/src/store/log_store.ts +37 -14
  45. package/src/test/fake_l1_state.ts +2 -2
  46. package/src/test/mock_l2_block_source.ts +49 -59
  47. package/src/test/mock_structs.ts +4 -4
@@ -12,13 +12,14 @@ import {
12
12
  Body,
13
13
  CheckpointedL2Block,
14
14
  CommitteeAttestation,
15
+ L2Block,
15
16
  L2BlockHash,
16
- L2BlockNew,
17
17
  type ValidateCheckpointResult,
18
18
  deserializeValidateCheckpointResult,
19
19
  serializeValidateCheckpointResult,
20
20
  } from '@aztec/stdlib/block';
21
21
  import { L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
22
+ import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
22
23
  import { CheckpointHeader } from '@aztec/stdlib/rollup';
23
24
  import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
24
25
  import {
@@ -27,6 +28,7 @@ import {
27
28
  TxEffect,
28
29
  TxHash,
29
30
  TxReceipt,
31
+ TxStatus,
30
32
  deserializeIndexedTxEffect,
31
33
  serializeIndexedTxEffect,
32
34
  } from '@aztec/stdlib/tx';
@@ -111,7 +113,10 @@ export class BlockStore {
111
113
 
112
114
  #log = createLogger('archiver:block_store');
113
115
 
114
- constructor(private db: AztecAsyncKVStore) {
116
+ constructor(
117
+ private db: AztecAsyncKVStore,
118
+ private l1Constants: Pick<L1RollupConstants, 'epochDuration'>,
119
+ ) {
115
120
  this.#blocks = db.openMap('archiver_blocks');
116
121
  this.#blockTxs = db.openMap('archiver_block_txs');
117
122
  this.#txEffects = db.openMap('archiver_tx_effects');
@@ -124,12 +129,24 @@ export class BlockStore {
124
129
  this.#checkpoints = db.openMap('archiver_checkpoints');
125
130
  }
126
131
 
132
+ /**
133
+ * Computes the finalized block number based on the proven block number.
134
+ * A block is considered finalized when it's 2 epochs behind the proven block.
135
+ * TODO(#13569): Compute proper finalized block number based on L1 finalized block.
136
+ * TODO(palla/mbps): Even the provisional computation is wrong, since it should subtract checkpoints, not blocks
137
+ * @returns The finalized block number.
138
+ */
139
+ async getFinalizedL2BlockNumber(): Promise<BlockNumber> {
140
+ const provenBlockNumber = await this.getProvenBlockNumber();
141
+ return BlockNumber(Math.max(provenBlockNumber - this.l1Constants.epochDuration * 2, 0));
142
+ }
143
+
127
144
  /**
128
145
  * Append new blocks to the store's list. All blocks must be for the 'current' checkpoint
129
146
  * @param blocks - The L2 blocks to be added to the store.
130
147
  * @returns True if the operation is successful.
131
148
  */
132
- async addBlocks(blocks: L2BlockNew[], opts: { force?: boolean } = {}): Promise<boolean> {
149
+ async addBlocks(blocks: L2Block[], opts: { force?: boolean } = {}): Promise<boolean> {
133
150
  if (blocks.length === 0) {
134
151
  return true;
135
152
  }
@@ -182,7 +199,7 @@ export class BlockStore {
182
199
  }
183
200
 
184
201
  // Iterate over blocks array and insert them, checking that the block numbers and indexes are sequential. Also check they are for the correct checkpoint.
185
- let previousBlock: L2BlockNew | undefined = undefined;
202
+ let previousBlock: L2Block | undefined = undefined;
186
203
  for (const block of blocks) {
187
204
  if (!opts.force && previousBlock) {
188
205
  if (previousBlock.number + 1 !== block.number) {
@@ -241,7 +258,7 @@ export class BlockStore {
241
258
  }
242
259
 
243
260
  let previousBlockNumber: BlockNumber | undefined = undefined;
244
- let previousBlock: L2BlockNew | undefined = undefined;
261
+ let previousBlock: L2Block | undefined = undefined;
245
262
 
246
263
  // If we have a previous checkpoint then we need to get the previous block number
247
264
  if (previousCheckpointData !== undefined) {
@@ -322,7 +339,7 @@ export class BlockStore {
322
339
  });
323
340
  }
324
341
 
325
- private async addBlockToDatabase(block: L2BlockNew, checkpointNumber: number, indexWithinCheckpoint: number) {
342
+ private async addBlockToDatabase(block: L2Block, checkpointNumber: number, indexWithinCheckpoint: number) {
326
343
  const blockHash = L2BlockHash.fromField(await block.hash());
327
344
 
328
345
  await this.#blocks.set(block.number, {
@@ -351,7 +368,7 @@ export class BlockStore {
351
368
  }
352
369
 
353
370
  /** Deletes a block and all associated data (tx effects, indices). */
354
- private async deleteBlock(block: L2BlockNew): Promise<void> {
371
+ private async deleteBlock(block: L2Block): Promise<void> {
355
372
  // Delete the block from the main blocks map
356
373
  await this.#blocks.delete(block.number);
357
374
 
@@ -449,7 +466,7 @@ export class BlockStore {
449
466
  return data;
450
467
  }
451
468
 
452
- async getBlocksForCheckpoint(checkpointNumber: CheckpointNumber): Promise<L2BlockNew[] | undefined> {
469
+ async getBlocksForCheckpoint(checkpointNumber: CheckpointNumber): Promise<L2Block[] | undefined> {
453
470
  const checkpoint = await this.#checkpoints.getAsync(checkpointNumber);
454
471
  if (!checkpoint) {
455
472
  return undefined;
@@ -472,8 +489,8 @@ export class BlockStore {
472
489
  * @param slotNumber - The slot number to search for.
473
490
  * @returns All blocks with the given slot number, in ascending block number order.
474
491
  */
475
- async getBlocksForSlot(slotNumber: SlotNumber): Promise<L2BlockNew[]> {
476
- const blocks: L2BlockNew[] = [];
492
+ async getBlocksForSlot(slotNumber: SlotNumber): Promise<L2Block[]> {
493
+ const blocks: L2Block[] = [];
477
494
 
478
495
  // Iterate backwards through all blocks and filter by slot number
479
496
  // This is more efficient since we usually query for the most recent slot
@@ -496,9 +513,9 @@ export class BlockStore {
496
513
  * @param blockNumber - The block number to remove after.
497
514
  * @returns The removed blocks (for event emission).
498
515
  */
499
- async unwindBlocksAfter(blockNumber: BlockNumber): Promise<L2BlockNew[]> {
516
+ async unwindBlocksAfter(blockNumber: BlockNumber): Promise<L2Block[]> {
500
517
  return await this.db.transactionAsync(async () => {
501
- const removedBlocks: L2BlockNew[] = [];
518
+ const removedBlocks: L2Block[] = [];
502
519
 
503
520
  // Get the latest block number to determine the range
504
521
  const latestBlockNumber = await this.getLatestBlockNumber();
@@ -620,7 +637,7 @@ export class BlockStore {
620
637
  * @param limit - The number of blocks to return.
621
638
  * @returns The requested L2 blocks
622
639
  */
623
- async *getBlocks(start: BlockNumber, limit: number): AsyncIterableIterator<L2BlockNew> {
640
+ async *getBlocks(start: BlockNumber, limit: number): AsyncIterableIterator<L2Block> {
624
641
  for await (const [blockNumber, blockStorage] of this.getBlockStorages(start, limit)) {
625
642
  const block = await this.getBlockFromBlockStorage(blockNumber, blockStorage);
626
643
  if (block) {
@@ -634,7 +651,7 @@ export class BlockStore {
634
651
  * @param blockNumber - The number of the block to return.
635
652
  * @returns The requested L2 block.
636
653
  */
637
- async getBlock(blockNumber: BlockNumber): Promise<L2BlockNew | undefined> {
654
+ async getBlock(blockNumber: BlockNumber): Promise<L2Block | undefined> {
638
655
  const blockStorage = await this.#blocks.getAsync(blockNumber);
639
656
  if (!blockStorage || !blockStorage.header) {
640
657
  return Promise.resolve(undefined);
@@ -647,7 +664,7 @@ export class BlockStore {
647
664
  * @param blockHash - The hash of the block to return.
648
665
  * @returns The requested L2 block.
649
666
  */
650
- async getBlockByHash(blockHash: L2BlockHash): Promise<L2BlockNew | undefined> {
667
+ async getBlockByHash(blockHash: L2BlockHash): Promise<L2Block | undefined> {
651
668
  const blockNumber = await this.#blockHashIndex.getAsync(blockHash.toString());
652
669
  if (blockNumber === undefined) {
653
670
  return undefined;
@@ -660,7 +677,7 @@ export class BlockStore {
660
677
  * @param archive - The archive root of the block to return.
661
678
  * @returns The requested L2 block.
662
679
  */
663
- async getBlockByArchive(archive: Fr): Promise<L2BlockNew | undefined> {
680
+ async getBlockByArchive(archive: Fr): Promise<L2Block | undefined> {
664
681
  const blockNumber = await this.#blockArchiveIndex.getAsync(archive.toString());
665
682
  if (blockNumber === undefined) {
666
683
  return undefined;
@@ -736,7 +753,7 @@ export class BlockStore {
736
753
  private async getBlockFromBlockStorage(
737
754
  blockNumber: number,
738
755
  blockStorage: BlockStorage,
739
- ): Promise<L2BlockNew | undefined> {
756
+ ): Promise<L2Block | undefined> {
740
757
  const header = BlockHeader.fromBuffer(blockStorage.header);
741
758
  const archive = AppendOnlyTreeSnapshot.fromBuffer(blockStorage.archive);
742
759
  const blockHash = blockStorage.blockHash;
@@ -760,7 +777,7 @@ export class BlockStore {
760
777
  txEffects.push(deserializeIndexedTxEffect(txEffect).data);
761
778
  }
762
779
  const body = new Body(txEffects);
763
- const block = new L2BlockNew(
780
+ const block = new L2Block(
764
781
  archive,
765
782
  header,
766
783
  body,
@@ -802,13 +819,34 @@ export class BlockStore {
802
819
  return undefined;
803
820
  }
804
821
 
822
+ const blockNumber = BlockNumber(txEffect.l2BlockNumber);
823
+
824
+ // Use existing archiver methods to determine finalization level
825
+ const [provenBlockNumber, checkpointedBlockNumber, finalizedBlockNumber] = await Promise.all([
826
+ this.getProvenBlockNumber(),
827
+ this.getCheckpointedL2BlockNumber(),
828
+ this.getFinalizedL2BlockNumber(),
829
+ ]);
830
+
831
+ let status: TxStatus;
832
+ if (blockNumber <= finalizedBlockNumber) {
833
+ status = TxStatus.FINALIZED;
834
+ } else if (blockNumber <= provenBlockNumber) {
835
+ status = TxStatus.PROVEN;
836
+ } else if (blockNumber <= checkpointedBlockNumber) {
837
+ status = TxStatus.CHECKPOINTED;
838
+ } else {
839
+ status = TxStatus.PROPOSED;
840
+ }
841
+
805
842
  return new TxReceipt(
806
843
  txHash,
807
- TxReceipt.statusFromRevertCode(txEffect.data.revertCode),
808
- '',
844
+ status,
845
+ TxReceipt.executionResultFromRevertCode(txEffect.data.revertCode),
846
+ undefined,
809
847
  txEffect.data.transactionFee.toBigInt(),
810
848
  txEffect.l2BlockHash,
811
- BlockNumber(txEffect.l2BlockNumber),
849
+ blockNumber,
812
850
  );
813
851
  }
814
852
 
@@ -6,7 +6,7 @@ import { createLogger } from '@aztec/foundation/log';
6
6
  import type { AztecAsyncKVStore, CustomRange, StoreSize } from '@aztec/kv-store';
7
7
  import { FunctionSelector } from '@aztec/stdlib/abi';
8
8
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
9
- import { CheckpointedL2Block, L2BlockHash, L2BlockNew, type ValidateCheckpointResult } from '@aztec/stdlib/block';
9
+ import { CheckpointedL2Block, L2Block, L2BlockHash, type ValidateCheckpointResult } from '@aztec/stdlib/block';
10
10
  import type { PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
11
11
  import type {
12
12
  ContractClassPublic,
@@ -16,6 +16,7 @@ import type {
16
16
  ExecutablePrivateFunctionWithMembershipProof,
17
17
  UtilityFunctionWithMembershipProof,
18
18
  } from '@aztec/stdlib/contract';
19
+ import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
19
20
  import type { GetContractClassLogsResponse, GetPublicLogsResponse } from '@aztec/stdlib/interfaces/client';
20
21
  import type { LogFilter, SiloedTag, Tag, TxScopedL2Log } from '@aztec/stdlib/logs';
21
22
  import type { BlockHeader, TxHash, TxReceipt } from '@aztec/stdlib/tx';
@@ -64,8 +65,9 @@ export class KVArchiverDataStore implements ContractDataSource {
64
65
  constructor(
65
66
  private db: AztecAsyncKVStore,
66
67
  logsMaxPageSize: number = 1000,
68
+ l1Constants: Pick<L1RollupConstants, 'epochDuration'>,
67
69
  ) {
68
- this.#blockStore = new BlockStore(db);
70
+ this.#blockStore = new BlockStore(db, l1Constants);
69
71
  this.#logStore = new LogStore(db, this.#blockStore, logsMaxPageSize);
70
72
  this.#messageStore = new MessageStore(db);
71
73
  this.#contractClassStore = new ContractClassStore(db);
@@ -101,6 +103,11 @@ export class KVArchiverDataStore implements ContractDataSource {
101
103
  return this.db.close();
102
104
  }
103
105
 
106
+ /** Computes the finalized block number based on the proven block number. */
107
+ getFinalizedL2BlockNumber(): Promise<BlockNumber> {
108
+ return this.#blockStore.getFinalizedL2BlockNumber();
109
+ }
110
+
104
111
  /** Looks up a public function name given a selector. */
105
112
  getDebugFunctionName(_address: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
106
113
  return Promise.resolve(this.functionNames.get(selector.toString()));
@@ -232,7 +239,7 @@ export class KVArchiverDataStore implements ContractDataSource {
232
239
  * @param blocks - The L2 blocks to be added to the store and the last processed L1 block.
233
240
  * @returns True if the operation is successful.
234
241
  */
235
- addBlocks(blocks: L2BlockNew[], opts: { force?: boolean; checkpointNumber?: number } = {}): Promise<boolean> {
242
+ addBlocks(blocks: L2Block[], opts: { force?: boolean; checkpointNumber?: number } = {}): Promise<boolean> {
236
243
  return this.#blockStore.addBlocks(blocks, opts);
237
244
  }
238
245
 
@@ -298,21 +305,21 @@ export class KVArchiverDataStore implements ContractDataSource {
298
305
  * Returns the block for the given number, or undefined if not exists.
299
306
  * @param number - The block number to return.
300
307
  */
301
- getBlock(number: BlockNumber): Promise<L2BlockNew | undefined> {
308
+ getBlock(number: BlockNumber): Promise<L2Block | undefined> {
302
309
  return this.#blockStore.getBlock(number);
303
310
  }
304
311
  /**
305
312
  * Returns the block for the given hash, or undefined if not exists.
306
313
  * @param blockHash - The block hash to return.
307
314
  */
308
- getBlockByHash(blockHash: Fr): Promise<L2BlockNew | undefined> {
315
+ getBlockByHash(blockHash: Fr): Promise<L2Block | undefined> {
309
316
  return this.#blockStore.getBlockByHash(L2BlockHash.fromField(blockHash));
310
317
  }
311
318
  /**
312
319
  * Returns the block for the given archive root, or undefined if not exists.
313
320
  * @param archive - The archive root to return.
314
321
  */
315
- getBlockByArchive(archive: Fr): Promise<L2BlockNew | undefined> {
322
+ getBlockByArchive(archive: Fr): Promise<L2Block | undefined> {
316
323
  return this.#blockStore.getBlockByArchive(archive);
317
324
  }
318
325
 
@@ -322,7 +329,7 @@ export class KVArchiverDataStore implements ContractDataSource {
322
329
  * @param limit - The number of blocks to return.
323
330
  * @returns The requested L2 blocks.
324
331
  */
325
- getBlocks(from: BlockNumber, limit: number): Promise<L2BlockNew[]> {
332
+ getBlocks(from: BlockNumber, limit: number): Promise<L2Block[]> {
326
333
  return toArray(this.#blockStore.getBlocks(from, limit));
327
334
  }
328
335
 
@@ -385,11 +392,11 @@ export class KVArchiverDataStore implements ContractDataSource {
385
392
  * @param blocks - The blocks for which to add the logs.
386
393
  * @returns True if the operation is successful.
387
394
  */
388
- addLogs(blocks: L2BlockNew[]): Promise<boolean> {
395
+ addLogs(blocks: L2Block[]): Promise<boolean> {
389
396
  return this.#logStore.addLogs(blocks);
390
397
  }
391
398
 
392
- deleteLogs(blocks: L2BlockNew[]): Promise<boolean> {
399
+ deleteLogs(blocks: L2Block[]): Promise<boolean> {
393
400
  return this.#logStore.deleteLogs(blocks);
394
401
  }
395
402
 
@@ -434,24 +441,33 @@ export class KVArchiverDataStore implements ContractDataSource {
434
441
  }
435
442
 
436
443
  /**
437
- * Gets all private logs that match any of the `tags`. For each tag, an array of matching logs is returned. An empty
444
+ * Gets private logs that match any of the `tags`. For each tag, an array of matching logs is returned. An empty
438
445
  * array implies no logs match that tag.
446
+ * @param tags - The tags to search for.
447
+ * @param page - The page number (0-indexed) for pagination. Returns at most 10 logs per tag per page.
439
448
  */
440
- getPrivateLogsByTags(tags: SiloedTag[]): Promise<TxScopedL2Log[][]> {
449
+ getPrivateLogsByTags(tags: SiloedTag[], page?: number): Promise<TxScopedL2Log[][]> {
441
450
  try {
442
- return this.#logStore.getPrivateLogsByTags(tags);
451
+ return this.#logStore.getPrivateLogsByTags(tags, page);
443
452
  } catch (err) {
444
453
  return Promise.reject(err);
445
454
  }
446
455
  }
447
456
 
448
457
  /**
449
- * Gets all public logs that match any of the `tags` from the specified contract. For each tag, an array of matching
458
+ * Gets public logs that match any of the `tags` from the specified contract. For each tag, an array of matching
450
459
  * logs is returned. An empty array implies no logs match that tag.
451
- */
452
- getPublicLogsByTagsFromContract(contractAddress: AztecAddress, tags: Tag[]): Promise<TxScopedL2Log[][]> {
460
+ * @param contractAddress - The contract address to search logs for.
461
+ * @param tags - The tags to search for.
462
+ * @param page - The page number (0-indexed) for pagination. Returns at most 10 logs per tag per page.
463
+ */
464
+ getPublicLogsByTagsFromContract(
465
+ contractAddress: AztecAddress,
466
+ tags: Tag[],
467
+ page?: number,
468
+ ): Promise<TxScopedL2Log[][]> {
453
469
  try {
454
- return this.#logStore.getPublicLogsByTagsFromContract(contractAddress, tags);
470
+ return this.#logStore.getPublicLogsByTagsFromContract(contractAddress, tags, page);
455
471
  } catch (err) {
456
472
  return Promise.reject(err);
457
473
  }
@@ -589,7 +605,7 @@ export class KVArchiverDataStore implements ContractDataSource {
589
605
  * @param checkpointNumber Retrieves all blocks for the given checkpoint
590
606
  * @returns The collection of blocks for the requested checkpoint if available (undefined otherwise)
591
607
  */
592
- getBlocksForCheckpoint(checkpointNumber: CheckpointNumber): Promise<L2BlockNew[] | undefined> {
608
+ getBlocksForCheckpoint(checkpointNumber: CheckpointNumber): Promise<L2Block[] | undefined> {
593
609
  return this.#blockStore.getBlocksForCheckpoint(checkpointNumber);
594
610
  }
595
611
 
@@ -607,7 +623,7 @@ export class KVArchiverDataStore implements ContractDataSource {
607
623
  * @param slotNumber - The slot number to search for.
608
624
  * @returns All blocks with the given slot number.
609
625
  */
610
- getBlocksForSlot(slotNumber: SlotNumber): Promise<L2BlockNew[]> {
626
+ getBlocksForSlot(slotNumber: SlotNumber): Promise<L2Block[]> {
611
627
  return this.#blockStore.getBlocksForSlot(slotNumber);
612
628
  }
613
629
 
@@ -616,7 +632,7 @@ export class KVArchiverDataStore implements ContractDataSource {
616
632
  * @param blockNumber - The block number to remove after.
617
633
  * @returns The removed blocks (for event emission).
618
634
  */
619
- removeBlocksAfter(blockNumber: BlockNumber): Promise<L2BlockNew[]> {
635
+ removeBlocksAfter(blockNumber: BlockNumber): Promise<L2Block[]> {
620
636
  return this.#blockStore.unwindBlocksAfter(blockNumber);
621
637
  }
622
638
  }
@@ -6,7 +6,8 @@ import { createLogger } from '@aztec/foundation/log';
6
6
  import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize';
7
7
  import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
8
8
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
9
- import { L2BlockHash, L2BlockNew } from '@aztec/stdlib/block';
9
+ import { L2Block, L2BlockHash } from '@aztec/stdlib/block';
10
+ import { MAX_LOGS_PER_TAG } from '@aztec/stdlib/interfaces/api-limit';
10
11
  import type { GetContractClassLogsResponse, GetPublicLogsResponse } from '@aztec/stdlib/interfaces/client';
11
12
  import {
12
13
  ContractClassLog,
@@ -58,7 +59,7 @@ export class LogStore {
58
59
  * @param block - The L2 block to extract logs from.
59
60
  * @returns An object containing the private and public tagged logs for the block.
60
61
  */
61
- #extractTaggedLogsFromBlock(block: L2BlockNew) {
62
+ #extractTaggedLogsFromBlock(block: L2Block) {
62
63
  // SiloedTag (as string) -> array of log buffers.
63
64
  const privateTaggedLogs = new Map<string, Buffer[]>();
64
65
  // "{contractAddress}_{tag}" (as string) -> array of log buffers.
@@ -119,7 +120,7 @@ export class LogStore {
119
120
  * @returns A map from tag (as string) to an array of serialized private logs belonging to that tag, and a map from
120
121
  * "{contractAddress}_{tag}" (as string) to an array of serialized public logs belonging to that key.
121
122
  */
122
- #extractTaggedLogs(blocks: L2BlockNew[]): {
123
+ #extractTaggedLogs(blocks: L2Block[]): {
123
124
  privateTaggedLogs: Map<string, Buffer[]>;
124
125
  publicTaggedLogs: Map<string, Buffer[]>;
125
126
  } {
@@ -145,7 +146,7 @@ export class LogStore {
145
146
  return { privateTaggedLogs, publicTaggedLogs };
146
147
  }
147
148
 
148
- async #addPrivateLogs(blocks: L2BlockNew[]): Promise<void> {
149
+ async #addPrivateLogs(blocks: L2Block[]): Promise<void> {
149
150
  const newBlocks = await filterAsync(
150
151
  blocks,
151
152
  async block => !(await this.#privateLogKeysByBlock.hasAsync(block.number)),
@@ -180,7 +181,7 @@ export class LogStore {
180
181
  }
181
182
  }
182
183
 
183
- async #addPublicLogs(blocks: L2BlockNew[]): Promise<void> {
184
+ async #addPublicLogs(blocks: L2Block[]): Promise<void> {
184
185
  const newBlocks = await filterAsync(
185
186
  blocks,
186
187
  async block => !(await this.#publicLogKeysByBlock.hasAsync(block.number)),
@@ -228,7 +229,7 @@ export class LogStore {
228
229
  }
229
230
  }
230
231
 
231
- async #addContractClassLogs(blocks: L2BlockNew[]): Promise<void> {
232
+ async #addContractClassLogs(blocks: L2Block[]): Promise<void> {
232
233
  const newBlocks = await filterAsync(
233
234
  blocks,
234
235
  async block => !(await this.#contractClassLogsByBlock.hasAsync(block.number)),
@@ -259,7 +260,7 @@ export class LogStore {
259
260
  * @param blocks - The blocks for which to add the logs.
260
261
  * @returns True if the operation is successful.
261
262
  */
262
- addLogs(blocks: L2BlockNew[]): Promise<boolean> {
263
+ addLogs(blocks: L2Block[]): Promise<boolean> {
263
264
  return this.db.transactionAsync(async () => {
264
265
  await Promise.all([
265
266
  this.#addPrivateLogs(blocks),
@@ -284,7 +285,7 @@ export class LogStore {
284
285
  return L2BlockHash.fromField(blockHash);
285
286
  }
286
287
 
287
- deleteLogs(blocks: L2BlockNew[]): Promise<boolean> {
288
+ deleteLogs(blocks: L2Block[]): Promise<boolean> {
288
289
  return this.db.transactionAsync(async () => {
289
290
  await Promise.all(
290
291
  blocks.map(async block => {
@@ -314,27 +315,49 @@ export class LogStore {
314
315
  }
315
316
 
316
317
  /**
317
- * Gets all private logs that match any of the `tags`. For each tag, an array of matching logs is returned. An empty
318
+ * Gets private logs that match any of the `tags`. For each tag, an array of matching logs is returned. An empty
318
319
  * array implies no logs match that tag.
320
+ * @param tags - The tags to search for.
321
+ * @param page - The page number (0-indexed) for pagination.
322
+ * @returns An array of log arrays, one per tag. Returns at most MAX_LOGS_PER_TAG logs per tag per page. If
323
+ * MAX_LOGS_PER_TAG logs are returned for a tag, the caller should fetch the next page to check for more logs.
319
324
  */
320
- async getPrivateLogsByTags(tags: SiloedTag[]): Promise<TxScopedL2Log[][]> {
325
+ async getPrivateLogsByTags(tags: SiloedTag[], page: number = 0): Promise<TxScopedL2Log[][]> {
321
326
  const logs = await Promise.all(tags.map(tag => this.#privateLogsByTag.getAsync(tag.toString())));
327
+ const start = page * MAX_LOGS_PER_TAG;
328
+ const end = start + MAX_LOGS_PER_TAG;
322
329
 
323
- return logs.map(logBuffers => logBuffers?.map(logBuffer => TxScopedL2Log.fromBuffer(logBuffer)) ?? []);
330
+ return logs.map(
331
+ logBuffers => logBuffers?.slice(start, end).map(logBuffer => TxScopedL2Log.fromBuffer(logBuffer)) ?? [],
332
+ );
324
333
  }
325
334
 
326
335
  /**
327
- * Gets all public logs that match any of the `tags` from the specified contract. For each tag, an array of matching
336
+ * Gets public logs that match any of the `tags` from the specified contract. For each tag, an array of matching
328
337
  * logs is returned. An empty array implies no logs match that tag.
338
+ * @param contractAddress - The contract address to search logs for.
339
+ * @param tags - The tags to search for.
340
+ * @param page - The page number (0-indexed) for pagination.
341
+ * @returns An array of log arrays, one per tag. Returns at most MAX_LOGS_PER_TAG logs per tag per page. If
342
+ * MAX_LOGS_PER_TAG logs are returned for a tag, the caller should fetch the next page to check for more logs.
329
343
  */
330
- async getPublicLogsByTagsFromContract(contractAddress: AztecAddress, tags: Tag[]): Promise<TxScopedL2Log[][]> {
344
+ async getPublicLogsByTagsFromContract(
345
+ contractAddress: AztecAddress,
346
+ tags: Tag[],
347
+ page: number = 0,
348
+ ): Promise<TxScopedL2Log[][]> {
331
349
  const logs = await Promise.all(
332
350
  tags.map(tag => {
333
351
  const key = `${contractAddress.toString()}_${tag.value.toString()}`;
334
352
  return this.#publicLogsByContractAndTag.getAsync(key);
335
353
  }),
336
354
  );
337
- return logs.map(logBuffers => logBuffers?.map(logBuffer => TxScopedL2Log.fromBuffer(logBuffer)) ?? []);
355
+ const start = page * MAX_LOGS_PER_TAG;
356
+ const end = start + MAX_LOGS_PER_TAG;
357
+
358
+ return logs.map(
359
+ logBuffers => logBuffers?.slice(start, end).map(logBuffer => TxScopedL2Log.fromBuffer(logBuffer)) ?? [],
360
+ );
338
361
  }
339
362
 
340
363
  /**
@@ -10,7 +10,7 @@ import { Fr } from '@aztec/foundation/curves/bn254';
10
10
  import { EthAddress } from '@aztec/foundation/eth-address';
11
11
  import { createLogger } from '@aztec/foundation/log';
12
12
  import { RollupAbi } from '@aztec/l1-artifacts';
13
- import { CommitteeAttestation, CommitteeAttestationsAndSigners, L2BlockNew } from '@aztec/stdlib/block';
13
+ import { CommitteeAttestation, CommitteeAttestationsAndSigners, L2Block } from '@aztec/stdlib/block';
14
14
  import { Checkpoint } from '@aztec/stdlib/checkpoint';
15
15
  import { getSlotAtTimestamp } from '@aztec/stdlib/epoch-helpers';
16
16
  import { InboxLeaf } from '@aztec/stdlib/messaging';
@@ -51,7 +51,7 @@ type AddCheckpointOptions = {
51
51
  /** Number of L2 blocks in the checkpoint. Default: 1 */
52
52
  numBlocks?: number;
53
53
  /** Or the actual blocks for the checkpoint */
54
- blocks?: L2BlockNew[];
54
+ blocks?: L2Block[];
55
55
  /** Number of transactions per block. Default: 4 */
56
56
  txsPerBlock?: number;
57
57
  /** Max number of effects per tx (for generating large blobs). Default: undefined */