@aztec/archiver 0.0.1-commit.2ed92850 → 0.0.1-commit.3469e52
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 +0 -9
- package/dest/archiver.d.ts +4 -4
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +20 -19
- package/dest/errors.d.ts +1 -6
- package/dest/errors.d.ts.map +1 -1
- package/dest/errors.js +0 -8
- package/dest/factory.d.ts +2 -3
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +3 -5
- 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 +17 -16
- package/dest/modules/data_source_base.d.ts.map +1 -1
- package/dest/modules/data_source_base.js +52 -21
- package/dest/modules/data_store_updater.d.ts +19 -23
- package/dest/modules/data_store_updater.d.ts.map +1 -1
- package/dest/modules/data_store_updater.js +49 -47
- package/dest/modules/instrumentation.d.ts +3 -3
- package/dest/modules/instrumentation.d.ts.map +1 -1
- package/dest/modules/l1_synchronizer.js +7 -7
- package/dest/store/block_store.d.ts +19 -33
- package/dest/store/block_store.d.ts.map +1 -1
- package/dest/store/block_store.js +39 -80
- package/dest/store/kv_archiver_store.d.ts +22 -26
- package/dest/store/kv_archiver_store.d.ts.map +1 -1
- package/dest/store/kv_archiver_store.js +14 -18
- package/dest/store/log_store.d.ts +4 -4
- package/dest/store/log_store.d.ts.map +1 -1
- 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_archiver.js +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 +40 -39
- package/dest/test/mock_structs.js +4 -4
- package/package.json +13 -13
- package/src/archiver.ts +26 -24
- package/src/errors.ts +0 -12
- package/src/factory.ts +2 -4
- package/src/l1/bin/retrieve-calldata.ts +2 -7
- package/src/l1/data_retrieval.ts +3 -3
- package/src/modules/data_source_base.ts +76 -25
- package/src/modules/data_store_updater.ts +55 -59
- package/src/modules/instrumentation.ts +2 -2
- package/src/modules/l1_synchronizer.ts +9 -9
- package/src/store/block_store.ts +56 -103
- package/src/store/kv_archiver_store.ts +24 -32
- package/src/store/log_store.ts +8 -8
- package/src/test/fake_l1_state.ts +2 -2
- package/src/test/mock_archiver.ts +1 -1
- package/src/test/mock_l2_block_source.ts +60 -50
- package/src/test/mock_structs.ts +4 -4
package/src/archiver.ts
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
type ArchiverEmitter,
|
|
18
18
|
type CheckpointId,
|
|
19
19
|
GENESIS_CHECKPOINT_HEADER_HASH,
|
|
20
|
-
|
|
20
|
+
L2BlockNew,
|
|
21
21
|
type L2BlockSink,
|
|
22
22
|
type L2Tips,
|
|
23
23
|
type ValidateCheckpointResult,
|
|
@@ -46,7 +46,7 @@ export type { ArchiverEmitter };
|
|
|
46
46
|
|
|
47
47
|
/** Request to add a block to the archiver, queued for processing by the sync loop. */
|
|
48
48
|
type AddBlockRequest = {
|
|
49
|
-
block:
|
|
49
|
+
block: L2BlockNew;
|
|
50
50
|
resolve: () => void;
|
|
51
51
|
reject: (err: Error) => void;
|
|
52
52
|
};
|
|
@@ -187,7 +187,7 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
187
187
|
* @param block - The L2 block to add.
|
|
188
188
|
* @returns A promise that resolves when the block has been added to the store, or rejects on error.
|
|
189
189
|
*/
|
|
190
|
-
public addBlock(block:
|
|
190
|
+
public addBlock(block: L2BlockNew): Promise<void> {
|
|
191
191
|
return new Promise<void>((resolve, reject) => {
|
|
192
192
|
this.blockQueue.push({ block, resolve, reject });
|
|
193
193
|
this.log.debug(`Queued block ${block.number} for processing`);
|
|
@@ -215,7 +215,7 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
215
215
|
// Process each block individually to properly resolve/reject each promise
|
|
216
216
|
for (const { block, resolve, reject } of queuedItems) {
|
|
217
217
|
try {
|
|
218
|
-
await this.updater.
|
|
218
|
+
await this.updater.addBlocks([block]);
|
|
219
219
|
this.log.debug(`Added block ${block.number} to store`);
|
|
220
220
|
resolve();
|
|
221
221
|
} catch (err: any) {
|
|
@@ -323,11 +323,8 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
323
323
|
}
|
|
324
324
|
|
|
325
325
|
public async isEpochComplete(epochNumber: EpochNumber): Promise<boolean> {
|
|
326
|
-
// The epoch is complete if the current
|
|
327
|
-
|
|
328
|
-
// prematurely when proposed blocks have been pushed to the archiver but not yet checkpointed on L1.
|
|
329
|
-
const checkpointedBlockNumber = await this.getCheckpointedL2BlockNumber();
|
|
330
|
-
const header = checkpointedBlockNumber > 0 ? await this.getBlockHeader(checkpointedBlockNumber) : undefined;
|
|
326
|
+
// The epoch is complete if the current L2 block is the last one in the epoch (or later)
|
|
327
|
+
const header = await this.getBlockHeader('latest');
|
|
331
328
|
const slot = header ? header.globalVariables.slotNumber : undefined;
|
|
332
329
|
const [_startSlot, endSlot] = getSlotRangeForEpoch(epochNumber, this.l1Constants);
|
|
333
330
|
if (slot && slot >= endSlot) {
|
|
@@ -358,8 +355,8 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
358
355
|
return this.initialSyncComplete;
|
|
359
356
|
}
|
|
360
357
|
|
|
361
|
-
public
|
|
362
|
-
return this.updater.
|
|
358
|
+
public unwindCheckpoints(from: CheckpointNumber, checkpointsToUnwind: number): Promise<boolean> {
|
|
359
|
+
return this.updater.unwindCheckpoints(from, checkpointsToUnwind);
|
|
363
360
|
}
|
|
364
361
|
|
|
365
362
|
/** Used by TXE to add checkpoints directly without syncing from L1. */
|
|
@@ -367,18 +364,22 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
367
364
|
checkpoints: PublishedCheckpoint[],
|
|
368
365
|
pendingChainValidationStatus?: ValidateCheckpointResult,
|
|
369
366
|
): Promise<boolean> {
|
|
370
|
-
await this.updater.
|
|
367
|
+
await this.updater.setNewCheckpointData(checkpoints, pendingChainValidationStatus);
|
|
371
368
|
return true;
|
|
372
369
|
}
|
|
373
370
|
|
|
374
371
|
public async getL2Tips(): Promise<L2Tips> {
|
|
375
|
-
const [latestBlockNumber, provenBlockNumber, checkpointedBlockNumber
|
|
372
|
+
const [latestBlockNumber, provenBlockNumber, checkpointedBlockNumber] = await Promise.all([
|
|
376
373
|
this.getBlockNumber(),
|
|
377
374
|
this.getProvenBlockNumber(),
|
|
378
|
-
this.
|
|
379
|
-
this.getFinalizedL2BlockNumber(),
|
|
375
|
+
this.getCheckpointedBlockNumber(),
|
|
380
376
|
] as const);
|
|
381
377
|
|
|
378
|
+
// TODO(#13569): Compute proper finalized block number based on L1 finalized block.
|
|
379
|
+
// We just force it 2 epochs worth of proven data for now.
|
|
380
|
+
// NOTE: update end-to-end/src/e2e_epochs/epochs_empty_blocks.test.ts as that uses finalized blocks in computations
|
|
381
|
+
const finalizedBlockNumber = BlockNumber(Math.max(provenBlockNumber - this.l1Constants.epochDuration * 2, 0));
|
|
382
|
+
|
|
382
383
|
const beforeInitialblockNumber = BlockNumber(INITIAL_L2_BLOCK_NUM - 1);
|
|
383
384
|
|
|
384
385
|
// Get the latest block header and checkpointed blocks for proven, finalised and checkpointed blocks
|
|
@@ -424,12 +425,14 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
424
425
|
// Now attempt to retrieve checkpoints for proven, finalised and checkpointed blocks
|
|
425
426
|
const [[provenBlockCheckpoint], [finalizedBlockCheckpoint], [checkpointedBlockCheckpoint]] = await Promise.all([
|
|
426
427
|
provenCheckpointedBlock !== undefined
|
|
427
|
-
? await this.
|
|
428
|
+
? await this.getPublishedCheckpoints(provenCheckpointedBlock?.checkpointNumber, 1)
|
|
428
429
|
: [undefined],
|
|
429
430
|
finalizedCheckpointedBlock !== undefined
|
|
430
|
-
? await this.
|
|
431
|
+
? await this.getPublishedCheckpoints(finalizedCheckpointedBlock?.checkpointNumber, 1)
|
|
432
|
+
: [undefined],
|
|
433
|
+
checkpointedBlock !== undefined
|
|
434
|
+
? await this.getPublishedCheckpoints(checkpointedBlock?.checkpointNumber, 1)
|
|
431
435
|
: [undefined],
|
|
432
|
-
checkpointedBlock !== undefined ? await this.getCheckpoints(checkpointedBlock?.checkpointNumber, 1) : [undefined],
|
|
433
436
|
]);
|
|
434
437
|
|
|
435
438
|
const initialcheckpointId: CheckpointId = {
|
|
@@ -487,12 +490,13 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
487
490
|
if (targetL2BlockNumber >= currentL2Block) {
|
|
488
491
|
throw new Error(`Target L2 block ${targetL2BlockNumber} must be less than current L2 block ${currentL2Block}`);
|
|
489
492
|
}
|
|
493
|
+
const blocksToUnwind = currentL2Block - targetL2BlockNumber;
|
|
490
494
|
const targetL2Block = await this.store.getCheckpointedBlock(targetL2BlockNumber);
|
|
491
495
|
if (!targetL2Block) {
|
|
492
496
|
throw new Error(`Target L2 block ${targetL2BlockNumber} not found`);
|
|
493
497
|
}
|
|
494
498
|
const targetL1BlockNumber = targetL2Block.l1.blockNumber;
|
|
495
|
-
const targetCheckpointNumber =
|
|
499
|
+
const targetCheckpointNumber = CheckpointNumber.fromBlockNumber(targetL2BlockNumber);
|
|
496
500
|
const targetL1Block = await this.publicClient.getBlock({
|
|
497
501
|
blockNumber: targetL1BlockNumber,
|
|
498
502
|
includeTransactions: false,
|
|
@@ -501,11 +505,9 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
501
505
|
throw new Error(`Missing L1 block ${targetL1BlockNumber}`);
|
|
502
506
|
}
|
|
503
507
|
const targetL1BlockHash = Buffer32.fromString(targetL1Block.hash);
|
|
504
|
-
this.log.info(
|
|
505
|
-
|
|
506
|
-
);
|
|
507
|
-
await this.updater.removeCheckpointsAfter(targetCheckpointNumber);
|
|
508
|
-
this.log.info(`Rolling back L1 to L2 messages to checkpoint ${targetCheckpointNumber}`);
|
|
508
|
+
this.log.info(`Unwinding ${blocksToUnwind} checkpoints from L2 block ${currentL2Block}`);
|
|
509
|
+
await this.updater.unwindCheckpoints(CheckpointNumber(currentL2Block), blocksToUnwind);
|
|
510
|
+
this.log.info(`Unwinding L1 to L2 messages to checkpoint ${targetCheckpointNumber}`);
|
|
509
511
|
await this.store.rollbackL1ToL2MessagesToCheckpoint(targetCheckpointNumber);
|
|
510
512
|
this.log.info(`Setting L1 syncpoints to ${targetL1BlockNumber}`);
|
|
511
513
|
await this.store.setCheckpointSynchedL1BlockNumber(targetL1BlockNumber);
|
package/src/errors.ts
CHANGED
|
@@ -88,15 +88,3 @@ export class BlockNotFoundError extends Error {
|
|
|
88
88
|
super(`Failed to find expected block number ${blockNumber}`);
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
|
-
|
|
92
|
-
export class CannotOverwriteCheckpointedBlockError extends Error {
|
|
93
|
-
constructor(
|
|
94
|
-
public readonly blockNumber: number,
|
|
95
|
-
public readonly lastCheckpointedBlock: number,
|
|
96
|
-
) {
|
|
97
|
-
super(
|
|
98
|
-
`Cannot add block ${blockNumber}: would overwrite checkpointed data (checkpointed up to block ${lastCheckpointedBlock})`,
|
|
99
|
-
);
|
|
100
|
-
this.name = 'CannotOverwriteCheckpointedBlockError';
|
|
101
|
-
}
|
|
102
|
-
}
|
package/src/factory.ts
CHANGED
|
@@ -15,7 +15,6 @@ import { BundledProtocolContractsProvider } from '@aztec/protocol-contracts/prov
|
|
|
15
15
|
import { FunctionType, decodeFunctionSignature } from '@aztec/stdlib/abi';
|
|
16
16
|
import type { ArchiverEmitter } from '@aztec/stdlib/block';
|
|
17
17
|
import { type ContractClassPublic, computePublicBytecodeCommitment } from '@aztec/stdlib/contract';
|
|
18
|
-
import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
|
|
19
18
|
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
20
19
|
|
|
21
20
|
import { EventEmitter } from 'events';
|
|
@@ -32,14 +31,13 @@ export const ARCHIVER_STORE_NAME = 'archiver';
|
|
|
32
31
|
/** Creates an archiver store. */
|
|
33
32
|
export async function createArchiverStore(
|
|
34
33
|
userConfig: Pick<ArchiverConfig, 'archiverStoreMapSizeKb' | 'maxLogs'> & DataStoreConfig,
|
|
35
|
-
l1Constants: Pick<L1RollupConstants, 'epochDuration'>,
|
|
36
34
|
) {
|
|
37
35
|
const config = {
|
|
38
36
|
...userConfig,
|
|
39
37
|
dataStoreMapSizeKb: userConfig.archiverStoreMapSizeKb ?? userConfig.dataStoreMapSizeKb,
|
|
40
38
|
};
|
|
41
39
|
const store = await createStore(ARCHIVER_STORE_NAME, ARCHIVER_DB_VERSION, config, createLogger('archiver:lmdb'));
|
|
42
|
-
return new KVArchiverDataStore(store, config.maxLogs
|
|
40
|
+
return new KVArchiverDataStore(store, config.maxLogs);
|
|
43
41
|
}
|
|
44
42
|
|
|
45
43
|
/**
|
|
@@ -54,7 +52,7 @@ export async function createArchiver(
|
|
|
54
52
|
deps: ArchiverDeps,
|
|
55
53
|
opts: { blockUntilSync: boolean } = { blockUntilSync: true },
|
|
56
54
|
): Promise<Archiver> {
|
|
57
|
-
const archiverStore = await createArchiverStore(config
|
|
55
|
+
const archiverStore = await createArchiverStore(config);
|
|
58
56
|
await registerProtocolContracts(archiverStore);
|
|
59
57
|
|
|
60
58
|
// Create Ethereum clients
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import type { ViemPublicClient, ViemPublicDebugClient } from '@aztec/ethereum/types';
|
|
3
|
-
import {
|
|
3
|
+
import { CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
4
4
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
5
5
|
import { createLogger } from '@aztec/foundation/log';
|
|
6
6
|
|
|
@@ -142,12 +142,7 @@ async function main() {
|
|
|
142
142
|
logger.info('');
|
|
143
143
|
|
|
144
144
|
// For this script, we don't have blob hashes or expected hashes, so pass empty arrays/objects
|
|
145
|
-
const result = await retriever.getCheckpointFromRollupTx(
|
|
146
|
-
txHash,
|
|
147
|
-
[],
|
|
148
|
-
CheckpointNumber.fromBlockNumber(BlockNumber(l2BlockNumber)),
|
|
149
|
-
{},
|
|
150
|
-
);
|
|
145
|
+
const result = await retriever.getCheckpointFromRollupTx(txHash, [], CheckpointNumber(l2BlockNumber), {});
|
|
151
146
|
|
|
152
147
|
logger.info(' Successfully retrieved block header!');
|
|
153
148
|
logger.info('');
|
package/src/l1/data_retrieval.ts
CHANGED
|
@@ -20,7 +20,7 @@ import { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
20
20
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
21
21
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
22
22
|
import { RollupAbi } from '@aztec/l1-artifacts';
|
|
23
|
-
import { Body, CommitteeAttestation,
|
|
23
|
+
import { Body, CommitteeAttestation, L2BlockNew } from '@aztec/stdlib/block';
|
|
24
24
|
import { Checkpoint, L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
25
25
|
import { Proof } from '@aztec/stdlib/proofs';
|
|
26
26
|
import { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
@@ -69,7 +69,7 @@ export async function retrievedToPublishedCheckpoint({
|
|
|
69
69
|
const l1toL2MessageTreeRoot = blocksBlobData[0].l1ToL2MessageRoot!;
|
|
70
70
|
|
|
71
71
|
const spongeBlob = SpongeBlob.init();
|
|
72
|
-
const l2Blocks:
|
|
72
|
+
const l2Blocks: L2BlockNew[] = [];
|
|
73
73
|
for (let i = 0; i < blocksBlobData.length; i++) {
|
|
74
74
|
const blockBlobData = blocksBlobData[i];
|
|
75
75
|
const { blockEndMarker, blockEndStateField, lastArchiveRoot, noteHashRoot, nullifierRoot, publicDataRoot } =
|
|
@@ -119,7 +119,7 @@ export async function retrievedToPublishedCheckpoint({
|
|
|
119
119
|
|
|
120
120
|
const newArchive = new AppendOnlyTreeSnapshot(newArchiveRoots[i], l2BlockNumber + 1);
|
|
121
121
|
|
|
122
|
-
l2Blocks.push(new
|
|
122
|
+
l2Blocks.push(new L2BlockNew(newArchive, header, body, checkpointNumber, IndexWithinCheckpoint(i)));
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
const lastBlock = l2Blocks.at(-1)!;
|
|
@@ -4,7 +4,7 @@ import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
|
4
4
|
import { isDefined } from '@aztec/foundation/types';
|
|
5
5
|
import type { FunctionSelector } from '@aztec/stdlib/abi';
|
|
6
6
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
7
|
-
import { CheckpointedL2Block, CommitteeAttestation,
|
|
7
|
+
import { CheckpointedL2Block, CommitteeAttestation, L2BlockNew, type L2Tips } from '@aztec/stdlib/block';
|
|
8
8
|
import { Checkpoint, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
9
9
|
import type { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
10
10
|
import { type L1RollupConstants, getSlotRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
|
|
@@ -87,14 +87,10 @@ export abstract class ArchiverDataSourceBase
|
|
|
87
87
|
return this.store.getCheckpointedBlock(number);
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
public
|
|
90
|
+
public getCheckpointedBlockNumber(): Promise<BlockNumber> {
|
|
91
91
|
return this.store.getCheckpointedL2BlockNumber();
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
public getFinalizedL2BlockNumber(): Promise<BlockNumber> {
|
|
95
|
-
return this.store.getFinalizedL2BlockNumber();
|
|
96
|
-
}
|
|
97
|
-
|
|
98
94
|
public async getCheckpointHeader(number: CheckpointNumber | 'latest'): Promise<CheckpointHeader | undefined> {
|
|
99
95
|
if (number === 'latest') {
|
|
100
96
|
number = await this.store.getSynchedCheckpointNumber();
|
|
@@ -117,8 +113,18 @@ export abstract class ArchiverDataSourceBase
|
|
|
117
113
|
return BlockNumber(checkpointData.startBlock + checkpointData.numBlocks - 1);
|
|
118
114
|
}
|
|
119
115
|
|
|
120
|
-
public getCheckpointedBlocks(
|
|
121
|
-
|
|
116
|
+
public async getCheckpointedBlocks(
|
|
117
|
+
from: BlockNumber,
|
|
118
|
+
limit: number,
|
|
119
|
+
proven?: boolean,
|
|
120
|
+
): Promise<CheckpointedL2Block[]> {
|
|
121
|
+
const blocks = await this.store.getCheckpointedBlocks(from, limit);
|
|
122
|
+
|
|
123
|
+
if (proven === true) {
|
|
124
|
+
const provenBlockNumber = await this.store.getProvenBlockNumber();
|
|
125
|
+
return blocks.filter(b => b.block.number <= provenBlockNumber);
|
|
126
|
+
}
|
|
127
|
+
return blocks;
|
|
122
128
|
}
|
|
123
129
|
|
|
124
130
|
public getBlockHeaderByHash(blockHash: Fr): Promise<BlockHeader | undefined> {
|
|
@@ -129,7 +135,7 @@ export abstract class ArchiverDataSourceBase
|
|
|
129
135
|
return this.store.getBlockHeaderByArchive(archive);
|
|
130
136
|
}
|
|
131
137
|
|
|
132
|
-
public async
|
|
138
|
+
public async getL2BlockNew(number: BlockNumber): Promise<L2BlockNew | undefined> {
|
|
133
139
|
// If the number provided is -ve, then return the latest block.
|
|
134
140
|
if (number < 0) {
|
|
135
141
|
number = await this.store.getLatestBlockNumber();
|
|
@@ -157,6 +163,16 @@ export abstract class ArchiverDataSourceBase
|
|
|
157
163
|
return (await this.store.getPendingChainValidationStatus()) ?? { valid: true };
|
|
158
164
|
}
|
|
159
165
|
|
|
166
|
+
public async getL2BlocksNew(from: BlockNumber, limit: number, proven?: boolean): Promise<L2BlockNew[]> {
|
|
167
|
+
const blocks = await this.store.getBlocks(from, limit);
|
|
168
|
+
|
|
169
|
+
if (proven === true) {
|
|
170
|
+
const provenBlockNumber = await this.store.getProvenBlockNumber();
|
|
171
|
+
return blocks.filter(b => b.number <= provenBlockNumber);
|
|
172
|
+
}
|
|
173
|
+
return blocks;
|
|
174
|
+
}
|
|
175
|
+
|
|
160
176
|
public getPrivateLogsByTags(tags: SiloedTag[], page?: number): Promise<TxScopedL2Log[][]> {
|
|
161
177
|
return this.store.getPrivateLogsByTags(tags, page);
|
|
162
178
|
}
|
|
@@ -221,7 +237,10 @@ export abstract class ArchiverDataSourceBase
|
|
|
221
237
|
return this.store.getL1ToL2MessageIndex(l1ToL2Message);
|
|
222
238
|
}
|
|
223
239
|
|
|
224
|
-
public async
|
|
240
|
+
public async getPublishedCheckpoints(
|
|
241
|
+
checkpointNumber: CheckpointNumber,
|
|
242
|
+
limit: number,
|
|
243
|
+
): Promise<PublishedCheckpoint[]> {
|
|
225
244
|
const checkpoints = await this.store.getRangeOfCheckpoints(checkpointNumber, limit);
|
|
226
245
|
const blocks = (
|
|
227
246
|
await Promise.all(checkpoints.map(ch => this.store.getBlocksForCheckpoint(ch.checkpointNumber)))
|
|
@@ -247,17 +266,17 @@ export abstract class ArchiverDataSourceBase
|
|
|
247
266
|
return fullCheckpoints;
|
|
248
267
|
}
|
|
249
268
|
|
|
250
|
-
public getBlocksForSlot(slotNumber: SlotNumber): Promise<
|
|
269
|
+
public getBlocksForSlot(slotNumber: SlotNumber): Promise<L2BlockNew[]> {
|
|
251
270
|
return this.store.getBlocksForSlot(slotNumber);
|
|
252
271
|
}
|
|
253
272
|
|
|
254
|
-
public async
|
|
273
|
+
public async getBlocksForEpoch(epochNumber: EpochNumber): Promise<L2BlockNew[]> {
|
|
255
274
|
if (!this.l1Constants) {
|
|
256
275
|
throw new Error('L1 constants not set');
|
|
257
276
|
}
|
|
258
277
|
|
|
259
278
|
const [start, end] = getSlotRangeForEpoch(epochNumber, this.l1Constants);
|
|
260
|
-
const blocks:
|
|
279
|
+
const blocks: L2BlockNew[] = [];
|
|
261
280
|
|
|
262
281
|
// Walk the list of checkpoints backwards and filter by slots matching the requested epoch.
|
|
263
282
|
// We'll typically ask for checkpoints for a very recent epoch, so we shouldn't need an index here.
|
|
@@ -268,9 +287,9 @@ export abstract class ArchiverDataSourceBase
|
|
|
268
287
|
// push the blocks on backwards
|
|
269
288
|
const endBlock = checkpoint.startBlock + checkpoint.numBlocks - 1;
|
|
270
289
|
for (let i = endBlock; i >= checkpoint.startBlock; i--) {
|
|
271
|
-
const
|
|
272
|
-
if (
|
|
273
|
-
blocks.push(
|
|
290
|
+
const block = await this.getBlock(BlockNumber(i));
|
|
291
|
+
if (block) {
|
|
292
|
+
blocks.push(block);
|
|
274
293
|
}
|
|
275
294
|
}
|
|
276
295
|
}
|
|
@@ -280,7 +299,7 @@ export abstract class ArchiverDataSourceBase
|
|
|
280
299
|
return blocks.reverse();
|
|
281
300
|
}
|
|
282
301
|
|
|
283
|
-
public async
|
|
302
|
+
public async getBlockHeadersForEpoch(epochNumber: EpochNumber): Promise<BlockHeader[]> {
|
|
284
303
|
if (!this.l1Constants) {
|
|
285
304
|
throw new Error('L1 constants not set');
|
|
286
305
|
}
|
|
@@ -323,7 +342,7 @@ export abstract class ArchiverDataSourceBase
|
|
|
323
342
|
while (checkpointData && slot(checkpointData) >= start) {
|
|
324
343
|
if (slot(checkpointData) <= end) {
|
|
325
344
|
// push the checkpoints on backwards
|
|
326
|
-
const [checkpoint] = await this.
|
|
345
|
+
const [checkpoint] = await this.getPublishedCheckpoints(checkpointData.checkpointNumber, 1);
|
|
327
346
|
checkpoints.push(checkpoint.checkpoint);
|
|
328
347
|
}
|
|
329
348
|
checkpointData = await this.store.getCheckpointData(CheckpointNumber(checkpointData.checkpointNumber - 1));
|
|
@@ -332,7 +351,33 @@ export abstract class ArchiverDataSourceBase
|
|
|
332
351
|
return checkpoints.reverse();
|
|
333
352
|
}
|
|
334
353
|
|
|
335
|
-
public async
|
|
354
|
+
public async getPublishedBlocks(from: BlockNumber, limit: number, proven?: boolean): Promise<CheckpointedL2Block[]> {
|
|
355
|
+
const checkpoints = await this.store.getRangeOfCheckpoints(CheckpointNumber(from), limit);
|
|
356
|
+
const provenCheckpointNumber = await this.store.getProvenCheckpointNumber();
|
|
357
|
+
const blocks = (
|
|
358
|
+
await Promise.all(checkpoints.map(ch => this.store.getBlocksForCheckpoint(ch.checkpointNumber)))
|
|
359
|
+
).filter(isDefined);
|
|
360
|
+
|
|
361
|
+
const publishedBlocks: CheckpointedL2Block[] = [];
|
|
362
|
+
for (let i = 0; i < checkpoints.length; i++) {
|
|
363
|
+
const blockForCheckpoint = blocks[i][0];
|
|
364
|
+
const checkpoint = checkpoints[i];
|
|
365
|
+
if (checkpoint.checkpointNumber > provenCheckpointNumber && proven === true) {
|
|
366
|
+
// this checkpoint isn't proven and we only want proven
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
const publishedBlock = new CheckpointedL2Block(
|
|
370
|
+
checkpoint.checkpointNumber,
|
|
371
|
+
blockForCheckpoint,
|
|
372
|
+
checkpoint.l1,
|
|
373
|
+
checkpoint.attestations.map(x => CommitteeAttestation.fromBuffer(x)),
|
|
374
|
+
);
|
|
375
|
+
publishedBlocks.push(publishedBlock);
|
|
376
|
+
}
|
|
377
|
+
return publishedBlocks;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
public async getBlock(number: BlockNumber): Promise<L2BlockNew | undefined> {
|
|
336
381
|
// If the number provided is -ve, then return the latest block.
|
|
337
382
|
if (number < 0) {
|
|
338
383
|
number = await this.store.getLatestBlockNumber();
|
|
@@ -343,24 +388,30 @@ export abstract class ArchiverDataSourceBase
|
|
|
343
388
|
return this.store.getBlock(number);
|
|
344
389
|
}
|
|
345
390
|
|
|
346
|
-
public getBlocks(from: BlockNumber, limit: number): Promise<
|
|
347
|
-
|
|
391
|
+
public async getBlocks(from: BlockNumber, limit: number, proven?: boolean): Promise<L2BlockNew[]> {
|
|
392
|
+
const blocks = await this.store.getBlocks(from, limit);
|
|
393
|
+
|
|
394
|
+
if (proven === true) {
|
|
395
|
+
const provenBlockNumber = await this.store.getProvenBlockNumber();
|
|
396
|
+
return blocks.filter(b => b.number <= provenBlockNumber);
|
|
397
|
+
}
|
|
398
|
+
return blocks;
|
|
348
399
|
}
|
|
349
400
|
|
|
350
|
-
public
|
|
401
|
+
public getPublishedBlockByHash(blockHash: Fr): Promise<CheckpointedL2Block | undefined> {
|
|
351
402
|
return this.store.getCheckpointedBlockByHash(blockHash);
|
|
352
403
|
}
|
|
353
404
|
|
|
354
|
-
public
|
|
405
|
+
public getPublishedBlockByArchive(archive: Fr): Promise<CheckpointedL2Block | undefined> {
|
|
355
406
|
return this.store.getCheckpointedBlockByArchive(archive);
|
|
356
407
|
}
|
|
357
408
|
|
|
358
|
-
public async
|
|
409
|
+
public async getL2BlockNewByHash(blockHash: Fr): Promise<L2BlockNew | undefined> {
|
|
359
410
|
const checkpointedBlock = await this.store.getCheckpointedBlockByHash(blockHash);
|
|
360
411
|
return checkpointedBlock?.block;
|
|
361
412
|
}
|
|
362
413
|
|
|
363
|
-
public async
|
|
414
|
+
public async getL2BlockNewByArchive(archive: Fr): Promise<L2BlockNew | undefined> {
|
|
364
415
|
const checkpointedBlock = await this.store.getCheckpointedBlockByArchive(archive);
|
|
365
416
|
return checkpointedBlock?.block;
|
|
366
417
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
1
|
+
import { BlockNumber, type CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
2
2
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
4
|
import {
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
ContractInstancePublishedEvent,
|
|
11
11
|
ContractInstanceUpdatedEvent,
|
|
12
12
|
} from '@aztec/protocol-contracts/instance-registry';
|
|
13
|
-
import type {
|
|
13
|
+
import type { L2BlockNew, ValidateCheckpointResult } from '@aztec/stdlib/block';
|
|
14
14
|
import type { PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
15
15
|
import {
|
|
16
16
|
type ExecutablePrivateFunctionWithMembershipProof,
|
|
@@ -35,7 +35,7 @@ enum Operation {
|
|
|
35
35
|
/** Result of adding checkpoints with information about any pruned blocks. */
|
|
36
36
|
type ReconcileCheckpointsResult = {
|
|
37
37
|
/** Blocks that were pruned due to conflict with L1 checkpoints. */
|
|
38
|
-
prunedBlocks:
|
|
38
|
+
prunedBlocks: L2BlockNew[] | undefined;
|
|
39
39
|
/** Last block number that was already inserted locally, or undefined if none. */
|
|
40
40
|
lastAlreadyInsertedBlockNumber: BlockNumber | undefined;
|
|
41
41
|
};
|
|
@@ -47,21 +47,17 @@ export class ArchiverDataStoreUpdater {
|
|
|
47
47
|
constructor(private store: KVArchiverDataStore) {}
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
|
-
* Adds
|
|
51
|
-
* These are uncheckpointed blocks that have been proposed by the sequencer but not yet included in a checkpoint on L1.
|
|
50
|
+
* Adds blocks to the store with contract class/instance extraction from logs.
|
|
52
51
|
* Extracts ContractClassPublished, ContractInstancePublished, ContractInstanceUpdated events,
|
|
53
52
|
* and individually broadcasted functions from the block logs.
|
|
54
53
|
*
|
|
55
|
-
* @param blocks - The
|
|
54
|
+
* @param blocks - The L2 blocks to add.
|
|
56
55
|
* @param pendingChainValidationStatus - Optional validation status to set.
|
|
57
56
|
* @returns True if the operation is successful.
|
|
58
57
|
*/
|
|
59
|
-
public
|
|
60
|
-
blocks: L2Block[],
|
|
61
|
-
pendingChainValidationStatus?: ValidateCheckpointResult,
|
|
62
|
-
): Promise<boolean> {
|
|
58
|
+
public addBlocks(blocks: L2BlockNew[], pendingChainValidationStatus?: ValidateCheckpointResult): Promise<boolean> {
|
|
63
59
|
return this.store.transactionAsync(async () => {
|
|
64
|
-
await this.store.
|
|
60
|
+
await this.store.addBlocks(blocks);
|
|
65
61
|
|
|
66
62
|
const opResults = await Promise.all([
|
|
67
63
|
// Update the pending chain validation status if provided
|
|
@@ -69,7 +65,7 @@ export class ArchiverDataStoreUpdater {
|
|
|
69
65
|
// Add any logs emitted during the retrieved blocks
|
|
70
66
|
this.store.addLogs(blocks),
|
|
71
67
|
// Unroll all logs emitted during the retrieved blocks and extract any contract classes and instances from them
|
|
72
|
-
...blocks.map(block => this.
|
|
68
|
+
...blocks.map(block => this.addBlockDataToDB(block)),
|
|
73
69
|
]);
|
|
74
70
|
|
|
75
71
|
return opResults.every(Boolean);
|
|
@@ -78,7 +74,7 @@ export class ArchiverDataStoreUpdater {
|
|
|
78
74
|
|
|
79
75
|
/**
|
|
80
76
|
* Reconciles local blocks with incoming checkpoints from L1.
|
|
81
|
-
* Adds
|
|
77
|
+
* Adds checkpoints to the store with contract class/instance extraction from logs.
|
|
82
78
|
* Prunes any local blocks that conflict with checkpoint data (by comparing archive roots).
|
|
83
79
|
* Extracts ContractClassPublished, ContractInstancePublished, ContractInstanceUpdated events,
|
|
84
80
|
* and individually broadcasted functions from the checkpoint block logs.
|
|
@@ -87,7 +83,7 @@ export class ArchiverDataStoreUpdater {
|
|
|
87
83
|
* @param pendingChainValidationStatus - Optional validation status to set.
|
|
88
84
|
* @returns Result with information about any pruned blocks.
|
|
89
85
|
*/
|
|
90
|
-
public
|
|
86
|
+
public setNewCheckpointData(
|
|
91
87
|
checkpoints: PublishedCheckpoint[],
|
|
92
88
|
pendingChainValidationStatus?: ValidateCheckpointResult,
|
|
93
89
|
): Promise<ReconcileCheckpointsResult> {
|
|
@@ -97,7 +93,7 @@ export class ArchiverDataStoreUpdater {
|
|
|
97
93
|
|
|
98
94
|
await this.store.addCheckpoints(checkpoints);
|
|
99
95
|
|
|
100
|
-
// Filter out blocks that were already inserted via
|
|
96
|
+
// Filter out blocks that were already inserted via addBlocks() to avoid duplicating logs/contract data
|
|
101
97
|
const newBlocks = checkpoints
|
|
102
98
|
.flatMap((ch: PublishedCheckpoint) => ch.checkpoint.blocks)
|
|
103
99
|
.filter(b => lastAlreadyInsertedBlockNumber === undefined || b.number > lastAlreadyInsertedBlockNumber);
|
|
@@ -108,7 +104,7 @@ export class ArchiverDataStoreUpdater {
|
|
|
108
104
|
// Add any logs emitted during the retrieved blocks
|
|
109
105
|
this.store.addLogs(newBlocks),
|
|
110
106
|
// Unroll all logs emitted during the retrieved blocks and extract any contract classes and instances from them
|
|
111
|
-
...newBlocks.map(block => this.
|
|
107
|
+
...newBlocks.map(block => this.addBlockDataToDB(block)),
|
|
112
108
|
]);
|
|
113
109
|
|
|
114
110
|
return { prunedBlocks, lastAlreadyInsertedBlockNumber };
|
|
@@ -189,80 +185,80 @@ export class ArchiverDataStoreUpdater {
|
|
|
189
185
|
}
|
|
190
186
|
|
|
191
187
|
/**
|
|
192
|
-
* Removes all
|
|
188
|
+
* Removes all blocks strictly after the specified block number and cleans up associated contract data.
|
|
193
189
|
* This handles removal of provisionally added blocks along with their contract classes/instances.
|
|
194
|
-
* Verifies that each block being removed is not part of a stored checkpoint.
|
|
195
190
|
*
|
|
196
191
|
* @param blockNumber - Remove all blocks with number greater than this.
|
|
197
192
|
* @returns The removed blocks.
|
|
198
|
-
* @throws Error if any block to be removed is checkpointed.
|
|
199
193
|
*/
|
|
200
|
-
public
|
|
194
|
+
public removeBlocksAfter(blockNumber: BlockNumber): Promise<L2BlockNew[]> {
|
|
201
195
|
return this.store.transactionAsync(async () => {
|
|
202
|
-
//
|
|
203
|
-
const
|
|
204
|
-
if (blockNumber < lastCheckpointedBlockNumber) {
|
|
205
|
-
throw new Error(
|
|
206
|
-
`Cannot remove blocks after ${blockNumber} because checkpointed blocks exist up to ${lastCheckpointedBlockNumber}`,
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
return await this.removeBlocksAfter(blockNumber);
|
|
211
|
-
});
|
|
212
|
-
}
|
|
196
|
+
// First get the blocks to be removed so we can clean up contract data
|
|
197
|
+
const removedBlocks = await this.store.removeBlocksAfter(blockNumber);
|
|
213
198
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
// First get the blocks to be removed so we can clean up contract data
|
|
220
|
-
const removedBlocks = await this.store.removeBlocksAfter(blockNumber);
|
|
221
|
-
|
|
222
|
-
// Clean up contract data and logs for the removed blocks
|
|
223
|
-
await Promise.all([
|
|
224
|
-
this.store.deleteLogs(removedBlocks),
|
|
225
|
-
...removedBlocks.map(block => this.removeContractDataFromDb(block)),
|
|
226
|
-
]);
|
|
199
|
+
// Clean up contract data and logs for the removed blocks
|
|
200
|
+
await Promise.all([
|
|
201
|
+
this.store.deleteLogs(removedBlocks),
|
|
202
|
+
...removedBlocks.map(block => this.removeBlockDataFromDB(block)),
|
|
203
|
+
]);
|
|
227
204
|
|
|
228
|
-
|
|
205
|
+
return removedBlocks;
|
|
206
|
+
});
|
|
229
207
|
}
|
|
230
208
|
|
|
231
209
|
/**
|
|
232
|
-
*
|
|
210
|
+
* Unwinds checkpoints from the store with reverse contract extraction.
|
|
233
211
|
* Deletes ContractClassPublished, ContractInstancePublished, ContractInstanceUpdated data
|
|
234
|
-
* that was stored for the
|
|
235
|
-
* and uncheckpointed) after the last block of the given checkpoint.
|
|
212
|
+
* that was stored for the unwound checkpoints.
|
|
236
213
|
*
|
|
237
|
-
* @param
|
|
214
|
+
* @param from - The checkpoint number to unwind from (must be the current tip).
|
|
215
|
+
* @param checkpointsToUnwind - The number of checkpoints to unwind.
|
|
238
216
|
* @returns True if the operation is successful.
|
|
239
217
|
*/
|
|
240
|
-
public async
|
|
241
|
-
|
|
218
|
+
public async unwindCheckpoints(from: CheckpointNumber, checkpointsToUnwind: number): Promise<boolean> {
|
|
219
|
+
if (checkpointsToUnwind <= 0) {
|
|
220
|
+
throw new Error(`Cannot unwind ${checkpointsToUnwind} blocks`);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const last = await this.store.getSynchedCheckpointNumber();
|
|
224
|
+
if (from != last) {
|
|
225
|
+
throw new Error(`Cannot unwind checkpoints from checkpoint ${from} when the last checkpoint is ${last}`);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const blocks = [];
|
|
229
|
+
const lastCheckpointNumber = from + checkpointsToUnwind - 1;
|
|
230
|
+
for (let checkpointNumber = from; checkpointNumber <= lastCheckpointNumber; checkpointNumber++) {
|
|
231
|
+
const blocksForCheckpoint = await this.store.getBlocksForCheckpoint(checkpointNumber);
|
|
232
|
+
if (!blocksForCheckpoint) {
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
blocks.push(...blocksForCheckpoint);
|
|
236
|
+
}
|
|
242
237
|
|
|
243
238
|
const opResults = await Promise.all([
|
|
244
239
|
// Prune rolls back to the last proven block, which is by definition valid
|
|
245
240
|
this.store.setPendingChainValidationStatus({ valid: true }),
|
|
246
|
-
// Remove contract data for all blocks being
|
|
247
|
-
...
|
|
248
|
-
this.store.deleteLogs(
|
|
241
|
+
// Remove contract data for all blocks being unwound
|
|
242
|
+
...blocks.map(block => this.removeBlockDataFromDB(block)),
|
|
243
|
+
this.store.deleteLogs(blocks),
|
|
244
|
+
this.store.unwindCheckpoints(from, checkpointsToUnwind),
|
|
249
245
|
]);
|
|
250
246
|
|
|
251
247
|
return opResults.every(Boolean);
|
|
252
248
|
}
|
|
253
249
|
|
|
254
250
|
/** Extracts and stores contract data from a single block. */
|
|
255
|
-
private
|
|
256
|
-
return this.
|
|
251
|
+
private addBlockDataToDB(block: L2BlockNew): Promise<boolean> {
|
|
252
|
+
return this.editContractBlockData(block, Operation.Store);
|
|
257
253
|
}
|
|
258
254
|
|
|
259
255
|
/** Removes contract data associated with a block. */
|
|
260
|
-
private
|
|
261
|
-
return this.
|
|
256
|
+
private removeBlockDataFromDB(block: L2BlockNew): Promise<boolean> {
|
|
257
|
+
return this.editContractBlockData(block, Operation.Delete);
|
|
262
258
|
}
|
|
263
259
|
|
|
264
260
|
/** Adds or remove contract data associated with a block. */
|
|
265
|
-
private async
|
|
261
|
+
private async editContractBlockData(block: L2BlockNew, operation: Operation): Promise<boolean> {
|
|
266
262
|
const contractClassLogs = block.body.txEffects.flatMap(txEffect => txEffect.contractClassLogs);
|
|
267
263
|
const privateLogs = block.body.txEffects.flatMap(txEffect => txEffect.privateLogs);
|
|
268
264
|
const publicLogs = block.body.txEffects.flatMap(txEffect => txEffect.publicLogs);
|