@aztec/archiver 0.0.1-commit.3469e52 → 0.0.1-commit.381b1a9

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 (97) hide show
  1. package/README.md +9 -0
  2. package/dest/archiver.d.ts +12 -8
  3. package/dest/archiver.d.ts.map +1 -1
  4. package/dest/archiver.js +81 -120
  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 +3 -1
  9. package/dest/factory.d.ts.map +1 -1
  10. package/dest/factory.js +14 -11
  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 +4 -7
  19. package/dest/l1/data_retrieval.d.ts.map +1 -1
  20. package/dest/l1/data_retrieval.js +12 -16
  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 +25 -21
  28. package/dest/modules/data_source_base.d.ts.map +1 -1
  29. package/dest/modules/data_source_base.js +45 -120
  30. package/dest/modules/data_store_updater.d.ts +40 -21
  31. package/dest/modules/data_store_updater.d.ts.map +1 -1
  32. package/dest/modules/data_store_updater.js +114 -64
  33. package/dest/modules/instrumentation.d.ts +6 -4
  34. package/dest/modules/instrumentation.d.ts.map +1 -1
  35. package/dest/modules/instrumentation.js +26 -12
  36. package/dest/modules/l1_synchronizer.d.ts +5 -8
  37. package/dest/modules/l1_synchronizer.d.ts.map +1 -1
  38. package/dest/modules/l1_synchronizer.js +46 -20
  39. package/dest/store/block_store.d.ts +49 -32
  40. package/dest/store/block_store.d.ts.map +1 -1
  41. package/dest/store/block_store.js +165 -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 +53 -25
  46. package/dest/store/kv_archiver_store.d.ts.map +1 -1
  47. package/dest/store/kv_archiver_store.js +50 -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 +105 -47
  54. package/dest/store/message_store.js +1 -1
  55. package/dest/test/fake_l1_state.d.ts +16 -4
  56. package/dest/test/fake_l1_state.d.ts.map +1 -1
  57. package/dest/test/fake_l1_state.js +84 -20
  58. package/dest/test/index.js +3 -1
  59. package/dest/test/mock_archiver.d.ts +1 -1
  60. package/dest/test/mock_archiver.d.ts.map +1 -1
  61. package/dest/test/mock_archiver.js +3 -2
  62. package/dest/test/mock_l2_block_source.d.ts +39 -23
  63. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  64. package/dest/test/mock_l2_block_source.js +157 -112
  65. package/dest/test/mock_structs.d.ts +6 -2
  66. package/dest/test/mock_structs.d.ts.map +1 -1
  67. package/dest/test/mock_structs.js +24 -10
  68. package/dest/test/noop_l1_archiver.d.ts +26 -0
  69. package/dest/test/noop_l1_archiver.d.ts.map +1 -0
  70. package/dest/test/noop_l1_archiver.js +72 -0
  71. package/package.json +14 -13
  72. package/src/archiver.ts +106 -149
  73. package/src/errors.ts +12 -0
  74. package/src/factory.ts +29 -12
  75. package/src/index.ts +1 -0
  76. package/src/l1/README.md +25 -68
  77. package/src/l1/bin/retrieve-calldata.ts +45 -33
  78. package/src/l1/calldata_retriever.ts +249 -379
  79. package/src/l1/data_retrieval.ts +10 -20
  80. package/src/l1/spire_proposer.ts +7 -15
  81. package/src/l1/validate_trace.ts +24 -6
  82. package/src/modules/data_source_base.ts +76 -166
  83. package/src/modules/data_store_updater.ts +130 -66
  84. package/src/modules/instrumentation.ts +26 -14
  85. package/src/modules/l1_synchronizer.ts +55 -26
  86. package/src/store/block_store.ts +216 -92
  87. package/src/store/contract_class_store.ts +11 -7
  88. package/src/store/kv_archiver_store.ts +88 -30
  89. package/src/store/l2_tips_cache.ts +89 -0
  90. package/src/store/log_store.ts +171 -55
  91. package/src/store/message_store.ts +1 -1
  92. package/src/test/fake_l1_state.ts +112 -23
  93. package/src/test/index.ts +3 -0
  94. package/src/test/mock_archiver.ts +3 -2
  95. package/src/test/mock_l2_block_source.ts +211 -129
  96. package/src/test/mock_structs.ts +45 -15
  97. package/src/test/noop_l1_archiver.ts +115 -0
