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

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 (95) hide show
  1. package/README.md +9 -0
  2. package/dest/archiver.d.ts +10 -6
  3. package/dest/archiver.d.ts.map +1 -1
  4. package/dest/archiver.js +50 -111
  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 +16 -13
  11. package/dest/index.d.ts +2 -1
  12. package/dest/index.d.ts.map +1 -1
  13. package/dest/index.js +1 -0
  14. package/dest/l1/bin/retrieve-calldata.js +35 -32
  15. package/dest/l1/calldata_retriever.d.ts +73 -50
  16. package/dest/l1/calldata_retriever.d.ts.map +1 -1
  17. package/dest/l1/calldata_retriever.js +190 -259
  18. package/dest/l1/data_retrieval.d.ts +9 -9
  19. package/dest/l1/data_retrieval.d.ts.map +1 -1
  20. package/dest/l1/data_retrieval.js +24 -22
  21. package/dest/l1/spire_proposer.d.ts +5 -5
  22. package/dest/l1/spire_proposer.d.ts.map +1 -1
  23. package/dest/l1/spire_proposer.js +9 -17
  24. package/dest/l1/validate_trace.d.ts +6 -3
  25. package/dest/l1/validate_trace.d.ts.map +1 -1
  26. package/dest/l1/validate_trace.js +13 -9
  27. package/dest/modules/data_source_base.d.ts +23 -19
  28. package/dest/modules/data_source_base.d.ts.map +1 -1
  29. package/dest/modules/data_source_base.js +44 -119
  30. package/dest/modules/data_store_updater.d.ts +31 -20
  31. package/dest/modules/data_store_updater.d.ts.map +1 -1
  32. package/dest/modules/data_store_updater.js +79 -60
  33. package/dest/modules/instrumentation.d.ts +17 -4
  34. package/dest/modules/instrumentation.d.ts.map +1 -1
  35. package/dest/modules/instrumentation.js +36 -12
  36. package/dest/modules/l1_synchronizer.d.ts +4 -8
  37. package/dest/modules/l1_synchronizer.d.ts.map +1 -1
  38. package/dest/modules/l1_synchronizer.js +23 -19
  39. package/dest/store/block_store.d.ts +50 -32
  40. package/dest/store/block_store.d.ts.map +1 -1
  41. package/dest/store/block_store.js +147 -54
  42. package/dest/store/contract_class_store.d.ts +1 -1
  43. package/dest/store/contract_class_store.d.ts.map +1 -1
  44. package/dest/store/contract_class_store.js +11 -7
  45. package/dest/store/kv_archiver_store.d.ts +43 -25
  46. package/dest/store/kv_archiver_store.d.ts.map +1 -1
  47. package/dest/store/kv_archiver_store.js +38 -17
  48. package/dest/store/l2_tips_cache.d.ts +19 -0
  49. package/dest/store/l2_tips_cache.d.ts.map +1 -0
  50. package/dest/store/l2_tips_cache.js +89 -0
  51. package/dest/store/log_store.d.ts +4 -4
  52. package/dest/store/log_store.d.ts.map +1 -1
  53. package/dest/store/log_store.js +57 -37
  54. package/dest/test/fake_l1_state.d.ts +9 -4
  55. package/dest/test/fake_l1_state.d.ts.map +1 -1
  56. package/dest/test/fake_l1_state.js +56 -18
  57. package/dest/test/index.js +3 -1
  58. package/dest/test/mock_archiver.d.ts +1 -1
  59. package/dest/test/mock_archiver.d.ts.map +1 -1
  60. package/dest/test/mock_archiver.js +3 -2
  61. package/dest/test/mock_l2_block_source.d.ts +36 -21
  62. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  63. package/dest/test/mock_l2_block_source.js +151 -109
  64. package/dest/test/mock_structs.d.ts +3 -2
  65. package/dest/test/mock_structs.d.ts.map +1 -1
  66. package/dest/test/mock_structs.js +11 -9
  67. package/dest/test/noop_l1_archiver.d.ts +23 -0
  68. package/dest/test/noop_l1_archiver.d.ts.map +1 -0
  69. package/dest/test/noop_l1_archiver.js +68 -0
  70. package/package.json +14 -13
  71. package/src/archiver.ts +71 -136
  72. package/src/errors.ts +12 -0
  73. package/src/factory.ts +30 -14
  74. package/src/index.ts +1 -0
  75. package/src/l1/README.md +25 -68
  76. package/src/l1/bin/retrieve-calldata.ts +45 -33
  77. package/src/l1/calldata_retriever.ts +249 -379
  78. package/src/l1/data_retrieval.ts +27 -29
  79. package/src/l1/spire_proposer.ts +7 -15
  80. package/src/l1/validate_trace.ts +24 -6
  81. package/src/modules/data_source_base.ts +73 -163
  82. package/src/modules/data_store_updater.ts +92 -63
  83. package/src/modules/instrumentation.ts +46 -14
  84. package/src/modules/l1_synchronizer.ts +26 -24
  85. package/src/store/block_store.ts +188 -92
  86. package/src/store/contract_class_store.ts +11 -7
  87. package/src/store/kv_archiver_store.ts +69 -29
  88. package/src/store/l2_tips_cache.ts +89 -0
  89. package/src/store/log_store.ts +105 -43
  90. package/src/test/fake_l1_state.ts +77 -19
  91. package/src/test/index.ts +3 -0
  92. package/src/test/mock_archiver.ts +3 -2
  93. package/src/test/mock_l2_block_source.ts +196 -126
  94. package/src/test/mock_structs.ts +26 -10
  95. package/src/test/noop_l1_archiver.ts +109 -0
@@ -6,19 +6,21 @@ import { createLogger } from '@aztec/foundation/log';
6
6
  import { BufferReader } from '@aztec/foundation/serialize';
7
7
  import { bufferToHex } from '@aztec/foundation/string';
8
8
  import { isDefined } from '@aztec/foundation/types';
9
- import { Body, CheckpointedL2Block, CommitteeAttestation, L2BlockHash, L2BlockNew, deserializeValidateCheckpointResult, serializeValidateCheckpointResult } from '@aztec/stdlib/block';
9
+ import { Body, CheckpointedL2Block, CommitteeAttestation, L2Block, deserializeValidateCheckpointResult, serializeValidateCheckpointResult } from '@aztec/stdlib/block';
10
10
  import { L1PublishedData } from '@aztec/stdlib/checkpoint';
11
11
  import { CheckpointHeader } from '@aztec/stdlib/rollup';
12
12
  import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
