@aztec/archiver 0.0.1-commit.fcb71a6 → 0.0.1-commit.ff7989d6c

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 (200) hide show
  1. package/README.md +156 -22
  2. package/dest/archiver.d.ts +139 -0
  3. package/dest/archiver.d.ts.map +1 -0
  4. package/dest/archiver.js +699 -0
  5. package/dest/{archiver/config.d.ts → config.d.ts} +9 -1
  6. package/dest/config.d.ts.map +1 -0
  7. package/dest/{archiver/config.js → config.js} +11 -2
  8. package/dest/errors.d.ts +41 -0
  9. package/dest/errors.d.ts.map +1 -0
  10. package/dest/{archiver/errors.js → errors.js} +8 -0
  11. package/dest/factory.d.ts +9 -7
  12. package/dest/factory.d.ts.map +1 -1
  13. package/dest/factory.js +94 -11
  14. package/dest/index.d.ts +11 -4
  15. package/dest/index.d.ts.map +1 -1
  16. package/dest/index.js +9 -3
  17. package/dest/interfaces.d.ts +9 -0
  18. package/dest/interfaces.d.ts.map +1 -0
  19. package/dest/interfaces.js +3 -0
  20. package/dest/{archiver/l1 → l1}/bin/retrieve-calldata.d.ts +1 -1
  21. package/dest/l1/bin/retrieve-calldata.d.ts.map +1 -0
  22. package/dest/{archiver/l1 → l1}/bin/retrieve-calldata.js +17 -18
  23. package/dest/{archiver/l1 → l1}/calldata_retriever.d.ts +9 -3
  24. package/dest/l1/calldata_retriever.d.ts.map +1 -0
  25. package/dest/{archiver/l1 → l1}/calldata_retriever.js +19 -6
  26. package/dest/l1/data_retrieval.d.ts +89 -0
  27. package/dest/l1/data_retrieval.d.ts.map +1 -0
  28. package/dest/{archiver/l1 → l1}/data_retrieval.js +39 -57
  29. package/dest/{archiver/l1 → l1}/debug_tx.d.ts +1 -1
  30. package/dest/l1/debug_tx.d.ts.map +1 -0
  31. package/dest/{archiver/l1 → l1}/spire_proposer.d.ts +1 -1
  32. package/dest/l1/spire_proposer.d.ts.map +1 -0
  33. package/dest/{archiver/l1 → l1}/trace_tx.d.ts +1 -1
  34. package/dest/l1/trace_tx.d.ts.map +1 -0
  35. package/dest/l1/types.d.ts +12 -0
  36. package/dest/l1/types.d.ts.map +1 -0
  37. package/dest/{archiver/l1 → l1}/validate_trace.d.ts +6 -3
  38. package/dest/l1/validate_trace.d.ts.map +1 -0
  39. package/dest/{archiver/l1 → l1}/validate_trace.js +14 -10
  40. package/dest/modules/data_source_base.d.ts +89 -0
  41. package/dest/modules/data_source_base.d.ts.map +1 -0
  42. package/dest/modules/data_source_base.js +216 -0
  43. package/dest/modules/data_store_updater.d.ts +80 -0
  44. package/dest/modules/data_store_updater.d.ts.map +1 -0
  45. package/dest/modules/data_store_updater.js +323 -0
  46. package/dest/modules/instrumentation.d.ts +39 -0
  47. package/dest/modules/instrumentation.d.ts.map +1 -0
  48. package/dest/{archiver → modules}/instrumentation.js +33 -67
  49. package/dest/modules/l1_synchronizer.d.ts +76 -0
  50. package/dest/modules/l1_synchronizer.d.ts.map +1 -0
  51. package/dest/modules/l1_synchronizer.js +1112 -0
  52. package/dest/modules/validation.d.ts +17 -0
  53. package/dest/modules/validation.d.ts.map +1 -0
  54. package/dest/{archiver → modules}/validation.js +7 -1
  55. package/dest/store/block_store.d.ts +196 -0
  56. package/dest/store/block_store.d.ts.map +1 -0
  57. package/dest/{archiver/kv_archiver_store → store}/block_store.js +228 -62
  58. package/dest/store/contract_class_store.d.ts +18 -0
  59. package/dest/store/contract_class_store.d.ts.map +1 -0
  60. package/dest/{archiver/kv_archiver_store → store}/contract_class_store.js +12 -8
  61. package/dest/store/contract_instance_store.d.ts +24 -0
  62. package/dest/store/contract_instance_store.d.ts.map +1 -0
  63. package/dest/{archiver/kv_archiver_store → store}/contract_instance_store.js +1 -1
  64. package/dest/store/kv_archiver_store.d.ts +354 -0
  65. package/dest/store/kv_archiver_store.d.ts.map +1 -0
  66. package/dest/store/kv_archiver_store.js +464 -0
  67. package/dest/store/l2_tips_cache.d.ts +19 -0
  68. package/dest/store/l2_tips_cache.d.ts.map +1 -0
  69. package/dest/store/l2_tips_cache.js +89 -0
  70. package/dest/store/log_store.d.ts +54 -0
  71. package/dest/store/log_store.d.ts.map +1 -0
  72. package/dest/{archiver/kv_archiver_store → store}/log_store.js +146 -91
  73. package/dest/{archiver/kv_archiver_store → store}/message_store.d.ts +1 -1
  74. package/dest/store/message_store.d.ts.map +1 -0
  75. package/dest/{archiver/structs → structs}/data_retrieval.d.ts +1 -1
  76. package/dest/structs/data_retrieval.d.ts.map +1 -0
  77. package/dest/structs/inbox_message.d.ts +15 -0
  78. package/dest/structs/inbox_message.d.ts.map +1 -0
  79. package/dest/{archiver/structs → structs}/published.d.ts +1 -1
  80. package/dest/structs/published.d.ts.map +1 -0
  81. package/dest/test/fake_l1_state.d.ts +193 -0
  82. package/dest/test/fake_l1_state.d.ts.map +1 -0
  83. package/dest/test/fake_l1_state.js +389 -0
  84. package/dest/test/index.d.ts +2 -1
  85. package/dest/test/index.d.ts.map +1 -1
  86. package/dest/test/index.js +4 -1
  87. package/dest/test/mock_archiver.d.ts +2 -2
  88. package/dest/test/mock_archiver.d.ts.map +1 -1
  89. package/dest/test/mock_archiver.js +3 -3
  90. package/dest/test/mock_l1_to_l2_message_source.d.ts +2 -2
  91. package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
  92. package/dest/test/mock_l1_to_l2_message_source.js +12 -3
  93. package/dest/test/mock_l2_block_source.d.ts +39 -17
  94. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  95. package/dest/test/mock_l2_block_source.js +232 -83
  96. package/dest/test/mock_structs.d.ts +78 -3
  97. package/dest/test/mock_structs.d.ts.map +1 -1
  98. package/dest/test/mock_structs.js +140 -7
  99. package/dest/test/noop_l1_archiver.d.ts +23 -0
  100. package/dest/test/noop_l1_archiver.d.ts.map +1 -0
  101. package/dest/test/noop_l1_archiver.js +68 -0
  102. package/package.json +16 -17
  103. package/src/archiver.ts +443 -0
  104. package/src/{archiver/config.ts → config.ts} +13 -2
  105. package/src/{archiver/errors.ts → errors.ts} +12 -0
  106. package/src/factory.ts +140 -11
  107. package/src/index.ts +11 -3
  108. package/src/interfaces.ts +9 -0
  109. package/src/{archiver/l1 → l1}/bin/retrieve-calldata.ts +16 -17
  110. package/src/{archiver/l1 → l1}/calldata_retriever.ts +28 -6
  111. package/src/{archiver/l1 → l1}/data_retrieval.ts +60 -74
  112. package/src/{archiver/l1 → l1}/validate_trace.ts +25 -7
  113. package/src/modules/data_source_base.ts +328 -0
  114. package/src/modules/data_store_updater.ts +448 -0
  115. package/src/{archiver → modules}/instrumentation.ts +33 -70
  116. package/src/modules/l1_synchronizer.ts +932 -0
  117. package/src/{archiver → modules}/validation.ts +11 -6
  118. package/src/{archiver/kv_archiver_store → store}/block_store.ts +293 -100
  119. package/src/{archiver/kv_archiver_store → store}/contract_class_store.ts +12 -8
  120. package/src/{archiver/kv_archiver_store → store}/contract_instance_store.ts +1 -1
  121. package/src/{archiver/kv_archiver_store → store}/kv_archiver_store.ts +273 -40
  122. package/src/store/l2_tips_cache.ts +89 -0
  123. package/src/{archiver/kv_archiver_store → store}/log_store.ts +242 -121
  124. package/src/test/fake_l1_state.ts +607 -0
  125. package/src/test/index.ts +4 -0
  126. package/src/test/mock_archiver.ts +4 -3
  127. package/src/test/mock_l1_to_l2_message_source.ts +10 -4
  128. package/src/test/mock_l2_block_source.ts +276 -90
  129. package/src/test/mock_structs.ts +269 -8
  130. package/src/test/noop_l1_archiver.ts +109 -0
  131. package/dest/archiver/archiver.d.ts +0 -304
  132. package/dest/archiver/archiver.d.ts.map +0 -1
  133. package/dest/archiver/archiver.js +0 -1645
  134. package/dest/archiver/archiver_store.d.ts +0 -308
  135. package/dest/archiver/archiver_store.d.ts.map +0 -1
  136. package/dest/archiver/archiver_store.js +0 -4
  137. package/dest/archiver/archiver_store_test_suite.d.ts +0 -8
  138. package/dest/archiver/archiver_store_test_suite.d.ts.map +0 -1
  139. package/dest/archiver/archiver_store_test_suite.js +0 -2770
  140. package/dest/archiver/config.d.ts.map +0 -1
  141. package/dest/archiver/errors.d.ts +0 -36
  142. package/dest/archiver/errors.d.ts.map +0 -1
  143. package/dest/archiver/index.d.ts +0 -7
  144. package/dest/archiver/index.d.ts.map +0 -1
  145. package/dest/archiver/index.js +0 -4
  146. package/dest/archiver/instrumentation.d.ts +0 -37
  147. package/dest/archiver/instrumentation.d.ts.map +0 -1
  148. package/dest/archiver/kv_archiver_store/block_store.d.ts +0 -157
  149. package/dest/archiver/kv_archiver_store/block_store.d.ts.map +0 -1
  150. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +0 -18
  151. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +0 -1
  152. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +0 -24
  153. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +0 -1
  154. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +0 -158
  155. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +0 -1
  156. package/dest/archiver/kv_archiver_store/kv_archiver_store.js +0 -313
  157. package/dest/archiver/kv_archiver_store/log_store.d.ts +0 -45
  158. package/dest/archiver/kv_archiver_store/log_store.d.ts.map +0 -1
  159. package/dest/archiver/kv_archiver_store/message_store.d.ts.map +0 -1
  160. package/dest/archiver/l1/bin/retrieve-calldata.d.ts.map +0 -1
  161. package/dest/archiver/l1/calldata_retriever.d.ts.map +0 -1
  162. package/dest/archiver/l1/data_retrieval.d.ts +0 -90
  163. package/dest/archiver/l1/data_retrieval.d.ts.map +0 -1
  164. package/dest/archiver/l1/debug_tx.d.ts.map +0 -1
  165. package/dest/archiver/l1/spire_proposer.d.ts.map +0 -1
  166. package/dest/archiver/l1/trace_tx.d.ts.map +0 -1
  167. package/dest/archiver/l1/types.d.ts +0 -12
  168. package/dest/archiver/l1/types.d.ts.map +0 -1
  169. package/dest/archiver/l1/validate_trace.d.ts.map +0 -1
  170. package/dest/archiver/structs/data_retrieval.d.ts.map +0 -1
  171. package/dest/archiver/structs/inbox_message.d.ts +0 -15
  172. package/dest/archiver/structs/inbox_message.d.ts.map +0 -1
  173. package/dest/archiver/structs/published.d.ts.map +0 -1
  174. package/dest/archiver/validation.d.ts +0 -17
  175. package/dest/archiver/validation.d.ts.map +0 -1
  176. package/dest/rpc/index.d.ts +0 -9
  177. package/dest/rpc/index.d.ts.map +0 -1
  178. package/dest/rpc/index.js +0 -15
  179. package/src/archiver/archiver.ts +0 -2157
  180. package/src/archiver/archiver_store.ts +0 -372
  181. package/src/archiver/archiver_store_test_suite.ts +0 -2843
  182. package/src/archiver/index.ts +0 -6
  183. package/src/rpc/index.ts +0 -16
  184. /package/dest/{archiver/l1 → l1}/debug_tx.js +0 -0
  185. /package/dest/{archiver/l1 → l1}/spire_proposer.js +0 -0
  186. /package/dest/{archiver/l1 → l1}/trace_tx.js +0 -0
  187. /package/dest/{archiver/l1 → l1}/types.js +0 -0
  188. /package/dest/{archiver/kv_archiver_store → store}/message_store.js +0 -0
  189. /package/dest/{archiver/structs → structs}/data_retrieval.js +0 -0
  190. /package/dest/{archiver/structs → structs}/inbox_message.js +0 -0
  191. /package/dest/{archiver/structs → structs}/published.js +0 -0
  192. /package/src/{archiver/l1 → l1}/README.md +0 -0
  193. /package/src/{archiver/l1 → l1}/debug_tx.ts +0 -0
  194. /package/src/{archiver/l1 → l1}/spire_proposer.ts +0 -0
  195. /package/src/{archiver/l1 → l1}/trace_tx.ts +0 -0
  196. /package/src/{archiver/l1 → l1}/types.ts +0 -0
  197. /package/src/{archiver/kv_archiver_store → store}/message_store.ts +0 -0
  198. /package/src/{archiver/structs → structs}/data_retrieval.ts +0 -0
  199. /package/src/{archiver/structs → structs}/inbox_message.ts +0 -0
  200. /package/src/{archiver/structs → structs}/published.ts +0 -0
