@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.
- package/README.md +9 -0
- package/dest/archiver.d.ts +3 -3
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +12 -12
- package/dest/factory.d.ts +3 -2
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +5 -3
- package/dest/l1/bin/retrieve-calldata.js +2 -2
- package/dest/l1/data_retrieval.d.ts +1 -1
- package/dest/l1/data_retrieval.d.ts.map +1 -1
- package/dest/l1/data_retrieval.js +2 -2
- package/dest/modules/data_source_base.d.ts +18 -19
- package/dest/modules/data_source_base.d.ts.map +1 -1
- package/dest/modules/data_source_base.js +25 -56
- package/dest/modules/data_store_updater.d.ts +5 -5
- package/dest/modules/data_store_updater.d.ts.map +1 -1
- package/dest/modules/instrumentation.d.ts +3 -3
- package/dest/modules/instrumentation.d.ts.map +1 -1
- package/dest/store/block_store.d.ts +21 -11
- package/dest/store/block_store.d.ts.map +1 -1
- package/dest/store/block_store.js +34 -5
- package/dest/store/kv_archiver_store.d.ts +25 -17
- package/dest/store/kv_archiver_store.d.ts.map +1 -1
- package/dest/store/kv_archiver_store.js +16 -8
- package/dest/store/log_store.d.ts +17 -8
- package/dest/store/log_store.d.ts.map +1 -1
- package/dest/store/log_store.js +20 -6
- package/dest/test/fake_l1_state.d.ts +4 -4
- package/dest/test/fake_l1_state.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.d.ts +18 -18
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +37 -38
- package/dest/test/mock_structs.js +4 -4
- package/package.json +13 -13
- package/src/archiver.ts +15 -18
- package/src/factory.ts +4 -2
- package/src/l1/bin/retrieve-calldata.ts +7 -2
- package/src/l1/data_retrieval.ts +3 -3
- package/src/modules/data_source_base.ts +33 -80
- package/src/modules/data_store_updater.ts +7 -7
- package/src/modules/instrumentation.ts +2 -2
- package/src/store/block_store.ts +59 -21
- package/src/store/kv_archiver_store.ts +35 -19
- package/src/store/log_store.ts +37 -14
- package/src/test/fake_l1_state.ts +2 -2
- package/src/test/mock_l2_block_source.ts +49 -59
- package/src/test/mock_structs.ts +4 -4
package/src/store/block_store.ts
CHANGED
|
@@ -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(
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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<
|
|
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<
|
|
476
|
-
const blocks:
|
|
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<
|
|
516
|
+
async unwindBlocksAfter(blockNumber: BlockNumber): Promise<L2Block[]> {
|
|
500
517
|
return await this.db.transactionAsync(async () => {
|
|
501
|
-
const removedBlocks:
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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
|
|
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
|
-
|
|
808
|
-
|
|
844
|
+
status,
|
|
845
|
+
TxReceipt.executionResultFromRevertCode(txEffect.data.revertCode),
|
|
846
|
+
undefined,
|
|
809
847
|
txEffect.data.transactionFee.toBigInt(),
|
|
810
848
|
txEffect.l2BlockHash,
|
|
811
|
-
|
|
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,
|
|
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:
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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:
|
|
395
|
+
addLogs(blocks: L2Block[]): Promise<boolean> {
|
|
389
396
|
return this.#logStore.addLogs(blocks);
|
|
390
397
|
}
|
|
391
398
|
|
|
392
|
-
deleteLogs(blocks:
|
|
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
|
|
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
|
|
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
|
-
|
|
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<
|
|
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<
|
|
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<
|
|
635
|
+
removeBlocksAfter(blockNumber: BlockNumber): Promise<L2Block[]> {
|
|
620
636
|
return this.#blockStore.unwindBlocksAfter(blockNumber);
|
|
621
637
|
}
|
|
622
638
|
}
|
package/src/store/log_store.ts
CHANGED
|
@@ -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 {
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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(
|
|
330
|
+
return logs.map(
|
|
331
|
+
logBuffers => logBuffers?.slice(start, end).map(logBuffer => TxScopedL2Log.fromBuffer(logBuffer)) ?? [],
|
|
332
|
+
);
|
|
324
333
|
}
|
|
325
334
|
|
|
326
335
|
/**
|
|
327
|
-
* Gets
|
|
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(
|
|
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
|
-
|
|
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,
|
|
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?:
|
|
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 */
|