@@ -6,12 +6,13 @@ 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
+ import { getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
11
12
  import { CheckpointHeader } from '@aztec/stdlib/rollup';
12
13
  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';
14
+ import { BlockHeader, TxHash, TxReceipt, TxStatus, deserializeIndexedTxEffect, serializeIndexedTxEffect } from '@aztec/stdlib/tx';
15
+ import { BlockArchiveNotConsistentError, BlockIndexNotSequentialError, BlockNotFoundError, BlockNumberNotSequentialError, CannotOverwriteCheckpointedBlockError, CheckpointNotFoundError, CheckpointNumberNotConsistentError, CheckpointNumberNotSequentialError, InitialBlockNumberNotSequentialError, InitialCheckpointNumberNotSequentialError } from '../errors.js';
15
16
  export { TxReceipt } from '@aztec/stdlib/tx';
16
17
  /**
17
18
  * LMDB-based block storage for the archiver.
@@ -19,10 +20,12 @@ export { TxReceipt } from '@aztec/stdlib/tx';
19
20
  db;
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;
25
27
  /** Stores last proven checkpoint */ #lastProvenCheckpoint;
28
+ /** Stores last finalized checkpoint (proven at or before the finalized L1 block) */ #lastFinalizedCheckpoint;
26
29
  /** Stores the pending chain validation status */ #pendingChainValidationStatus;
27
30
  /** Index mapping a contract's address (as a string) to its location in a block */ #contractIndex;
28
31
  /** Index mapping block hash to block number */ #blockHashIndex;
@@ -39,14 +42,33 @@ export { TxReceipt } from '@aztec/stdlib/tx';
39
42
  this.#blockArchiveIndex = db.openMap('archiver_block_archive_index');
40
43
  this.#lastSynchedL1Block = db.openSingleton('archiver_last_synched_l1_block');
41
44
  this.#lastProvenCheckpoint = db.openSingleton('archiver_last_proven_l2_checkpoint');
45
+ this.#lastFinalizedCheckpoint = db.openSingleton('archiver_last_finalized_l2_checkpoint');
42
46
  this.#pendingChainValidationStatus = db.openSingleton('archiver_pending_chain_validation_status');
43
47
  this.#checkpoints = db.openMap('archiver_checkpoints');
48
+ this.#slotToCheckpoint = db.openMap('archiver_slot_to_checkpoint');
44
49
  }