@@ -1,5 +1,5 @@
1
1
  import { INITIAL_CHECKPOINT_NUMBER, INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
2
- import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
2
+ import { BlockNumber, CheckpointNumber, IndexWithinCheckpoint, SlotNumber } from '@aztec/foundation/branded-types';
3
3
  import { Fr } from '@aztec/foundation/curves/bn254';
4
4
  import { toArray } from '@aztec/foundation/iterable';
5
5
  import { createLogger } from '@aztec/foundation/log';
@@ -9,16 +9,18 @@ import { isDefined } from '@aztec/foundation/types';
9
9
  import type { AztecAsyncKVStore, AztecAsyncMap, AztecAsyncSingleton, Range } from '@aztec/kv-store';
10
10
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
11
11
  import {
12
+ type BlockData,
13
+ BlockHash,
12
14
  Body,
13
15
  CheckpointedL2Block,
14
16
  CommitteeAttestation,
15
- L2BlockHash,
16
- L2BlockNew,
17
- type ValidateBlockResult,
18
- deserializeValidateBlockResult,
19
- serializeValidateBlockResult,
17
+ L2Block,
18
+ type ValidateCheckpointResult,
19
+ deserializeValidateCheckpointResult,
20
+ serializeValidateCheckpointResult,
20
21
  } from '@aztec/stdlib/block';
21
- import { L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
22
+ import { type CheckpointData, L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
23
+ import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
22
24
  import { CheckpointHeader } from '@aztec/stdlib/rollup';
23
25
  import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
24
26
  import {
@@ -27,6 +29,7 @@ import {
27
29
  TxEffect,
28
30
  TxHash,
29
31
  TxReceipt,
32
+ TxStatus,
30
33
  deserializeIndexedTxEffect,
31
34
  serializeIndexedTxEffect,
32
35
  } from '@aztec/stdlib/tx';
@@ -36,6 +39,7 @@ import {
36
39
  BlockIndexNotSequentialError,
37
40
  BlockNotFoundError,
38
41
  BlockNumberNotSequentialError,
42
+ CannotOverwriteCheckpointedBlockError,
39
43
  CheckpointNotFoundError,
40
44
  CheckpointNumberNotConsistentError,
41
45
  CheckpointNumberNotSequentialError,
@@ -58,25 +62,18 @@ type BlockStorage = {
58
62
  type CheckpointStorage = {
59
63
  header: Buffer;
60
64
  archive: Buffer;
65
+ checkpointOutHash: Buffer;
61
66
  checkpointNumber: number;
62
67
  startBlock: number;
63
- numBlocks: number;
68
+ blockCount: number;
64
69
  l1: Buffer;
65
70
  attestations: Buffer[];
66
71
  };
67
72
 
68
- export type CheckpointData = {
69
- checkpointNumber: CheckpointNumber;
70
- header: CheckpointHeader;
71
- archive: AppendOnlyTreeSnapshot;
72
- startBlock: number;
73
- numBlocks: number;
74
- l1: L1PublishedData;
75
- attestations: Buffer[];
76
- };
73
+ export type RemoveCheckpointsResult = { blocksRemoved: L2Block[] | undefined };
77
74
 
78
75
  /**
79
- * LMDB implementation of the ArchiverDataStore interface.
76
+ * LMDB-based block storage for the archiver.
80
77
  */
81
78
  export class BlockStore {
82
79
  /** Map block number to block data */
@@ -85,6 +82,9 @@ export class BlockStore {
85
82
  /** Map checkpoint number to checkpoint data */
86
83
  #checkpoints: AztecAsyncMap<number, CheckpointStorage>;
87
84
 
85
+ /** Map slot number to checkpoint number, for looking up checkpoints by slot range. */
86
+ #slotToCheckpoint: AztecAsyncMap<number, number>;
87
+
88
88
  /** Map block hash to list of tx hashes */
89
89
  #blockTxs: AztecAsyncMap<string, Buffer>;
90
90
 
@@ -111,7 +111,10 @@ export class BlockStore {
111
111
 
112
112
  #log = createLogger('archiver:block_store');
113
113
 
114
- constructor(private db: AztecAsyncKVStore) {
114
+ constructor(
115
+ private db: AztecAsyncKVStore,
116
+ private l1Constants: Pick<L1RollupConstants, 'epochDuration'>,
117
+ ) {
115
118
  this.#blocks = db.openMap('archiver_blocks');
116
119
  this.#blockTxs = db.openMap('archiver_block_txs');
117
120
  this.#txEffects = db.openMap('archiver_tx_effects');
@@ -122,14 +125,29 @@ export class BlockStore {
122
125
  this.#lastProvenCheckpoint = db.openSingleton('archiver_last_proven_l2_checkpoint');
123
126
  this.#pendingChainValidationStatus = db.openSingleton('archiver_pending_chain_validation_status');
124
127
  this.#checkpoints = db.openMap('archiver_checkpoints');
128
+ this.#slotToCheckpoint = db.openMap('archiver_slot_to_checkpoint');
129
+ }
130
+
131
+ /**
132
+ * Computes the finalized block number based on the proven block number.
133
+ * A block is considered finalized when it's 2 epochs behind the proven block.
134
+ * TODO(#13569): Compute proper finalized block number based on L1 finalized block.
135
+ * TODO(palla/mbps): Even the provisional computation is wrong, since it should subtract checkpoints, not blocks
136
+ * @returns The finalized block number.
137
+ */
138
+ async getFinalizedL2BlockNumber(): Promise<BlockNumber> {
139
+ const provenBlockNumber = await this.getProvenBlockNumber();
140
+ return BlockNumber(Math.max(provenBlockNumber - this.l1Constants.epochDuration * 2, 0));
125
141
  }
126
142
 
127
143
  /**
128
- * Append new blocks to the store's list. All blocks must be for the 'current' checkpoint
129
- * @param blocks - The L2 blocks to be added to the store.
144
+ * Append new proposed blocks to the store's list. All blocks must be for the 'current' checkpoint.
145
+ * These are uncheckpointed blocks that have been proposed by the sequencer but not yet included in a checkpoint on L1.
146
+ * For checkpointed blocks (already published to L1), use addCheckpoints() instead.
147
+ * @param blocks - The proposed L2 blocks to be added to the store.
130
148
  * @returns True if the operation is successful.
131
149
  */
132
- async addBlocks(blocks: L2BlockNew[], opts: { force?: boolean } = {}): Promise<boolean> {
150
+ async addProposedBlocks(blocks: L2Block[], opts: { force?: boolean } = {}): Promise<boolean> {
133
151
  if (blocks.length === 0) {
134
152
  return true;
135
153
  }
@@ -145,6 +163,12 @@ export class BlockStore {
145
163
  const previousBlockNumber = await this.getLatestBlockNumber();
146
164
  const previousCheckpointNumber = await this.getLatestCheckpointNumber();
147
165
 
166
+ // Verify we're not overwriting checkpointed blocks
167
+ const lastCheckpointedBlockNumber = await this.getCheckpointedL2BlockNumber();
168
+ if (!opts.force && firstBlockNumber <= lastCheckpointedBlockNumber) {
169
+ throw new CannotOverwriteCheckpointedBlockError(firstBlockNumber, lastCheckpointedBlockNumber);
170
+ }
171
+
148
172
  // Check that the first block number is the expected one
149
173
  if (!opts.force && previousBlockNumber !== firstBlockNumber - 1) {
150
174
  throw new InitialBlockNumberNotSequentialError(firstBlockNumber, previousBlockNumber);
@@ -182,7 +206,7 @@ export class BlockStore {
182
206
  }
183
207
 
184
208
  // Iterate over blocks array and insert them, checking that the block numbers and indexes are sequential. Also check they are for the correct checkpoint.
185
- let previousBlock: L2BlockNew | undefined = undefined;
209
+ let previousBlock: L2Block | undefined = undefined;
186
210
  for (const block of blocks) {
187
211
  if (!opts.force && previousBlock) {
188
212
  if (previousBlock.number + 1 !== block.number) {
@@ -241,11 +265,11 @@ export class BlockStore {
241
265
  }
242
266
 
243
267
  let previousBlockNumber: BlockNumber | undefined = undefined;
244
- let previousBlock: L2BlockNew | undefined = undefined;
268
+ let previousBlock: L2Block | undefined = undefined;
245
269
 
246
270
  // If we have a previous checkpoint then we need to get the previous block number
247
271
  if (previousCheckpointData !== undefined) {
248
- previousBlockNumber = BlockNumber(previousCheckpointData.startBlock + previousCheckpointData.numBlocks - 1);
272
+ previousBlockNumber = BlockNumber(previousCheckpointData.startBlock + previousCheckpointData.blockCount - 1);
249
273
  previousBlock = await this.getBlock(previousBlockNumber);
250
274
  if (previousBlock === undefined) {
251
275
  // We should be able to get the required previous block
@@ -309,12 +333,16 @@ export class BlockStore {
309
333
  await this.#checkpoints.set(checkpoint.checkpoint.number, {
310
334
  header: checkpoint.checkpoint.header.toBuffer(),
311
335
  archive: checkpoint.checkpoint.archive.toBuffer(),
336
+ checkpointOutHash: checkpoint.checkpoint.getCheckpointOutHash().toBuffer(),
312
337
  l1: checkpoint.l1.toBuffer(),
313
338
  attestations: checkpoint.attestations.map(attestation => attestation.toBuffer()),
314
339
  checkpointNumber: checkpoint.checkpoint.number,
315
340
  startBlock: checkpoint.checkpoint.blocks[0].number,
316
- numBlocks: checkpoint.checkpoint.blocks.length,
341
+ blockCount: checkpoint.checkpoint.blocks.length,
317
342
  });
343
+
344
+ // Update slot-to-checkpoint index
345
+ await this.#slotToCheckpoint.set(checkpoint.checkpoint.header.slotNumber, checkpoint.checkpoint.number);
318
346
  }
319
347
 
320
348
  await this.#lastSynchedL1Block.set(checkpoints[checkpoints.length - 1].l1.blockNumber);
@@ -322,8 +350,8 @@ export class BlockStore {
322
350
  });
323
351
  }
324
352
 
325
- private async addBlockToDatabase(block: L2BlockNew, checkpointNumber: number, indexWithinCheckpoint: number) {
326
- const blockHash = L2BlockHash.fromField(await block.hash());
353
+ private async addBlockToDatabase(block: L2Block, checkpointNumber: number, indexWithinCheckpoint: number) {
354
+ const blockHash = await block.hash();
327
355
 
328
356
  await this.#blocks.set(block.number, {
329
357
  header: block.header.toBuffer(),
@@ -350,57 +378,71 @@ export class BlockStore {
350
378
  await this.#blockArchiveIndex.set(block.archive.root.toString(), block.number);
351
379
  }
352
380
 
381
+ /** Deletes a block and all associated data (tx effects, indices). */
382
+ private async deleteBlock(block: L2Block): Promise<void> {
383
+ // Delete the block from the main blocks map
384
+ await this.#blocks.delete(block.number);
385
+
386
+ // Delete all tx effects for this block
387
+ await Promise.all(block.body.txEffects.map(tx => this.#txEffects.delete(tx.txHash.toString())));
388
+
389
+ // Delete block txs mapping
390
+ const blockHash = (await block.hash()).toString();
391
+ await this.#blockTxs.delete(blockHash);
392
+
393
+ // Clean up indices
394
+ await this.#blockHashIndex.delete(blockHash);
395
+ await this.#blockArchiveIndex.delete(block.archive.root.toString());
396
+ }
397
+
353
398
  /**
354
- * Unwinds checkpoints from the database
355
- * @param from - The tip of the chain, passed for verification purposes,
356
- * ensuring that we don't end up deleting something we did not intend
357
- * @param checkpointsToUnwind - The number of checkpoints we are to unwind
358
- * @returns True if the operation is successful
399
+ * Removes all checkpoints with checkpoint number > checkpointNumber.
400
+ * Also removes ALL blocks (both checkpointed and uncheckpointed) after the last block of the given checkpoint.
401
+ * @param checkpointNumber - Remove all checkpoints strictly after this one.
359
402
  */
360
- async unwindCheckpoints(from: CheckpointNumber, checkpointsToUnwind: number) {
403
+ async removeCheckpointsAfter(checkpointNumber: CheckpointNumber): Promise<RemoveCheckpointsResult> {
361
404
  return await this.db.transactionAsync(async () => {
362
- const last = await this.getLatestCheckpointNumber();
363
- if (from !== last) {
364
- throw new Error(`Can only unwind checkpoints from the tip (requested ${from} but current tip is ${last})`);
405
+ const latestCheckpointNumber = await this.getLatestCheckpointNumber();
406
+
407
+ if (checkpointNumber >= latestCheckpointNumber) {
408
+ this.#log.warn(`No checkpoints to remove after ${checkpointNumber} (latest is ${latestCheckpointNumber})`);
409
+ return { blocksRemoved: undefined };
365
410
  }
366
411
 
412
+ // If the proven checkpoint is beyond the target, update it
367
413
  const proven = await this.getProvenCheckpointNumber();
368
- if (from - checkpointsToUnwind < proven) {
369
- await this.setProvenCheckpointNumber(CheckpointNumber(from - checkpointsToUnwind));
414
+ if (proven > checkpointNumber) {
415
+ this.#log.warn(`Updating proven checkpoint ${proven} to last valid checkpoint ${checkpointNumber}`);
416
+ await this.setProvenCheckpointNumber(checkpointNumber);
370
417
  }
371
418
 
372
- for (let i = 0; i < checkpointsToUnwind; i++) {
373
- const checkpointNumber = from - i;
374
- const checkpoint = await this.#checkpoints.getAsync(checkpointNumber);
375
-
376
- if (checkpoint === undefined) {
377
- this.#log.warn(`Cannot remove checkpoint ${checkpointNumber} from the store since we don't have it`);
378
- continue;
419
+ // Find the last block number to keep (last block of the given checkpoint, or 0 if no checkpoint)
420
+ let lastBlockToKeep: BlockNumber;
421
+ if (checkpointNumber <= 0) {
422
+ lastBlockToKeep = BlockNumber(INITIAL_L2_BLOCK_NUM - 1);
423
+ } else {
424
+ const targetCheckpoint = await this.#checkpoints.getAsync(checkpointNumber);
425
+ if (!targetCheckpoint) {
426
+ throw new Error(`Target checkpoint ${checkpointNumber} not found in store`);
379
427
  }
380
- await this.#checkpoints.delete(checkpointNumber);
381
- const maxBlock = checkpoint.startBlock + checkpoint.numBlocks - 1;
382
-
383
- for (let blockNumber = checkpoint.startBlock; blockNumber <= maxBlock; blockNumber++) {
384
- const block = await this.getBlock(BlockNumber(blockNumber));
385
-
386
- if (block === undefined) {
387
- this.#log.warn(`Cannot remove block ${blockNumber} from the store since we don't have it`);
388
- continue;
389
- }
390
- await this.#blocks.delete(block.number);
391
- await Promise.all(block.body.txEffects.map(tx => this.#txEffects.delete(tx.txHash.toString())));
392
- const blockHash = (await block.hash()).toString();
393
- await this.#blockTxs.delete(blockHash);
428
+ lastBlockToKeep = BlockNumber(targetCheckpoint.startBlock + targetCheckpoint.blockCount - 1);
429
+ }
394
430
 
395
- // Clean up indices
396
- await this.#blockHashIndex.delete(blockHash);
397
- await this.#blockArchiveIndex.delete(block.archive.root.toString());
431
+ // Remove all blocks after lastBlockToKeep (both checkpointed and uncheckpointed)
432
+ const blocksRemoved = await this.removeBlocksAfter(lastBlockToKeep);
398
433
 
399
- this.#log.debug(`Unwound block ${blockNumber} ${blockHash} for checkpoint ${checkpointNumber}`);
434
+ // Remove all checkpoints after the target
435
+ for (let c = latestCheckpointNumber; c > checkpointNumber; c = CheckpointNumber(c - 1)) {
436
+ const checkpointStorage = await this.#checkpoints.getAsync(c);
437
+ if (checkpointStorage) {
438
+ const slotNumber = CheckpointHeader.fromBuffer(checkpointStorage.header).slotNumber;
439
+ await this.#slotToCheckpoint.delete(slotNumber);
400
440
  }
441
+ await this.#checkpoints.delete(c);
442
+ this.#log.debug(`Removed checkpoint ${c}`);
401
443
  }
402
444
 
403
- return true;
445
+ return { blocksRemoved };
404
446
  });
405
447
  }
406
448
 
@@ -424,20 +466,35 @@ export class BlockStore {
424
466
  return checkpoints;
425
467
  }
426
468
 
427
- private checkpointDataFromCheckpointStorage(checkpointStorage: CheckpointStorage) {
428
- const data: CheckpointData = {
469
+ /** Returns checkpoint data for all checkpoints whose slot falls within the given range (inclusive). */
470
+ async getCheckpointDataForSlotRange(startSlot: SlotNumber, endSlot: SlotNumber): Promise<CheckpointData[]> {
471
+ const result: CheckpointData[] = [];
472
+ for await (const [, checkpointNumber] of this.#slotToCheckpoint.entriesAsync({
473
+ start: startSlot,
474
+ end: endSlot + 1,
475
+ })) {
476
+ const checkpointStorage = await this.#checkpoints.getAsync(checkpointNumber);
477
+ if (checkpointStorage) {
478
+ result.push(this.checkpointDataFromCheckpointStorage(checkpointStorage));
479
+ }
480
+ }
481
+ return result;
482
+ }
483
+
484
+ private checkpointDataFromCheckpointStorage(checkpointStorage: CheckpointStorage): CheckpointData {
485
+ return {
429
486
  header: CheckpointHeader.fromBuffer(checkpointStorage.header),
430
487
  archive: AppendOnlyTreeSnapshot.fromBuffer(checkpointStorage.archive),
488
+ checkpointOutHash: Fr.fromBuffer(checkpointStorage.checkpointOutHash),
431
489
  checkpointNumber: CheckpointNumber(checkpointStorage.checkpointNumber),
432
- startBlock: checkpointStorage.startBlock,
433
- numBlocks: checkpointStorage.numBlocks,
490
+ startBlock: BlockNumber(checkpointStorage.startBlock),
491
+ blockCount: checkpointStorage.blockCount,
434
492
  l1: L1PublishedData.fromBuffer(checkpointStorage.l1),
435
- attestations: checkpointStorage.attestations,
493
+ attestations: checkpointStorage.attestations.map(buf => CommitteeAttestation.fromBuffer(buf)),
436
494
  };
437
- return data;
438
495
  }
439
496
 
440
- async getBlocksForCheckpoint(checkpointNumber: CheckpointNumber): Promise<L2BlockNew[] | undefined> {
497
+ async getBlocksForCheckpoint(checkpointNumber: CheckpointNumber): Promise<L2Block[] | undefined> {
441
498
  const checkpoint = await this.#checkpoints.getAsync(checkpointNumber);
442
499
  if (!checkpoint) {
443
500
  return undefined;
@@ -446,7 +503,7 @@ export class BlockStore {
446
503
  const blocksForCheckpoint = await toArray(
447
504
  this.#blocks.entriesAsync({
448
505
  start: checkpoint.startBlock,
449
- end: checkpoint.startBlock + checkpoint.numBlocks,
506
+ end: checkpoint.startBlock + checkpoint.blockCount,
450
507
  }),
451
508
  );
452
509
 
@@ -454,6 +511,62 @@ export class BlockStore {
454
511
  return converted.filter(isDefined);
455
512
  }
456
513
 
514
+ /**
515
+ * Gets all blocks that have the given slot number.
516
+ * Iterates backwards through blocks for efficiency since we usually query for the last slot.
517
+ * @param slotNumber - The slot number to search for.
518
+ * @returns All blocks with the given slot number, in ascending block number order.
519
+ */
520
+ async getBlocksForSlot(slotNumber: SlotNumber): Promise<L2Block[]> {
521
+ const blocks: L2Block[] = [];
522
+
523
+ // Iterate backwards through all blocks and filter by slot number
524
+ // This is more efficient since we usually query for the most recent slot
525
+ for await (const [blockNumber, blockStorage] of this.#blocks.entriesAsync({ reverse: true })) {
526
+ const block = await this.getBlockFromBlockStorage(blockNumber, blockStorage);
527
+ const blockSlot = block?.header.globalVariables.slotNumber;
528
+ if (block && blockSlot === slotNumber) {
529
+ blocks.push(block);
530
+ } else if (blockSlot && blockSlot < slotNumber) {
531
+ break; // Blocks are stored in slot ascending order, so we can stop searching
532
+ }
533
+ }
534
+
535
+ // Reverse to return blocks in ascending order (block number order)
536
+ return blocks.reverse();
537
+ }
538
+
539
+ /**
540
+ * Removes all blocks with block number > blockNumber.
541
+ * Does not remove any associated checkpoints.
542
+ * @param blockNumber - The block number to remove after.
543
+ * @returns The removed blocks (for event emission).
544
+ */
545
+ async removeBlocksAfter(blockNumber: BlockNumber): Promise<L2Block[]> {
546
+ return await this.db.transactionAsync(async () => {
547
+ const removedBlocks: L2Block[] = [];
548
+
549
+ // Get the latest block number to determine the range
550
+ const latestBlockNumber = await this.getLatestBlockNumber();
551
+
552
+ // Iterate from blockNumber + 1 to latestBlockNumber
553
+ for (let bn = blockNumber + 1; bn <= latestBlockNumber; bn++) {
554
+ const block = await this.getBlock(BlockNumber(bn));
555
+
556
+ if (block === undefined) {
557
+ this.#log.warn(`Cannot remove block ${bn} from the store since we don't have it`);
558
+ continue;
559
+ }
560
+
561
+ removedBlocks.push(block);
562
+ await this.deleteBlock(block);
563
+ this.#log.debug(`Removed block ${bn} ${(await block.hash()).toString()}`);
564
+ }
565
+
566
+ return removedBlocks;
567
+ });
568
+ }
569
+
457
570
  async getProvenBlockNumber(): Promise<BlockNumber> {
458
571
  const provenCheckpointNumber = await this.getProvenCheckpointNumber();
459
572
  if (provenCheckpointNumber === INITIAL_CHECKPOINT_NUMBER - 1) {
@@ -463,7 +576,7 @@ export class BlockStore {
463
576
  if (!checkpointStorage) {
464
577
  throw new CheckpointNotFoundError(provenCheckpointNumber);
465
578
  } else {
466
- return BlockNumber(checkpointStorage.startBlock + checkpointStorage.numBlocks - 1);
579
+ return BlockNumber(checkpointStorage.startBlock + checkpointStorage.blockCount - 1);
467
580
  }
468
581
  }
469
582
 
@@ -503,13 +616,42 @@ export class BlockStore {
503
616
  );
504
617
  }
505
618
 
506
- async getCheckpointedBlockByHash(blockHash: Fr): Promise<CheckpointedL2Block | undefined> {
619
+ /**
620
+ * Gets up to `limit` amount of Checkpointed L2 blocks starting from `from`.
621
+ * @param start - Number of the first block to return (inclusive).
622
+ * @param limit - The number of blocks to return.
623
+ * @returns The requested L2 blocks
624
+ */
625
+ async *getCheckpointedBlocks(start: BlockNumber, limit: number): AsyncIterableIterator<CheckpointedL2Block> {
626
+ const checkpointCache = new Map<CheckpointNumber, CheckpointStorage>();
627
+ for await (const [blockNumber, blockStorage] of this.getBlockStorages(start, limit)) {
628
+ const block = await this.getBlockFromBlockStorage(blockNumber, blockStorage);
629
+ if (block) {
630
+ const checkpoint =
631
+ checkpointCache.get(CheckpointNumber(blockStorage.checkpointNumber)) ??
632
+ (await this.#checkpoints.getAsync(blockStorage.checkpointNumber));
633
+ if (checkpoint) {
634
+ checkpointCache.set(CheckpointNumber(blockStorage.checkpointNumber), checkpoint);
635
+ const checkpointedBlock = new CheckpointedL2Block(
636
+ CheckpointNumber(checkpoint.checkpointNumber),
637
+ block,
638
+ L1PublishedData.fromBuffer(checkpoint.l1),
639
+ checkpoint.attestations.map(buf => CommitteeAttestation.fromBuffer(buf)),
640
+ );
641
+ yield checkpointedBlock;
642
+ }
643
+ }
644
+ }
645
+ }
646
+
647
+ async getCheckpointedBlockByHash(blockHash: BlockHash): Promise<CheckpointedL2Block | undefined> {
507
648
  const blockNumber = await this.#blockHashIndex.getAsync(blockHash.toString());
508
649
  if (blockNumber === undefined) {
509
650
  return undefined;
510
651
  }
511
652
  return this.getCheckpointedBlock(BlockNumber(blockNumber));
512
653
  }
654
+
513
655
  async getCheckpointedBlockByArchive(archive: Fr): Promise<CheckpointedL2Block | undefined> {
514
656
  const blockNumber = await this.#blockArchiveIndex.getAsync(archive.toString());
515
657
  if (blockNumber === undefined) {
@@ -524,7 +666,7 @@ export class BlockStore {
524
666
  * @param limit - The number of blocks to return.
525
667
  * @returns The requested L2 blocks
526
668
  */
527
- async *getBlocks(start: BlockNumber, limit: number): AsyncIterableIterator<L2BlockNew> {
669
+ async *getBlocks(start: BlockNumber, limit: number): AsyncIterableIterator<L2Block> {
528
670
  for await (const [blockNumber, blockStorage] of this.getBlockStorages(start, limit)) {
529
671
  const block = await this.getBlockFromBlockStorage(blockNumber, blockStorage);
530
672
  if (block) {
@@ -533,12 +675,38 @@ export class BlockStore {
533
675
  }
534
676
  }
535
677
 
678
+ /**
679
+ * Gets block metadata (without tx data) by block number.
680
+ * @param blockNumber - The number of the block to return.
681
+ * @returns The requested block data.
682
+ */
683
+ async getBlockData(blockNumber: BlockNumber): Promise<BlockData | undefined> {
684
+ const blockStorage = await this.#blocks.getAsync(blockNumber);
685
+ if (!blockStorage || !blockStorage.header) {
686
+ return undefined;
687
+ }
688
+ return this.getBlockDataFromBlockStorage(blockStorage);
689
+ }
690
+
691
+ /**
692
+ * Gets block metadata (without tx data) by archive root.
693
+ * @param archive - The archive root of the block to return.
694
+ * @returns The requested block data.
695
+ */
696
+ async getBlockDataByArchive(archive: Fr): Promise<BlockData | undefined> {
697
+ const blockNumber = await this.#blockArchiveIndex.getAsync(archive.toString());
698
+ if (blockNumber === undefined) {
699
+ return undefined;
700
+ }
701
+ return this.getBlockData(BlockNumber(blockNumber));
702
+ }
703
+
536
704
  /**
537
705
  * Gets an L2 block.
538
706
  * @param blockNumber - The number of the block to return.
539
707
  * @returns The requested L2 block.
540
708
  */
541
- async getBlock(blockNumber: BlockNumber): Promise<L2BlockNew | undefined> {
709
+ async getBlock(blockNumber: BlockNumber): Promise<L2Block | undefined> {
542
710
  const blockStorage = await this.#blocks.getAsync(blockNumber);
543
711
  if (!blockStorage || !blockStorage.header) {
544
712
  return Promise.resolve(undefined);
@@ -551,7 +719,7 @@ export class BlockStore {
551
719
  * @param blockHash - The hash of the block to return.
552
720
  * @returns The requested L2 block.
553
721
  */
554
- async getBlockByHash(blockHash: L2BlockHash): Promise<L2BlockNew | undefined> {
722
+ async getBlockByHash(blockHash: BlockHash): Promise<L2Block | undefined> {
555
723
  const blockNumber = await this.#blockHashIndex.getAsync(blockHash.toString());
556
724
  if (blockNumber === undefined) {
557
725
  return undefined;
@@ -564,7 +732,7 @@ export class BlockStore {
564
732
  * @param archive - The archive root of the block to return.
565
733
  * @returns The requested L2 block.
566
734
  */
567
- async getBlockByArchive(archive: Fr): Promise<L2BlockNew | undefined> {
735
+ async getBlockByArchive(archive: Fr): Promise<L2Block | undefined> {
568
736
  const blockNumber = await this.#blockArchiveIndex.getAsync(archive.toString());
569
737
  if (blockNumber === undefined) {
570
738
  return undefined;
@@ -577,7 +745,7 @@ export class BlockStore {
577
745
  * @param blockHash - The hash of the block to return.
578
746
  * @returns The requested block header.
579
747
  */
580
- async getBlockHeaderByHash(blockHash: L2BlockHash): Promise<BlockHeader | undefined> {
748
+ async getBlockHeaderByHash(blockHash: BlockHash): Promise<BlockHeader | undefined> {
581
749
  const blockNumber = await this.#blockHashIndex.getAsync(blockHash.toString());
582
750
  if (blockNumber === undefined) {
583
751
  return undefined;
@@ -637,14 +805,24 @@ export class BlockStore {
637
805
  }
638
806
  }
639
807
 
808
+ private getBlockDataFromBlockStorage(blockStorage: BlockStorage): BlockData {
809
+ return {
810
+ header: BlockHeader.fromBuffer(blockStorage.header),
811
+ archive: AppendOnlyTreeSnapshot.fromBuffer(blockStorage.archive),
812
+ blockHash: Fr.fromBuffer(blockStorage.blockHash),
813
+ checkpointNumber: CheckpointNumber(blockStorage.checkpointNumber),
814
+ indexWithinCheckpoint: IndexWithinCheckpoint(blockStorage.indexWithinCheckpoint),
815
+ };
816
+ }
817
+
640
818
  private async getBlockFromBlockStorage(
641
819
  blockNumber: number,
642
820
  blockStorage: BlockStorage,
643
- ): Promise<L2BlockNew | undefined> {
644
- const header = BlockHeader.fromBuffer(blockStorage.header);
645
- const archive = AppendOnlyTreeSnapshot.fromBuffer(blockStorage.archive);
646
- const blockHash = blockStorage.blockHash;
647
- const blockHashString = bufferToHex(blockHash);
821
+ ): Promise<L2Block | undefined> {
822
+ const { header, archive, blockHash, checkpointNumber, indexWithinCheckpoint } =
823
+ this.getBlockDataFromBlockStorage(blockStorage);
824
+ header.setHash(blockHash);
825
+ const blockHashString = bufferToHex(blockStorage.blockHash);
648
826
  const blockTxsBuffer = await this.#blockTxs.getAsync(blockHashString);
649
827
  if (blockTxsBuffer === undefined) {
650
828
  this.#log.warn(`Could not find body for block ${header.globalVariables.blockNumber} ${blockHash}`);
@@ -663,13 +841,7 @@ export class BlockStore {
663
841
  txEffects.push(deserializeIndexedTxEffect(txEffect).data);
664
842
  }
665
843
  const body = new Body(txEffects);
666
- const block = new L2BlockNew(
667
- archive,
668
- header,
669
- body,
670
- CheckpointNumber(blockStorage.checkpointNumber!),
671
- blockStorage.indexWithinCheckpoint,
672
- );
844
+ const block = new L2Block(archive, header, body, checkpointNumber, indexWithinCheckpoint);
673
845
 
674
846
  if (block.number !== blockNumber) {
675
847
  throw new Error(
@@ -705,13 +877,34 @@ export class BlockStore {
705
877
  return undefined;
706
878
  }
707
879
 
880
+ const blockNumber = BlockNumber(txEffect.l2BlockNumber);
881
+
882
+ // Use existing archiver methods to determine finalization level
883
+ const [provenBlockNumber, checkpointedBlockNumber, finalizedBlockNumber] = await Promise.all([
884
+ this.getProvenBlockNumber(),
885
+ this.getCheckpointedL2BlockNumber(),
886
+ this.getFinalizedL2BlockNumber(),
887
+ ]);
888
+
889
+ let status: TxStatus;
890
+ if (blockNumber <= finalizedBlockNumber) {
891
+ status = TxStatus.FINALIZED;
892
+ } else if (blockNumber <= provenBlockNumber) {
893
+ status = TxStatus.PROVEN;
894
+ } else if (blockNumber <= checkpointedBlockNumber) {
895
+ status = TxStatus.CHECKPOINTED;
896
+ } else {
897
+ status = TxStatus.PROPOSED;
898
+ }
899
+
708
900
  return new TxReceipt(
709
901
  txHash,
710
- TxReceipt.statusFromRevertCode(txEffect.data.revertCode),
711
- '',
902
+ status,
903
+ TxReceipt.executionResultFromRevertCode(txEffect.data.revertCode),
904
+ undefined,
712
905
  txEffect.data.transactionFee.toBigInt(),
713
906
  txEffect.l2BlockHash,
714
- BlockNumber(txEffect.l2BlockNumber),
907
+ blockNumber,
715
908
  );
716
909
  }
717
910
 
@@ -748,7 +941,7 @@ export class BlockStore {
748
941
  if (!checkpoint) {
749
942
  return BlockNumber(INITIAL_L2_BLOCK_NUM - 1);
750
943
  }
751
- return BlockNumber(checkpoint.startBlock + checkpoint.numBlocks - 1);
944
+ return BlockNumber(checkpoint.startBlock + checkpoint.blockCount - 1);
752
945
  }
753
946
 
754
947
  async getLatestL2BlockNumber(): Promise<BlockNumber> {
@@ -799,21 +992,21 @@ export class BlockStore {
799
992
  * Gets the pending chain validation status.
800
993
  * @returns The validation status or undefined if not set.
801
994
  */
802
- async getPendingChainValidationStatus(): Promise<ValidateBlockResult | undefined> {
995
+ async getPendingChainValidationStatus(): Promise<ValidateCheckpointResult | undefined> {
803
996
  const buffer = await this.#pendingChainValidationStatus.getAsync();
804
997
  if (!buffer) {
805
998
  return undefined;
806
999
  }
807
- return deserializeValidateBlockResult(buffer);
1000
+ return deserializeValidateCheckpointResult(buffer);
808
1001
  }
809
1002
 
810
1003
  /**
811
1004
  * Sets the pending chain validation status.
812
1005
  * @param status - The validation status to store.
813
1006
  */
814
- async setPendingChainValidationStatus(status: ValidateBlockResult | undefined): Promise<void> {
1007
+ async setPendingChainValidationStatus(status: ValidateCheckpointResult | undefined): Promise<void> {
815
1008
  if (status) {
816
- const buffer = serializeValidateBlockResult(status);
1009
+ const buffer = serializeValidateCheckpointResult(status);
817
1010
  await this.#pendingChainValidationStatus.set(buffer);
818
1011
  } else {
819
1012
  await this.#pendingChainValidationStatus.delete();