@aztec/archiver 0.0.1-commit.f295ac2 → 0.0.1-commit.f8ca9b2f3
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 +6 -5
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +34 -22
- package/dest/errors.d.ts +6 -1
- package/dest/errors.d.ts.map +1 -1
- package/dest/errors.js +8 -0
- package/dest/factory.d.ts +5 -2
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +11 -8
- package/dest/l1/bin/retrieve-calldata.js +17 -18
- 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 +3 -3
- package/dest/l1/validate_trace.d.ts +6 -3
- package/dest/l1/validate_trace.d.ts.map +1 -1
- package/dest/l1/validate_trace.js +13 -9
- package/dest/modules/data_source_base.d.ts +19 -20
- 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 +23 -19
- package/dest/modules/data_store_updater.d.ts.map +1 -1
- package/dest/modules/data_store_updater.js +47 -49
- package/dest/modules/instrumentation.d.ts +3 -3
- package/dest/modules/instrumentation.d.ts.map +1 -1
- package/dest/modules/instrumentation.js +17 -10
- package/dest/modules/l1_synchronizer.d.ts +1 -1
- package/dest/modules/l1_synchronizer.d.ts.map +1 -1
- package/dest/modules/l1_synchronizer.js +9 -10
- package/dest/store/block_store.d.ts +35 -21
- package/dest/store/block_store.d.ts.map +1 -1
- package/dest/store/block_store.js +81 -40
- package/dest/store/contract_class_store.d.ts +1 -1
- package/dest/store/contract_class_store.d.ts.map +1 -1
- package/dest/store/contract_class_store.js +11 -7
- package/dest/store/kv_archiver_store.d.ts +37 -28
- package/dest/store/kv_archiver_store.d.ts.map +1 -1
- package/dest/store/kv_archiver_store.js +31 -23
- 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 +77 -43
- package/dest/test/fake_l1_state.d.ts +4 -4
- package/dest/test/fake_l1_state.d.ts.map +1 -1
- package/dest/test/index.js +3 -1
- package/dest/test/mock_archiver.js +1 -1
- package/dest/test/mock_l2_block_source.d.ts +20 -20
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +40 -41
- package/dest/test/mock_structs.d.ts +3 -2
- package/dest/test/mock_structs.d.ts.map +1 -1
- package/dest/test/mock_structs.js +11 -9
- package/dest/test/noop_l1_archiver.d.ts +23 -0
- package/dest/test/noop_l1_archiver.d.ts.map +1 -0
- package/dest/test/noop_l1_archiver.js +68 -0
- package/package.json +14 -13
- package/src/archiver.ts +46 -28
- package/src/errors.ts +12 -0
- package/src/factory.ts +23 -13
- package/src/l1/bin/retrieve-calldata.ts +16 -17
- package/src/l1/data_retrieval.ts +4 -4
- package/src/l1/validate_trace.ts +24 -6
- package/src/modules/data_source_base.ts +34 -81
- package/src/modules/data_store_updater.ts +59 -55
- package/src/modules/instrumentation.ts +17 -12
- package/src/modules/l1_synchronizer.ts +11 -12
- package/src/store/block_store.ts +107 -60
- package/src/store/contract_class_store.ts +11 -7
- package/src/store/kv_archiver_store.ts +52 -35
- package/src/store/log_store.ts +134 -49
- package/src/test/fake_l1_state.ts +2 -2
- package/src/test/index.ts +3 -0
- package/src/test/mock_archiver.ts +1 -1
- package/src/test/mock_l2_block_source.ts +54 -64
- package/src/test/mock_structs.ts +26 -10
- package/src/test/noop_l1_archiver.ts +109 -0
package/src/store/block_store.ts
CHANGED
|
@@ -9,16 +9,17 @@ import { isDefined } from '@aztec/foundation/types';
|
|
|
9
9
|
import type { AztecAsyncKVStore, AztecAsyncMap, AztecAsyncSingleton, Range } from '@aztec/kv-store';
|
|
10
10
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
11
11
|
import {
|
|
12
|
+
BlockHash,
|
|
12
13
|
Body,
|
|
13
14
|
CheckpointedL2Block,
|
|
14
15
|
CommitteeAttestation,
|
|
15
|
-
|
|
16
|
-
L2BlockNew,
|
|
16
|
+
L2Block,
|
|
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';
|
|
@@ -36,6 +38,7 @@ import {
|
|
|
36
38
|
BlockIndexNotSequentialError,
|
|
37
39
|
BlockNotFoundError,
|
|
38
40
|
BlockNumberNotSequentialError,
|
|
41
|
+
CannotOverwriteCheckpointedBlockError,
|
|
39
42
|
CheckpointNotFoundError,
|
|
40
43
|
CheckpointNumberNotConsistentError,
|
|
41
44
|
CheckpointNumberNotSequentialError,
|
|
@@ -75,6 +78,8 @@ export type CheckpointData = {
|
|
|
75
78
|
attestations: Buffer[];
|
|
76
79
|
};
|
|
77
80
|
|
|
81
|
+
export type RemoveCheckpointsResult = { blocksRemoved: L2Block[] | undefined };
|
|
82
|
+
|
|
78
83
|
/**
|
|
79
84
|
* LMDB-based block storage for the archiver.
|
|
80
85
|
*/
|
|
@@ -111,7 +116,10 @@ export class BlockStore {
|
|
|
111
116
|
|
|
112
117
|
#log = createLogger('archiver:block_store');
|
|
113
118
|
|
|
114
|
-
constructor(
|
|
119
|
+
constructor(
|
|
120
|
+
private db: AztecAsyncKVStore,
|
|
121
|
+
private l1Constants: Pick<L1RollupConstants, 'epochDuration'>,
|
|
122
|
+
) {
|
|
115
123
|
this.#blocks = db.openMap('archiver_blocks');
|
|
116
124
|
this.#blockTxs = db.openMap('archiver_block_txs');
|
|
117
125
|
this.#txEffects = db.openMap('archiver_tx_effects');
|
|
@@ -125,11 +133,25 @@ export class BlockStore {
|
|
|
125
133
|
}
|
|
126
134
|
|
|
127
135
|
/**
|
|
128
|
-
*
|
|
129
|
-
*
|
|
136
|
+
* Computes the finalized block number based on the proven block number.
|
|
137
|
+
* A block is considered finalized when it's 2 epochs behind the proven block.
|
|
138
|
+
* TODO(#13569): Compute proper finalized block number based on L1 finalized block.
|
|
139
|
+
* TODO(palla/mbps): Even the provisional computation is wrong, since it should subtract checkpoints, not blocks
|
|
140
|
+
* @returns The finalized block number.
|
|
141
|
+
*/
|
|
142
|
+
async getFinalizedL2BlockNumber(): Promise<BlockNumber> {
|
|
143
|
+
const provenBlockNumber = await this.getProvenBlockNumber();
|
|
144
|
+
return BlockNumber(Math.max(provenBlockNumber - this.l1Constants.epochDuration * 2, 0));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Append new proposed blocks to the store's list. All blocks must be for the 'current' checkpoint.
|
|
149
|
+
* These are uncheckpointed blocks that have been proposed by the sequencer but not yet included in a checkpoint on L1.
|
|
150
|
+
* For checkpointed blocks (already published to L1), use addCheckpoints() instead.
|
|
151
|
+
* @param blocks - The proposed L2 blocks to be added to the store.
|
|
130
152
|
* @returns True if the operation is successful.
|
|
131
153
|
*/
|
|
132
|
-
async
|
|
154
|
+
async addProposedBlocks(blocks: L2Block[], opts: { force?: boolean } = {}): Promise<boolean> {
|
|
133
155
|
if (blocks.length === 0) {
|
|
134
156
|
return true;
|
|
135
157
|
}
|
|
@@ -145,6 +167,12 @@ export class BlockStore {
|
|
|
145
167
|
const previousBlockNumber = await this.getLatestBlockNumber();
|
|
146
168
|
const previousCheckpointNumber = await this.getLatestCheckpointNumber();
|
|
147
169
|
|
|
170
|
+
// Verify we're not overwriting checkpointed blocks
|
|
171
|
+
const lastCheckpointedBlockNumber = await this.getCheckpointedL2BlockNumber();
|
|
172
|
+
if (!opts.force && firstBlockNumber <= lastCheckpointedBlockNumber) {
|
|
173
|
+
throw new CannotOverwriteCheckpointedBlockError(firstBlockNumber, lastCheckpointedBlockNumber);
|
|
174
|
+
}
|
|
175
|
+
|
|
148
176
|
// Check that the first block number is the expected one
|
|
149
177
|
if (!opts.force && previousBlockNumber !== firstBlockNumber - 1) {
|
|
150
178
|
throw new InitialBlockNumberNotSequentialError(firstBlockNumber, previousBlockNumber);
|
|
@@ -182,7 +210,7 @@ export class BlockStore {
|
|
|
182
210
|
}
|
|
183
211
|
|
|
184
212
|
// 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:
|
|
213
|
+
let previousBlock: L2Block | undefined = undefined;
|
|
186
214
|
for (const block of blocks) {
|
|
187
215
|
if (!opts.force && previousBlock) {
|
|
188
216
|
if (previousBlock.number + 1 !== block.number) {
|
|
@@ -241,7 +269,7 @@ export class BlockStore {
|
|
|
241
269
|
}
|
|
242
270
|
|
|
243
271
|
let previousBlockNumber: BlockNumber | undefined = undefined;
|
|
244
|
-
let previousBlock:
|
|
272
|
+
let previousBlock: L2Block | undefined = undefined;
|
|
245
273
|
|
|
246
274
|
// If we have a previous checkpoint then we need to get the previous block number
|
|
247
275
|
if (previousCheckpointData !== undefined) {
|
|
@@ -322,8 +350,8 @@ export class BlockStore {
|
|
|
322
350
|
});
|
|
323
351
|
}
|
|
324
352
|
|
|
325
|
-
private async addBlockToDatabase(block:
|
|
326
|
-
const blockHash =
|
|
353
|
+
private async addBlockToDatabase(block: L2Block, checkpointNumber: number, indexWithinCheckpoint: number) {
|
|
354
|
+
const blockHash = await block.hash();
|
|
327
355
|
|
|
328
356
|
await this.#blocks.set(block.number, {
|
|
329
357
|
header: block.header.toBuffer(),
|
|
@@ -351,7 +379,7 @@ export class BlockStore {
|
|
|
351
379
|
}
|
|
352
380
|
|
|
353
381
|
/** Deletes a block and all associated data (tx effects, indices). */
|
|
354
|
-
private async deleteBlock(block:
|
|
382
|
+
private async deleteBlock(block: L2Block): Promise<void> {
|
|
355
383
|
// Delete the block from the main blocks map
|
|
356
384
|
await this.#blocks.delete(block.number);
|
|
357
385
|
|
|
@@ -368,51 +396,48 @@ export class BlockStore {
|
|
|
368
396
|
}
|
|
369
397
|
|
|
370
398
|
/**
|
|
371
|
-
*
|
|
372
|
-
*
|
|
373
|
-
*
|
|
374
|
-
* @param checkpointsToUnwind - The number of checkpoints we are to unwind
|
|
375
|
-
* @returns True if the operation is successful
|
|
399
|
+
* Removes all checkpoints with checkpoint number > checkpointNumber.
|
|
400
|
+
* Also removes ALL blocks (both checkpointed and uncheckpointed) after the last block of the given checkpoint.
|
|
401
|
+
* @param checkpointNumber - Remove all checkpoints strictly after this one.
|
|
376
402
|
*/
|
|
377
|
-
async
|
|
403
|
+
async removeCheckpointsAfter(checkpointNumber: CheckpointNumber): Promise<RemoveCheckpointsResult> {
|
|
378
404
|
return await this.db.transactionAsync(async () => {
|
|
379
|
-
const
|
|
380
|
-
|
|
381
|
-
|
|
405
|
+
const latestCheckpointNumber = await this.getLatestCheckpointNumber();
|
|
406
|
+
|
|
407
|
+
if (checkpointNumber >= latestCheckpointNumber) {
|
|
408
|
+
this.#log.warn(`No checkpoints to remove after ${checkpointNumber} (latest is ${latestCheckpointNumber})`);
|
|
409
|
+
return { blocksRemoved: undefined };
|
|
382
410
|
}
|
|
383
411
|
|
|
412
|
+
// If the proven checkpoint is beyond the target, update it
|
|
384
413
|
const proven = await this.getProvenCheckpointNumber();
|
|
385
|
-
if (
|
|
386
|
-
|
|
414
|
+
if (proven > checkpointNumber) {
|
|
415
|
+
this.#log.warn(`Updating proven checkpoint ${proven} to last valid checkpoint ${checkpointNumber}`);
|
|
416
|
+
await this.setProvenCheckpointNumber(checkpointNumber);
|
|
387
417
|
}
|
|
388
418
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
419
|
+
// Find the last block number to keep (last block of the given checkpoint, or 0 if no checkpoint)
|
|
420
|
+
let lastBlockToKeep: BlockNumber;
|
|
421
|
+
if (checkpointNumber <= 0) {
|
|
422
|
+
lastBlockToKeep = BlockNumber(INITIAL_L2_BLOCK_NUM - 1);
|
|
423
|
+
} else {
|
|
424
|
+
const targetCheckpoint = await this.#checkpoints.getAsync(checkpointNumber);
|
|
425
|
+
if (!targetCheckpoint) {
|
|
426
|
+
throw new Error(`Target checkpoint ${checkpointNumber} not found in store`);
|
|
396
427
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
for (let blockNumber = checkpoint.startBlock; blockNumber <= maxBlock; blockNumber++) {
|
|
401
|
-
const block = await this.getBlock(BlockNumber(blockNumber));
|
|
428
|
+
lastBlockToKeep = BlockNumber(targetCheckpoint.startBlock + targetCheckpoint.numBlocks - 1);
|
|
429
|
+
}
|
|
402
430
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
continue;
|
|
406
|
-
}
|
|
431
|
+
// Remove all blocks after lastBlockToKeep (both checkpointed and uncheckpointed)
|
|
432
|
+
const blocksRemoved = await this.removeBlocksAfter(lastBlockToKeep);
|
|
407
433
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
}
|
|
434
|
+
// Remove all checkpoints after the target
|
|
435
|
+
for (let c = latestCheckpointNumber; c > checkpointNumber; c = CheckpointNumber(c - 1)) {
|
|
436
|
+
await this.#checkpoints.delete(c);
|
|
437
|
+
this.#log.debug(`Removed checkpoint ${c}`);
|
|
413
438
|
}
|
|
414
439
|
|
|
415
|
-
return
|
|
440
|
+
return { blocksRemoved };
|
|
416
441
|
});
|
|
417
442
|
}
|
|
418
443
|
|
|
@@ -449,7 +474,7 @@ export class BlockStore {
|
|
|
449
474
|
return data;
|
|
450
475
|
}
|
|
451
476
|
|
|
452
|
-
async getBlocksForCheckpoint(checkpointNumber: CheckpointNumber): Promise<
|
|
477
|
+
async getBlocksForCheckpoint(checkpointNumber: CheckpointNumber): Promise<L2Block[] | undefined> {
|
|
453
478
|
const checkpoint = await this.#checkpoints.getAsync(checkpointNumber);
|
|
454
479
|
if (!checkpoint) {
|
|
455
480
|
return undefined;
|
|
@@ -472,8 +497,8 @@ export class BlockStore {
|
|
|
472
497
|
* @param slotNumber - The slot number to search for.
|
|
473
498
|
* @returns All blocks with the given slot number, in ascending block number order.
|
|
474
499
|
*/
|
|
475
|
-
async getBlocksForSlot(slotNumber: SlotNumber): Promise<
|
|
476
|
-
const blocks:
|
|
500
|
+
async getBlocksForSlot(slotNumber: SlotNumber): Promise<L2Block[]> {
|
|
501
|
+
const blocks: L2Block[] = [];
|
|
477
502
|
|
|
478
503
|
// Iterate backwards through all blocks and filter by slot number
|
|
479
504
|
// This is more efficient since we usually query for the most recent slot
|
|
@@ -493,12 +518,13 @@ export class BlockStore {
|
|
|
493
518
|
|
|
494
519
|
/**
|
|
495
520
|
* Removes all blocks with block number > blockNumber.
|
|
521
|
+
* Does not remove any associated checkpoints.
|
|
496
522
|
* @param blockNumber - The block number to remove after.
|
|
497
523
|
* @returns The removed blocks (for event emission).
|
|
498
524
|
*/
|
|
499
|
-
async
|
|
525
|
+
async removeBlocksAfter(blockNumber: BlockNumber): Promise<L2Block[]> {
|
|
500
526
|
return await this.db.transactionAsync(async () => {
|
|
501
|
-
const removedBlocks:
|
|
527
|
+
const removedBlocks: L2Block[] = [];
|
|
502
528
|
|
|
503
529
|
// Get the latest block number to determine the range
|
|
504
530
|
const latestBlockNumber = await this.getLatestBlockNumber();
|
|
@@ -598,7 +624,7 @@ export class BlockStore {
|
|
|
598
624
|
}
|
|
599
625
|
}
|
|
600
626
|
|
|
601
|
-
async getCheckpointedBlockByHash(blockHash:
|
|
627
|
+
async getCheckpointedBlockByHash(blockHash: BlockHash): Promise<CheckpointedL2Block | undefined> {
|
|
602
628
|
const blockNumber = await this.#blockHashIndex.getAsync(blockHash.toString());
|
|
603
629
|
if (blockNumber === undefined) {
|
|
604
630
|
return undefined;
|
|
@@ -620,7 +646,7 @@ export class BlockStore {
|
|
|
620
646
|
* @param limit - The number of blocks to return.
|
|
621
647
|
* @returns The requested L2 blocks
|
|
622
648
|
*/
|
|
623
|
-
async *getBlocks(start: BlockNumber, limit: number): AsyncIterableIterator<
|
|
649
|
+
async *getBlocks(start: BlockNumber, limit: number): AsyncIterableIterator<L2Block> {
|
|
624
650
|
for await (const [blockNumber, blockStorage] of this.getBlockStorages(start, limit)) {
|
|
625
651
|
const block = await this.getBlockFromBlockStorage(blockNumber, blockStorage);
|
|
626
652
|
if (block) {
|
|
@@ -634,7 +660,7 @@ export class BlockStore {
|
|
|
634
660
|
* @param blockNumber - The number of the block to return.
|
|
635
661
|
* @returns The requested L2 block.
|
|
636
662
|
*/
|
|
637
|
-
async getBlock(blockNumber: BlockNumber): Promise<
|
|
663
|
+
async getBlock(blockNumber: BlockNumber): Promise<L2Block | undefined> {
|
|
638
664
|
const blockStorage = await this.#blocks.getAsync(blockNumber);
|
|
639
665
|
if (!blockStorage || !blockStorage.header) {
|
|
640
666
|
return Promise.resolve(undefined);
|
|
@@ -647,7 +673,7 @@ export class BlockStore {
|
|
|
647
673
|
* @param blockHash - The hash of the block to return.
|
|
648
674
|
* @returns The requested L2 block.
|
|
649
675
|
*/
|
|
650
|
-
async getBlockByHash(blockHash:
|
|
676
|
+
async getBlockByHash(blockHash: BlockHash): Promise<L2Block | undefined> {
|
|
651
677
|
const blockNumber = await this.#blockHashIndex.getAsync(blockHash.toString());
|
|
652
678
|
if (blockNumber === undefined) {
|
|
653
679
|
return undefined;
|
|
@@ -660,7 +686,7 @@ export class BlockStore {
|
|
|
660
686
|
* @param archive - The archive root of the block to return.
|
|
661
687
|
* @returns The requested L2 block.
|
|
662
688
|
*/
|
|
663
|
-
async getBlockByArchive(archive: Fr): Promise<
|
|
689
|
+
async getBlockByArchive(archive: Fr): Promise<L2Block | undefined> {
|
|
664
690
|
const blockNumber = await this.#blockArchiveIndex.getAsync(archive.toString());
|
|
665
691
|
if (blockNumber === undefined) {
|
|
666
692
|
return undefined;
|
|
@@ -673,7 +699,7 @@ export class BlockStore {
|
|
|
673
699
|
* @param blockHash - The hash of the block to return.
|
|
674
700
|
* @returns The requested block header.
|
|
675
701
|
*/
|
|
676
|
-
async getBlockHeaderByHash(blockHash:
|
|
702
|
+
async getBlockHeaderByHash(blockHash: BlockHash): Promise<BlockHeader | undefined> {
|
|
677
703
|
const blockNumber = await this.#blockHashIndex.getAsync(blockHash.toString());
|
|
678
704
|
if (blockNumber === undefined) {
|
|
679
705
|
return undefined;
|
|
@@ -736,7 +762,7 @@ export class BlockStore {
|
|
|
736
762
|
private async getBlockFromBlockStorage(
|
|
737
763
|
blockNumber: number,
|
|
738
764
|
blockStorage: BlockStorage,
|
|
739
|
-
): Promise<
|
|
765
|
+
): Promise<L2Block | undefined> {
|
|
740
766
|
const header = BlockHeader.fromBuffer(blockStorage.header);
|
|
741
767
|
const archive = AppendOnlyTreeSnapshot.fromBuffer(blockStorage.archive);
|
|
742
768
|
const blockHash = blockStorage.blockHash;
|
|
@@ -760,7 +786,7 @@ export class BlockStore {
|
|
|
760
786
|
txEffects.push(deserializeIndexedTxEffect(txEffect).data);
|
|
761
787
|
}
|
|
762
788
|
const body = new Body(txEffects);
|
|
763
|
-
const block = new
|
|
789
|
+
const block = new L2Block(
|
|
764
790
|
archive,
|
|
765
791
|
header,
|
|
766
792
|
body,
|
|
@@ -802,13 +828,34 @@ export class BlockStore {
|
|
|
802
828
|
return undefined;
|
|
803
829
|
}
|
|
804
830
|
|
|
831
|
+
const blockNumber = BlockNumber(txEffect.l2BlockNumber);
|
|
832
|
+
|
|
833
|
+
// Use existing archiver methods to determine finalization level
|
|
834
|
+
const [provenBlockNumber, checkpointedBlockNumber, finalizedBlockNumber] = await Promise.all([
|
|
835
|
+
this.getProvenBlockNumber(),
|
|
836
|
+
this.getCheckpointedL2BlockNumber(),
|
|
837
|
+
this.getFinalizedL2BlockNumber(),
|
|
838
|
+
]);
|
|
839
|
+
|
|
840
|
+
let status: TxStatus;
|
|
841
|
+
if (blockNumber <= finalizedBlockNumber) {
|
|
842
|
+
status = TxStatus.FINALIZED;
|
|
843
|
+
} else if (blockNumber <= provenBlockNumber) {
|
|
844
|
+
status = TxStatus.PROVEN;
|
|
845
|
+
} else if (blockNumber <= checkpointedBlockNumber) {
|
|
846
|
+
status = TxStatus.CHECKPOINTED;
|
|
847
|
+
} else {
|
|
848
|
+
status = TxStatus.PROPOSED;
|
|
849
|
+
}
|
|
850
|
+
|
|
805
851
|
return new TxReceipt(
|
|
806
852
|
txHash,
|
|
807
|
-
|
|
808
|
-
|
|
853
|
+
status,
|
|
854
|
+
TxReceipt.executionResultFromRevertCode(txEffect.data.revertCode),
|
|
855
|
+
undefined,
|
|
809
856
|
txEffect.data.transactionFee.toBigInt(),
|
|
810
857
|
txEffect.l2BlockHash,
|
|
811
|
-
|
|
858
|
+
blockNumber,
|
|
812
859
|
);
|
|
813
860
|
}
|
|
814
861
|
|
|
@@ -28,18 +28,22 @@ export class ContractClassStore {
|
|
|
28
28
|
bytecodeCommitment: Fr,
|
|
29
29
|
blockNumber: number,
|
|
30
30
|
): Promise<void> {
|
|
31
|
-
await this
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
await this.db.transactionAsync(async () => {
|
|
32
|
+
await this.#contractClasses.setIfNotExists(
|
|
33
|
+
contractClass.id.toString(),
|
|
34
|
+
serializeContractClassPublic({ ...contractClass, l2BlockNumber: blockNumber }),
|
|
35
|
+
);
|
|
36
|
+
await this.#bytecodeCommitments.setIfNotExists(contractClass.id.toString(), bytecodeCommitment.toBuffer());
|
|
37
|
+
});
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
async deleteContractClasses(contractClass: ContractClassPublic, blockNumber: number): Promise<void> {
|
|
39
41
|
const restoredContractClass = await this.#contractClasses.getAsync(contractClass.id.toString());
|
|
40
42
|
if (restoredContractClass && deserializeContractClassPublic(restoredContractClass).l2BlockNumber >= blockNumber) {
|
|
41
|
-
await this
|
|
42
|
-
|
|
43
|
+
await this.db.transactionAsync(async () => {
|
|
44
|
+
await this.#contractClasses.delete(contractClass.id.toString());
|
|
45
|
+
await this.#bytecodeCommitments.delete(contractClass.id.toString());
|
|
46
|
+
});
|
|
43
47
|
}
|
|
44
48
|
}
|
|
45
49
|
|
|
@@ -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 {
|
|
9
|
+
import { BlockHash, CheckpointedL2Block, L2Block, 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';
|
|
@@ -24,7 +25,7 @@ import type { UInt64 } from '@aztec/stdlib/types';
|
|
|
24
25
|
import { join } from 'path';
|
|
25
26
|
|
|
26
27
|
import type { InboxMessage } from '../structs/inbox_message.js';
|
|
27
|
-
import { BlockStore, type CheckpointData } from './block_store.js';
|
|
28
|
+
import { BlockStore, type CheckpointData, type RemoveCheckpointsResult } from './block_store.js';
|
|
28
29
|
import { ContractClassStore } from './contract_class_store.js';
|
|
29
30
|
import { ContractInstanceStore } from './contract_instance_store.js';
|
|
30
31
|
import { LogStore } from './log_store.js';
|
|
@@ -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()));
|
|
@@ -228,12 +235,14 @@ export class KVArchiverDataStore implements ContractDataSource {
|
|
|
228
235
|
}
|
|
229
236
|
|
|
230
237
|
/**
|
|
231
|
-
* Append new blocks to the store's list.
|
|
232
|
-
*
|
|
238
|
+
* Append new proposed blocks to the store's list.
|
|
239
|
+
* These are uncheckpointed blocks that have been proposed by the sequencer but not yet included in a checkpoint on L1.
|
|
240
|
+
* For checkpointed blocks (already published to L1), use addCheckpoints() instead.
|
|
241
|
+
* @param blocks - The proposed L2 blocks to be added to the store.
|
|
233
242
|
* @returns True if the operation is successful.
|
|
234
243
|
*/
|
|
235
|
-
|
|
236
|
-
return this.#blockStore.
|
|
244
|
+
addProposedBlocks(blocks: L2Block[], opts: { force?: boolean; checkpointNumber?: number } = {}): Promise<boolean> {
|
|
245
|
+
return this.#blockStore.addProposedBlocks(blocks, opts);
|
|
237
246
|
}
|
|
238
247
|
|
|
239
248
|
/**
|
|
@@ -254,14 +263,12 @@ export class KVArchiverDataStore implements ContractDataSource {
|
|
|
254
263
|
}
|
|
255
264
|
|
|
256
265
|
/**
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
*
|
|
260
|
-
* @param checkpointsToUnwind - The number of checkpoints we are to unwind
|
|
261
|
-
* @returns True if the operation is successful
|
|
266
|
+
* Removes all checkpoints with checkpoint number > checkpointNumber.
|
|
267
|
+
* Also removes ALL blocks (both checkpointed and uncheckpointed) after the last block of the given checkpoint.
|
|
268
|
+
* @param checkpointNumber - Remove all checkpoints strictly after this one.
|
|
262
269
|
*/
|
|
263
|
-
|
|
264
|
-
return this.#blockStore.
|
|
270
|
+
removeCheckpointsAfter(checkpointNumber: CheckpointNumber): Promise<RemoveCheckpointsResult> {
|
|
271
|
+
return this.#blockStore.removeCheckpointsAfter(checkpointNumber);
|
|
265
272
|
}
|
|
266
273
|
|
|
267
274
|
/**
|
|
@@ -284,7 +291,7 @@ export class KVArchiverDataStore implements ContractDataSource {
|
|
|
284
291
|
* Returns the block for the given hash, or undefined if not exists.
|
|
285
292
|
* @param blockHash - The block hash to return.
|
|
286
293
|
*/
|
|
287
|
-
getCheckpointedBlockByHash(blockHash:
|
|
294
|
+
getCheckpointedBlockByHash(blockHash: BlockHash): Promise<CheckpointedL2Block | undefined> {
|
|
288
295
|
return this.#blockStore.getCheckpointedBlockByHash(blockHash);
|
|
289
296
|
}
|
|
290
297
|
/**
|
|
@@ -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:
|
|
309
|
-
return this.#blockStore.getBlockByHash(
|
|
315
|
+
getBlockByHash(blockHash: BlockHash): Promise<L2Block | undefined> {
|
|
316
|
+
return this.#blockStore.getBlockByHash(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
|
|
|
@@ -350,8 +357,8 @@ export class KVArchiverDataStore implements ContractDataSource {
|
|
|
350
357
|
* Returns the block header for the given hash, or undefined if not exists.
|
|
351
358
|
* @param blockHash - The block hash to return.
|
|
352
359
|
*/
|
|
353
|
-
getBlockHeaderByHash(blockHash:
|
|
354
|
-
return this.#blockStore.getBlockHeaderByHash(
|
|
360
|
+
getBlockHeaderByHash(blockHash: BlockHash): Promise<BlockHeader | undefined> {
|
|
361
|
+
return this.#blockStore.getBlockHeaderByHash(blockHash);
|
|
355
362
|
}
|
|
356
363
|
|
|
357
364
|
/**
|
|
@@ -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,16 +623,17 @@ 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
|
|
|
614
630
|
/**
|
|
615
631
|
* Removes all blocks with block number > blockNumber.
|
|
632
|
+
* Does not remove any associated checkpoints.
|
|
616
633
|
* @param blockNumber - The block number to remove after.
|
|
617
634
|
* @returns The removed blocks (for event emission).
|
|
618
635
|
*/
|
|
619
|
-
removeBlocksAfter(blockNumber: BlockNumber): Promise<
|
|
620
|
-
return this.#blockStore.
|
|
636
|
+
removeBlocksAfter(blockNumber: BlockNumber): Promise<L2Block[]> {
|
|
637
|
+
return this.#blockStore.removeBlocksAfter(blockNumber);
|
|
621
638
|
}
|
|
622
639
|
}
|