@aztec/archiver 0.0.1-commit.f295ac2 → 0.0.1-commit.f2ce05ee
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
|
@@ -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 { type BlockHash, CheckpointedL2Block, CommitteeAttestation, L2Block, 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,10 +87,14 @@ export abstract class ArchiverDataSourceBase
|
|
|
87
87
|
return this.store.getCheckpointedBlock(number);
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
public
|
|
90
|
+
public getCheckpointedL2BlockNumber(): Promise<BlockNumber> {
|
|
91
91
|
return this.store.getCheckpointedL2BlockNumber();
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
public getFinalizedL2BlockNumber(): Promise<BlockNumber> {
|
|
95
|
+
return this.store.getFinalizedL2BlockNumber();
|
|
96
|
+
}
|
|
97
|
+
|
|
94
98
|
public async getCheckpointHeader(number: CheckpointNumber | 'latest'): Promise<CheckpointHeader | undefined> {
|
|
95
99
|
if (number === 'latest') {
|
|
96
100
|
number = await this.store.getSynchedCheckpointNumber();
|
|
@@ -113,21 +117,11 @@ export abstract class ArchiverDataSourceBase
|
|
|
113
117
|
return BlockNumber(checkpointData.startBlock + checkpointData.numBlocks - 1);
|
|
114
118
|
}
|
|
115
119
|
|
|
116
|
-
public
|
|
117
|
-
from
|
|
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;
|
|
120
|
+
public getCheckpointedBlocks(from: BlockNumber, limit: number): Promise<CheckpointedL2Block[]> {
|
|
121
|
+
return this.store.getCheckpointedBlocks(from, limit);
|
|
128
122
|
}
|
|
129
123
|
|
|
130
|
-
public getBlockHeaderByHash(blockHash:
|
|
124
|
+
public getBlockHeaderByHash(blockHash: BlockHash): Promise<BlockHeader | undefined> {
|
|
131
125
|
return this.store.getBlockHeaderByHash(blockHash);
|
|
132
126
|
}
|
|
133
127
|
|
|
@@ -135,7 +129,7 @@ export abstract class ArchiverDataSourceBase
|
|
|
135
129
|
return this.store.getBlockHeaderByArchive(archive);
|
|
136
130
|
}
|
|
137
131
|
|
|
138
|
-
public async
|
|
132
|
+
public async getL2Block(number: BlockNumber): Promise<L2Block | undefined> {
|
|
139
133
|
// If the number provided is -ve, then return the latest block.
|
|
140
134
|
if (number < 0) {
|
|
141
135
|
number = await this.store.getLatestBlockNumber();
|
|
@@ -163,22 +157,16 @@ export abstract class ArchiverDataSourceBase
|
|
|
163
157
|
return (await this.store.getPendingChainValidationStatus()) ?? { valid: true };
|
|
164
158
|
}
|
|
165
159
|
|
|
166
|
-
public
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
if (proven === true) {
|
|
170
|
-
const provenBlockNumber = await this.store.getProvenBlockNumber();
|
|
171
|
-
return blocks.filter(b => b.number <= provenBlockNumber);
|
|
172
|
-
}
|
|
173
|
-
return blocks;
|
|
160
|
+
public getPrivateLogsByTags(tags: SiloedTag[], page?: number): Promise<TxScopedL2Log[][]> {
|
|
161
|
+
return this.store.getPrivateLogsByTags(tags, page);
|
|
174
162
|
}
|
|
175
163
|
|
|
176
|
-
public
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
return this.store.getPublicLogsByTagsFromContract(contractAddress, tags);
|
|
164
|
+
public getPublicLogsByTagsFromContract(
|
|
165
|
+
contractAddress: AztecAddress,
|
|
166
|
+
tags: Tag[],
|
|
167
|
+
page?: number,
|
|
168
|
+
): Promise<TxScopedL2Log[][]> {
|
|
169
|
+
return this.store.getPublicLogsByTagsFromContract(contractAddress, tags, page);
|
|
182
170
|
}
|
|
183
171
|
|
|
184
172
|
public getPublicLogs(filter: LogFilter): Promise<GetPublicLogsResponse> {
|
|
@@ -233,10 +221,7 @@ export abstract class ArchiverDataSourceBase
|
|
|
233
221
|
return this.store.getL1ToL2MessageIndex(l1ToL2Message);
|
|
234
222
|
}
|
|
235
223
|
|
|
236
|
-
public async
|
|
237
|
-
checkpointNumber: CheckpointNumber,
|
|
238
|
-
limit: number,
|
|
239
|
-
): Promise<PublishedCheckpoint[]> {
|
|
224
|
+
public async getCheckpoints(checkpointNumber: CheckpointNumber, limit: number): Promise<PublishedCheckpoint[]> {
|
|
240
225
|
const checkpoints = await this.store.getRangeOfCheckpoints(checkpointNumber, limit);
|
|
241
226
|
const blocks = (
|
|
242
227
|
await Promise.all(checkpoints.map(ch => this.store.getBlocksForCheckpoint(ch.checkpointNumber)))
|
|
@@ -262,17 +247,17 @@ export abstract class ArchiverDataSourceBase
|
|
|
262
247
|
return fullCheckpoints;
|
|
263
248
|
}
|
|
264
249
|
|
|
265
|
-
public getBlocksForSlot(slotNumber: SlotNumber): Promise<
|
|
250
|
+
public getBlocksForSlot(slotNumber: SlotNumber): Promise<L2Block[]> {
|
|
266
251
|
return this.store.getBlocksForSlot(slotNumber);
|
|
267
252
|
}
|
|
268
253
|
|
|
269
|
-
public async
|
|
254
|
+
public async getCheckpointedBlocksForEpoch(epochNumber: EpochNumber): Promise<CheckpointedL2Block[]> {
|
|
270
255
|
if (!this.l1Constants) {
|
|
271
256
|
throw new Error('L1 constants not set');
|
|
272
257
|
}
|
|
273
258
|
|
|
274
259
|
const [start, end] = getSlotRangeForEpoch(epochNumber, this.l1Constants);
|
|
275
|
-
const blocks:
|
|
260
|
+
const blocks: CheckpointedL2Block[] = [];
|
|
276
261
|
|
|
277
262
|
// Walk the list of checkpoints backwards and filter by slots matching the requested epoch.
|
|
278
263
|
// We'll typically ask for checkpoints for a very recent epoch, so we shouldn't need an index here.
|
|
@@ -283,9 +268,9 @@ export abstract class ArchiverDataSourceBase
|
|
|
283
268
|
// push the blocks on backwards
|
|
284
269
|
const endBlock = checkpoint.startBlock + checkpoint.numBlocks - 1;
|
|
285
270
|
for (let i = endBlock; i >= checkpoint.startBlock; i--) {
|
|
286
|
-
const
|
|
287
|
-
if (
|
|
288
|
-
blocks.push(
|
|
271
|
+
const checkpointedBlock = await this.getCheckpointedBlock(BlockNumber(i));
|
|
272
|
+
if (checkpointedBlock) {
|
|
273
|
+
blocks.push(checkpointedBlock);
|
|
289
274
|
}
|
|
290
275
|
}
|
|
291
276
|
}
|
|
@@ -295,7 +280,7 @@ export abstract class ArchiverDataSourceBase
|
|
|
295
280
|
return blocks.reverse();
|
|
296
281
|
}
|
|
297
282
|
|
|
298
|
-
public async
|
|
283
|
+
public async getCheckpointedBlockHeadersForEpoch(epochNumber: EpochNumber): Promise<BlockHeader[]> {
|
|
299
284
|
if (!this.l1Constants) {
|
|
300
285
|
throw new Error('L1 constants not set');
|
|
301
286
|
}
|
|
@@ -338,7 +323,7 @@ export abstract class ArchiverDataSourceBase
|
|
|
338
323
|
while (checkpointData && slot(checkpointData) >= start) {
|
|
339
324
|
if (slot(checkpointData) <= end) {
|
|
340
325
|
// push the checkpoints on backwards
|
|
341
|
-
const [checkpoint] = await this.
|
|
326
|
+
const [checkpoint] = await this.getCheckpoints(checkpointData.checkpointNumber, 1);
|
|
342
327
|
checkpoints.push(checkpoint.checkpoint);
|
|
343
328
|
}
|
|
344
329
|
checkpointData = await this.store.getCheckpointData(CheckpointNumber(checkpointData.checkpointNumber - 1));
|
|
@@ -347,33 +332,7 @@ export abstract class ArchiverDataSourceBase
|
|
|
347
332
|
return checkpoints.reverse();
|
|
348
333
|
}
|
|
349
334
|
|
|
350
|
-
public async
|
|
351
|
-
const checkpoints = await this.store.getRangeOfCheckpoints(CheckpointNumber(from), limit);
|
|
352
|
-
const provenCheckpointNumber = await this.store.getProvenCheckpointNumber();
|
|
353
|
-
const blocks = (
|
|
354
|
-
await Promise.all(checkpoints.map(ch => this.store.getBlocksForCheckpoint(ch.checkpointNumber)))
|
|
355
|
-
).filter(isDefined);
|
|
356
|
-
|
|
357
|
-
const publishedBlocks: CheckpointedL2Block[] = [];
|
|
358
|
-
for (let i = 0; i < checkpoints.length; i++) {
|
|
359
|
-
const blockForCheckpoint = blocks[i][0];
|
|
360
|
-
const checkpoint = checkpoints[i];
|
|
361
|
-
if (checkpoint.checkpointNumber > provenCheckpointNumber && proven === true) {
|
|
362
|
-
// this checkpoint isn't proven and we only want proven
|
|
363
|
-
continue;
|
|
364
|
-
}
|
|
365
|
-
const publishedBlock = new CheckpointedL2Block(
|
|
366
|
-
checkpoint.checkpointNumber,
|
|
367
|
-
blockForCheckpoint,
|
|
368
|
-
checkpoint.l1,
|
|
369
|
-
checkpoint.attestations.map(x => CommitteeAttestation.fromBuffer(x)),
|
|
370
|
-
);
|
|
371
|
-
publishedBlocks.push(publishedBlock);
|
|
372
|
-
}
|
|
373
|
-
return publishedBlocks;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
public async getBlock(number: BlockNumber): Promise<L2BlockNew | undefined> {
|
|
335
|
+
public async getBlock(number: BlockNumber): Promise<L2Block | undefined> {
|
|
377
336
|
// If the number provided is -ve, then return the latest block.
|
|
378
337
|
if (number < 0) {
|
|
379
338
|
number = await this.store.getLatestBlockNumber();
|
|
@@ -384,30 +343,24 @@ export abstract class ArchiverDataSourceBase
|
|
|
384
343
|
return this.store.getBlock(number);
|
|
385
344
|
}
|
|
386
345
|
|
|
387
|
-
public
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
if (proven === true) {
|
|
391
|
-
const provenBlockNumber = await this.store.getProvenBlockNumber();
|
|
392
|
-
return blocks.filter(b => b.number <= provenBlockNumber);
|
|
393
|
-
}
|
|
394
|
-
return blocks;
|
|
346
|
+
public getBlocks(from: BlockNumber, limit: number): Promise<L2Block[]> {
|
|
347
|
+
return this.store.getBlocks(from, limit);
|
|
395
348
|
}
|
|
396
349
|
|
|
397
|
-
public
|
|
350
|
+
public getCheckpointedBlockByHash(blockHash: BlockHash): Promise<CheckpointedL2Block | undefined> {
|
|
398
351
|
return this.store.getCheckpointedBlockByHash(blockHash);
|
|
399
352
|
}
|
|
400
353
|
|
|
401
|
-
public
|
|
354
|
+
public getCheckpointedBlockByArchive(archive: Fr): Promise<CheckpointedL2Block | undefined> {
|
|
402
355
|
return this.store.getCheckpointedBlockByArchive(archive);
|
|
403
356
|
}
|
|
404
357
|
|
|
405
|
-
public async
|
|
358
|
+
public async getL2BlockByHash(blockHash: BlockHash): Promise<L2Block | undefined> {
|
|
406
359
|
const checkpointedBlock = await this.store.getCheckpointedBlockByHash(blockHash);
|
|
407
360
|
return checkpointedBlock?.block;
|
|
408
361
|
}
|
|
409
362
|
|
|
410
|
-
public async
|
|
363
|
+
public async getL2BlockByArchive(archive: Fr): Promise<L2Block | undefined> {
|
|
411
364
|
const checkpointedBlock = await this.store.getCheckpointedBlockByArchive(archive);
|
|
412
365
|
return checkpointedBlock?.block;
|
|
413
366
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BlockNumber,
|
|
1
|
+
import { BlockNumber, 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 { L2Block, 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: L2Block[] | undefined;
|
|
39
39
|
/** Last block number that was already inserted locally, or undefined if none. */
|
|
40
40
|
lastAlreadyInsertedBlockNumber: BlockNumber | undefined;
|
|
41
41
|
};
|
|
@@ -47,17 +47,21 @@ export class ArchiverDataStoreUpdater {
|
|
|
47
47
|
constructor(private store: KVArchiverDataStore) {}
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
|
-
* Adds blocks to the store with contract class/instance extraction from logs.
|
|
50
|
+
* Adds proposed blocks to the store with contract class/instance extraction from logs.
|
|
51
|
+
* These are uncheckpointed blocks that have been proposed by the sequencer but not yet included in a checkpoint on L1.
|
|
51
52
|
* Extracts ContractClassPublished, ContractInstancePublished, ContractInstanceUpdated events,
|
|
52
53
|
* and individually broadcasted functions from the block logs.
|
|
53
54
|
*
|
|
54
|
-
* @param blocks - The L2 blocks to add.
|
|
55
|
+
* @param blocks - The proposed L2 blocks to add.
|
|
55
56
|
* @param pendingChainValidationStatus - Optional validation status to set.
|
|
56
57
|
* @returns True if the operation is successful.
|
|
57
58
|
*/
|
|
58
|
-
public
|
|
59
|
+
public addProposedBlocks(
|
|
60
|
+
blocks: L2Block[],
|
|
61
|
+
pendingChainValidationStatus?: ValidateCheckpointResult,
|
|
62
|
+
): Promise<boolean> {
|
|
59
63
|
return this.store.transactionAsync(async () => {
|
|
60
|
-
await this.store.
|
|
64
|
+
await this.store.addProposedBlocks(blocks);
|
|
61
65
|
|
|
62
66
|
const opResults = await Promise.all([
|
|
63
67
|
// Update the pending chain validation status if provided
|
|
@@ -65,7 +69,7 @@ export class ArchiverDataStoreUpdater {
|
|
|
65
69
|
// Add any logs emitted during the retrieved blocks
|
|
66
70
|
this.store.addLogs(blocks),
|
|
67
71
|
// Unroll all logs emitted during the retrieved blocks and extract any contract classes and instances from them
|
|
68
|
-
...blocks.map(block => this.
|
|
72
|
+
...blocks.map(block => this.addContractDataToDb(block)),
|
|
69
73
|
]);
|
|
70
74
|
|
|
71
75
|
return opResults.every(Boolean);
|
|
@@ -74,7 +78,7 @@ export class ArchiverDataStoreUpdater {
|
|
|
74
78
|
|
|
75
79
|
/**
|
|
76
80
|
* Reconciles local blocks with incoming checkpoints from L1.
|
|
77
|
-
* Adds checkpoints to the store with contract class/instance extraction from logs.
|
|
81
|
+
* Adds new checkpoints to the store with contract class/instance extraction from logs.
|
|
78
82
|
* Prunes any local blocks that conflict with checkpoint data (by comparing archive roots).
|
|
79
83
|
* Extracts ContractClassPublished, ContractInstancePublished, ContractInstanceUpdated events,
|
|
80
84
|
* and individually broadcasted functions from the checkpoint block logs.
|
|
@@ -83,7 +87,7 @@ export class ArchiverDataStoreUpdater {
|
|
|
83
87
|
* @param pendingChainValidationStatus - Optional validation status to set.
|
|
84
88
|
* @returns Result with information about any pruned blocks.
|
|
85
89
|
*/
|
|
86
|
-
public
|
|
90
|
+
public addCheckpoints(
|
|
87
91
|
checkpoints: PublishedCheckpoint[],
|
|
88
92
|
pendingChainValidationStatus?: ValidateCheckpointResult,
|
|
89
93
|
): Promise<ReconcileCheckpointsResult> {
|
|
@@ -93,7 +97,7 @@ export class ArchiverDataStoreUpdater {
|
|
|
93
97
|
|
|
94
98
|
await this.store.addCheckpoints(checkpoints);
|
|
95
99
|
|
|
96
|
-
// Filter out blocks that were already inserted via
|
|
100
|
+
// Filter out blocks that were already inserted via addProposedBlocks() to avoid duplicating logs/contract data
|
|
97
101
|
const newBlocks = checkpoints
|
|
98
102
|
.flatMap((ch: PublishedCheckpoint) => ch.checkpoint.blocks)
|
|
99
103
|
.filter(b => lastAlreadyInsertedBlockNumber === undefined || b.number > lastAlreadyInsertedBlockNumber);
|
|
@@ -104,7 +108,7 @@ export class ArchiverDataStoreUpdater {
|
|
|
104
108
|
// Add any logs emitted during the retrieved blocks
|
|
105
109
|
this.store.addLogs(newBlocks),
|
|
106
110
|
// Unroll all logs emitted during the retrieved blocks and extract any contract classes and instances from them
|
|
107
|
-
...newBlocks.map(block => this.
|
|
111
|
+
...newBlocks.map(block => this.addContractDataToDb(block)),
|
|
108
112
|
]);
|
|
109
113
|
|
|
110
114
|
return { prunedBlocks, lastAlreadyInsertedBlockNumber };
|
|
@@ -185,80 +189,80 @@ export class ArchiverDataStoreUpdater {
|
|
|
185
189
|
}
|
|
186
190
|
|
|
187
191
|
/**
|
|
188
|
-
* Removes all blocks strictly after the specified block number and cleans up associated contract data.
|
|
192
|
+
* Removes all uncheckpointed blocks strictly after the specified block number and cleans up associated contract data.
|
|
189
193
|
* 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.
|
|
190
195
|
*
|
|
191
196
|
* @param blockNumber - Remove all blocks with number greater than this.
|
|
192
197
|
* @returns The removed blocks.
|
|
198
|
+
* @throws Error if any block to be removed is checkpointed.
|
|
193
199
|
*/
|
|
194
|
-
public
|
|
200
|
+
public removeUncheckpointedBlocksAfter(blockNumber: BlockNumber): Promise<L2Block[]> {
|
|
195
201
|
return this.store.transactionAsync(async () => {
|
|
196
|
-
//
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
]);
|
|
202
|
+
// Verify we're only removing uncheckpointed blocks
|
|
203
|
+
const lastCheckpointedBlockNumber = await this.store.getCheckpointedL2BlockNumber();
|
|
204
|
+
if (blockNumber < lastCheckpointedBlockNumber) {
|
|
205
|
+
throw new Error(
|
|
206
|
+
`Cannot remove blocks after ${blockNumber} because checkpointed blocks exist up to ${lastCheckpointedBlockNumber}`,
|
|
207
|
+
);
|
|
208
|
+
}
|
|
204
209
|
|
|
205
|
-
return
|
|
210
|
+
return await this.removeBlocksAfter(blockNumber);
|
|
206
211
|
});
|
|
207
212
|
}
|
|
208
213
|
|
|
209
214
|
/**
|
|
210
|
-
*
|
|
215
|
+
* Removes all blocks strictly after the given block number along with any logs and contract data.
|
|
216
|
+
* Does not remove their checkpoints.
|
|
217
|
+
*/
|
|
218
|
+
private async removeBlocksAfter(blockNumber: BlockNumber): Promise<L2Block[]> {
|
|
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
|
+
]);
|
|
227
|
+
|
|
228
|
+
return removedBlocks;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Removes all checkpoints after the given checkpoint number.
|
|
211
233
|
* Deletes ContractClassPublished, ContractInstancePublished, ContractInstanceUpdated data
|
|
212
|
-
* that was stored for the
|
|
234
|
+
* that was stored for the removed checkpoints. Also removes ALL blocks (both checkpointed
|
|
235
|
+
* and uncheckpointed) after the last block of the given checkpoint.
|
|
213
236
|
*
|
|
214
|
-
* @param
|
|
215
|
-
* @param checkpointsToUnwind - The number of checkpoints to unwind.
|
|
237
|
+
* @param checkpointNumber - Remove all checkpoints strictly after this one.
|
|
216
238
|
* @returns True if the operation is successful.
|
|
217
239
|
*/
|
|
218
|
-
public async
|
|
219
|
-
|
|
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
|
-
}
|
|
240
|
+
public async removeCheckpointsAfter(checkpointNumber: CheckpointNumber): Promise<boolean> {
|
|
241
|
+
const { blocksRemoved = [] } = await this.store.removeCheckpointsAfter(checkpointNumber);
|
|
237
242
|
|
|
238
243
|
const opResults = await Promise.all([
|
|
239
244
|
// Prune rolls back to the last proven block, which is by definition valid
|
|
240
245
|
this.store.setPendingChainValidationStatus({ valid: true }),
|
|
241
|
-
// Remove contract data for all blocks being
|
|
242
|
-
...
|
|
243
|
-
this.store.deleteLogs(
|
|
244
|
-
this.store.unwindCheckpoints(from, checkpointsToUnwind),
|
|
246
|
+
// Remove contract data for all blocks being removed
|
|
247
|
+
...blocksRemoved.map(block => this.removeContractDataFromDb(block)),
|
|
248
|
+
this.store.deleteLogs(blocksRemoved),
|
|
245
249
|
]);
|
|
246
250
|
|
|
247
251
|
return opResults.every(Boolean);
|
|
248
252
|
}
|
|
249
253
|
|
|
250
254
|
/** Extracts and stores contract data from a single block. */
|
|
251
|
-
private
|
|
252
|
-
return this.
|
|
255
|
+
private addContractDataToDb(block: L2Block): Promise<boolean> {
|
|
256
|
+
return this.updateContractDataOnDb(block, Operation.Store);
|
|
253
257
|
}
|
|
254
258
|
|
|
255
259
|
/** Removes contract data associated with a block. */
|
|
256
|
-
private
|
|
257
|
-
return this.
|
|
260
|
+
private removeContractDataFromDb(block: L2Block): Promise<boolean> {
|
|
261
|
+
return this.updateContractDataOnDb(block, Operation.Delete);
|
|
258
262
|
}
|
|
259
263
|
|
|
260
264
|
/** Adds or remove contract data associated with a block. */
|
|
261
|
-
private async
|
|
265
|
+
private async updateContractDataOnDb(block: L2Block, operation: Operation): Promise<boolean> {
|
|
262
266
|
const contractClassLogs = block.body.txEffects.flatMap(txEffect => txEffect.contractClassLogs);
|
|
263
267
|
const privateLogs = block.body.txEffects.flatMap(txEffect => txEffect.privateLogs);
|
|
264
268
|
const publicLogs = block.body.txEffects.flatMap(txEffect => txEffect.publicLogs);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
|
-
import type {
|
|
2
|
+
import type { L2Block } from '@aztec/stdlib/block';
|
|
3
3
|
import {
|
|
4
4
|
Attributes,
|
|
5
5
|
type Gauge,
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
type TelemetryClient,
|
|
11
11
|
type Tracer,
|
|
12
12
|
type UpDownCounter,
|
|
13
|
+
createUpDownCounterWithDefault,
|
|
13
14
|
} from '@aztec/telemetry-client';
|
|
14
15
|
|
|
15
16
|
export class ArchiverInstrumentation {
|
|
@@ -48,15 +49,17 @@ export class ArchiverInstrumentation {
|
|
|
48
49
|
|
|
49
50
|
this.l1BlockHeight = meter.createGauge(Metrics.ARCHIVER_L1_BLOCK_HEIGHT);
|
|
50
51
|
|
|
51
|
-
this.txCount = meter
|
|
52
|
+
this.txCount = createUpDownCounterWithDefault(meter, Metrics.ARCHIVER_TOTAL_TXS);
|
|
52
53
|
|
|
53
|
-
this.proofsSubmittedCount = meter
|
|
54
|
+
this.proofsSubmittedCount = createUpDownCounterWithDefault(meter, Metrics.ARCHIVER_ROLLUP_PROOF_COUNT, {
|
|
55
|
+
[Attributes.PROOF_TIMED_OUT]: [true, false],
|
|
56
|
+
});
|
|
54
57
|
|
|
55
58
|
this.proofsSubmittedDelay = meter.createHistogram(Metrics.ARCHIVER_ROLLUP_PROOF_DELAY);
|
|
56
59
|
|
|
57
60
|
this.syncDurationPerBlock = meter.createHistogram(Metrics.ARCHIVER_SYNC_PER_BLOCK);
|
|
58
61
|
|
|
59
|
-
this.syncBlockCount = meter
|
|
62
|
+
this.syncBlockCount = createUpDownCounterWithDefault(meter, Metrics.ARCHIVER_SYNC_BLOCK_COUNT);
|
|
60
63
|
|
|
61
64
|
this.manaPerBlock = meter.createHistogram(Metrics.ARCHIVER_MANA_PER_BLOCK);
|
|
62
65
|
|
|
@@ -64,13 +67,19 @@ export class ArchiverInstrumentation {
|
|
|
64
67
|
|
|
65
68
|
this.syncDurationPerMessage = meter.createHistogram(Metrics.ARCHIVER_SYNC_PER_MESSAGE);
|
|
66
69
|
|
|
67
|
-
this.syncMessageCount = meter
|
|
70
|
+
this.syncMessageCount = createUpDownCounterWithDefault(meter, Metrics.ARCHIVER_SYNC_MESSAGE_COUNT);
|
|
68
71
|
|
|
69
72
|
this.pruneDuration = meter.createHistogram(Metrics.ARCHIVER_PRUNE_DURATION);
|
|
70
73
|
|
|
71
|
-
this.pruneCount = meter
|
|
74
|
+
this.pruneCount = createUpDownCounterWithDefault(meter, Metrics.ARCHIVER_PRUNE_COUNT);
|
|
72
75
|
|
|
73
|
-
this.blockProposalTxTargetCount =
|
|
76
|
+
this.blockProposalTxTargetCount = createUpDownCounterWithDefault(
|
|
77
|
+
meter,
|
|
78
|
+
Metrics.ARCHIVER_BLOCK_PROPOSAL_TX_TARGET_COUNT,
|
|
79
|
+
{
|
|
80
|
+
[Attributes.L1_BLOCK_PROPOSAL_USED_TRACE]: [true, false],
|
|
81
|
+
},
|
|
82
|
+
);
|
|
74
83
|
|
|
75
84
|
this.dbMetrics = new LmdbMetrics(
|
|
76
85
|
meter,
|
|
@@ -84,10 +93,6 @@ export class ArchiverInstrumentation {
|
|
|
84
93
|
public static async new(telemetry: TelemetryClient, lmdbStats?: LmdbStatsCallback) {
|
|
85
94
|
const instance = new ArchiverInstrumentation(telemetry, lmdbStats);
|
|
86
95
|
|
|
87
|
-
instance.syncBlockCount.add(0);
|
|
88
|
-
instance.syncMessageCount.add(0);
|
|
89
|
-
instance.pruneCount.add(0);
|
|
90
|
-
|
|
91
96
|
await instance.telemetry.flush();
|
|
92
97
|
|
|
93
98
|
return instance;
|
|
@@ -97,7 +102,7 @@ export class ArchiverInstrumentation {
|
|
|
97
102
|
return this.telemetry.isEnabled();
|
|
98
103
|
}
|
|
99
104
|
|
|
100
|
-
public processNewBlocks(syncTimePerBlock: number, blocks:
|
|
105
|
+
public processNewBlocks(syncTimePerBlock: number, blocks: L2Block[]) {
|
|
101
106
|
this.syncDurationPerBlock.record(Math.ceil(syncTimePerBlock));
|
|
102
107
|
this.blockHeight.record(Math.max(...blocks.map(b => b.number)));
|
|
103
108
|
this.syncBlockCount.add(blocks.length);
|
|
@@ -16,7 +16,7 @@ import { DateProvider, Timer, elapsed } from '@aztec/foundation/timer';
|
|
|
16
16
|
import { isDefined } from '@aztec/foundation/types';
|
|
17
17
|
import { type ArchiverEmitter, L2BlockSourceEvents, type ValidateCheckpointResult } from '@aztec/stdlib/block';
|
|
18
18
|
import { PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
19
|
-
import { type L1RollupConstants, getEpochAtSlot,
|
|
19
|
+
import { type L1RollupConstants, getEpochAtSlot, getSlotAtNextL1Block } from '@aztec/stdlib/epoch-helpers';
|
|
20
20
|
import { computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
|
|
21
21
|
import { type Traceable, type Tracer, execInSpan, trackSpan } from '@aztec/telemetry-client';
|
|
22
22
|
|
|
@@ -249,8 +249,7 @@ export class ArchiverL1Synchronizer implements Traceable {
|
|
|
249
249
|
const firstUncheckpointedBlockSlot = firstUncheckpointedBlockHeader?.getSlot();
|
|
250
250
|
|
|
251
251
|
// What's the slot at the next L1 block? All blocks for slots strictly before this one should've been checkpointed by now.
|
|
252
|
-
const
|
|
253
|
-
const slotAtNextL1Block = getSlotAtTimestamp(nextL1BlockTimestamp, this.l1Constants);
|
|
252
|
+
const slotAtNextL1Block = getSlotAtNextL1Block(currentL1Timestamp, this.l1Constants);
|
|
254
253
|
|
|
255
254
|
// Prune provisional blocks from slots that have ended without being checkpointed
|
|
256
255
|
if (firstUncheckpointedBlockSlot !== undefined && firstUncheckpointedBlockSlot < slotAtNextL1Block) {
|
|
@@ -258,7 +257,7 @@ export class ArchiverL1Synchronizer implements Traceable {
|
|
|
258
257
|
`Pruning blocks after block ${lastCheckpointedBlockNumber} due to slot ${firstUncheckpointedBlockSlot} not being checkpointed`,
|
|
259
258
|
{ firstUncheckpointedBlockHeader: firstUncheckpointedBlockHeader.toInspect(), slotAtNextL1Block },
|
|
260
259
|
);
|
|
261
|
-
const prunedBlocks = await this.updater.
|
|
260
|
+
const prunedBlocks = await this.updater.removeUncheckpointedBlocksAfter(lastCheckpointedBlockNumber);
|
|
262
261
|
|
|
263
262
|
if (prunedBlocks.length > 0) {
|
|
264
263
|
this.events.emit(L2BlockSourceEvents.L2PruneUncheckpointed, {
|
|
@@ -331,10 +330,10 @@ export class ArchiverL1Synchronizer implements Traceable {
|
|
|
331
330
|
this.log.debug(
|
|
332
331
|
`L2 prune from ${provenCheckpointNumber + 1} to ${localPendingCheckpointNumber} will occur on next checkpoint submission.`,
|
|
333
332
|
);
|
|
334
|
-
await this.updater.
|
|
333
|
+
await this.updater.removeCheckpointsAfter(provenCheckpointNumber);
|
|
335
334
|
this.log.warn(
|
|
336
|
-
`
|
|
337
|
-
`
|
|
335
|
+
`Removed ${count(checkpointsToUnwind, 'checkpoint')} after checkpoint ${provenCheckpointNumber} ` +
|
|
336
|
+
`due to predicted reorg at L1 block ${currentL1BlockNumber}. ` +
|
|
338
337
|
`Updated latest checkpoint is ${await this.store.getSynchedCheckpointNumber()}.`,
|
|
339
338
|
);
|
|
340
339
|
this.instrumentation.processPrune(timer.ms());
|
|
@@ -675,11 +674,11 @@ export class ArchiverL1Synchronizer implements Traceable {
|
|
|
675
674
|
tipAfterUnwind--;
|
|
676
675
|
}
|
|
677
676
|
|
|
678
|
-
const
|
|
679
|
-
await this.updater.
|
|
677
|
+
const checkpointsToRemove = localPendingCheckpointNumber - tipAfterUnwind;
|
|
678
|
+
await this.updater.removeCheckpointsAfter(CheckpointNumber(tipAfterUnwind));
|
|
680
679
|
|
|
681
680
|
this.log.warn(
|
|
682
|
-
`
|
|
681
|
+
`Removed ${count(checkpointsToRemove, 'checkpoint')} after checkpoint ${tipAfterUnwind} ` +
|
|
683
682
|
`due to mismatched checkpoint hashes at L1 block ${currentL1BlockNumber}. ` +
|
|
684
683
|
`Updated L2 latest checkpoint is ${await this.store.getSynchedCheckpointNumber()}.`,
|
|
685
684
|
);
|
|
@@ -806,8 +805,8 @@ export class ArchiverL1Synchronizer implements Traceable {
|
|
|
806
805
|
const updatedValidationResult =
|
|
807
806
|
rollupStatus.validationResult === initialValidationResult ? undefined : rollupStatus.validationResult;
|
|
808
807
|
const [processDuration, result] = await elapsed(() =>
|
|
809
|
-
execInSpan(this.tracer, 'Archiver.
|
|
810
|
-
this.updater.
|
|
808
|
+
execInSpan(this.tracer, 'Archiver.addCheckpoints', () =>
|
|
809
|
+
this.updater.addCheckpoints(validCheckpoints, updatedValidationResult),
|
|
811
810
|
),
|
|
812
811
|
);
|
|
813
812
|
this.instrumentation.processNewBlocks(
|