13
- import { BlockHeader, TxHash, TxReceipt, deserializeIndexedTxEffect, serializeIndexedTxEffect } from '@aztec/stdlib/tx';
14
- import { BlockArchiveNotConsistentError, BlockIndexNotSequentialError, BlockNotFoundError, BlockNumberNotSequentialError, CheckpointNotFoundError, CheckpointNumberNotConsistentError, CheckpointNumberNotSequentialError, InitialBlockNumberNotSequentialError, InitialCheckpointNumberNotSequentialError } from '../errors.js';
13
+ import { BlockHeader, TxHash, TxReceipt, TxStatus, deserializeIndexedTxEffect, serializeIndexedTxEffect } from '@aztec/stdlib/tx';
14
+ import { BlockArchiveNotConsistentError, BlockIndexNotSequentialError, BlockNotFoundError, BlockNumberNotSequentialError, CannotOverwriteCheckpointedBlockError, CheckpointNotFoundError, CheckpointNumberNotConsistentError, CheckpointNumberNotSequentialError, InitialBlockNumberNotSequentialError, InitialCheckpointNumberNotSequentialError } from '../errors.js';
15
15
  export { TxReceipt } from '@aztec/stdlib/tx';
16
16
  /**
17
17
  * LMDB-based block storage for the archiver.
18
18
  */ export class BlockStore {
19
19
  db;
20
+ l1Constants;
20
21
  /** Map block number to block data */ #blocks;
21
22
  /** Map checkpoint number to checkpoint data */ #checkpoints;
23
+ /** Map slot number to checkpoint number, for looking up checkpoints by slot range. */ #slotToCheckpoint;
22
24
  /** Map block hash to list of tx hashes */ #blockTxs;
23
25
  /** Tx hash to serialized IndexedTxEffect */ #txEffects;
24
26
  /** Stores L1 block number in which the last processed L2 block was included */ #lastSynchedL1Block;
@@ -28,8 +30,9 @@ export { TxReceipt } from '@aztec/stdlib/tx';
28
30
  /** Index mapping block hash to block number */ #blockHashIndex;
29
31
  /** Index mapping block archive to block number */ #blockArchiveIndex;
30
32
  #log;
31
- constructor(db){
33
+ constructor(db, l1Constants){
32
34
  this.db = db;
35
+ this.l1Constants = l1Constants;
33
36
  this.#log = createLogger('archiver:block_store');
34
37
  this.#blocks = db.openMap('archiver_blocks');
35
38
  this.#blockTxs = db.openMap('archiver_block_txs');
@@ -41,12 +44,25 @@ export { TxReceipt } from '@aztec/stdlib/tx';
41
44
  this.#lastProvenCheckpoint = db.openSingleton('archiver_last_proven_l2_checkpoint');
42
45
  this.#pendingChainValidationStatus = db.openSingleton('archiver_pending_chain_validation_status');
43
46
  this.#checkpoints = db.openMap('archiver_checkpoints');
47
+ this.#slotToCheckpoint = db.openMap('archiver_slot_to_checkpoint');
44
48
  }
45
49
  /**
46
- * Append new blocks to the store's list. All blocks must be for the 'current' checkpoint
47
- * @param blocks - The L2 blocks to be added to the store.
50
+ * Computes the finalized block number based on the proven block number.
51
+ * A block is considered finalized when it's 2 epochs behind the proven block.
52
+ * TODO(#13569): Compute proper finalized block number based on L1 finalized block.
53
+ * TODO(palla/mbps): Even the provisional computation is wrong, since it should subtract checkpoints, not blocks
54
+ * @returns The finalized block number.
55
+ */ async getFinalizedL2BlockNumber() {
56
+ const provenBlockNumber = await this.getProvenBlockNumber();
57
+ return BlockNumber(Math.max(provenBlockNumber - this.l1Constants.epochDuration * 2, 0));
58
+ }
59
+ /**
60
+ * Append new proposed blocks to the store's list. All blocks must be for the 'current' checkpoint.
61
+ * These are uncheckpointed blocks that have been proposed by the sequencer but not yet included in a checkpoint on L1.
62
+ * For checkpointed blocks (already published to L1), use addCheckpoints() instead.
63
+ * @param blocks - The proposed L2 blocks to be added to the store.
48
64
  * @returns True if the operation is successful.
49
- */ async addBlocks(blocks, opts = {}) {
65
+ */ async addProposedBlocks(blocks, opts = {}) {
50
66
  if (blocks.length === 0) {
51
67
  return true;
52
68
  }
@@ -59,6 +75,11 @@ export { TxReceipt } from '@aztec/stdlib/tx';
59
75
  // Extract the latest block and checkpoint numbers
60
76
  const previousBlockNumber = await this.getLatestBlockNumber();
61
77
  const previousCheckpointNumber = await this.getLatestCheckpointNumber();
78
+ // Verify we're not overwriting checkpointed blocks
79
+ const lastCheckpointedBlockNumber = await this.getCheckpointedL2BlockNumber();
80
+ if (!opts.force && firstBlockNumber <= lastCheckpointedBlockNumber) {
81
+ throw new CannotOverwriteCheckpointedBlockError(firstBlockNumber, lastCheckpointedBlockNumber);
82
+ }
62
83
  // Check that the first block number is the expected one
63
84
  if (!opts.force && previousBlockNumber !== firstBlockNumber - 1) {
64
85
  throw new InitialBlockNumberNotSequentialError(firstBlockNumber, previousBlockNumber);
@@ -136,7 +157,7 @@ export { TxReceipt } from '@aztec/stdlib/tx';
136
157
  let previousBlock = undefined;
137
158
  // If we have a previous checkpoint then we need to get the previous block number
138
159
  if (previousCheckpointData !== undefined) {
139
- previousBlockNumber = BlockNumber(previousCheckpointData.startBlock + previousCheckpointData.numBlocks - 1);
160
+ previousBlockNumber = BlockNumber(previousCheckpointData.startBlock + previousCheckpointData.blockCount - 1);
140
161
  previousBlock = await this.getBlock(previousBlockNumber);
141
162
  if (previousBlock === undefined) {
142
163
  // We should be able to get the required previous block
@@ -181,19 +202,22 @@ export { TxReceipt } from '@aztec/stdlib/tx';
181
202
  await this.#checkpoints.set(checkpoint.checkpoint.number, {
182
203
  header: checkpoint.checkpoint.header.toBuffer(),
183
204
  archive: checkpoint.checkpoint.archive.toBuffer(),
205
+ checkpointOutHash: checkpoint.checkpoint.getCheckpointOutHash().toBuffer(),
184
206
  l1: checkpoint.l1.toBuffer(),
185
207
  attestations: checkpoint.attestations.map((attestation)=>attestation.toBuffer()),
186
208
  checkpointNumber: checkpoint.checkpoint.number,
187
209
  startBlock: checkpoint.checkpoint.blocks[0].number,
188
- numBlocks: checkpoint.checkpoint.blocks.length
210
+ blockCount: checkpoint.checkpoint.blocks.length
189
211
  });
212
+ // Update slot-to-checkpoint index
213
+ await this.#slotToCheckpoint.set(checkpoint.checkpoint.header.slotNumber, checkpoint.checkpoint.number);
190
214
  }
191
215
  await this.#lastSynchedL1Block.set(checkpoints[checkpoints.length - 1].l1.blockNumber);
192
216
  return true;
193
217
  });
194
218
  }
195
219
  async addBlockToDatabase(block, checkpointNumber, indexWithinCheckpoint) {
196
- const blockHash = L2BlockHash.fromField(await block.hash());
220
+ const blockHash = await block.hash();
197
221
  await this.#blocks.set(block.number, {
198
222
  header: block.header.toBuffer(),
199
223
  blockHash: blockHash.toBuffer(),
@@ -228,41 +252,50 @@ export { TxReceipt } from '@aztec/stdlib/tx';
228
252
  await this.#blockArchiveIndex.delete(block.archive.root.toString());
229
253
  }
230
254
  /**
231
- * Unwinds checkpoints from the database
232
- * @param from - The tip of the chain, passed for verification purposes,
233
- * ensuring that we don't end up deleting something we did not intend
234
- * @param checkpointsToUnwind - The number of checkpoints we are to unwind
235
- * @returns True if the operation is successful
236
- */ async unwindCheckpoints(from, checkpointsToUnwind) {
255
+ * Removes all checkpoints with checkpoint number > checkpointNumber.
256
+ * Also removes ALL blocks (both checkpointed and uncheckpointed) after the last block of the given checkpoint.
257
+ * @param checkpointNumber - Remove all checkpoints strictly after this one.
258
+ */ async removeCheckpointsAfter(checkpointNumber) {
237
259
  return await this.db.transactionAsync(async ()=>{
238
- const last = await this.getLatestCheckpointNumber();
239
- if (from !== last) {
240
- throw new Error(`Can only unwind checkpoints from the tip (requested ${from} but current tip is ${last})`);
260
+ const latestCheckpointNumber = await this.getLatestCheckpointNumber();
261
+ if (checkpointNumber >= latestCheckpointNumber) {
262
+ this.#log.warn(`No checkpoints to remove after ${checkpointNumber} (latest is ${latestCheckpointNumber})`);
263
+ return {
264
+ blocksRemoved: undefined
265
+ };
241
266
  }
267
+ // If the proven checkpoint is beyond the target, update it
242
268
  const proven = await this.getProvenCheckpointNumber();
243
- if (from - checkpointsToUnwind < proven) {
244
- await this.setProvenCheckpointNumber(CheckpointNumber(from - checkpointsToUnwind));
269
+ if (proven > checkpointNumber) {
270
+ this.#log.warn(`Updating proven checkpoint ${proven} to last valid checkpoint ${checkpointNumber}`);
271
+ await this.setProvenCheckpointNumber(checkpointNumber);
245
272
  }
246
- for(let i = 0; i < checkpointsToUnwind; i++){
247
- const checkpointNumber = from - i;
248
- const checkpoint = await this.#checkpoints.getAsync(checkpointNumber);
249
- if (checkpoint === undefined) {
250
- this.#log.warn(`Cannot remove checkpoint ${checkpointNumber} from the store since we don't have it`);
251
- continue;
273
+ // Find the last block number to keep (last block of the given checkpoint, or 0 if no checkpoint)
274
+ let lastBlockToKeep;
275
+ if (checkpointNumber <= 0) {
276
+ lastBlockToKeep = BlockNumber(INITIAL_L2_BLOCK_NUM - 1);
277
+ } else {
278
+ const targetCheckpoint = await this.#checkpoints.getAsync(checkpointNumber);
279
+ if (!targetCheckpoint) {
280
+ throw new Error(`Target checkpoint ${checkpointNumber} not found in store`);
252
281
  }
253
- await this.#checkpoints.delete(checkpointNumber);
254
- const maxBlock = checkpoint.startBlock + checkpoint.numBlocks - 1;
255
- for(let blockNumber = checkpoint.startBlock; blockNumber <= maxBlock; blockNumber++){
256
- const block = await this.getBlock(BlockNumber(blockNumber));
257
- if (block === undefined) {
258
- this.#log.warn(`Cannot remove block ${blockNumber} from the store since we don't have it`);
259
- continue;
260
- }
261
- await this.deleteBlock(block);
262
- this.#log.debug(`Unwound block ${blockNumber} ${(await block.hash()).toString()} for checkpoint ${checkpointNumber}`);
282
+ lastBlockToKeep = BlockNumber(targetCheckpoint.startBlock + targetCheckpoint.blockCount - 1);
283
+ }
284
+ // Remove all blocks after lastBlockToKeep (both checkpointed and uncheckpointed)
285
+ const blocksRemoved = await this.removeBlocksAfter(lastBlockToKeep);
286
+ // Remove all checkpoints after the target
287
+ for(let c = latestCheckpointNumber; c > checkpointNumber; c = CheckpointNumber(c - 1)){
288
+ const checkpointStorage = await this.#checkpoints.getAsync(c);
289
+ if (checkpointStorage) {
290
+ const slotNumber = CheckpointHeader.fromBuffer(checkpointStorage.header).slotNumber;
291
+ await this.#slotToCheckpoint.delete(slotNumber);
263
292
  }
293
+ await this.#checkpoints.delete(c);
294
+ this.#log.debug(`Removed checkpoint ${c}`);
264
295
  }
265
- return true;
296
+ return {
297
+ blocksRemoved
298
+ };
266
299
  });
267
300
  }
268
301
  async getCheckpointData(checkpointNumber) {
@@ -283,17 +316,30 @@ export { TxReceipt } from '@aztec/stdlib/tx';
283
316
  }
284
317
  return checkpoints;
285
318
  }
319
+ /** Returns checkpoint data for all checkpoints whose slot falls within the given range (inclusive). */ async getCheckpointDataForSlotRange(startSlot, endSlot) {
320
+ const result = [];
321
+ for await (const [, checkpointNumber] of this.#slotToCheckpoint.entriesAsync({
322
+ start: startSlot,
323
+ end: endSlot + 1
324
+ })){
325
+ const checkpointStorage = await this.#checkpoints.getAsync(checkpointNumber);
326
+ if (checkpointStorage) {
327
+ result.push(this.checkpointDataFromCheckpointStorage(checkpointStorage));
328
+ }
329
+ }
330
+ return result;
331
+ }
286
332
  checkpointDataFromCheckpointStorage(checkpointStorage) {
287
- const data = {
333
+ return {
288
334
  header: CheckpointHeader.fromBuffer(checkpointStorage.header),
289
335
  archive: AppendOnlyTreeSnapshot.fromBuffer(checkpointStorage.archive),
336
+ checkpointOutHash: Fr.fromBuffer(checkpointStorage.checkpointOutHash),
290
337
  checkpointNumber: CheckpointNumber(checkpointStorage.checkpointNumber),
291
- startBlock: checkpointStorage.startBlock,
292
- numBlocks: checkpointStorage.numBlocks,
338
+ startBlock: BlockNumber(checkpointStorage.startBlock),
339
+ blockCount: checkpointStorage.blockCount,
293
340
  l1: L1PublishedData.fromBuffer(checkpointStorage.l1),
294
- attestations: checkpointStorage.attestations
341
+ attestations: checkpointStorage.attestations.map((buf)=>CommitteeAttestation.fromBuffer(buf))
295
342
  };
296
- return data;
297
343
  }
298
344
  async getBlocksForCheckpoint(checkpointNumber) {
299
345
  const checkpoint = await this.#checkpoints.getAsync(checkpointNumber);
@@ -302,7 +348,7 @@ export { TxReceipt } from '@aztec/stdlib/tx';
302
348
  }
303
349
  const blocksForCheckpoint = await toArray(this.#blocks.entriesAsync({
304
350
  start: checkpoint.startBlock,
305
- end: checkpoint.startBlock + checkpoint.numBlocks
351
+ end: checkpoint.startBlock + checkpoint.blockCount
306
352
  }));
307
353
  const converted = await Promise.all(blocksForCheckpoint.map((x)=>this.getBlockFromBlockStorage(x[0], x[1])));
308
354
  return converted.filter(isDefined);
@@ -332,9 +378,10 @@ export { TxReceipt } from '@aztec/stdlib/tx';
332
378
  }
333
379
  /**
334
380
  * Removes all blocks with block number > blockNumber.
381
+ * Does not remove any associated checkpoints.
335
382
  * @param blockNumber - The block number to remove after.
336
383
  * @returns The removed blocks (for event emission).
337
- */ async unwindBlocksAfter(blockNumber) {
384
+ */ async removeBlocksAfter(blockNumber) {
338
385
  return await this.db.transactionAsync(async ()=>{
339
386
  const removedBlocks = [];
340
387
  // Get the latest block number to determine the range
@@ -362,7 +409,7 @@ export { TxReceipt } from '@aztec/stdlib/tx';
362
409
  if (!checkpointStorage) {
363
410
  throw new CheckpointNotFoundError(provenCheckpointNumber);
364
411
  } else {
365
- return BlockNumber(checkpointStorage.startBlock + checkpointStorage.numBlocks - 1);
412
+ return BlockNumber(checkpointStorage.startBlock + checkpointStorage.blockCount - 1);
366
413
  }
367
414
  }
368
415
  async getLatestBlockNumber() {
@@ -444,6 +491,28 @@ export { TxReceipt } from '@aztec/stdlib/tx';
444
491
  }
445
492
  }
446
493
  /**
494
+ * Gets block metadata (without tx data) by block number.
495
+ * @param blockNumber - The number of the block to return.
496
+ * @returns The requested block data.
497
+ */ async getBlockData(blockNumber) {
498
+ const blockStorage = await this.#blocks.getAsync(blockNumber);
499
+ if (!blockStorage || !blockStorage.header) {
500
+ return undefined;
501
+ }
502
+ return this.getBlockDataFromBlockStorage(blockStorage);
503
+ }
504
+ /**
505
+ * Gets block metadata (without tx data) by archive root.
506
+ * @param archive - The archive root of the block to return.
507
+ * @returns The requested block data.
508
+ */ async getBlockDataByArchive(archive) {
509
+ const blockNumber = await this.#blockArchiveIndex.getAsync(archive.toString());
510
+ if (blockNumber === undefined) {
511
+ return undefined;
512
+ }
513
+ return this.getBlockData(BlockNumber(blockNumber));
514
+ }
515
+ /**
447
516
  * Gets an L2 block.
448
517
  * @param blockNumber - The number of the block to return.
449
518
  * @returns The requested L2 block.
@@ -533,12 +602,19 @@ export { TxReceipt } from '@aztec/stdlib/tx';
533
602
  ];
534
603
  }
535
604
  }
605
+ getBlockDataFromBlockStorage(blockStorage) {
606
+ return {
607
+ header: BlockHeader.fromBuffer(blockStorage.header),
608
+ archive: AppendOnlyTreeSnapshot.fromBuffer(blockStorage.archive),
609
+ blockHash: Fr.fromBuffer(blockStorage.blockHash),
610
+ checkpointNumber: CheckpointNumber(blockStorage.checkpointNumber),
611
+ indexWithinCheckpoint: IndexWithinCheckpoint(blockStorage.indexWithinCheckpoint)
612
+ };
613
+ }
536
614
  async getBlockFromBlockStorage(blockNumber, blockStorage) {
537
- const header = BlockHeader.fromBuffer(blockStorage.header);
538
- const archive = AppendOnlyTreeSnapshot.fromBuffer(blockStorage.archive);
539
- const blockHash = blockStorage.blockHash;
540
- header.setHash(Fr.fromBuffer(blockHash));
541
- const blockHashString = bufferToHex(blockHash);
615
+ const { header, archive, blockHash, checkpointNumber, indexWithinCheckpoint } = this.getBlockDataFromBlockStorage(blockStorage);
616
+ header.setHash(blockHash);
617
+ const blockHashString = bufferToHex(blockStorage.blockHash);
542
618
  const blockTxsBuffer = await this.#blockTxs.getAsync(blockHashString);
543
619
  if (blockTxsBuffer === undefined) {
544
620
  this.#log.warn(`Could not find body for block ${header.globalVariables.blockNumber} ${blockHash}`);
@@ -556,7 +632,7 @@ export { TxReceipt } from '@aztec/stdlib/tx';
556
632
  txEffects.push(deserializeIndexedTxEffect(txEffect).data);
557
633
  }
558
634
  const body = new Body(txEffects);
559
- const block = new L2BlockNew(archive, header, body, CheckpointNumber(blockStorage.checkpointNumber), IndexWithinCheckpoint(blockStorage.indexWithinCheckpoint));
635
+ const block = new L2Block(archive, header, body, checkpointNumber, indexWithinCheckpoint);
560
636
  if (block.number !== blockNumber) {
561
637
  throw new Error(`Block number mismatch when retrieving block from archive (expected ${blockNumber} but got ${block.number} with hash ${blockHashString})`);
562
638
  }
@@ -582,7 +658,24 @@ export { TxReceipt } from '@aztec/stdlib/tx';
582
658
  if (!txEffect) {
583
659
  return undefined;
584
660
  }
585
- return new TxReceipt(txHash, TxReceipt.statusFromRevertCode(txEffect.data.revertCode), '', txEffect.data.transactionFee.toBigInt(), txEffect.l2BlockHash, BlockNumber(txEffect.l2BlockNumber));
661
+ const blockNumber = BlockNumber(txEffect.l2BlockNumber);
662
+ // Use existing archiver methods to determine finalization level
663
+ const [provenBlockNumber, checkpointedBlockNumber, finalizedBlockNumber] = await Promise.all([
664
+ this.getProvenBlockNumber(),
665
+ this.getCheckpointedL2BlockNumber(),
666
+ this.getFinalizedL2BlockNumber()
667
+ ]);
668
+ let status;
669
+ if (blockNumber <= finalizedBlockNumber) {
670
+ status = TxStatus.FINALIZED;
671
+ } else if (blockNumber <= provenBlockNumber) {
672
+ status = TxStatus.PROVEN;
673
+ } else if (blockNumber <= checkpointedBlockNumber) {
674
+ status = TxStatus.CHECKPOINTED;
675
+ } else {
676
+ status = TxStatus.PROPOSED;
677
+ }
678
+ return new TxReceipt(txHash, status, TxReceipt.executionResultFromRevertCode(txEffect.data.revertCode), undefined, txEffect.data.transactionFee.toBigInt(), txEffect.l2BlockHash, blockNumber);
586
679
  }
587
680
  /**
588
681
  * Looks up which block included the requested tx effect.
@@ -615,7 +708,7 @@ export { TxReceipt } from '@aztec/stdlib/tx';
615
708
  if (!checkpoint) {
616
709
  return BlockNumber(INITIAL_L2_BLOCK_NUM - 1);
617
710
  }
618
- return BlockNumber(checkpoint.startBlock + checkpoint.numBlocks - 1);
711
+ return BlockNumber(checkpoint.startBlock + checkpoint.blockCount - 1);
619
712
  }
620
713
  async getLatestL2BlockNumber() {
621
714
  const [lastBlockNumber] = await toArray(this.#blocks.keysAsync({
@@ -15,4 +15,4 @@ export declare class ContractClassStore {
15
15
  getContractClassIds(): Promise<Fr[]>;
16
16
  addFunctions(contractClassId: Fr, newPrivateFunctions: ExecutablePrivateFunctionWithMembershipProof[], newUtilityFunctions: UtilityFunctionWithMembershipProof[]): Promise<boolean>;
17
17
  }
18
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udHJhY3RfY2xhc3Nfc3RvcmUuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zdG9yZS9jb250cmFjdF9jbGFzc19zdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsRUFBRSxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFHcEQsT0FBTyxLQUFLLEVBQUUsaUJBQWlCLEVBQWlCLE1BQU0saUJBQWlCLENBQUM7QUFFeEUsT0FBTyxLQUFLLEVBQ1YsbUJBQW1CLEVBRW5CLDRDQUE0QyxFQUM1QyxrQ0FBa0MsRUFDbkMsTUFBTSx3QkFBd0IsQ0FBQztBQUdoQzs7R0FFRztBQUNILHFCQUFhLGtCQUFrQjs7SUFJakIsT0FBTyxDQUFDLEVBQUU7SUFBdEIsWUFBb0IsRUFBRSxFQUFFLGlCQUFpQixFQUd4QztJQUVLLGdCQUFnQixDQUNwQixhQUFhLEVBQUUsbUJBQW1CLEVBQ2xDLGtCQUFrQixFQUFFLEVBQUUsRUFDdEIsV0FBVyxFQUFFLE1BQU0sR0FDbEIsT0FBTyxDQUFDLElBQUksQ0FBQyxDQU1mO0lBRUsscUJBQXFCLENBQUMsYUFBYSxFQUFFLG1CQUFtQixFQUFFLFdBQVcsRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQU1sRztJQUVLLGdCQUFnQixDQUFDLEVBQUUsRUFBRSxFQUFFLEdBQUcsT0FBTyxDQUFDLG1CQUFtQixHQUFHLFNBQVMsQ0FBQyxDQUd2RTtJQUVLLHFCQUFxQixDQUFDLEVBQUUsRUFBRSxFQUFFLEdBQUcsT0FBTyxDQUFDLEVBQUUsR0FBRyxTQUFTLENBQUMsQ0FHM0Q7SUFFSyxtQkFBbUIsSUFBSSxPQUFPLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FFekM7SUFFSyxZQUFZLENBQ2hCLGVBQWUsRUFBRSxFQUFFLEVBQ25CLG1CQUFtQixFQUFFLDRDQUE0QyxFQUFFLEVBQ25FLG1CQUFtQixFQUFFLGtDQUFrQyxFQUFFLEdBQ3hELE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0F5QmxCO0NBQ0YifQ==
18
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udHJhY3RfY2xhc3Nfc3RvcmUuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zdG9yZS9jb250cmFjdF9jbGFzc19zdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsRUFBRSxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFHcEQsT0FBTyxLQUFLLEVBQUUsaUJBQWlCLEVBQWlCLE1BQU0saUJBQWlCLENBQUM7QUFFeEUsT0FBTyxLQUFLLEVBQ1YsbUJBQW1CLEVBRW5CLDRDQUE0QyxFQUM1QyxrQ0FBa0MsRUFDbkMsTUFBTSx3QkFBd0IsQ0FBQztBQUdoQzs7R0FFRztBQUNILHFCQUFhLGtCQUFrQjs7SUFJakIsT0FBTyxDQUFDLEVBQUU7SUFBdEIsWUFBb0IsRUFBRSxFQUFFLGlCQUFpQixFQUd4QztJQUVLLGdCQUFnQixDQUNwQixhQUFhLEVBQUUsbUJBQW1CLEVBQ2xDLGtCQUFrQixFQUFFLEVBQUUsRUFDdEIsV0FBVyxFQUFFLE1BQU0sR0FDbEIsT0FBTyxDQUFDLElBQUksQ0FBQyxDQVFmO0lBRUsscUJBQXFCLENBQUMsYUFBYSxFQUFFLG1CQUFtQixFQUFFLFdBQVcsRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQVFsRztJQUVLLGdCQUFnQixDQUFDLEVBQUUsRUFBRSxFQUFFLEdBQUcsT0FBTyxDQUFDLG1CQUFtQixHQUFHLFNBQVMsQ0FBQyxDQUd2RTtJQUVLLHFCQUFxQixDQUFDLEVBQUUsRUFBRSxFQUFFLEdBQUcsT0FBTyxDQUFDLEVBQUUsR0FBRyxTQUFTLENBQUMsQ0FHM0Q7SUFFSyxtQkFBbUIsSUFBSSxPQUFPLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FFekM7SUFFSyxZQUFZLENBQ2hCLGVBQWUsRUFBRSxFQUFFLEVBQ25CLG1CQUFtQixFQUFFLDRDQUE0QyxFQUFFLEVBQ25FLG1CQUFtQixFQUFFLGtDQUFrQyxFQUFFLEdBQ3hELE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0F5QmxCO0NBQ0YifQ==
@@ -1 +1 @@
1
- {"version":3,"file":"contract_class_store.d.ts","sourceRoot":"","sources":["../../src/store/contract_class_store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAGpD,OAAO,KAAK,EAAE,iBAAiB,EAAiB,MAAM,iBAAiB,CAAC;AAExE,OAAO,KAAK,EACV,mBAAmB,EAEnB,4CAA4C,EAC5C,kCAAkC,EACnC,MAAM,wBAAwB,CAAC;AAGhC;;GAEG;AACH,qBAAa,kBAAkB;;IAIjB,OAAO,CAAC,EAAE;IAAtB,YAAoB,EAAE,EAAE,iBAAiB,EAGxC;IAEK,gBAAgB,CACpB,aAAa,EAAE,mBAAmB,EAClC,kBAAkB,EAAE,EAAE,EACtB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAMf;IAEK,qBAAqB,CAAC,aAAa,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMlG;IAEK,gBAAgB,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC,CAGvE;IAEK,qBAAqB,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,EAAE,GAAG,SAAS,CAAC,CAG3D;IAEK,mBAAmB,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC,CAEzC;IAEK,YAAY,CAChB,eAAe,EAAE,EAAE,EACnB,mBAAmB,EAAE,4CAA4C,EAAE,EACnE,mBAAmB,EAAE,kCAAkC,EAAE,GACxD,OAAO,CAAC,OAAO,CAAC,CAyBlB;CACF"}
1
+ {"version":3,"file":"contract_class_store.d.ts","sourceRoot":"","sources":["../../src/store/contract_class_store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAGpD,OAAO,KAAK,EAAE,iBAAiB,EAAiB,MAAM,iBAAiB,CAAC;AAExE,OAAO,KAAK,EACV,mBAAmB,EAEnB,4CAA4C,EAC5C,kCAAkC,EACnC,MAAM,wBAAwB,CAAC;AAGhC;;GAEG;AACH,qBAAa,kBAAkB;;IAIjB,OAAO,CAAC,EAAE;IAAtB,YAAoB,EAAE,EAAE,iBAAiB,EAGxC;IAEK,gBAAgB,CACpB,aAAa,EAAE,mBAAmB,EAClC,kBAAkB,EAAE,EAAE,EACtB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAQf;IAEK,qBAAqB,CAAC,aAAa,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQlG;IAEK,gBAAgB,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC,CAGvE;IAEK,qBAAqB,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,EAAE,GAAG,SAAS,CAAC,CAG3D;IAEK,mBAAmB,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC,CAEzC;IAEK,YAAY,CAChB,eAAe,EAAE,EAAE,EACnB,mBAAmB,EAAE,4CAA4C,EAAE,EACnE,mBAAmB,EAAE,kCAAkC,EAAE,GACxD,OAAO,CAAC,OAAO,CAAC,CAyBlB;CACF"}
@@ -15,17 +15,21 @@ import { Vector } from '@aztec/stdlib/types';
15
15
  this.#bytecodeCommitments = db.openMap('archiver_bytecode_commitments');
16
16
  }
17
17
  async addContractClass(contractClass, bytecodeCommitment, blockNumber) {
18
- await this.#contractClasses.setIfNotExists(contractClass.id.toString(), serializeContractClassPublic({
19
- ...contractClass,
20
- l2BlockNumber: blockNumber
21
- }));
22
- await this.#bytecodeCommitments.setIfNotExists(contractClass.id.toString(), bytecodeCommitment.toBuffer());
18
+ await this.db.transactionAsync(async ()=>{
19
+ await this.#contractClasses.setIfNotExists(contractClass.id.toString(), serializeContractClassPublic({
20
+ ...contractClass,
21
+ l2BlockNumber: blockNumber
22
+ }));
23
+ await this.#bytecodeCommitments.setIfNotExists(contractClass.id.toString(), bytecodeCommitment.toBuffer());
24
+ });
23
25
  }
24
26
  async deleteContractClasses(contractClass, blockNumber) {
25
27
  const restoredContractClass = await this.#contractClasses.getAsync(contractClass.id.toString());
26
28
  if (restoredContractClass && deserializeContractClassPublic(restoredContractClass).l2BlockNumber >= blockNumber) {
27
- await this.#contractClasses.delete(contractClass.id.toString());
28
- await this.#bytecodeCommitments.delete(contractClass.id.toString());
29
+ await this.db.transactionAsync(async ()=>{
30
+ await this.#contractClasses.delete(contractClass.id.toString());
31
+ await this.#bytecodeCommitments.delete(contractClass.id.toString());
32
+ });
29
33
  }
30
34
  }
31
35
  async getContractClass(id) {
@@ -4,15 +4,16 @@ import type { Fr } from '@aztec/foundation/curves/bn254';
4
4
  import type { AztecAsyncKVStore, CustomRange, StoreSize } from '@aztec/kv-store';
5
5
  import { FunctionSelector } from '@aztec/stdlib/abi';
6
6
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
7
- import { CheckpointedL2Block, L2BlockNew, type ValidateCheckpointResult } from '@aztec/stdlib/block';
8
- import type { PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
7
+ import { type BlockData, BlockHash, CheckpointedL2Block, L2Block, type ValidateCheckpointResult } from '@aztec/stdlib/block';
8
+ import type { CheckpointData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
9
9
  import type { ContractClassPublic, ContractDataSource, ContractInstanceUpdateWithAddress, ContractInstanceWithAddress, ExecutablePrivateFunctionWithMembershipProof, UtilityFunctionWithMembershipProof } from '@aztec/stdlib/contract';
10
+ import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
10
11
  import type { GetContractClassLogsResponse, GetPublicLogsResponse } from '@aztec/stdlib/interfaces/client';
11
12
  import type { LogFilter, SiloedTag, Tag, TxScopedL2Log } from '@aztec/stdlib/logs';
12
13
  import type { BlockHeader, TxHash, TxReceipt } from '@aztec/stdlib/tx';
13
14
  import type { UInt64 } from '@aztec/stdlib/types';
14
15
  import type { InboxMessage } from '../structs/inbox_message.js';
15
- import { type CheckpointData } from './block_store.js';
16
+ import { BlockStore, type RemoveCheckpointsResult } from './block_store.js';
16
17
  export declare const ARCHIVER_DB_VERSION = 5;
17
18
  export declare const MAX_FUNCTION_SIGNATURES = 1000;
18
19
  export declare const MAX_FUNCTION_NAME_LEN = 256;
@@ -34,7 +35,9 @@ export declare class KVArchiverDataStore implements ContractDataSource {
34
35
  private db;
35
36
  static readonly SCHEMA_VERSION = 5;
36
37
  private functionNames;
37
- constructor(db: AztecAsyncKVStore, logsMaxPageSize?: number);
38
+ constructor(db: AztecAsyncKVStore, logsMaxPageSize: number | undefined, l1Constants: Pick<L1RollupConstants, 'epochDuration'>);
39
+ /** Returns the underlying block store. Used by L2TipsCache. */
40
+ get blockStore(): BlockStore;
38
41
  /** Opens a new transaction to the underlying store and runs all operations within it. */
39
42
  transactionAsync<T>(callback: () => Promise<T>): Promise<T>;
40
43
  getBlockNumber(): Promise<BlockNumber>;
@@ -43,6 +46,8 @@ export declare class KVArchiverDataStore implements ContractDataSource {
43
46
  backupTo(path: string, compress?: boolean): Promise<string>;
44
47
  /** Closes the underlying data store. */
45
48
  close(): Promise<void>;
49
+ /** Computes the finalized block number based on the proven block number. */
50
+ getFinalizedL2BlockNumber(): Promise<BlockNumber>;
46
51
  /** Looks up a public function name given a selector. */
47
52
  getDebugFunctionName(_address: AztecAddress, selector: FunctionSelector): Promise<string | undefined>;
48
53
  /** Register a public function signature, so it can be looked up by selector. */
@@ -91,11 +96,13 @@ export declare class KVArchiverDataStore implements ContractDataSource {
91
96
  addContractInstanceUpdates(data: ContractInstanceUpdateWithAddress[], timestamp: UInt64): Promise<boolean>;
92
97
  deleteContractInstanceUpdates(data: ContractInstanceUpdateWithAddress[], timestamp: UInt64): Promise<boolean>;
93
98
  /**
94
- * Append new blocks to the store's list.
95
- * @param blocks - The L2 blocks to be added to the store and the last processed L1 block.
99
+ * Append new proposed blocks to the store's list.
100
+ * These are uncheckpointed blocks that have been proposed by the sequencer but not yet included in a checkpoint on L1.
101
+ * For checkpointed blocks (already published to L1), use addCheckpoints() instead.
102
+ * @param blocks - The proposed L2 blocks to be added to the store.
96
103
  * @returns True if the operation is successful.
97
104
  */
98
- addBlocks(blocks: L2BlockNew[], opts?: {
105
+ addProposedBlocks(blocks: L2Block[], opts?: {
99
106
  force?: boolean;
100
107
  checkpointNumber?: number;
101
108
  }): Promise<boolean>;
@@ -112,13 +119,11 @@ export declare class KVArchiverDataStore implements ContractDataSource {
112
119
  */
113
120
  getLatestBlockNumber(): Promise<BlockNumber>;
114
121
  /**
115
- * Unwinds checkpoints from the database
116
- * @param from - The tip of the chain, passed for verification purposes,
117
- * ensuring that we don't end up deleting something we did not intend
118
- * @param checkpointsToUnwind - The number of checkpoints we are to unwind
119
- * @returns True if the operation is successful
122
+ * Removes all checkpoints with checkpoint number > checkpointNumber.
123
+ * Also removes ALL blocks (both checkpointed and uncheckpointed) after the last block of the given checkpoint.
124
+ * @param checkpointNumber - Remove all checkpoints strictly after this one.
120
125
  */
121
- unwindCheckpoints(from: CheckpointNumber, checkpointsToUnwind: number): Promise<boolean>;
126
+ removeCheckpointsAfter(checkpointNumber: CheckpointNumber): Promise<RemoveCheckpointsResult>;
122
127
  /**
123
128
  * Appends new checkpoints, and their blocks to the store's collection
124
129
  * @param checkpoints The collection of checkpoints to be added
@@ -134,7 +139,7 @@ export declare class KVArchiverDataStore implements ContractDataSource {
134
139
  * Returns the block for the given hash, or undefined if not exists.
135
140
  * @param blockHash - The block hash to return.
136
141
  */
137
- getCheckpointedBlockByHash(blockHash: Fr): Promise<CheckpointedL2Block | undefined>;
142
+ getCheckpointedBlockByHash(blockHash: BlockHash): Promise<CheckpointedL2Block | undefined>;
138
143
  /**
139
144
  * Returns the block for the given archive root, or undefined if not exists.
140
145
  * @param archive - The archive root to return.
@@ -144,24 +149,24 @@ export declare class KVArchiverDataStore implements ContractDataSource {
144
149
  * Returns the block for the given number, or undefined if not exists.
145
150
  * @param number - The block number to return.
146
151
  */
147
- getBlock(number: BlockNumber): Promise<L2BlockNew | undefined>;
152
+ getBlock(number: BlockNumber): Promise<L2Block | undefined>;
148
153
  /**
149
154
  * Returns the block for the given hash, or undefined if not exists.
150
155
  * @param blockHash - The block hash to return.
151
156
  */
152
- getBlockByHash(blockHash: Fr): Promise<L2BlockNew | undefined>;
157
+ getBlockByHash(blockHash: BlockHash): Promise<L2Block | undefined>;
153
158
  /**
154
159
  * Returns the block for the given archive root, or undefined if not exists.
155
160
  * @param archive - The archive root to return.
156
161
  */
157
- getBlockByArchive(archive: Fr): Promise<L2BlockNew | undefined>;
162
+ getBlockByArchive(archive: Fr): Promise<L2Block | undefined>;
158
163
  /**
159
164
  * Gets up to `limit` amount of published L2 blocks starting from `from`.
160
165
  * @param from - Number of the first block to return (inclusive).
161
166
  * @param limit - The number of blocks to return.
162
167
  * @returns The requested L2 blocks.
163
168
  */
164
- getBlocks(from: BlockNumber, limit: number): Promise<L2BlockNew[]>;
169
+ getBlocks(from: BlockNumber, limit: number): Promise<L2Block[]>;
165
170
  /**
166
171
  * Gets up to `limit` amount of checkpointed L2 blocks starting from `from`.
167
172
  * @param from - Number of the first block to return (inclusive).
@@ -180,12 +185,22 @@ export declare class KVArchiverDataStore implements ContractDataSource {
180
185
  * Returns the block header for the given hash, or undefined if not exists.
181
186
  * @param blockHash - The block hash to return.
182
187
  */
183
- getBlockHeaderByHash(blockHash: Fr): Promise<BlockHeader | undefined>;
188
+ getBlockHeaderByHash(blockHash: BlockHash): Promise<BlockHeader | undefined>;
184
189
  /**
185
190
  * Returns the block header for the given archive root, or undefined if not exists.
186
191
  * @param archive - The archive root to return.
187
192
  */
188
193
  getBlockHeaderByArchive(archive: Fr): Promise<BlockHeader | undefined>;
194
+ /**
195
+ * Gets block metadata (without tx data) by block number.
196
+ * @param blockNumber - The block number to return.
197
+ */
198
+ getBlockData(blockNumber: BlockNumber): Promise<BlockData | undefined>;
199
+ /**
200
+ * Gets block metadata (without tx data) by archive root.
201
+ * @param archive - The archive root to return.
202
+ */
203
+ getBlockDataByArchive(archive: Fr): Promise<BlockData | undefined>;
189
204
  /**
190
205
  * Gets a tx effect.
191
206
  * @param txHash - The hash of the tx corresponding to the tx effect.
@@ -203,8 +218,8 @@ export declare class KVArchiverDataStore implements ContractDataSource {
203
218
  * @param blocks - The blocks for which to add the logs.
204
219
  * @returns True if the operation is successful.
205
220
  */
206
- addLogs(blocks: L2BlockNew[]): Promise<boolean>;
207
- deleteLogs(blocks: L2BlockNew[]): Promise<boolean>;
221
+ addLogs(blocks: L2Block[]): Promise<boolean>;
222
+ deleteLogs(blocks: L2Block[]): Promise<boolean>;
208
223
  /**
209
224
  * Get the total number of L1 to L2 messages
210
225
  * @returns The number of L1 to L2 messages in the store
@@ -313,24 +328,27 @@ export declare class KVArchiverDataStore implements ContractDataSource {
313
328
  * @param checkpointNumber Retrieves all blocks for the given checkpoint
314
329
  * @returns The collection of blocks for the requested checkpoint if available (undefined otherwise)
315
330
  */
316
- getBlocksForCheckpoint(checkpointNumber: CheckpointNumber): Promise<L2BlockNew[] | undefined>;
331
+ getBlocksForCheckpoint(checkpointNumber: CheckpointNumber): Promise<L2Block[] | undefined>;
317
332
  /**
318
333
  * Returns checkpoint data for the requested checkpoint number
319
334
  * @param checkpointNumber - The checkpoint requested
320
335
  * @returns The checkpoint data or undefined if not found
321
336
  */
322
337
  getCheckpointData(checkpointNumber: CheckpointNumber): Promise<CheckpointData | undefined>;
338
+ /** Returns checkpoint data for all checkpoints whose slot falls within the given range (inclusive). */
339
+ getCheckpointDataForSlotRange(startSlot: SlotNumber, endSlot: SlotNumber): Promise<CheckpointData[]>;
323
340
  /**
324
341
  * Gets all blocks that have the given slot number.
325
342
  * @param slotNumber - The slot number to search for.
326
343
  * @returns All blocks with the given slot number.
327
344
  */
328
- getBlocksForSlot(slotNumber: SlotNumber): Promise<L2BlockNew[]>;
345
+ getBlocksForSlot(slotNumber: SlotNumber): Promise<L2Block[]>;
329
346
  /**
330
347
  * Removes all blocks with block number > blockNumber.
348
+ * Does not remove any associated checkpoints.
331
349
  * @param blockNumber - The block number to remove after.
332
350
  * @returns The removed blocks (for event emission).
333
351
  */
334
- removeBlocksAfter(blockNumber: BlockNumber): Promise<L2BlockNew[]>;
352
+ removeBlocksAfter(blockNumber: BlockNumber): Promise<L2Block[]>;
335
353
  }
336
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia3ZfYXJjaGl2ZXJfc3RvcmUuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zdG9yZS9rdl9hcmNoaXZlcl9zdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMxRCxPQUFPLEtBQUssRUFBRSxXQUFXLEVBQUUsZ0JBQWdCLEVBQUUsVUFBVSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDakcsT0FBTyxLQUFLLEVBQUUsRUFBRSxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFHekQsT0FBTyxLQUFLLEVBQUUsaUJBQWlCLEVBQUUsV0FBVyxFQUFFLFNBQVMsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ2pGLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3JELE9BQU8sS0FBSyxFQUFFLFlBQVksRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ2hFLE9BQU8sRUFBRSxtQkFBbUIsRUFBZSxVQUFVLEVBQUUsS0FBSyx3QkFBd0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ2xILE9BQU8sS0FBSyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDcEUsT0FBTyxLQUFLLEVBQ1YsbUJBQW1CLEVBQ25CLGtCQUFrQixFQUNsQixpQ0FBaUMsRUFDakMsMkJBQTJCLEVBQzNCLDRDQUE0QyxFQUM1QyxrQ0FBa0MsRUFDbkMsTUFBTSx3QkFBd0IsQ0FBQztBQUNoQyxPQUFPLEtBQUssRUFBRSw0QkFBNEIsRUFBRSxxQkFBcUIsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQzNHLE9BQU8sS0FBSyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLGFBQWEsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ25GLE9BQU8sS0FBSyxFQUFFLFdBQVcsRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLE1BQU0sa0JB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
354
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia3ZfYXJjaGl2ZXJfc3RvcmUuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zdG9yZS9rdl9hcmNoaXZlcl9zdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMxRCxPQUFPLEtBQUssRUFBRSxXQUFXLEVBQUUsZ0JBQWdCLEVBQUUsVUFBVSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDakcsT0FBTyxLQUFLLEVBQUUsRUFBRSxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFHekQsT0FBTyxLQUFLLEVBQUUsaUJBQWlCLEVBQUUsV0FBVyxFQUFFLFNBQVMsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ2pGLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3JELE9BQU8sS0FBSyxFQUFFLFlBQVksRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ2hFLE9BQU8sRUFDTCxLQUFLLFNBQVMsRUFDZCxTQUFTLEVBQ1QsbUJBQW1CLEVBQ25CLE9BQU8sRUFDUCxLQUFLLHdCQUF3QixFQUM5QixNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sS0FBSyxFQUFFLGNBQWMsRUFBRSxtQkFBbUIsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3BGLE9BQU8sS0FBSyxFQUNWLG1CQUFtQixFQUNuQixrQkFBa0IsRUFDbEIsaUNBQWlDLEVBQ2pDLDJCQUEyQixFQUMzQiw0Q0FBNEMsRUFDNUMsa0NBQWtDLEVBQ25DLE1BQU0sd0JBQXdCLENBQUM7QUFDaEMsT0FBTyxLQUFLLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUNyRSxPQUFPLEtBQUssRUFBRSw0QkFBNEIsRUFBRSxxQkFBcUIsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQzNHLE9BQU8sS0FBSyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFF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