@aztec/archiver 0.0.1-commit.d431d1c → 0.0.1-commit.d6f2b3f94

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.
Files changed (75) hide show
  1. package/README.md +9 -0
  2. package/dest/archiver.d.ts +6 -5
  3. package/dest/archiver.d.ts.map +1 -1
  4. package/dest/archiver.js +34 -22
  5. package/dest/errors.d.ts +6 -1
  6. package/dest/errors.d.ts.map +1 -1
  7. package/dest/errors.js +8 -0
  8. package/dest/factory.d.ts +5 -2
  9. package/dest/factory.d.ts.map +1 -1
  10. package/dest/factory.js +11 -8
  11. package/dest/l1/bin/retrieve-calldata.js +17 -18
  12. package/dest/l1/data_retrieval.d.ts +1 -1
  13. package/dest/l1/data_retrieval.d.ts.map +1 -1
  14. package/dest/l1/data_retrieval.js +3 -3
  15. package/dest/l1/validate_trace.d.ts +6 -3
  16. package/dest/l1/validate_trace.d.ts.map +1 -1
  17. package/dest/l1/validate_trace.js +13 -9
  18. package/dest/modules/data_source_base.d.ts +17 -18
  19. package/dest/modules/data_source_base.d.ts.map +1 -1
  20. package/dest/modules/data_source_base.js +21 -52
  21. package/dest/modules/data_store_updater.d.ts +23 -19
  22. package/dest/modules/data_store_updater.d.ts.map +1 -1
  23. package/dest/modules/data_store_updater.js +47 -49
  24. package/dest/modules/instrumentation.d.ts +3 -3
  25. package/dest/modules/instrumentation.d.ts.map +1 -1
  26. package/dest/modules/instrumentation.js +17 -10
  27. package/dest/modules/l1_synchronizer.d.ts +1 -1
  28. package/dest/modules/l1_synchronizer.d.ts.map +1 -1
  29. package/dest/modules/l1_synchronizer.js +9 -10
  30. package/dest/store/block_store.d.ts +35 -21
  31. package/dest/store/block_store.d.ts.map +1 -1
  32. package/dest/store/block_store.js +81 -40
  33. package/dest/store/contract_class_store.d.ts +1 -1
  34. package/dest/store/contract_class_store.d.ts.map +1 -1
  35. package/dest/store/contract_class_store.js +11 -7
  36. package/dest/store/kv_archiver_store.d.ts +28 -24
  37. package/dest/store/kv_archiver_store.d.ts.map +1 -1
  38. package/dest/store/kv_archiver_store.js +20 -17
  39. package/dest/store/log_store.d.ts +4 -4
  40. package/dest/store/log_store.d.ts.map +1 -1
  41. package/dest/store/log_store.js +57 -37
  42. package/dest/test/fake_l1_state.d.ts +4 -4
  43. package/dest/test/fake_l1_state.d.ts.map +1 -1
  44. package/dest/test/index.js +3 -1
  45. package/dest/test/mock_archiver.js +1 -1
  46. package/dest/test/mock_l2_block_source.d.ts +20 -20
  47. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  48. package/dest/test/mock_l2_block_source.js +40 -41
  49. package/dest/test/mock_structs.d.ts +3 -2
  50. package/dest/test/mock_structs.d.ts.map +1 -1
  51. package/dest/test/mock_structs.js +11 -9
  52. package/dest/test/noop_l1_archiver.d.ts +23 -0
  53. package/dest/test/noop_l1_archiver.d.ts.map +1 -0
  54. package/dest/test/noop_l1_archiver.js +68 -0
  55. package/package.json +14 -13
  56. package/src/archiver.ts +46 -28
  57. package/src/errors.ts +12 -0
  58. package/src/factory.ts +23 -13
  59. package/src/l1/bin/retrieve-calldata.ts +16 -17
  60. package/src/l1/data_retrieval.ts +4 -4
  61. package/src/l1/validate_trace.ts +24 -6
  62. package/src/modules/data_source_base.ts +26 -77
  63. package/src/modules/data_store_updater.ts +59 -55
  64. package/src/modules/instrumentation.ts +17 -12
  65. package/src/modules/l1_synchronizer.ts +11 -12
  66. package/src/store/block_store.ts +107 -60
  67. package/src/store/contract_class_store.ts +11 -7
  68. package/src/store/kv_archiver_store.ts +36 -28
  69. package/src/store/log_store.ts +105 -43
  70. package/src/test/fake_l1_state.ts +2 -2
  71. package/src/test/index.ts +3 -0
  72. package/src/test/mock_archiver.ts +1 -1
  73. package/src/test/mock_l2_block_source.ts +54 -64
  74. package/src/test/mock_structs.ts +26 -10
  75. 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, L2BlockNew, type L2Tips } from '@aztec/stdlib/block';
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 getCheckpointedBlockNumber(): Promise<BlockNumber> {
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 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;
120
+ public getCheckpointedBlocks(from: BlockNumber, limit: number): Promise<CheckpointedL2Block[]> {
121
+ return this.store.getCheckpointedBlocks(from, limit);
128
122
  }
129
123
 
130
- public getBlockHeaderByHash(blockHash: Fr): Promise<BlockHeader | undefined> {
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 getL2BlockNew(number: BlockNumber): Promise<L2BlockNew | undefined> {
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,16 +157,6 @@ export abstract class ArchiverDataSourceBase
163
157
  return (await this.store.getPendingChainValidationStatus()) ?? { valid: true };
164
158
  }
165
159
 
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
-
176
160
  public getPrivateLogsByTags(tags: SiloedTag[], page?: number): Promise<TxScopedL2Log[][]> {
177
161
  return this.store.getPrivateLogsByTags(tags, page);
178
162
  }
@@ -237,10 +221,7 @@ export abstract class ArchiverDataSourceBase
237
221
  return this.store.getL1ToL2MessageIndex(l1ToL2Message);
238
222
  }
239
223
 
240
- public async getPublishedCheckpoints(
241
- checkpointNumber: CheckpointNumber,
242
- limit: number,
243
- ): Promise<PublishedCheckpoint[]> {
224
+ public async getCheckpoints(checkpointNumber: CheckpointNumber, limit: number): Promise<PublishedCheckpoint[]> {
244
225
  const checkpoints = await this.store.getRangeOfCheckpoints(checkpointNumber, limit);
245
226
  const blocks = (
246
227
  await Promise.all(checkpoints.map(ch => this.store.getBlocksForCheckpoint(ch.checkpointNumber)))
@@ -266,17 +247,17 @@ export abstract class ArchiverDataSourceBase
266
247
  return fullCheckpoints;
267
248
  }
268
249
 
269
- public getBlocksForSlot(slotNumber: SlotNumber): Promise<L2BlockNew[]> {
250
+ public getBlocksForSlot(slotNumber: SlotNumber): Promise<L2Block[]> {
270
251
  return this.store.getBlocksForSlot(slotNumber);
271
252
  }
272
253
 
273
- public async getBlocksForEpoch(epochNumber: EpochNumber): Promise<L2BlockNew[]> {
254
+ public async getCheckpointedBlocksForEpoch(epochNumber: EpochNumber): Promise<CheckpointedL2Block[]> {
274
255
  if (!this.l1Constants) {
275
256
  throw new Error('L1 constants not set');
276
257
  }
277
258
 
278
259
  const [start, end] = getSlotRangeForEpoch(epochNumber, this.l1Constants);
279
- const blocks: L2BlockNew[] = [];
260
+ const blocks: CheckpointedL2Block[] = [];
280
261
 
281
262
  // Walk the list of checkpoints backwards and filter by slots matching the requested epoch.
282
263
  // We'll typically ask for checkpoints for a very recent epoch, so we shouldn't need an index here.
@@ -287,9 +268,9 @@ export abstract class ArchiverDataSourceBase
287
268
  // push the blocks on backwards
288
269
  const endBlock = checkpoint.startBlock + checkpoint.numBlocks - 1;
289
270
  for (let i = endBlock; i >= checkpoint.startBlock; i--) {
290
- const block = await this.getBlock(BlockNumber(i));
291
- if (block) {
292
- blocks.push(block);
271
+ const checkpointedBlock = await this.getCheckpointedBlock(BlockNumber(i));
272
+ if (checkpointedBlock) {
273
+ blocks.push(checkpointedBlock);
293
274
  }
294
275
  }
295
276
  }
@@ -299,7 +280,7 @@ export abstract class ArchiverDataSourceBase
299
280
  return blocks.reverse();
300
281
  }
301
282
 
302
- public async getBlockHeadersForEpoch(epochNumber: EpochNumber): Promise<BlockHeader[]> {
283
+ public async getCheckpointedBlockHeadersForEpoch(epochNumber: EpochNumber): Promise<BlockHeader[]> {
303
284
  if (!this.l1Constants) {
304
285
  throw new Error('L1 constants not set');
305
286
  }
@@ -342,7 +323,7 @@ export abstract class ArchiverDataSourceBase
342
323
  while (checkpointData && slot(checkpointData) >= start) {
343
324
  if (slot(checkpointData) <= end) {
344
325
  // push the checkpoints on backwards
345
- const [checkpoint] = await this.getPublishedCheckpoints(checkpointData.checkpointNumber, 1);
326
+ const [checkpoint] = await this.getCheckpoints(checkpointData.checkpointNumber, 1);
346
327
  checkpoints.push(checkpoint.checkpoint);
347
328
  }
348
329
  checkpointData = await this.store.getCheckpointData(CheckpointNumber(checkpointData.checkpointNumber - 1));
@@ -351,33 +332,7 @@ export abstract class ArchiverDataSourceBase
351
332
  return checkpoints.reverse();
352
333
  }
353
334
 
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> {
335
+ public async getBlock(number: BlockNumber): Promise<L2Block | undefined> {
381
336
  // If the number provided is -ve, then return the latest block.
382
337
  if (number < 0) {
383
338
  number = await this.store.getLatestBlockNumber();
@@ -388,30 +343,24 @@ export abstract class ArchiverDataSourceBase
388
343
  return this.store.getBlock(number);
389
344
  }
390
345
 
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;
346
+ public getBlocks(from: BlockNumber, limit: number): Promise<L2Block[]> {
347
+ return this.store.getBlocks(from, limit);
399
348
  }
400
349
 
401
- public getPublishedBlockByHash(blockHash: Fr): Promise<CheckpointedL2Block | undefined> {
350
+ public getCheckpointedBlockByHash(blockHash: BlockHash): Promise<CheckpointedL2Block | undefined> {
402
351
  return this.store.getCheckpointedBlockByHash(blockHash);
403
352
  }
404
353
 
405
- public getPublishedBlockByArchive(archive: Fr): Promise<CheckpointedL2Block | undefined> {
354
+ public getCheckpointedBlockByArchive(archive: Fr): Promise<CheckpointedL2Block | undefined> {
406
355
  return this.store.getCheckpointedBlockByArchive(archive);
407
356
  }
408
357
 
409
- public async getL2BlockNewByHash(blockHash: Fr): Promise<L2BlockNew | undefined> {
358
+ public async getL2BlockByHash(blockHash: BlockHash): Promise<L2Block | undefined> {
410
359
  const checkpointedBlock = await this.store.getCheckpointedBlockByHash(blockHash);
411
360
  return checkpointedBlock?.block;
412
361
  }
413
362
 
414
- public async getL2BlockNewByArchive(archive: Fr): Promise<L2BlockNew | undefined> {
363
+ public async getL2BlockByArchive(archive: Fr): Promise<L2Block | undefined> {
415
364
  const checkpointedBlock = await this.store.getCheckpointedBlockByArchive(archive);
416
365
  return checkpointedBlock?.block;
417
366
  }
@@ -1,4 +1,4 @@
1
- import { BlockNumber, type CheckpointNumber } from '@aztec/foundation/branded-types';
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 { L2BlockNew, ValidateCheckpointResult } from '@aztec/stdlib/block';
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: L2BlockNew[] | undefined;
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 addBlocks(blocks: L2BlockNew[], pendingChainValidationStatus?: ValidateCheckpointResult): Promise<boolean> {
59
+ public addProposedBlocks(
60
+ blocks: L2Block[],
61
+ pendingChainValidationStatus?: ValidateCheckpointResult,
62
+ ): Promise<boolean> {
59
63
  return this.store.transactionAsync(async () => {
60
- await this.store.addBlocks(blocks);
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.addBlockDataToDB(block)),
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 setNewCheckpointData(
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 addBlocks() to avoid duplicating logs/contract data
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.addBlockDataToDB(block)),
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 removeBlocksAfter(blockNumber: BlockNumber): Promise<L2BlockNew[]> {
200
+ public removeUncheckpointedBlocksAfter(blockNumber: BlockNumber): Promise<L2Block[]> {
195
201
  return this.store.transactionAsync(async () => {
196
- // First get the blocks to be removed so we can clean up contract data
197
- const removedBlocks = await this.store.removeBlocksAfter(blockNumber);
198
-
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
- ]);
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 removedBlocks;
210
+ return await this.removeBlocksAfter(blockNumber);
206
211
  });
207
212
  }
208
213
 
209
214
  /**
210
- * Unwinds checkpoints from the store with reverse contract extraction.
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 unwound checkpoints.
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 from - The checkpoint number to unwind from (must be the current tip).
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 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
- }
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 unwound
242
- ...blocks.map(block => this.removeBlockDataFromDB(block)),
243
- this.store.deleteLogs(blocks),
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 addBlockDataToDB(block: L2BlockNew): Promise<boolean> {
252
- return this.editContractBlockData(block, Operation.Store);
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 removeBlockDataFromDB(block: L2BlockNew): Promise<boolean> {
257
- return this.editContractBlockData(block, Operation.Delete);
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 editContractBlockData(block: L2BlockNew, operation: Operation): Promise<boolean> {
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 { L2BlockNew } from '@aztec/stdlib/block';
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.createUpDownCounter(Metrics.ARCHIVER_TOTAL_TXS);
52
+ this.txCount = createUpDownCounterWithDefault(meter, Metrics.ARCHIVER_TOTAL_TXS);
52
53
 
53
- this.proofsSubmittedCount = meter.createUpDownCounter(Metrics.ARCHIVER_ROLLUP_PROOF_COUNT);
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.createUpDownCounter(Metrics.ARCHIVER_SYNC_BLOCK_COUNT);
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.createUpDownCounter(Metrics.ARCHIVER_SYNC_MESSAGE_COUNT);
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.createUpDownCounter(Metrics.ARCHIVER_PRUNE_COUNT);
74
+ this.pruneCount = createUpDownCounterWithDefault(meter, Metrics.ARCHIVER_PRUNE_COUNT);
72
75
 
73
- this.blockProposalTxTargetCount = meter.createUpDownCounter(Metrics.ARCHIVER_BLOCK_PROPOSAL_TX_TARGET_COUNT);
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: L2BlockNew[]) {
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, getSlotAtTimestamp } from '@aztec/stdlib/epoch-helpers';
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 nextL1BlockTimestamp = currentL1Timestamp + BigInt(this.l1Constants.ethereumSlotDuration);
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.removeBlocksAfter(lastCheckpointedBlockNumber);
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.unwindCheckpoints(localPendingCheckpointNumber, checkpointsToUnwind);
333
+ await this.updater.removeCheckpointsAfter(provenCheckpointNumber);
335
334
  this.log.warn(
336
- `Unwound ${count(checkpointsToUnwind, 'checkpoint')} from checkpoint ${localPendingCheckpointNumber} ` +
337
- `to ${provenCheckpointNumber} due to predicted reorg at L1 block ${currentL1BlockNumber}. ` +
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 checkpointsToUnwind = localPendingCheckpointNumber - tipAfterUnwind;
679
- await this.updater.unwindCheckpoints(localPendingCheckpointNumber, checkpointsToUnwind);
677
+ const checkpointsToRemove = localPendingCheckpointNumber - tipAfterUnwind;
678
+ await this.updater.removeCheckpointsAfter(CheckpointNumber(tipAfterUnwind));
680
679
 
681
680
  this.log.warn(
682
- `Unwound ${count(checkpointsToUnwind, 'checkpoint')} from checkpoint ${localPendingCheckpointNumber} ` +
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.setCheckpointData', () =>
810
- this.updater.setNewCheckpointData(validCheckpoints, updatedValidationResult),
808
+ execInSpan(this.tracer, 'Archiver.addCheckpoints', () =>
809
+ this.updater.addCheckpoints(validCheckpoints, updatedValidationResult),
811
810
  ),
812
811
  );
813
812
  this.instrumentation.processNewBlocks(