45
50
  /**
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.
51
+ * Returns the finalized L2 block number. An L2 block is finalized when it was proven
52
+ * in an L1 block that has itself been finalized on Ethereum.
53
+ * @returns The finalized block number.
54
+ */ async getFinalizedL2BlockNumber() {
55
+ const finalizedCheckpointNumber = await this.getFinalizedCheckpointNumber();
56
+ if (finalizedCheckpointNumber === INITIAL_CHECKPOINT_NUMBER - 1) {
57
+ return BlockNumber(INITIAL_L2_BLOCK_NUM - 1);
58
+ }
59
+ const checkpointStorage = await this.#checkpoints.getAsync(finalizedCheckpointNumber);
60
+ if (!checkpointStorage) {
61
+ throw new CheckpointNotFoundError(finalizedCheckpointNumber);
62
+ }
63
+ return BlockNumber(checkpointStorage.startBlock + checkpointStorage.blockCount - 1);
64
+ }
65
+ /**
66
+ * Append new proposed blocks to the store's list. All blocks must be for the 'current' checkpoint.
67
+ * These are uncheckpointed blocks that have been proposed by the sequencer but not yet included in a checkpoint on L1.
68
+ * For checkpointed blocks (already published to L1), use addCheckpoints() instead.
69
+ * @param blocks - The proposed L2 blocks to be added to the store.
48
70
  * @returns True if the operation is successful.
49
- */ async addBlocks(blocks, opts = {}) {
71
+ */ async addProposedBlocks(blocks, opts = {}) {
50
72
  if (blocks.length === 0) {
51
73
  return true;
52
74
  }
@@ -59,6 +81,11 @@ export { TxReceipt } from '@aztec/stdlib/tx';
59
81
  // Extract the latest block and checkpoint numbers
60
82
  const previousBlockNumber = await this.getLatestBlockNumber();
61
83
  const previousCheckpointNumber = await this.getLatestCheckpointNumber();
84
+ // Verify we're not overwriting checkpointed blocks
85
+ const lastCheckpointedBlockNumber = await this.getCheckpointedL2BlockNumber();
86
+ if (!opts.force && firstBlockNumber <= lastCheckpointedBlockNumber) {
87
+ throw new CannotOverwriteCheckpointedBlockError(firstBlockNumber, lastCheckpointedBlockNumber);
88
+ }
62
89
  // Check that the first block number is the expected one
63
90
  if (!opts.force && previousBlockNumber !== firstBlockNumber - 1) {
64
91
  throw new InitialBlockNumberNotSequentialError(firstBlockNumber, previousBlockNumber);
@@ -136,7 +163,7 @@ export { TxReceipt } from '@aztec/stdlib/tx';
136
163
  let previousBlock = undefined;
137
164
  // If we have a previous checkpoint then we need to get the previous block number
138
165
  if (previousCheckpointData !== undefined) {
139
- previousBlockNumber = BlockNumber(previousCheckpointData.startBlock + previousCheckpointData.numBlocks - 1);
166
+ previousBlockNumber = BlockNumber(previousCheckpointData.startBlock + previousCheckpointData.blockCount - 1);
140
167
  previousBlock = await this.getBlock(previousBlockNumber);
141
168
  if (previousBlock === undefined) {
142
169
  // We should be able to get the required previous block
@@ -181,19 +208,22 @@ export { TxReceipt } from '@aztec/stdlib/tx';
181
208
  await this.#checkpoints.set(checkpoint.checkpoint.number, {
182
209
  header: checkpoint.checkpoint.header.toBuffer(),
183
210
  archive: checkpoint.checkpoint.archive.toBuffer(),
211
+ checkpointOutHash: checkpoint.checkpoint.getCheckpointOutHash().toBuffer(),
184
212
  l1: checkpoint.l1.toBuffer(),
185
213
  attestations: checkpoint.attestations.map((attestation)=>attestation.toBuffer()),
186
214
  checkpointNumber: checkpoint.checkpoint.number,
187
215
  startBlock: checkpoint.checkpoint.blocks[0].number,
188
- numBlocks: checkpoint.checkpoint.blocks.length
216
+ blockCount: checkpoint.checkpoint.blocks.length
189
217
  });
218
+ // Update slot-to-checkpoint index
219
+ await this.#slotToCheckpoint.set(checkpoint.checkpoint.header.slotNumber, checkpoint.checkpoint.number);
190
220
  }
191
221
  await this.#lastSynchedL1Block.set(checkpoints[checkpoints.length - 1].l1.blockNumber);
192
222
  return true;
193
223
  });
194
224
  }
195
225
  async addBlockToDatabase(block, checkpointNumber, indexWithinCheckpoint) {
196
- const blockHash = L2BlockHash.fromField(await block.hash());
226
+ const blockHash = await block.hash();
197
227
  await this.#blocks.set(block.number, {
198
228
  header: block.header.toBuffer(),
199
229
  blockHash: blockHash.toBuffer(),
@@ -228,41 +258,50 @@ export { TxReceipt } from '@aztec/stdlib/tx';
228
258
  await this.#blockArchiveIndex.delete(block.archive.root.toString());
229
259
  }
