@aztec/archiver 0.0.1-commit.f504929 → 0.0.1-commit.f81dbcf
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 +3 -3
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +36 -14
- package/dest/factory.d.ts +2 -3
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +8 -8
- package/dest/l1/data_retrieval.d.ts +3 -6
- package/dest/l1/data_retrieval.d.ts.map +1 -1
- package/dest/l1/data_retrieval.js +6 -12
- package/dest/modules/data_source_base.d.ts +3 -3
- package/dest/modules/data_source_base.d.ts.map +1 -1
- package/dest/modules/data_source_base.js +1 -1
- package/dest/modules/data_store_updater.d.ts +11 -3
- package/dest/modules/data_store_updater.d.ts.map +1 -1
- package/dest/modules/data_store_updater.js +36 -5
- package/dest/modules/instrumentation.d.ts +1 -12
- package/dest/modules/instrumentation.d.ts.map +1 -1
- package/dest/modules/instrumentation.js +0 -10
- package/dest/modules/l1_synchronizer.d.ts +2 -1
- package/dest/modules/l1_synchronizer.d.ts.map +1 -1
- package/dest/modules/l1_synchronizer.js +31 -9
- package/dest/store/block_store.d.ts +8 -9
- package/dest/store/block_store.d.ts.map +1 -1
- package/dest/store/block_store.js +31 -13
- package/dest/store/kv_archiver_store.d.ts +13 -3
- package/dest/store/kv_archiver_store.d.ts.map +1 -1
- package/dest/store/kv_archiver_store.js +16 -4
- 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 +48 -10
- package/dest/store/message_store.js +1 -1
- package/dest/test/fake_l1_state.d.ts +8 -1
- package/dest/test/fake_l1_state.d.ts.map +1 -1
- package/dest/test/fake_l1_state.js +28 -2
- package/dest/test/mock_l2_block_source.d.ts +4 -3
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +7 -4
- package/dest/test/mock_structs.d.ts +4 -1
- package/dest/test/mock_structs.d.ts.map +1 -1
- package/dest/test/mock_structs.js +13 -1
- package/dest/test/noop_l1_archiver.d.ts +4 -1
- package/dest/test/noop_l1_archiver.d.ts.map +1 -1
- package/dest/test/noop_l1_archiver.js +5 -1
- package/package.json +13 -13
- package/src/archiver.ts +39 -17
- package/src/factory.ts +5 -4
- package/src/l1/data_retrieval.ts +9 -17
- package/src/modules/data_source_base.ts +3 -3
- package/src/modules/data_store_updater.ts +39 -4
- package/src/modules/instrumentation.ts +0 -20
- package/src/modules/l1_synchronizer.ts +38 -11
- package/src/store/block_store.ts +41 -13
- package/src/store/kv_archiver_store.ts +22 -4
- package/src/store/log_store.ts +66 -12
- package/src/store/message_store.ts +1 -1
- package/src/test/fake_l1_state.ts +35 -4
- package/src/test/mock_l2_block_source.ts +15 -3
- package/src/test/mock_structs.ts +20 -6
- package/src/test/noop_l1_archiver.ts +7 -1
package/src/store/log_store.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
2
2
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
|
-
import { filterAsync } from '@aztec/foundation/collection';
|
|
3
|
+
import { compactArray, filterAsync } from '@aztec/foundation/collection';
|
|
4
4
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
5
5
|
import { createLogger } from '@aztec/foundation/log';
|
|
6
6
|
import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize';
|
|
@@ -290,18 +290,49 @@ export class LogStore {
|
|
|
290
290
|
|
|
291
291
|
deleteLogs(blocks: L2Block[]): Promise<boolean> {
|
|
292
292
|
return this.db.transactionAsync(async () => {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
// Delete public logs
|
|
300
|
-
const publicKeys = (await this.#publicLogKeysByBlock.getAsync(block.number)) ?? [];
|
|
301
|
-
await Promise.all(publicKeys.map(key => this.#publicLogsByContractAndTag.delete(key)));
|
|
302
|
-
}),
|
|
293
|
+
const blockNumbers = new Set(blocks.map(block => block.number));
|
|
294
|
+
const firstBlockToDelete = Math.min(...blockNumbers);
|
|
295
|
+
|
|
296
|
+
// Collect all unique private tags across all blocks being deleted
|
|
297
|
+
const allPrivateTags = new Set(
|
|
298
|
+
compactArray(await Promise.all(blocks.map(block => this.#privateLogKeysByBlock.getAsync(block.number)))).flat(),
|
|
303
299
|
);
|
|
304
300
|
|
|
301
|
+
// Trim private logs: for each tag, delete all instances including and after the first block being deleted.
|
|
302
|
+
// This hinges on the invariant that logs for a given tag are always inserted in order of block number, which is enforced in #addPrivateLogs.
|
|
303
|
+
for (const tag of allPrivateTags) {
|
|
304
|
+
const existing = await this.#privateLogsByTag.getAsync(tag);
|
|
305
|
+
if (existing === undefined || existing.length === 0) {
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
const lastIndexToKeep = existing.findLastIndex(
|
|
309
|
+
buf => TxScopedL2Log.getBlockNumberFromBuffer(buf) < firstBlockToDelete,
|
|
310
|
+
);
|
|
311
|
+
const remaining = existing.slice(0, lastIndexToKeep + 1);
|
|
312
|
+
await (remaining.length > 0 ? this.#privateLogsByTag.set(tag, remaining) : this.#privateLogsByTag.delete(tag));
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Collect all unique public keys across all blocks being deleted
|
|
316
|
+
const allPublicKeys = new Set(
|
|
317
|
+
compactArray(await Promise.all(blocks.map(block => this.#publicLogKeysByBlock.getAsync(block.number)))).flat(),
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
// And do the same as we did with private logs
|
|
321
|
+
for (const key of allPublicKeys) {
|
|
322
|
+
const existing = await this.#publicLogsByContractAndTag.getAsync(key);
|
|
323
|
+
if (existing === undefined || existing.length === 0) {
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
const lastIndexToKeep = existing.findLastIndex(
|
|
327
|
+
buf => TxScopedL2Log.getBlockNumberFromBuffer(buf) < firstBlockToDelete,
|
|
328
|
+
);
|
|
329
|
+
const remaining = existing.slice(0, lastIndexToKeep + 1);
|
|
330
|
+
await (remaining.length > 0
|
|
331
|
+
? this.#publicLogsByContractAndTag.set(key, remaining)
|
|
332
|
+
: this.#publicLogsByContractAndTag.delete(key));
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// After trimming the tagged logs, we can delete the block-level keys that track which tags are in which blocks.
|
|
305
336
|
await Promise.all(
|
|
306
337
|
blocks.map(block =>
|
|
307
338
|
Promise.all([
|
|
@@ -588,11 +619,24 @@ export class LogStore {
|
|
|
588
619
|
txLogs: PublicLog[],
|
|
589
620
|
filter: LogFilter = {},
|
|
590
621
|
): boolean {
|
|
622
|
+
if (filter.fromBlock && blockNumber < filter.fromBlock) {
|
|
623
|
+
return false;
|
|
624
|
+
}
|
|
625
|
+
if (filter.toBlock && blockNumber >= filter.toBlock) {
|
|
626
|
+
return false;
|
|
627
|
+
}
|
|
628
|
+
if (filter.txHash && !txHash.equals(filter.txHash)) {
|
|
629
|
+
return false;
|
|
630
|
+
}
|
|
631
|
+
|
|
591
632
|
let maxLogsHit = false;
|
|
592
633
|
let logIndex = typeof filter.afterLog?.logIndex === 'number' ? filter.afterLog.logIndex + 1 : 0;
|
|
593
634
|
for (; logIndex < txLogs.length; logIndex++) {
|
|
594
635
|
const log = txLogs[logIndex];
|
|
595
|
-
if (
|
|
636
|
+
if (
|
|
637
|
+
(!filter.contractAddress || log.contractAddress.equals(filter.contractAddress)) &&
|
|
638
|
+
(!filter.tag || log.fields[0]?.equals(filter.tag))
|
|
639
|
+
) {
|
|
596
640
|
results.push(
|
|
597
641
|
new ExtendedPublicLog(new LogId(BlockNumber(blockNumber), blockHash, txHash, txIndex, logIndex), log),
|
|
598
642
|
);
|
|
@@ -616,6 +660,16 @@ export class LogStore {
|
|
|
616
660
|
txLogs: ContractClassLog[],
|
|
617
661
|
filter: LogFilter = {},
|
|
618
662
|
): boolean {
|
|
663
|
+
if (filter.fromBlock && blockNumber < filter.fromBlock) {
|
|
664
|
+
return false;
|
|
665
|
+
}
|
|
666
|
+
if (filter.toBlock && blockNumber >= filter.toBlock) {
|
|
667
|
+
return false;
|
|
668
|
+
}
|
|
669
|
+
if (filter.txHash && !txHash.equals(filter.txHash)) {
|
|
670
|
+
return false;
|
|
671
|
+
}
|
|
672
|
+
|
|
619
673
|
let maxLogsHit = false;
|
|
620
674
|
let logIndex = typeof filter.afterLog?.logIndex === 'number' ? filter.afterLog.logIndex + 1 : 0;
|
|
621
675
|
for (; logIndex < txLogs.length; logIndex++) {
|
|
@@ -137,7 +137,7 @@ export class MessageStore {
|
|
|
137
137
|
);
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
// Check the first message in a
|
|
140
|
+
// Check the first message in a checkpoint has the correct index.
|
|
141
141
|
if (
|
|
142
142
|
(!lastMessage || message.checkpointNumber > lastMessage.checkpointNumber) &&
|
|
143
143
|
message.index !== expectedStart
|
|
@@ -150,8 +150,12 @@ export class FakeL1State {
|
|
|
150
150
|
// Computed from checkpoints based on L1 block visibility
|
|
151
151
|
private pendingCheckpointNumber: CheckpointNumber = CheckpointNumber(0);
|
|
152
152
|
|
|
153
|
+
// The L1 block number reported as "finalized" (defaults to the start block)
|
|
154
|
+
private finalizedL1BlockNumber: bigint;
|
|
155
|
+
|
|
153
156
|
constructor(private readonly config: FakeL1StateConfig) {
|
|
154
157
|
this.l1BlockNumber = config.l1StartBlock;
|
|
158
|
+
this.finalizedL1BlockNumber = config.l1StartBlock;
|
|
155
159
|
this.lastArchive = new AppendOnlyTreeSnapshot(config.genesisArchiveRoot, 1);
|
|
156
160
|
}
|
|
157
161
|
|
|
@@ -283,11 +287,30 @@ export class FakeL1State {
|
|
|
283
287
|
this.updatePendingCheckpointNumber();
|
|
284
288
|
}
|
|
285
289
|
|
|
290
|
+
/** Sets the L1 block number that will be reported as "finalized". */
|
|
291
|
+
setFinalizedL1BlockNumber(blockNumber: bigint): void {
|
|
292
|
+
this.finalizedL1BlockNumber = blockNumber;
|
|
293
|
+
}
|
|
294
|
+
|
|
286
295
|
/** Marks a checkpoint as proven. Updates provenCheckpointNumber. */
|
|
287
296
|
markCheckpointAsProven(checkpointNumber: CheckpointNumber): void {
|
|
288
297
|
this.provenCheckpointNumber = checkpointNumber;
|
|
289
298
|
}
|
|
290
299
|
|
|
300
|
+
/**
|
|
301
|
+
* Simulates what `rollup.getProvenCheckpointNumber({ blockNumber: atL1Block })` would return.
|
|
302
|
+
*/
|
|
303
|
+
getProvenCheckpointNumberAtL1Block(atL1Block: bigint): CheckpointNumber {
|
|
304
|
+
if (this.provenCheckpointNumber === 0) {
|
|
305
|
+
return CheckpointNumber(0);
|
|
306
|
+
}
|
|
307
|
+
const checkpoint = this.checkpoints.find(cp => cp.checkpointNumber === this.provenCheckpointNumber);
|
|
308
|
+
if (checkpoint && checkpoint.l1BlockNumber <= atL1Block) {
|
|
309
|
+
return this.provenCheckpointNumber;
|
|
310
|
+
}
|
|
311
|
+
return CheckpointNumber(0);
|
|
312
|
+
}
|
|
313
|
+
|
|
291
314
|
/** Sets the target committee size for attestation validation. */
|
|
292
315
|
setTargetCommitteeSize(size: number): void {
|
|
293
316
|
this.targetCommitteeSize = size;
|
|
@@ -406,6 +429,11 @@ export class FakeL1State {
|
|
|
406
429
|
});
|
|
407
430
|
});
|
|
408
431
|
|
|
432
|
+
mockRollup.getProvenCheckpointNumber.mockImplementation((options?: { blockNumber?: bigint }) => {
|
|
433
|
+
const atBlock = options?.blockNumber ?? this.l1BlockNumber;
|
|
434
|
+
return Promise.resolve(this.getProvenCheckpointNumberAtL1Block(atBlock));
|
|
435
|
+
});
|
|
436
|
+
|
|
409
437
|
mockRollup.canPruneAtTime.mockImplementation(() => Promise.resolve(this.canPruneResult));
|
|
410
438
|
|
|
411
439
|
// Mock the wrapper method for fetching checkpoint events
|
|
@@ -449,10 +477,13 @@ export class FakeL1State {
|
|
|
449
477
|
publicClient.getChainId.mockResolvedValue(1);
|
|
450
478
|
publicClient.getBlockNumber.mockImplementation(() => Promise.resolve(this.l1BlockNumber));
|
|
451
479
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
480
|
+
publicClient.getBlock.mockImplementation((async (args: { blockNumber?: bigint; blockTag?: string } = {}) => {
|
|
481
|
+
let blockNum: bigint;
|
|
482
|
+
if (args.blockTag === 'finalized') {
|
|
483
|
+
blockNum = this.finalizedL1BlockNumber;
|
|
484
|
+
} else {
|
|
485
|
+
blockNum = args.blockNumber ?? (await publicClient.getBlockNumber());
|
|
486
|
+
}
|
|
456
487
|
return {
|
|
457
488
|
number: blockNum,
|
|
458
489
|
timestamp: BigInt(blockNum) * BigInt(this.config.ethereumSlotDuration) + this.config.l1GenesisTime,
|
|
@@ -18,7 +18,12 @@ import {
|
|
|
18
18
|
} from '@aztec/stdlib/block';
|
|
19
19
|
import { Checkpoint, type CheckpointData, L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
20
20
|
import type { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
21
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
EmptyL1RollupConstants,
|
|
23
|
+
type L1RollupConstants,
|
|
24
|
+
getEpochAtSlot,
|
|
25
|
+
getSlotRangeForEpoch,
|
|
26
|
+
} from '@aztec/stdlib/epoch-helpers';
|
|
22
27
|
import { computeCheckpointOutHash } from '@aztec/stdlib/messaging';
|
|
23
28
|
import { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
24
29
|
import { type BlockHeader, TxExecutionResult, TxHash, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
@@ -42,6 +47,12 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
42
47
|
await this.createCheckpoints(numBlocks, 1);
|
|
43
48
|
}
|
|
44
49
|
|
|
50
|
+
public getCheckpointNumber(): Promise<CheckpointNumber> {
|
|
51
|
+
return Promise.resolve(
|
|
52
|
+
this.checkpointList.length === 0 ? CheckpointNumber.ZERO : CheckpointNumber(this.checkpointList.length),
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
45
56
|
/** Creates checkpoints, each containing `blocksPerCheckpoint` blocks. */
|
|
46
57
|
public async createCheckpoints(numCheckpoints: number, blocksPerCheckpoint: number = 1) {
|
|
47
58
|
for (let c = 0; c < numCheckpoints; c++) {
|
|
@@ -388,6 +399,7 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
388
399
|
txEffect.transactionFee.toBigInt(),
|
|
389
400
|
await block.hash(),
|
|
390
401
|
block.number,
|
|
402
|
+
getEpochAtSlot(block.slot, EmptyL1RollupConstants),
|
|
391
403
|
);
|
|
392
404
|
}
|
|
393
405
|
}
|
|
@@ -441,11 +453,11 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
441
453
|
};
|
|
442
454
|
}
|
|
443
455
|
|
|
444
|
-
|
|
456
|
+
getSyncedL2EpochNumber(): Promise<EpochNumber> {
|
|
445
457
|
throw new Error('Method not implemented.');
|
|
446
458
|
}
|
|
447
459
|
|
|
448
|
-
|
|
460
|
+
getSyncedL2SlotNumber(): Promise<SlotNumber> {
|
|
449
461
|
throw new Error('Method not implemented.');
|
|
450
462
|
}
|
|
451
463
|
|
package/src/test/mock_structs.ts
CHANGED
|
@@ -127,6 +127,25 @@ export function makeL1PublishedData(l1BlockNumber: number): L1PublishedData {
|
|
|
127
127
|
return new L1PublishedData(BigInt(l1BlockNumber), BigInt(l1BlockNumber * 1000), makeBlockHash(l1BlockNumber));
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
/** Creates a Checkpoint from a list of blocks with a header that matches the blocks' structure. */
|
|
131
|
+
export function makeCheckpoint(blocks: L2Block[], checkpointNumber = CheckpointNumber(1)): Checkpoint {
|
|
132
|
+
const firstBlock = blocks[0];
|
|
133
|
+
const { slotNumber, timestamp, coinbase, feeRecipient, gasFees } = firstBlock.header.globalVariables;
|
|
134
|
+
return new Checkpoint(
|
|
135
|
+
blocks.at(-1)!.archive,
|
|
136
|
+
CheckpointHeader.random({
|
|
137
|
+
lastArchiveRoot: firstBlock.header.lastArchive.root,
|
|
138
|
+
slotNumber,
|
|
139
|
+
timestamp,
|
|
140
|
+
coinbase,
|
|
141
|
+
feeRecipient,
|
|
142
|
+
gasFees,
|
|
143
|
+
}),
|
|
144
|
+
blocks,
|
|
145
|
+
checkpointNumber,
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
130
149
|
/** Wraps a Checkpoint with L1 published data and random attestations. */
|
|
131
150
|
export function makePublishedCheckpoint(
|
|
132
151
|
checkpoint: Checkpoint,
|
|
@@ -301,11 +320,6 @@ export async function makeCheckpointWithLogs(
|
|
|
301
320
|
return txEffect;
|
|
302
321
|
});
|
|
303
322
|
|
|
304
|
-
const checkpoint =
|
|
305
|
-
AppendOnlyTreeSnapshot.random(),
|
|
306
|
-
CheckpointHeader.random(),
|
|
307
|
-
[block],
|
|
308
|
-
CheckpointNumber.fromBlockNumber(BlockNumber(blockNumber)),
|
|
309
|
-
);
|
|
323
|
+
const checkpoint = makeCheckpoint([block], CheckpointNumber.fromBlockNumber(BlockNumber(blockNumber)));
|
|
310
324
|
return makePublishedCheckpoint(checkpoint, blockNumber);
|
|
311
325
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { BlobClientInterface } from '@aztec/blob-client/client';
|
|
2
2
|
import type { RollupContract } from '@aztec/ethereum/contracts';
|
|
3
3
|
import type { ViemPublicClient, ViemPublicDebugClient } from '@aztec/ethereum/types';
|
|
4
|
+
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
4
5
|
import { Buffer32 } from '@aztec/foundation/buffer';
|
|
5
6
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
6
7
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
@@ -30,7 +31,7 @@ class NoopL1Synchronizer implements FunctionsOf<ArchiverL1Synchronizer> {
|
|
|
30
31
|
return 0n;
|
|
31
32
|
}
|
|
32
33
|
getL1Timestamp(): bigint | undefined {
|
|
33
|
-
return
|
|
34
|
+
return undefined;
|
|
34
35
|
}
|
|
35
36
|
testEthereumNodeSynced(): Promise<void> {
|
|
36
37
|
return Promise.resolve();
|
|
@@ -96,6 +97,11 @@ export class NoopL1Archiver extends Archiver {
|
|
|
96
97
|
this.runningPromise.start();
|
|
97
98
|
return Promise.resolve();
|
|
98
99
|
}
|
|
100
|
+
|
|
101
|
+
/** Always reports as fully synced since there is no real L1 to sync from. */
|
|
102
|
+
public override getSyncedL2SlotNumber(): Promise<SlotNumber | undefined> {
|
|
103
|
+
return Promise.resolve(SlotNumber(Number.MAX_SAFE_INTEGER));
|
|
104
|
+
}
|
|
99
105
|
}
|
|
100
106
|
|
|
101
107
|
/** Creates an archiver with mocked L1 connectivity for testing. */
|