@aztec/archiver 4.0.0-nightly.20260126 → 4.0.0-nightly.20260128
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/dest/archiver.d.ts +4 -3
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +8 -9
- 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 +3 -1
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +1 -1
- package/dest/modules/data_store_updater.d.ts +21 -17
- package/dest/modules/data_store_updater.d.ts.map +1 -1
- package/dest/modules/data_store_updater.js +47 -49
- package/dest/modules/l1_synchronizer.js +7 -7
- package/dest/store/block_store.d.ts +18 -14
- package/dest/store/block_store.d.ts.map +1 -1
- package/dest/store/block_store.js +48 -36
- package/dest/store/kv_archiver_store.d.ts +12 -11
- package/dest/store/kv_archiver_store.d.ts.map +1 -1
- package/dest/store/kv_archiver_store.js +16 -15
- package/dest/store/log_store.d.ts +1 -1
- package/dest/store/log_store.d.ts.map +1 -1
- package/dest/store/log_store.js +2 -2
- package/dest/test/index.d.ts +2 -1
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/index.js +1 -0
- package/dest/test/mock_archiver.js +1 -1
- package/dest/test/mock_l2_block_source.d.ts +4 -4
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +5 -5
- 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 +7 -5
- 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 +13 -13
- package/src/archiver.ts +11 -10
- package/src/errors.ts +12 -0
- package/src/factory.ts +2 -1
- package/src/modules/data_store_updater.ts +57 -53
- package/src/modules/l1_synchronizer.ts +9 -9
- package/src/store/block_store.ts +50 -41
- package/src/store/kv_archiver_store.ts +17 -16
- package/src/store/log_store.ts +4 -4
- package/src/test/index.ts +1 -0
- package/src/test/mock_archiver.ts +1 -1
- package/src/test/mock_l2_block_source.ts +5 -5
- package/src/test/mock_structs.ts +22 -6
- package/src/test/noop_l1_archiver.ts +109 -0
|
@@ -258,7 +258,7 @@ export class ArchiverL1Synchronizer implements Traceable {
|
|
|
258
258
|
`Pruning blocks after block ${lastCheckpointedBlockNumber} due to slot ${firstUncheckpointedBlockSlot} not being checkpointed`,
|
|
259
259
|
{ firstUncheckpointedBlockHeader: firstUncheckpointedBlockHeader.toInspect(), slotAtNextL1Block },
|
|
260
260
|
);
|
|
261
|
-
const prunedBlocks = await this.updater.
|
|
261
|
+
const prunedBlocks = await this.updater.removeUncheckpointedBlocksAfter(lastCheckpointedBlockNumber);
|
|
262
262
|
|
|
263
263
|
if (prunedBlocks.length > 0) {
|
|
264
264
|
this.events.emit(L2BlockSourceEvents.L2PruneUncheckpointed, {
|
|
@@ -331,10 +331,10 @@ export class ArchiverL1Synchronizer implements Traceable {
|
|
|
331
331
|
this.log.debug(
|
|
332
332
|
`L2 prune from ${provenCheckpointNumber + 1} to ${localPendingCheckpointNumber} will occur on next checkpoint submission.`,
|
|
333
333
|
);
|
|
334
|
-
await this.updater.
|
|
334
|
+
await this.updater.removeCheckpointsAfter(provenCheckpointNumber);
|
|
335
335
|
this.log.warn(
|
|
336
|
-
`
|
|
337
|
-
`
|
|
336
|
+
`Removed ${count(checkpointsToUnwind, 'checkpoint')} after checkpoint ${provenCheckpointNumber} ` +
|
|
337
|
+
`due to predicted reorg at L1 block ${currentL1BlockNumber}. ` +
|
|
338
338
|
`Updated latest checkpoint is ${await this.store.getSynchedCheckpointNumber()}.`,
|
|
339
339
|
);
|
|
340
340
|
this.instrumentation.processPrune(timer.ms());
|
|
@@ -675,11 +675,11 @@ export class ArchiverL1Synchronizer implements Traceable {
|
|
|
675
675
|
tipAfterUnwind--;
|
|
676
676
|
}
|
|
677
677
|
|
|
678
|
-
const
|
|
679
|
-
await this.updater.
|
|
678
|
+
const checkpointsToRemove = localPendingCheckpointNumber - tipAfterUnwind;
|
|
679
|
+
await this.updater.removeCheckpointsAfter(CheckpointNumber(tipAfterUnwind));
|
|
680
680
|
|
|
681
681
|
this.log.warn(
|
|
682
|
-
`
|
|
682
|
+
`Removed ${count(checkpointsToRemove, 'checkpoint')} after checkpoint ${tipAfterUnwind} ` +
|
|
683
683
|
`due to mismatched checkpoint hashes at L1 block ${currentL1BlockNumber}. ` +
|
|
684
684
|
`Updated L2 latest checkpoint is ${await this.store.getSynchedCheckpointNumber()}.`,
|
|
685
685
|
);
|
|
@@ -806,8 +806,8 @@ export class ArchiverL1Synchronizer implements Traceable {
|
|
|
806
806
|
const updatedValidationResult =
|
|
807
807
|
rollupStatus.validationResult === initialValidationResult ? undefined : rollupStatus.validationResult;
|
|
808
808
|
const [processDuration, result] = await elapsed(() =>
|
|
809
|
-
execInSpan(this.tracer, 'Archiver.
|
|
810
|
-
this.updater.
|
|
809
|
+
execInSpan(this.tracer, 'Archiver.addCheckpoints', () =>
|
|
810
|
+
this.updater.addCheckpoints(validCheckpoints, updatedValidationResult),
|
|
811
811
|
),
|
|
812
812
|
);
|
|
813
813
|
this.instrumentation.processNewBlocks(
|
package/src/store/block_store.ts
CHANGED
|
@@ -9,11 +9,11 @@ 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
|
L2Block,
|
|
16
|
-
L2BlockHash,
|
|
17
17
|
type ValidateCheckpointResult,
|
|
18
18
|
deserializeValidateCheckpointResult,
|
|
19
19
|
serializeValidateCheckpointResult,
|
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
BlockIndexNotSequentialError,
|
|
39
39
|
BlockNotFoundError,
|
|
40
40
|
BlockNumberNotSequentialError,
|
|
41
|
+
CannotOverwriteCheckpointedBlockError,
|
|
41
42
|
CheckpointNotFoundError,
|
|
42
43
|
CheckpointNumberNotConsistentError,
|
|
43
44
|
CheckpointNumberNotSequentialError,
|
|
@@ -77,6 +78,8 @@ export type CheckpointData = {
|
|
|
77
78
|
attestations: Buffer[];
|
|
78
79
|
};
|
|
79
80
|
|
|
81
|
+
export type RemoveCheckpointsResult = { blocksRemoved: L2Block[] | undefined };
|
|
82
|
+
|
|
80
83
|
/**
|
|
81
84
|
* LMDB-based block storage for the archiver.
|
|
82
85
|
*/
|
|
@@ -142,11 +145,13 @@ export class BlockStore {
|
|
|
142
145
|
}
|
|
143
146
|
|
|
144
147
|
/**
|
|
145
|
-
* Append new blocks to the store's list. All blocks must be for the 'current' checkpoint
|
|
146
|
-
*
|
|
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.
|
|
147
152
|
* @returns True if the operation is successful.
|
|
148
153
|
*/
|
|
149
|
-
async
|
|
154
|
+
async addProposedBlocks(blocks: L2Block[], opts: { force?: boolean } = {}): Promise<boolean> {
|
|
150
155
|
if (blocks.length === 0) {
|
|
151
156
|
return true;
|
|
152
157
|
}
|
|
@@ -162,6 +167,12 @@ export class BlockStore {
|
|
|
162
167
|
const previousBlockNumber = await this.getLatestBlockNumber();
|
|
163
168
|
const previousCheckpointNumber = await this.getLatestCheckpointNumber();
|
|
164
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
|
+
|
|
165
176
|
// Check that the first block number is the expected one
|
|
166
177
|
if (!opts.force && previousBlockNumber !== firstBlockNumber - 1) {
|
|
167
178
|
throw new InitialBlockNumberNotSequentialError(firstBlockNumber, previousBlockNumber);
|
|
@@ -340,7 +351,7 @@ export class BlockStore {
|
|
|
340
351
|
}
|
|
341
352
|
|
|
342
353
|
private async addBlockToDatabase(block: L2Block, checkpointNumber: number, indexWithinCheckpoint: number) {
|
|
343
|
-
const blockHash =
|
|
354
|
+
const blockHash = BlockHash.fromField(await block.hash());
|
|
344
355
|
|
|
345
356
|
await this.#blocks.set(block.number, {
|
|
346
357
|
header: block.header.toBuffer(),
|
|
@@ -385,51 +396,48 @@ export class BlockStore {
|
|
|
385
396
|
}
|
|
386
397
|
|
|
387
398
|
/**
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
*
|
|
391
|
-
* @param checkpointsToUnwind - The number of checkpoints we are to unwind
|
|
392
|
-
* @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.
|
|
393
402
|
*/
|
|
394
|
-
async
|
|
403
|
+
async removeCheckpointsAfter(checkpointNumber: CheckpointNumber): Promise<RemoveCheckpointsResult> {
|
|
395
404
|
return await this.db.transactionAsync(async () => {
|
|
396
|
-
const
|
|
397
|
-
|
|
398
|
-
|
|
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 };
|
|
399
410
|
}
|
|
400
411
|
|
|
412
|
+
// If the proven checkpoint is beyond the target, update it
|
|
401
413
|
const proven = await this.getProvenCheckpointNumber();
|
|
402
|
-
if (
|
|
403
|
-
|
|
414
|
+
if (proven > checkpointNumber) {
|
|
415
|
+
this.#log.warn(`Updating proven checkpoint ${proven} to last valid checkpoint ${checkpointNumber}`);
|
|
416
|
+
await this.setProvenCheckpointNumber(checkpointNumber);
|
|
404
417
|
}
|
|
405
418
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
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`);
|
|
413
427
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
for (let blockNumber = checkpoint.startBlock; blockNumber <= maxBlock; blockNumber++) {
|
|
418
|
-
const block = await this.getBlock(BlockNumber(blockNumber));
|
|
428
|
+
lastBlockToKeep = BlockNumber(targetCheckpoint.startBlock + targetCheckpoint.numBlocks - 1);
|
|
429
|
+
}
|
|
419
430
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
continue;
|
|
423
|
-
}
|
|
431
|
+
// Remove all blocks after lastBlockToKeep (both checkpointed and uncheckpointed)
|
|
432
|
+
const blocksRemoved = await this.removeBlocksAfter(lastBlockToKeep);
|
|
424
433
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
}
|
|
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}`);
|
|
430
438
|
}
|
|
431
439
|
|
|
432
|
-
return
|
|
440
|
+
return { blocksRemoved };
|
|
433
441
|
});
|
|
434
442
|
}
|
|
435
443
|
|
|
@@ -510,10 +518,11 @@ export class BlockStore {
|
|
|
510
518
|
|
|
511
519
|
/**
|
|
512
520
|
* Removes all blocks with block number > blockNumber.
|
|
521
|
+
* Does not remove any associated checkpoints.
|
|
513
522
|
* @param blockNumber - The block number to remove after.
|
|
514
523
|
* @returns The removed blocks (for event emission).
|
|
515
524
|
*/
|
|
516
|
-
async
|
|
525
|
+
async removeBlocksAfter(blockNumber: BlockNumber): Promise<L2Block[]> {
|
|
517
526
|
return await this.db.transactionAsync(async () => {
|
|
518
527
|
const removedBlocks: L2Block[] = [];
|
|
519
528
|
|
|
@@ -664,7 +673,7 @@ export class BlockStore {
|
|
|
664
673
|
* @param blockHash - The hash of the block to return.
|
|
665
674
|
* @returns The requested L2 block.
|
|
666
675
|
*/
|
|
667
|
-
async getBlockByHash(blockHash:
|
|
676
|
+
async getBlockByHash(blockHash: BlockHash): Promise<L2Block | undefined> {
|
|
668
677
|
const blockNumber = await this.#blockHashIndex.getAsync(blockHash.toString());
|
|
669
678
|
if (blockNumber === undefined) {
|
|
670
679
|
return undefined;
|
|
@@ -690,7 +699,7 @@ export class BlockStore {
|
|
|
690
699
|
* @param blockHash - The hash of the block to return.
|
|
691
700
|
* @returns The requested block header.
|
|
692
701
|
*/
|
|
693
|
-
async getBlockHeaderByHash(blockHash:
|
|
702
|
+
async getBlockHeaderByHash(blockHash: BlockHash): Promise<BlockHeader | undefined> {
|
|
694
703
|
const blockNumber = await this.#blockHashIndex.getAsync(blockHash.toString());
|
|
695
704
|
if (blockNumber === undefined) {
|
|
696
705
|
return undefined;
|
|
@@ -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, L2Block,
|
|
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,
|
|
@@ -25,7 +25,7 @@ import type { UInt64 } from '@aztec/stdlib/types';
|
|
|
25
25
|
import { join } from 'path';
|
|
26
26
|
|
|
27
27
|
import type { InboxMessage } from '../structs/inbox_message.js';
|
|
28
|
-
import { BlockStore, type CheckpointData } from './block_store.js';
|
|
28
|
+
import { BlockStore, type CheckpointData, type RemoveCheckpointsResult } from './block_store.js';
|
|
29
29
|
import { ContractClassStore } from './contract_class_store.js';
|
|
30
30
|
import { ContractInstanceStore } from './contract_instance_store.js';
|
|
31
31
|
import { LogStore } from './log_store.js';
|
|
@@ -235,12 +235,14 @@ export class KVArchiverDataStore implements ContractDataSource {
|
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
/**
|
|
238
|
-
* Append new blocks to the store's list.
|
|
239
|
-
*
|
|
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.
|
|
240
242
|
* @returns True if the operation is successful.
|
|
241
243
|
*/
|
|
242
|
-
|
|
243
|
-
return this.#blockStore.
|
|
244
|
+
addProposedBlocks(blocks: L2Block[], opts: { force?: boolean; checkpointNumber?: number } = {}): Promise<boolean> {
|
|
245
|
+
return this.#blockStore.addProposedBlocks(blocks, opts);
|
|
244
246
|
}
|
|
245
247
|
|
|
246
248
|
/**
|
|
@@ -261,14 +263,12 @@ export class KVArchiverDataStore implements ContractDataSource {
|
|
|
261
263
|
}
|
|
262
264
|
|
|
263
265
|
/**
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
* @param checkpointsToUnwind - The number of checkpoints we are to unwind
|
|
268
|
-
* @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.
|
|
269
269
|
*/
|
|
270
|
-
|
|
271
|
-
return this.#blockStore.
|
|
270
|
+
removeCheckpointsAfter(checkpointNumber: CheckpointNumber): Promise<RemoveCheckpointsResult> {
|
|
271
|
+
return this.#blockStore.removeCheckpointsAfter(checkpointNumber);
|
|
272
272
|
}
|
|
273
273
|
|
|
274
274
|
/**
|
|
@@ -313,7 +313,7 @@ export class KVArchiverDataStore implements ContractDataSource {
|
|
|
313
313
|
* @param blockHash - The block hash to return.
|
|
314
314
|
*/
|
|
315
315
|
getBlockByHash(blockHash: Fr): Promise<L2Block | undefined> {
|
|
316
|
-
return this.#blockStore.getBlockByHash(
|
|
316
|
+
return this.#blockStore.getBlockByHash(BlockHash.fromField(blockHash));
|
|
317
317
|
}
|
|
318
318
|
/**
|
|
319
319
|
* Returns the block for the given archive root, or undefined if not exists.
|
|
@@ -358,7 +358,7 @@ export class KVArchiverDataStore implements ContractDataSource {
|
|
|
358
358
|
* @param blockHash - The block hash to return.
|
|
359
359
|
*/
|
|
360
360
|
getBlockHeaderByHash(blockHash: Fr): Promise<BlockHeader | undefined> {
|
|
361
|
-
return this.#blockStore.getBlockHeaderByHash(
|
|
361
|
+
return this.#blockStore.getBlockHeaderByHash(BlockHash.fromField(blockHash));
|
|
362
362
|
}
|
|
363
363
|
|
|
364
364
|
/**
|
|
@@ -629,10 +629,11 @@ export class KVArchiverDataStore implements ContractDataSource {
|
|
|
629
629
|
|
|
630
630
|
/**
|
|
631
631
|
* Removes all blocks with block number > blockNumber.
|
|
632
|
+
* Does not remove any associated checkpoints.
|
|
632
633
|
* @param blockNumber - The block number to remove after.
|
|
633
634
|
* @returns The removed blocks (for event emission).
|
|
634
635
|
*/
|
|
635
636
|
removeBlocksAfter(blockNumber: BlockNumber): Promise<L2Block[]> {
|
|
636
|
-
return this.#blockStore.
|
|
637
|
+
return this.#blockStore.removeBlocksAfter(blockNumber);
|
|
637
638
|
}
|
|
638
639
|
}
|
package/src/store/log_store.ts
CHANGED
|
@@ -6,7 +6,7 @@ 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 { BlockHash, L2Block } from '@aztec/stdlib/block';
|
|
10
10
|
import { MAX_LOGS_PER_TAG } from '@aztec/stdlib/interfaces/api-limit';
|
|
11
11
|
import type { GetContractClassLogsResponse, GetPublicLogsResponse } from '@aztec/stdlib/interfaces/client';
|
|
12
12
|
import {
|
|
@@ -275,14 +275,14 @@ export class LogStore {
|
|
|
275
275
|
return Buffer.concat([blockHash.toBuffer(), ...data]);
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
-
#unpackBlockHash(reader: BufferReader):
|
|
278
|
+
#unpackBlockHash(reader: BufferReader): BlockHash {
|
|
279
279
|
const blockHash = reader.remainingBytes() > 0 ? reader.readObject(Fr) : undefined;
|
|
280
280
|
|
|
281
281
|
if (!blockHash) {
|
|
282
282
|
throw new Error('Failed to read block hash from log entry buffer');
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
-
return
|
|
285
|
+
return BlockHash.fromField(blockHash);
|
|
286
286
|
}
|
|
287
287
|
|
|
288
288
|
deleteLogs(blocks: L2Block[]): Promise<boolean> {
|
|
@@ -543,7 +543,7 @@ export class LogStore {
|
|
|
543
543
|
#accumulateLogs(
|
|
544
544
|
results: (ExtendedContractClassLog | ExtendedPublicLog)[],
|
|
545
545
|
blockNumber: number,
|
|
546
|
-
blockHash:
|
|
546
|
+
blockHash: BlockHash,
|
|
547
547
|
txIndex: number,
|
|
548
548
|
txLogs: (ContractClassLog | PublicLog)[],
|
|
549
549
|
filter: LogFilter = {},
|
package/src/test/index.ts
CHANGED
|
@@ -57,7 +57,7 @@ export class MockPrefilledArchiver extends MockArchiver {
|
|
|
57
57
|
|
|
58
58
|
const fromBlock = this.l2Blocks.length;
|
|
59
59
|
// TODO: Add L2 blocks and checkpoints separately once archiver has the apis for that.
|
|
60
|
-
this.
|
|
60
|
+
this.addProposedBlocks(this.prefilled.slice(fromBlock, fromBlock + numBlocks).flatMap(c => c.blocks));
|
|
61
61
|
return Promise.resolve();
|
|
62
62
|
}
|
|
63
63
|
}
|
|
@@ -8,9 +8,9 @@ import { createLogger } from '@aztec/foundation/log';
|
|
|
8
8
|
import type { FunctionSelector } from '@aztec/stdlib/abi';
|
|
9
9
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
10
10
|
import {
|
|
11
|
+
BlockHash,
|
|
11
12
|
CheckpointedL2Block,
|
|
12
13
|
L2Block,
|
|
13
|
-
L2BlockHash,
|
|
14
14
|
type L2BlockSource,
|
|
15
15
|
type L2Tips,
|
|
16
16
|
type ValidateCheckpointResult,
|
|
@@ -43,9 +43,9 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
43
43
|
this.log.verbose(`Created ${numBlocks} blocks in the mock L2 block source`);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
public
|
|
46
|
+
public addProposedBlocks(blocks: L2Block[]) {
|
|
47
47
|
this.l2Blocks.push(...blocks);
|
|
48
|
-
this.log.verbose(`Added ${blocks.length} blocks to the mock L2 block source`);
|
|
48
|
+
this.log.verbose(`Added ${blocks.length} proposed blocks to the mock L2 block source`);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
public removeBlocks(numBlocks: number) {
|
|
@@ -322,7 +322,7 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
322
322
|
return {
|
|
323
323
|
data: txEffect,
|
|
324
324
|
l2BlockNumber: block.number,
|
|
325
|
-
l2BlockHash:
|
|
325
|
+
l2BlockHash: BlockHash.fromField(await block.hash()),
|
|
326
326
|
txIndexInBlock: block.body.txEffects.indexOf(txEffect),
|
|
327
327
|
};
|
|
328
328
|
}
|
|
@@ -343,7 +343,7 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
343
343
|
TxExecutionResult.SUCCESS,
|
|
344
344
|
undefined,
|
|
345
345
|
txEffect.transactionFee.toBigInt(),
|
|
346
|
-
|
|
346
|
+
BlockHash.fromField(await block.hash()),
|
|
347
347
|
block.number,
|
|
348
348
|
);
|
|
349
349
|
}
|
package/src/test/mock_structs.ts
CHANGED
|
@@ -46,24 +46,40 @@ export function makeInboxMessage(
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
export function makeInboxMessages(
|
|
49
|
-
|
|
49
|
+
totalCount: number,
|
|
50
50
|
opts: {
|
|
51
51
|
initialHash?: Buffer16;
|
|
52
52
|
initialCheckpointNumber?: CheckpointNumber;
|
|
53
|
+
messagesPerCheckpoint?: number;
|
|
53
54
|
overrideFn?: (msg: InboxMessage, index: number) => InboxMessage;
|
|
54
55
|
} = {},
|
|
55
56
|
): InboxMessage[] {
|
|
56
|
-
const {
|
|
57
|
+
const {
|
|
58
|
+
initialHash = Buffer16.ZERO,
|
|
59
|
+
overrideFn = msg => msg,
|
|
60
|
+
initialCheckpointNumber = CheckpointNumber(1),
|
|
61
|
+
messagesPerCheckpoint = 1,
|
|
62
|
+
} = opts;
|
|
63
|
+
|
|
57
64
|
const messages: InboxMessage[] = [];
|
|
58
65
|
let rollingHash = initialHash;
|
|
59
|
-
for (let i = 0; i <
|
|
66
|
+
for (let i = 0; i < totalCount; i++) {
|
|
67
|
+
const msgIndex = i % messagesPerCheckpoint;
|
|
68
|
+
const checkpointNumber = CheckpointNumber.fromBigInt(
|
|
69
|
+
BigInt(initialCheckpointNumber) + BigInt(i) / BigInt(messagesPerCheckpoint),
|
|
70
|
+
);
|
|
60
71
|
const leaf = Fr.random();
|
|
61
|
-
const
|
|
62
|
-
|
|
72
|
+
const message = overrideFn(
|
|
73
|
+
makeInboxMessage(rollingHash, {
|
|
74
|
+
leaf,
|
|
75
|
+
checkpointNumber,
|
|
76
|
+
index: InboxLeaf.smallestIndexForCheckpoint(checkpointNumber) + BigInt(msgIndex),
|
|
77
|
+
}),
|
|
78
|
+
i,
|
|
79
|
+
);
|
|
63
80
|
rollingHash = message.rollingHash;
|
|
64
81
|
messages.push(message);
|
|
65
82
|
}
|
|
66
|
-
|
|
67
83
|
return messages;
|
|
68
84
|
}
|
|
69
85
|
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { BlobClientInterface } from '@aztec/blob-client/client';
|
|
2
|
+
import type { RollupContract } from '@aztec/ethereum/contracts';
|
|
3
|
+
import type { ViemPublicClient, ViemPublicDebugClient } from '@aztec/ethereum/types';
|
|
4
|
+
import { Buffer32 } from '@aztec/foundation/buffer';
|
|
5
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
6
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
7
|
+
import type { FunctionsOf } from '@aztec/foundation/types';
|
|
8
|
+
import type { ArchiverEmitter } from '@aztec/stdlib/block';
|
|
9
|
+
import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
|
|
10
|
+
import { type TelemetryClient, type Tracer, getTelemetryClient } from '@aztec/telemetry-client';
|
|
11
|
+
|
|
12
|
+
import { mock } from 'jest-mock-extended';
|
|
13
|
+
import { EventEmitter } from 'node:events';
|
|
14
|
+
|
|
15
|
+
import { Archiver } from '../archiver.js';
|
|
16
|
+
import { ArchiverInstrumentation } from '../modules/instrumentation.js';
|
|
17
|
+
import type { ArchiverL1Synchronizer } from '../modules/l1_synchronizer.js';
|
|
18
|
+
import type { KVArchiverDataStore } from '../store/kv_archiver_store.js';
|
|
19
|
+
|
|
20
|
+
/** Noop L1 synchronizer for testing without L1 connectivity. */
|
|
21
|
+
class NoopL1Synchronizer implements FunctionsOf<ArchiverL1Synchronizer> {
|
|
22
|
+
public readonly tracer: Tracer;
|
|
23
|
+
|
|
24
|
+
constructor(tracer: Tracer) {
|
|
25
|
+
this.tracer = tracer;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
setConfig(_config: unknown) {}
|
|
29
|
+
getL1BlockNumber(): bigint | undefined {
|
|
30
|
+
return 0n;
|
|
31
|
+
}
|
|
32
|
+
getL1Timestamp(): bigint | undefined {
|
|
33
|
+
return 0n;
|
|
34
|
+
}
|
|
35
|
+
testEthereumNodeSynced(): Promise<void> {
|
|
36
|
+
return Promise.resolve();
|
|
37
|
+
}
|
|
38
|
+
syncFromL1(_initialSyncComplete: boolean): Promise<void> {
|
|
39
|
+
return Promise.resolve();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Archiver with mocked L1 connectivity for testing.
|
|
45
|
+
* Uses mock L1 clients and a noop synchronizer, enabling tests that
|
|
46
|
+
* don't require real Ethereum connectivity.
|
|
47
|
+
*/
|
|
48
|
+
export class NoopL1Archiver extends Archiver {
|
|
49
|
+
constructor(
|
|
50
|
+
dataStore: KVArchiverDataStore,
|
|
51
|
+
l1Constants: L1RollupConstants & { genesisArchiveRoot: Fr },
|
|
52
|
+
instrumentation: ArchiverInstrumentation,
|
|
53
|
+
) {
|
|
54
|
+
// Create mocks for L1 clients
|
|
55
|
+
const publicClient = mock<ViemPublicClient>();
|
|
56
|
+
const debugClient = mock<ViemPublicDebugClient>();
|
|
57
|
+
const rollup = mock<RollupContract>();
|
|
58
|
+
const blobClient = mock<BlobClientInterface>();
|
|
59
|
+
|
|
60
|
+
// Mock methods called during start()
|
|
61
|
+
blobClient.testSources.mockResolvedValue();
|
|
62
|
+
publicClient.getBlockNumber.mockResolvedValue(1n);
|
|
63
|
+
|
|
64
|
+
const events = new EventEmitter() as ArchiverEmitter;
|
|
65
|
+
const synchronizer = new NoopL1Synchronizer(instrumentation.tracer);
|
|
66
|
+
|
|
67
|
+
super(
|
|
68
|
+
publicClient,
|
|
69
|
+
debugClient,
|
|
70
|
+
rollup,
|
|
71
|
+
{
|
|
72
|
+
registryAddress: EthAddress.ZERO,
|
|
73
|
+
governanceProposerAddress: EthAddress.ZERO,
|
|
74
|
+
slashFactoryAddress: EthAddress.ZERO,
|
|
75
|
+
slashingProposerAddress: EthAddress.ZERO,
|
|
76
|
+
},
|
|
77
|
+
dataStore,
|
|
78
|
+
{
|
|
79
|
+
pollingIntervalMs: 1000,
|
|
80
|
+
batchSize: 100,
|
|
81
|
+
skipValidateCheckpointAttestations: true,
|
|
82
|
+
maxAllowedEthClientDriftSeconds: 300,
|
|
83
|
+
ethereumAllowNoDebugHosts: true, // Skip trace validation
|
|
84
|
+
},
|
|
85
|
+
blobClient,
|
|
86
|
+
instrumentation,
|
|
87
|
+
{ ...l1Constants, l1StartBlockHash: Buffer32.random() },
|
|
88
|
+
synchronizer as ArchiverL1Synchronizer,
|
|
89
|
+
events,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Override start to skip L1 validation checks. */
|
|
94
|
+
public override start(_blockUntilSynced?: boolean): Promise<void> {
|
|
95
|
+
// Just start the running promise without L1 checks
|
|
96
|
+
this.runningPromise.start();
|
|
97
|
+
return Promise.resolve();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Creates an archiver with mocked L1 connectivity for testing. */
|
|
102
|
+
export async function createNoopL1Archiver(
|
|
103
|
+
dataStore: KVArchiverDataStore,
|
|
104
|
+
l1Constants: L1RollupConstants & { genesisArchiveRoot: Fr },
|
|
105
|
+
telemetry: TelemetryClient = getTelemetryClient(),
|
|
106
|
+
): Promise<NoopL1Archiver> {
|
|
107
|
+
const instrumentation = await ArchiverInstrumentation.new(telemetry, () => dataStore.estimateSize());
|
|
108
|
+
return new NoopL1Archiver(dataStore, l1Constants, instrumentation);
|
|
109
|
+
}
|