230
260
  /**
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) {
261
+ * Removes all checkpoints with checkpoint number > checkpointNumber.
262
+ * Also removes ALL blocks (both checkpointed and uncheckpointed) after the last block of the given checkpoint.
263
+ * @param checkpointNumber - Remove all checkpoints strictly after this one.
264
+ */ async removeCheckpointsAfter(checkpointNumber) {
237
265
  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})`);
266
+ const latestCheckpointNumber = await this.getLatestCheckpointNumber();
267
+ if (checkpointNumber >= latestCheckpointNumber) {
268
+ this.#log.warn(`No checkpoints to remove after ${checkpointNumber} (latest is ${latestCheckpointNumber})`);
269
+ return {
270
+ blocksRemoved: undefined
271
+ };
241
272
  }
273
+ // If the proven checkpoint is beyond the target, update it
242
274
  const proven = await this.getProvenCheckpointNumber();
243
- if (from - checkpointsToUnwind < proven) {
244
- await this.setProvenCheckpointNumber(CheckpointNumber(from - checkpointsToUnwind));
275
+ if (proven > checkpointNumber) {
276
+ this.#log.warn(`Updating proven checkpoint ${proven} to last valid checkpoint ${checkpointNumber}`);
277
+ await this.setProvenCheckpointNumber(checkpointNumber);
245
278
  }
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;
279
+ // Find the last block number to keep (last block of the given checkpoint, or 0 if no checkpoint)
280
+ let lastBlockToKeep;
281
+ if (checkpointNumber <= 0) {
282
+ lastBlockToKeep = BlockNumber(INITIAL_L2_BLOCK_NUM - 1);
283
+ } else {
284
+ const targetCheckpoint = await this.#checkpoints.getAsync(checkpointNumber);
285
+ if (!targetCheckpoint) {
286
+ throw new Error(`Target checkpoint ${checkpointNumber} not found in store`);
252
287
  }
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}`);
288
+ lastBlockToKeep = BlockNumber(targetCheckpoint.startBlock + targetCheckpoint.blockCount - 1);
289
+ }
290
+ // Remove all blocks after lastBlockToKeep (both checkpointed and uncheckpointed)
291
+ const blocksRemoved = await this.removeBlocksAfter(lastBlockToKeep);
292
+ // Remove all checkpoints after the target
293
+ for(let c = latestCheckpointNumber; c > checkpointNumber; c = CheckpointNumber(c - 1)){
294
+ const checkpointStorage = await this.#checkpoints.getAsync(c);
295
+ if (checkpointStorage) {
296
+ const slotNumber = CheckpointHeader.fromBuffer(checkpointStorage.header).slotNumber;
297
+ await this.#slotToCheckpoint.delete(slotNumber);
263
298
  }
299
+ await this.#checkpoints.delete(c);
300
+ this.#log.debug(`Removed checkpoint ${c}`);
264
301
  }
265
- return true;
302
+ return {
303
+ blocksRemoved
304
+ };
266
305
  });
267
306
  }
268
307
  async getCheckpointData(checkpointNumber) {
@@ -283,17 +322,30 @@ export { TxReceipt } from '@aztec/stdlib/tx';
283
322
  }
284
323
  return checkpoints;
285
324
  }
325
+ /** Returns checkpoint data for all checkpoints whose slot falls within the given range (inclusive). */ async getCheckpointDataForSlotRange(startSlot, endSlot) {
326
+ const result = [];
327
+ for await (const [, checkpointNumber] of this.#slotToCheckpoint.entriesAsync({
328
+ start: startSlot,
329
+ end: endSlot + 1
330
+ })){
331
+ const checkpointStorage = await this.#checkpoints.getAsync(checkpointNumber);
332
+ if (checkpointStorage) {
333
+ result.push(this.checkpointDataFromCheckpointStorage(checkpointStorage));
334
+ }
335
+ }
336
+ return result;
337
+ }
286
338
  checkpointDataFromCheckpointStorage(checkpointStorage) {
287
- const data = {
339
+ return {
288
340
  header: CheckpointHeader.fromBuffer(checkpointStorage.header),
289
341
  archive: AppendOnlyTreeSnapshot.fromBuffer(checkpointStorage.archive),
342
+ checkpointOutHash: Fr.fromBuffer(checkpointStorage.checkpointOutHash),
290
343
  checkpointNumber: CheckpointNumber(checkpointStorage.checkpointNumber),
291
- startBlock: checkpointStorage.startBlock,
292
- numBlocks: checkpointStorage.numBlocks,
344
+ startBlock: BlockNumber(checkpointStorage.startBlock),
345
+ blockCount: checkpointStorage.blockCount,
293
346
  l1: L1PublishedData.fromBuffer(checkpointStorage.l1),
294
- attestations: checkpointStorage.attestations
347
+ attestations: checkpointStorage.attestations.map((buf)=>CommitteeAttestation.fromBuffer(buf))
295
348
  };
296
- return data;
297
349
  }
298
350
  async getBlocksForCheckpoint(checkpointNumber) {
299
351
  const checkpoint = await this.#checkpoints.getAsync(checkpointNumber);
@@ -302,7 +354,7 @@ export { TxReceipt } from '@aztec/stdlib/tx';
302
354
  }
303
355
  const blocksForCheckpoint = await toArray(this.#blocks.entriesAsync({
304
356
  start: checkpoint.startBlock,
305
- end: checkpoint.startBlock + checkpoint.numBlocks
357
+ end: checkpoint.startBlock + checkpoint.blockCount
306
358
  }));
307
359
  const converted = await Promise.all(blocksForCheckpoint.map((x)=>this.getBlockFromBlockStorage(x[0], x[1])));
308
360
  return converted.filter(isDefined);
@@ -332,9 +384,10 @@ export { TxReceipt } from '@aztec/stdlib/tx';
332
384
  }
333
385
  /**
334
386
  * Removes all blocks with block number > blockNumber.
387
+ * Does not remove any associated checkpoints.
335
388
  * @param blockNumber - The block number to remove after.
336
389
  * @returns The removed blocks (for event emission).
337
- */ async unwindBlocksAfter(blockNumber) {
390
+ */ async removeBlocksAfter(blockNumber) {
338
391
  return await this.db.transactionAsync(async ()=>{
339
392
  const removedBlocks = [];
340
393
  // Get the latest block number to determine the range
@@ -362,7 +415,7 @@ export { TxReceipt } from '@aztec/stdlib/tx';
362
415
  if (!checkpointStorage) {
363
416
  throw new CheckpointNotFoundError(provenCheckpointNumber);
364
417
  } else {
365
- return BlockNumber(checkpointStorage.startBlock + checkpointStorage.numBlocks - 1);
418
+ return BlockNumber(checkpointStorage.startBlock + checkpointStorage.blockCount - 1);
366
419
  }
367
420
  }
368
421
  async getLatestBlockNumber() {
@@ -444,6 +497,28 @@ export { TxReceipt } from '@aztec/stdlib/tx';
444
497
  }
445
498
  }
446
499
  /**
500
+ * Gets block metadata (without tx data) by block number.
501
+ * @param blockNumber - The number of the block to return.
502
+ * @returns The requested block data.
503
+ */ async getBlockData(blockNumber) {
504
+ const blockStorage = await this.#blocks.getAsync(blockNumber);
505
+ if (!blockStorage || !blockStorage.header) {
506
+ return undefined;
507
+ }
508
+ return this.getBlockDataFromBlockStorage(blockStorage);
509
+ }
510
+ /**
511
+ * Gets block metadata (without tx data) by archive root.
512
+ * @param archive - The archive root of the block to return.
513
+ * @returns The requested block data.
514
+ */ async getBlockDataByArchive(archive) {
515
+ const blockNumber = await this.#blockArchiveIndex.getAsync(archive.toString());
516
+ if (blockNumber === undefined) {
517
+ return undefined;
518
+ }
519
+ return this.getBlockData(BlockNumber(blockNumber));
520
+ }
521
+ /**
447
522
  * Gets an L2 block.
448
523
  * @param blockNumber - The number of the block to return.
449
524
  * @returns The requested L2 block.
@@ -533,12 +608,19 @@ export { TxReceipt } from '@aztec/stdlib/tx';
533
608
  ];
534
609
  }
535
610
  }
611
+ getBlockDataFromBlockStorage(blockStorage) {
612
+ return {
613
+ header: BlockHeader.fromBuffer(blockStorage.header),
614
+ archive: AppendOnlyTreeSnapshot.fromBuffer(blockStorage.archive),
615
+ blockHash: Fr.fromBuffer(blockStorage.blockHash),
616
+ checkpointNumber: CheckpointNumber(blockStorage.checkpointNumber),
617
+ indexWithinCheckpoint: IndexWithinCheckpoint(blockStorage.indexWithinCheckpoint)
618
+ };
619
+ }
536
620
  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);
621
+ const { header, archive, blockHash, checkpointNumber, indexWithinCheckpoint } = this.getBlockDataFromBlockStorage(blockStorage);
622
+ header.setHash(blockHash);
623
+ const blockHashString = bufferToHex(blockStorage.blockHash);
542
624
  const blockTxsBuffer = await this.#blockTxs.getAsync(blockHashString);
543
625
  if (blockTxsBuffer === undefined) {
544
626
  this.#log.warn(`Could not find body for block ${header.globalVariables.blockNumber} ${blockHash}`);
@@ -556,7 +638,7 @@ export { TxReceipt } from '@aztec/stdlib/tx';
556
638
  txEffects.push(deserializeIndexedTxEffect(txEffect).data);
557
639
  }
558
640
  const body = new Body(txEffects);
559
- const block = new L2BlockNew(archive, header, body, CheckpointNumber(blockStorage.checkpointNumber), IndexWithinCheckpoint(blockStorage.indexWithinCheckpoint));
641
+ const block = new L2Block(archive, header, body, checkpointNumber, indexWithinCheckpoint);
560
642
  if (block.number !== blockNumber) {
561
643
  throw new Error(`Block number mismatch when retrieving block from archive (expected ${blockNumber} but got ${block.number} with hash ${blockHashString})`);
562
644
  }
@@ -577,12 +659,31 @@ export { TxReceipt } from '@aztec/stdlib/tx';
577
659
  * Gets a receipt of a settled tx.
578
660
  * @param txHash - The hash of a tx we try to get the receipt for.
579
661
  * @returns The requested tx receipt (or undefined if not found).
580
- */ async getSettledTxReceipt(txHash) {
662
+ */ async getSettledTxReceipt(txHash, l1Constants) {
581
663
  const txEffect = await this.getTxEffect(txHash);
582
664
  if (!txEffect) {
583
665
  return undefined;
584
666
  }
585
- return new TxReceipt(txHash, TxReceipt.statusFromRevertCode(txEffect.data.revertCode), '', txEffect.data.transactionFee.toBigInt(), txEffect.l2BlockHash, BlockNumber(txEffect.l2BlockNumber));
667
+ const blockNumber = BlockNumber(txEffect.l2BlockNumber);
668
+ // Use existing archiver methods to determine finalization level
669
+ const [provenBlockNumber, checkpointedBlockNumber, finalizedBlockNumber, blockData] = await Promise.all([
670
+ this.getProvenBlockNumber(),
671
+ this.getCheckpointedL2BlockNumber(),
672
+ this.getFinalizedL2BlockNumber(),
673
+ this.getBlockData(blockNumber)
674
+ ]);
675
+ let status;
676
+ if (blockNumber <= finalizedBlockNumber) {
677
+ status = TxStatus.FINALIZED;
678
+ } else if (blockNumber <= provenBlockNumber) {
679
+ status = TxStatus.PROVEN;
680
+ } else if (blockNumber <= checkpointedBlockNumber) {
681
+ status = TxStatus.CHECKPOINTED;
682
+ } else {
683
+ status = TxStatus.PROPOSED;
684
+ }
685
+ const epochNumber = blockData && l1Constants ? getEpochAtSlot(blockData.header.globalVariables.slotNumber, l1Constants) : undefined;
686
+ return new TxReceipt(txHash, status, TxReceipt.executionResultFromRevertCode(txEffect.data.revertCode), undefined, txEffect.data.transactionFee.toBigInt(), txEffect.l2BlockHash, blockNumber, epochNumber);
586
687
  }
587
688
  /**
588
689
  * Looks up which block included the requested tx effect.
@@ -615,7 +716,7 @@ export { TxReceipt } from '@aztec/stdlib/tx';
615
716
  if (!checkpoint) {
616
717
  return BlockNumber(INITIAL_L2_BLOCK_NUM - 1);
617
718
  }
618
- return BlockNumber(checkpoint.startBlock + checkpoint.numBlocks - 1);
719
+ return BlockNumber(checkpoint.startBlock + checkpoint.blockCount - 1);
619
720
  }
620
721
  async getLatestL2BlockNumber() {
621
722
  const [lastBlockNumber] = await toArray(this.#blocks.keysAsync({
@@ -644,6 +745,16 @@ export { TxReceipt } from '@aztec/stdlib/tx';
644
745
  const result = await this.#lastProvenCheckpoint.set(checkpointNumber);
645
746
  return result;
646
747
  }
748
+ async getFinalizedCheckpointNumber() {
749
+ const [latestCheckpointNumber, finalizedCheckpointNumber] = await Promise.all([
750
+ this.getLatestCheckpointNumber(),
751
+ this.#lastFinalizedCheckpoint.getAsync()
752
+ ]);
753
+ return (finalizedCheckpointNumber ?? 0) > latestCheckpointNumber ? latestCheckpointNumber : CheckpointNumber(finalizedCheckpointNumber ?? 0);
754
+ }
755
+ setFinalizedCheckpointNumber(checkpointNumber) {
756
+ return this.#lastFinalizedCheckpoint.set(checkpointNumber);
757
+ }
647
758
  #computeBlockRange(start, limit) {
648
759
  if (limit < 1) {
649
760
  throw new Error(`Invalid limit: ${limit}`);
@@ -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) {