@aztec/archiver 3.0.0-canary.a9708bd → 3.0.0-devnet.2-patch.1

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 (127) hide show
  1. package/README.md +27 -6
  2. package/dest/archiver/archiver.d.ts +87 -64
  3. package/dest/archiver/archiver.d.ts.map +1 -1
  4. package/dest/archiver/archiver.js +463 -278
  5. package/dest/archiver/archiver_store.d.ts +46 -28
  6. package/dest/archiver/archiver_store.d.ts.map +1 -1
  7. package/dest/archiver/archiver_store_test_suite.d.ts +1 -1
  8. package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
  9. package/dest/archiver/archiver_store_test_suite.js +316 -143
  10. package/dest/archiver/config.d.ts +6 -23
  11. package/dest/archiver/config.d.ts.map +1 -1
  12. package/dest/archiver/config.js +19 -12
  13. package/dest/archiver/errors.d.ts +1 -1
  14. package/dest/archiver/errors.d.ts.map +1 -1
  15. package/dest/archiver/index.d.ts +1 -1
  16. package/dest/archiver/instrumentation.d.ts +5 -3
  17. package/dest/archiver/instrumentation.d.ts.map +1 -1
  18. package/dest/archiver/instrumentation.js +14 -0
  19. package/dest/archiver/kv_archiver_store/block_store.d.ts +45 -9
  20. package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
  21. package/dest/archiver/kv_archiver_store/block_store.js +99 -12
  22. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +2 -2
  23. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +1 -1
  24. package/dest/archiver/kv_archiver_store/contract_class_store.js +1 -1
  25. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +2 -2
  26. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +1 -1
  27. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +30 -30
  28. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
  29. package/dest/archiver/kv_archiver_store/kv_archiver_store.js +26 -15
  30. package/dest/archiver/kv_archiver_store/log_store.d.ts +3 -10
  31. package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
  32. package/dest/archiver/kv_archiver_store/log_store.js +4 -26
  33. package/dest/archiver/kv_archiver_store/message_store.d.ts +6 -5
  34. package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
  35. package/dest/archiver/kv_archiver_store/message_store.js +15 -14
  36. package/dest/archiver/l1/bin/retrieve-calldata.d.ts +3 -0
  37. package/dest/archiver/l1/bin/retrieve-calldata.d.ts.map +1 -0
  38. package/dest/archiver/l1/bin/retrieve-calldata.js +147 -0
  39. package/dest/archiver/l1/calldata_retriever.d.ts +98 -0
  40. package/dest/archiver/l1/calldata_retriever.d.ts.map +1 -0
  41. package/dest/archiver/l1/calldata_retriever.js +403 -0
  42. package/dest/archiver/l1/data_retrieval.d.ts +87 -0
  43. package/dest/archiver/l1/data_retrieval.d.ts.map +1 -0
  44. package/dest/archiver/{data_retrieval.js → l1/data_retrieval.js} +118 -154
  45. package/dest/archiver/l1/debug_tx.d.ts +19 -0
  46. package/dest/archiver/l1/debug_tx.d.ts.map +1 -0
  47. package/dest/archiver/l1/debug_tx.js +73 -0
  48. package/dest/archiver/l1/spire_proposer.d.ts +70 -0
  49. package/dest/archiver/l1/spire_proposer.d.ts.map +1 -0
  50. package/dest/archiver/l1/spire_proposer.js +157 -0
  51. package/dest/archiver/l1/trace_tx.d.ts +97 -0
  52. package/dest/archiver/l1/trace_tx.d.ts.map +1 -0
  53. package/dest/archiver/l1/trace_tx.js +91 -0
  54. package/dest/archiver/l1/types.d.ts +12 -0
  55. package/dest/archiver/l1/types.d.ts.map +1 -0
  56. package/dest/archiver/l1/types.js +3 -0
  57. package/dest/archiver/l1/validate_trace.d.ts +29 -0
  58. package/dest/archiver/l1/validate_trace.d.ts.map +1 -0
  59. package/dest/archiver/l1/validate_trace.js +150 -0
  60. package/dest/archiver/structs/data_retrieval.d.ts +1 -1
  61. package/dest/archiver/structs/inbox_message.d.ts +4 -4
  62. package/dest/archiver/structs/inbox_message.d.ts.map +1 -1
  63. package/dest/archiver/structs/inbox_message.js +6 -5
  64. package/dest/archiver/structs/published.d.ts +3 -2
  65. package/dest/archiver/structs/published.d.ts.map +1 -1
  66. package/dest/archiver/validation.d.ts +10 -4
  67. package/dest/archiver/validation.d.ts.map +1 -1
  68. package/dest/archiver/validation.js +66 -44
  69. package/dest/factory.d.ts +3 -11
  70. package/dest/factory.d.ts.map +1 -1
  71. package/dest/factory.js +5 -17
  72. package/dest/index.d.ts +2 -2
  73. package/dest/index.d.ts.map +1 -1
  74. package/dest/index.js +1 -1
  75. package/dest/rpc/index.d.ts +2 -2
  76. package/dest/test/index.d.ts +1 -1
  77. package/dest/test/mock_archiver.d.ts +16 -8
  78. package/dest/test/mock_archiver.d.ts.map +1 -1
  79. package/dest/test/mock_archiver.js +19 -14
  80. package/dest/test/mock_l1_to_l2_message_source.d.ts +7 -6
  81. package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
  82. package/dest/test/mock_l1_to_l2_message_source.js +10 -9
  83. package/dest/test/mock_l2_block_source.d.ts +24 -20
  84. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  85. package/dest/test/mock_l2_block_source.js +79 -13
  86. package/dest/test/mock_structs.d.ts +3 -2
  87. package/dest/test/mock_structs.d.ts.map +1 -1
  88. package/dest/test/mock_structs.js +9 -8
  89. package/package.json +18 -17
  90. package/src/archiver/archiver.ts +610 -363
  91. package/src/archiver/archiver_store.ts +55 -28
  92. package/src/archiver/archiver_store_test_suite.ts +369 -143
  93. package/src/archiver/config.ts +26 -51
  94. package/src/archiver/instrumentation.ts +19 -2
  95. package/src/archiver/kv_archiver_store/block_store.ts +139 -21
  96. package/src/archiver/kv_archiver_store/contract_class_store.ts +1 -1
  97. package/src/archiver/kv_archiver_store/contract_instance_store.ts +1 -1
  98. package/src/archiver/kv_archiver_store/kv_archiver_store.ts +48 -33
  99. package/src/archiver/kv_archiver_store/log_store.ts +4 -30
  100. package/src/archiver/kv_archiver_store/message_store.ts +21 -18
  101. package/src/archiver/l1/README.md +98 -0
  102. package/src/archiver/l1/bin/retrieve-calldata.ts +182 -0
  103. package/src/archiver/l1/calldata_retriever.ts +531 -0
  104. package/src/archiver/{data_retrieval.ts → l1/data_retrieval.ts} +198 -242
  105. package/src/archiver/l1/debug_tx.ts +99 -0
  106. package/src/archiver/l1/spire_proposer.ts +160 -0
  107. package/src/archiver/l1/trace_tx.ts +128 -0
  108. package/src/archiver/l1/types.ts +13 -0
  109. package/src/archiver/l1/validate_trace.ts +211 -0
  110. package/src/archiver/structs/inbox_message.ts +8 -8
  111. package/src/archiver/structs/published.ts +2 -1
  112. package/src/archiver/validation.ts +86 -32
  113. package/src/factory.ts +6 -26
  114. package/src/index.ts +1 -1
  115. package/src/test/fixtures/debug_traceTransaction-multicall3.json +88 -0
  116. package/src/test/fixtures/debug_traceTransaction-multiplePropose.json +153 -0
  117. package/src/test/fixtures/debug_traceTransaction-proxied.json +122 -0
  118. package/src/test/fixtures/trace_transaction-multicall3.json +65 -0
  119. package/src/test/fixtures/trace_transaction-multiplePropose.json +319 -0
  120. package/src/test/fixtures/trace_transaction-proxied.json +128 -0
  121. package/src/test/fixtures/trace_transaction-randomRevert.json +216 -0
  122. package/src/test/mock_archiver.ts +22 -16
  123. package/src/test/mock_l1_to_l2_message_source.ts +10 -9
  124. package/src/test/mock_l2_block_source.ts +110 -27
  125. package/src/test/mock_structs.ts +10 -9
  126. package/dest/archiver/data_retrieval.d.ts +0 -78
  127. package/dest/archiver/data_retrieval.d.ts.map +0 -1
@@ -1,66 +1,27 @@
1
1
  import { type BlobSinkConfig, blobSinkConfigMapping } from '@aztec/blob-sink/client';
2
+ import { type L1ContractsConfig, l1ContractsConfigMappings } from '@aztec/ethereum/config';
3
+ import { l1ContractAddressesMapping } from '@aztec/ethereum/l1-contract-addresses';
4
+ import { type L1ReaderConfig, l1ReaderConfigMappings } from '@aztec/ethereum/l1-reader';
2
5
  import {
3
- type L1ContractAddresses,
4
- type L1ContractsConfig,
5
- type L1ReaderConfig,
6
- l1ContractAddressesMapping,
7
- l1ContractsConfigMappings,
8
- l1ReaderConfigMappings,
9
- } from '@aztec/ethereum';
10
- import { type ConfigMappingsType, getConfigFromMappings, numberConfigHelper } from '@aztec/foundation/config';
6
+ type ConfigMappingsType,
7
+ booleanConfigHelper,
8
+ getConfigFromMappings,
9
+ numberConfigHelper,
10
+ } from '@aztec/foundation/config';
11
11
  import { type ChainConfig, chainConfigMappings } from '@aztec/stdlib/config';
12
+ import type { ArchiverSpecificConfig } from '@aztec/stdlib/interfaces/server';
12
13
 
13
14
  /**
15
+ * The archiver configuration.
14
16
  * There are 2 polling intervals used in this configuration. The first is the archiver polling interval, archiverPollingIntervalMS.
15
17
  * This is the interval between successive calls to eth_blockNumber via viem.
16
18
  * Results of calls to eth_blockNumber are cached by viem with this cache being updated periodically at the interval specified by viemPollingIntervalMS.
17
19
  * As a result the maximum observed polling time for new blocks will be viemPollingIntervalMS + archiverPollingIntervalMS.
18
20
  */
19
-
20
- /**
21
- * The archiver configuration.
22
- */
23
- export type ArchiverConfig = {
24
- /** URL for an archiver service. If set, will return an archiver client as opposed to starting a new one. */
25
- archiverUrl?: string;
26
-
27
- /** List of URLS for L1 consensus clients */
28
- l1ConsensusHostUrls?: string[];
29
-
30
- /** The polling interval in ms for retrieving new L2 blocks and encrypted logs. */
31
- archiverPollingIntervalMS?: number;
32
-
33
- /** The number of L2 blocks the archiver will attempt to download at a time. */
34
- archiverBatchSize?: number;
35
-
36
- /** The polling interval viem uses in ms */
37
- viemPollingIntervalMS?: number;
38
-
39
- /** The deployed L1 contract addresses */
40
- l1Contracts: L1ContractAddresses;
41
-
42
- /** The max number of logs that can be obtained in 1 "getPublicLogs" call. */
43
- maxLogs?: number;
44
-
45
- /** The maximum possible size of the archiver DB in KB. Overwrites the general dataStoreMapSizeKB. */
46
- archiverStoreMapSizeKb?: number;
47
- } & L1ReaderConfig &
48
- L1ContractsConfig &
49
- BlobSinkConfig &
50
- ChainConfig;
21
+ export type ArchiverConfig = ArchiverSpecificConfig & L1ReaderConfig & L1ContractsConfig & BlobSinkConfig & ChainConfig;
51
22
 
52
23
  export const archiverConfigMappings: ConfigMappingsType<ArchiverConfig> = {
53
24
  ...blobSinkConfigMapping,
54
- archiverUrl: {
55
- env: 'ARCHIVER_URL',
56
- description:
57
- 'URL for an archiver service. If set, will return an archiver client as opposed to starting a new one.',
58
- },
59
- l1ConsensusHostUrls: {
60
- env: 'L1_CONSENSUS_HOST_URLS',
61
- description: 'List of URLS for L1 consensus clients.',
62
- parseEnv: (val: string) => val.split(',').map(url => url.trim().replace(/\/$/, '')),
63
- },
64
25
  archiverPollingIntervalMS: {
65
26
  env: 'ARCHIVER_POLLING_INTERVAL_MS',
66
27
  description: 'The polling interval in ms for retrieving new L2 blocks and encrypted logs.',
@@ -79,7 +40,21 @@ export const archiverConfigMappings: ConfigMappingsType<ArchiverConfig> = {
79
40
  archiverStoreMapSizeKb: {
80
41
  env: 'ARCHIVER_STORE_MAP_SIZE_KB',
81
42
  parseEnv: (val: string | undefined) => (val ? +val : undefined),
82
- description: 'The maximum possible size of the archiver DB in KB. Overwrites the general dataStoreMapSizeKB.',
43
+ description: 'The maximum possible size of the archiver DB in KB. Overwrites the general dataStoreMapSizeKb.',
44
+ },
45
+ skipValidateBlockAttestations: {
46
+ description: 'Whether to skip validating block attestations (use only for testing).',
47
+ ...booleanConfigHelper(false),
48
+ },
49
+ maxAllowedEthClientDriftSeconds: {
50
+ env: 'MAX_ALLOWED_ETH_CLIENT_DRIFT_SECONDS',
51
+ description: 'Maximum allowed drift in seconds between the Ethereum client and current time.',
52
+ ...numberConfigHelper(300),
53
+ },
54
+ ethereumAllowNoDebugHosts: {
55
+ env: 'ETHEREUM_ALLOW_NO_DEBUG_HOSTS',
56
+ description: 'Whether to allow starting the archiver without debug/trace method support on Ethereum hosts',
57
+ ...booleanConfigHelper(true),
83
58
  },
84
59
  ...chainConfigMappings,
85
60
  ...l1ReaderConfigMappings,
@@ -1,5 +1,5 @@
1
1
  import { createLogger } from '@aztec/foundation/log';
2
- import type { L2Block } from '@aztec/stdlib/block';
2
+ import type { L2BlockNew } from '@aztec/stdlib/block';
3
3
  import {
4
4
  Attributes,
5
5
  type Gauge,
@@ -34,6 +34,8 @@ export class ArchiverInstrumentation {
34
34
  private syncDurationPerMessage: Histogram;
35
35
  private syncMessageCount: UpDownCounter;
36
36
 
37
+ private blockProposalTxTargetCount: UpDownCounter;
38
+
37
39
  private log = createLogger('archiver:instrumentation');
38
40
 
39
41
  private constructor(
@@ -114,6 +116,11 @@ export class ArchiverInstrumentation {
114
116
  valueType: ValueType.INT,
115
117
  });
116
118
 
119
+ this.blockProposalTxTargetCount = meter.createUpDownCounter(Metrics.ARCHIVER_BLOCK_PROPOSAL_TX_TARGET_COUNT, {
120
+ description: 'Number of block proposals by tx target',
121
+ valueType: ValueType.INT,
122
+ });
123
+
117
124
  this.dbMetrics = new LmdbMetrics(
118
125
  meter,
119
126
  {
@@ -139,7 +146,7 @@ export class ArchiverInstrumentation {
139
146
  return this.telemetry.isEnabled();
140
147
  }
141
148
 
142
- public processNewBlocks(syncTimePerBlock: number, blocks: L2Block[]) {
149
+ public processNewBlocks(syncTimePerBlock: number, blocks: L2BlockNew[]) {
143
150
  this.syncDurationPerBlock.record(Math.ceil(syncTimePerBlock));
144
151
  this.blockHeight.record(Math.max(...blocks.map(b => b.number)));
145
152
  this.syncBlockCount.add(blocks.length);
@@ -152,6 +159,9 @@ export class ArchiverInstrumentation {
152
159
  }
153
160
 
154
161
  public processNewMessages(count: number, syncPerMessageMs: number) {
162
+ if (count === 0) {
163
+ return;
164
+ }
155
165
  this.syncMessageCount.add(count);
156
166
  this.syncDurationPerMessage.record(Math.ceil(syncPerMessageMs));
157
167
  }
@@ -181,4 +191,11 @@ export class ArchiverInstrumentation {
181
191
  public updateL1BlockHeight(blockNumber: bigint) {
182
192
  this.l1BlockHeight.record(Number(blockNumber));
183
193
  }
194
+
195
+ public recordBlockProposalTxTarget(target: string, usedTrace: boolean) {
196
+ this.blockProposalTxTargetCount.add(1, {
197
+ [Attributes.L1_BLOCK_PROPOSAL_TX_TARGET]: target.toLowerCase(),
198
+ [Attributes.L1_BLOCK_PROPOSAL_USED_TRACE]: usedTrace,
199
+ });
200
+ }
184
201
  }
@@ -1,12 +1,21 @@
1
1
  import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
2
- import { Fr } from '@aztec/foundation/fields';
2
+ import { BlockNumber } from '@aztec/foundation/branded-types';
3
+ import { Fr } from '@aztec/foundation/curves/bn254';
3
4
  import { toArray } from '@aztec/foundation/iterable';
4
5
  import { createLogger } from '@aztec/foundation/log';
5
6
  import { BufferReader } from '@aztec/foundation/serialize';
6
7
  import { bufferToHex } from '@aztec/foundation/string';
7
8
  import type { AztecAsyncKVStore, AztecAsyncMap, AztecAsyncSingleton, Range } from '@aztec/kv-store';
8
9
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
9
- import { Body, CommitteeAttestation, L2Block, L2BlockHash } from '@aztec/stdlib/block';
10
+ import {
11
+ Body,
12
+ CommitteeAttestation,
13
+ L2Block,
14
+ L2BlockHash,
15
+ PublishedL2Block,
16
+ type ValidateBlockResult,
17
+ } from '@aztec/stdlib/block';
18
+ import { L2BlockHeader, deserializeValidateBlockResult, serializeValidateBlockResult } from '@aztec/stdlib/block';
10
19
  import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
11
20
  import {
12
21
  BlockHeader,
@@ -19,7 +28,7 @@ import {
19
28
  } from '@aztec/stdlib/tx';
20
29
 
21
30
  import { BlockNumberNotSequentialError, InitialBlockNumberNotSequentialError } from '../errors.js';
22
- import type { L1PublishedData, PublishedL2Block } from '../structs/published.js';
31
+ import type { L1PublishedData } from '../structs/published.js';
23
32
 
24
33
  export { TxReceipt, type TxEffect, type TxHash } from '@aztec/stdlib/tx';
25
34
 
@@ -52,9 +61,18 @@ export class BlockStore {
52
61
  /** Stores l2 block number of the last proven block */
53
62
  #lastProvenL2Block: AztecAsyncSingleton<number>;
54
63
 
64
+ /** Stores the pending chain validation status */
65
+ #pendingChainValidationStatus: AztecAsyncSingleton<Buffer>;
66
+
55
67
  /** Index mapping a contract's address (as a string) to its location in a block */
56
68
  #contractIndex: AztecAsyncMap<string, BlockIndexValue>;
57
69
 
70
+ /** Index mapping block hash to block number */
71
+ #blockHashIndex: AztecAsyncMap<string, number>;
72
+
73
+ /** Index mapping block archive to block number */
74
+ #blockArchiveIndex: AztecAsyncMap<string, number>;
75
+
58
76
  #log = createLogger('archiver:block_store');
59
77
 
60
78
  constructor(private db: AztecAsyncKVStore) {
@@ -62,8 +80,11 @@ export class BlockStore {
62
80
  this.#blockTxs = db.openMap('archiver_block_txs');
63
81
  this.#txEffects = db.openMap('archiver_tx_effects');
64
82
  this.#contractIndex = db.openMap('archiver_contract_index');
83
+ this.#blockHashIndex = db.openMap('archiver_block_hash_index');
84
+ this.#blockArchiveIndex = db.openMap('archiver_block_archive_index');
65
85
  this.#lastSynchedL1Block = db.openSingleton('archiver_last_synched_l1_block');
66
86
  this.#lastProvenL2Block = db.openSingleton('archiver_last_proven_l2_block');
87
+ this.#pendingChainValidationStatus = db.openSingleton('archiver_pending_chain_validation_status');
67
88
  }
68
89
 
69
90
  /**
@@ -120,6 +141,10 @@ export class BlockStore {
120
141
  blockHash.toString(),
121
142
  Buffer.concat(block.block.body.txEffects.map(tx => tx.txHash.toBuffer())),
122
143
  );
144
+
145
+ // Update indices for block hash and archive
146
+ await this.#blockHashIndex.set(blockHash.toString(), block.block.number);
147
+ await this.#blockArchiveIndex.set(block.block.archive.root.toString(), block.block.number);
123
148
  }
124
149
 
125
150
  await this.#lastSynchedL1Block.set(blocks[blocks.length - 1].l1.blockNumber);
@@ -134,7 +159,7 @@ export class BlockStore {
134
159
  * @param blocksToUnwind - The number of blocks we are to unwind
135
160
  * @returns True if the operation is successful
136
161
  */
137
- async unwindBlocks(from: number, blocksToUnwind: number) {
162
+ async unwindBlocks(from: BlockNumber, blocksToUnwind: number) {
138
163
  return await this.db.transactionAsync(async () => {
139
164
  const last = await this.getSynchedL2BlockNumber();
140
165
  if (from !== last) {
@@ -143,12 +168,12 @@ export class BlockStore {
143
168
 
144
169
  const proven = await this.getProvenL2BlockNumber();
145
170
  if (from - blocksToUnwind < proven) {
146
- await this.setProvenL2BlockNumber(from - blocksToUnwind);
171
+ await this.setProvenL2BlockNumber(BlockNumber(from - blocksToUnwind));
147
172
  }
148
173
 
149
174
  for (let i = 0; i < blocksToUnwind; i++) {
150
175
  const blockNumber = from - i;
151
- const block = await this.getBlock(blockNumber);
176
+ const block = await this.getBlock(BlockNumber(blockNumber));
152
177
 
153
178
  if (block === undefined) {
154
179
  this.#log.warn(`Cannot remove block ${blockNumber} from the store since we don't have it`);
@@ -158,6 +183,11 @@ export class BlockStore {
158
183
  await Promise.all(block.block.body.txEffects.map(tx => this.#txEffects.delete(tx.txHash.toString())));
159
184
  const blockHash = (await block.block.hash()).toString();
160
185
  await this.#blockTxs.delete(blockHash);
186
+
187
+ // Clean up indices
188
+ await this.#blockHashIndex.delete(blockHash);
189
+ await this.#blockArchiveIndex.delete(block.block.archive.root.toString());
190
+
161
191
  this.#log.debug(`Unwound block ${blockNumber} ${blockHash}`);
162
192
  }
163
193
 
@@ -171,7 +201,7 @@ export class BlockStore {
171
201
  * @param limit - The number of blocks to return.
172
202
  * @returns The requested L2 blocks
173
203
  */
174
- async *getBlocks(start: number, limit: number): AsyncIterableIterator<PublishedL2Block> {
204
+ async *getBlocks(start: BlockNumber, limit: number): AsyncIterableIterator<PublishedL2Block> {
175
205
  for await (const [blockNumber, blockStorage] of this.getBlockStorages(start, limit)) {
176
206
  const block = await this.getBlockFromBlockStorage(blockNumber, blockStorage);
177
207
  if (block) {
@@ -185,7 +215,7 @@ export class BlockStore {
185
215
  * @param blockNumber - The number of the block to return.
186
216
  * @returns The requested L2 block.
187
217
  */
188
- async getBlock(blockNumber: number): Promise<PublishedL2Block | undefined> {
218
+ async getBlock(blockNumber: BlockNumber): Promise<PublishedL2Block | undefined> {
189
219
  const blockStorage = await this.#blocks.getAsync(blockNumber);
190
220
  if (!blockStorage || !blockStorage.header) {
191
221
  return Promise.resolve(undefined);
@@ -193,15 +223,75 @@ export class BlockStore {
193
223
  return this.getBlockFromBlockStorage(blockNumber, blockStorage);
194
224
  }
195
225
 
226
+ /**
227
+ * Gets an L2 block by its hash.
228
+ * @param blockHash - The hash of the block to return.
229
+ * @returns The requested L2 block.
230
+ */
231
+ async getBlockByHash(blockHash: L2BlockHash): Promise<PublishedL2Block | undefined> {
232
+ const blockNumber = await this.#blockHashIndex.getAsync(blockHash.toString());
233
+ if (blockNumber === undefined) {
234
+ return undefined;
235
+ }
236
+ return this.getBlock(BlockNumber(blockNumber));
237
+ }
238
+
239
+ /**
240
+ * Gets an L2 block by its archive root.
241
+ * @param archive - The archive root of the block to return.
242
+ * @returns The requested L2 block.
243
+ */
244
+ async getBlockByArchive(archive: Fr): Promise<PublishedL2Block | undefined> {
245
+ const blockNumber = await this.#blockArchiveIndex.getAsync(archive.toString());
246
+ if (blockNumber === undefined) {
247
+ return undefined;
248
+ }
249
+ return this.getBlock(BlockNumber(blockNumber));
250
+ }
251
+
252
+ /**
253
+ * Gets a block header by its hash.
254
+ * @param blockHash - The hash of the block to return.
255
+ * @returns The requested block header.
256
+ */
257
+ async getBlockHeaderByHash(blockHash: L2BlockHash): Promise<BlockHeader | undefined> {
258
+ const blockNumber = await this.#blockHashIndex.getAsync(blockHash.toString());
259
+ if (blockNumber === undefined) {
260
+ return undefined;
261
+ }
262
+ const blockStorage = await this.#blocks.getAsync(blockNumber);
263
+ if (!blockStorage || !blockStorage.header) {
264
+ return undefined;
265
+ }
266
+ return L2BlockHeader.fromBuffer(blockStorage.header).toBlockHeader();
267
+ }
268
+
269
+ /**
270
+ * Gets a block header by its archive root.
271
+ * @param archive - The archive root of the block to return.
272
+ * @returns The requested block header.
273
+ */
274
+ async getBlockHeaderByArchive(archive: Fr): Promise<BlockHeader | undefined> {
275
+ const blockNumber = await this.#blockArchiveIndex.getAsync(archive.toString());
276
+ if (blockNumber === undefined) {
277
+ return undefined;
278
+ }
279
+ const blockStorage = await this.#blocks.getAsync(blockNumber);
280
+ if (!blockStorage || !blockStorage.header) {
281
+ return undefined;
282
+ }
283
+ return L2BlockHeader.fromBuffer(blockStorage.header).toBlockHeader();
284
+ }
285
+
196
286
  /**
197
287
  * Gets the headers for a sequence of L2 blocks.
198
288
  * @param start - Number of the first block to return (inclusive).
199
289
  * @param limit - The number of blocks to return.
200
290
  * @returns The requested L2 block headers
201
291
  */
202
- async *getBlockHeaders(start: number, limit: number): AsyncIterableIterator<BlockHeader> {
292
+ async *getBlockHeaders(start: BlockNumber, limit: number): AsyncIterableIterator<BlockHeader> {
203
293
  for await (const [blockNumber, blockStorage] of this.getBlockStorages(start, limit)) {
204
- const header = BlockHeader.fromBuffer(blockStorage.header);
294
+ const header = L2BlockHeader.fromBuffer(blockStorage.header).toBlockHeader();
205
295
  if (header.getBlockNumber() !== blockNumber) {
206
296
  throw new Error(
207
297
  `Block number mismatch when retrieving block header from archive (expected ${blockNumber} but got ${header.getBlockNumber()})`,
@@ -211,7 +301,7 @@ export class BlockStore {
211
301
  }
212
302
  }
213
303
 
214
- private async *getBlockStorages(start: number, limit: number) {
304
+ private async *getBlockStorages(start: BlockNumber, limit: number) {
215
305
  let expectedBlockNumber = start;
216
306
  for await (const [blockNumber, blockStorage] of this.#blocks.entriesAsync(this.#computeBlockRange(start, limit))) {
217
307
  if (blockNumber !== expectedBlockNumber) {
@@ -224,8 +314,11 @@ export class BlockStore {
224
314
  }
225
315
  }
226
316
 
227
- private async getBlockFromBlockStorage(blockNumber: number, blockStorage: BlockStorage) {
228
- const header = BlockHeader.fromBuffer(blockStorage.header);
317
+ private async getBlockFromBlockStorage(
318
+ blockNumber: number,
319
+ blockStorage: BlockStorage,
320
+ ): Promise<PublishedL2Block | undefined> {
321
+ const header = L2BlockHeader.fromBuffer(blockStorage.header);
229
322
  const archive = AppendOnlyTreeSnapshot.fromBuffer(blockStorage.archive);
230
323
  const blockHash = blockStorage.blockHash;
231
324
  const blockHashString = bufferToHex(blockHash);
@@ -257,7 +350,7 @@ export class BlockStore {
257
350
  );
258
351
  }
259
352
  const attestations = blockStorage.attestations.map(CommitteeAttestation.fromBuffer);
260
- return { block, l1: blockStorage.l1, attestations };
353
+ return PublishedL2Block.fromFields({ block, l1: blockStorage.l1, attestations });
261
354
  }
262
355
 
263
356
  /**
@@ -290,7 +383,7 @@ export class BlockStore {
290
383
  '',
291
384
  txEffect.data.transactionFee.toBigInt(),
292
385
  txEffect.l2BlockHash,
293
- txEffect.l2BlockNumber,
386
+ BlockNumber(txEffect.l2BlockNumber),
294
387
  );
295
388
  }
296
389
 
@@ -321,9 +414,9 @@ export class BlockStore {
321
414
  * Gets the number of the latest L2 block processed.
322
415
  * @returns The number of the latest L2 block processed.
323
416
  */
324
- async getSynchedL2BlockNumber(): Promise<number> {
417
+ async getSynchedL2BlockNumber(): Promise<BlockNumber> {
325
418
  const [lastBlockNumber] = await toArray(this.#blocks.keysAsync({ reverse: true, limit: 1 }));
326
- return typeof lastBlockNumber === 'number' ? lastBlockNumber : INITIAL_L2_BLOCK_NUM - 1;
419
+ return typeof lastBlockNumber === 'number' ? BlockNumber(lastBlockNumber) : BlockNumber(INITIAL_L2_BLOCK_NUM - 1);
327
420
  }
328
421
 
329
422
  /**
@@ -338,19 +431,19 @@ export class BlockStore {
338
431
  return this.#lastSynchedL1Block.set(l1BlockNumber);
339
432
  }
340
433
 
341
- async getProvenL2BlockNumber(): Promise<number> {
434
+ async getProvenL2BlockNumber(): Promise<BlockNumber> {
342
435
  const [latestBlockNumber, provenBlockNumber] = await Promise.all([
343
436
  this.getSynchedL2BlockNumber(),
344
437
  this.#lastProvenL2Block.getAsync(),
345
438
  ]);
346
- return (provenBlockNumber ?? 0) > latestBlockNumber ? latestBlockNumber : (provenBlockNumber ?? 0);
439
+ return (provenBlockNumber ?? 0) > latestBlockNumber ? latestBlockNumber : BlockNumber(provenBlockNumber ?? 0);
347
440
  }
348
441
 
349
- setProvenL2BlockNumber(blockNumber: number) {
442
+ setProvenL2BlockNumber(blockNumber: BlockNumber) {
350
443
  return this.#lastProvenL2Block.set(blockNumber);
351
444
  }
352
445
 
353
- #computeBlockRange(start: number, limit: number): Required<Pick<Range<number>, 'start' | 'limit'>> {
446
+ #computeBlockRange(start: BlockNumber, limit: number): Required<Pick<Range<number>, 'start' | 'limit'>> {
354
447
  if (limit < 1) {
355
448
  throw new Error(`Invalid limit: ${limit}`);
356
449
  }
@@ -361,4 +454,29 @@ export class BlockStore {
361
454
 
362
455
  return { start, limit };
363
456
  }
457
+
458
+ /**
459
+ * Gets the pending chain validation status.
460
+ * @returns The validation status or undefined if not set.
461
+ */
462
+ async getPendingChainValidationStatus(): Promise<ValidateBlockResult | undefined> {
463
+ const buffer = await this.#pendingChainValidationStatus.getAsync();
464
+ if (!buffer) {
465
+ return undefined;
466
+ }
467
+ return deserializeValidateBlockResult(buffer);
468
+ }
469
+
470
+ /**
471
+ * Sets the pending chain validation status.
472
+ * @param status - The validation status to store.
473
+ */
474
+ async setPendingChainValidationStatus(status: ValidateBlockResult | undefined): Promise<void> {
475
+ if (status) {
476
+ const buffer = serializeValidateBlockResult(status);
477
+ await this.#pendingChainValidationStatus.set(buffer);
478
+ } else {
479
+ await this.#pendingChainValidationStatus.delete();
480
+ }
481
+ }
364
482
  }
@@ -1,4 +1,4 @@
1
- import { Fr } from '@aztec/foundation/fields';
1
+ import { Fr } from '@aztec/foundation/curves/bn254';
2
2
  import { toArray } from '@aztec/foundation/iterable';
3
3
  import { BufferReader, numToUInt8, serializeToBuffer } from '@aztec/foundation/serialize';
4
4
  import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
@@ -1,4 +1,4 @@
1
- import type { Fr } from '@aztec/foundation/fields';
1
+ import type { Fr } from '@aztec/foundation/curves/bn254';
2
2
  import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
3
3
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
4
4
  import {
@@ -1,11 +1,12 @@
1
- import type { L1BlockId } from '@aztec/ethereum';
2
- import type { Fr } from '@aztec/foundation/fields';
1
+ import type { L1BlockId } from '@aztec/ethereum/l1-types';
2
+ import type { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
3
+ import type { Fr } from '@aztec/foundation/curves/bn254';
3
4
  import { toArray } from '@aztec/foundation/iterable';
4
5
  import { createLogger } from '@aztec/foundation/log';
5
6
  import type { AztecAsyncKVStore, CustomRange, StoreSize } from '@aztec/kv-store';
6
7
  import { FunctionSelector } from '@aztec/stdlib/abi';
7
8
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
8
- import type { L2Block } from '@aztec/stdlib/block';
9
+ import { type L2Block, L2BlockHash, type ValidateBlockResult } from '@aztec/stdlib/block';
9
10
  import type {
10
11
  ContractClassPublic,
11
12
  ContractDataSource,
@@ -15,7 +16,7 @@ import type {
15
16
  UtilityFunctionWithMembershipProof,
16
17
  } from '@aztec/stdlib/contract';
17
18
  import type { GetContractClassLogsResponse, GetPublicLogsResponse } from '@aztec/stdlib/interfaces/client';
18
- import { type LogFilter, PrivateLog, type TxScopedL2Log } from '@aztec/stdlib/logs';
19
+ import type { LogFilter, TxScopedL2Log } from '@aztec/stdlib/logs';
19
20
  import type { BlockHeader, TxHash, TxReceipt } from '@aztec/stdlib/tx';
20
21
  import type { UInt64 } from '@aztec/stdlib/types';
21
22
 
@@ -30,7 +31,7 @@ import { ContractInstanceStore } from './contract_instance_store.js';
30
31
  import { LogStore } from './log_store.js';
31
32
  import { MessageStore } from './message_store.js';
32
33
 
33
- export const ARCHIVER_DB_VERSION = 3;
34
+ export const ARCHIVER_DB_VERSION = 4;
34
35
  export const MAX_FUNCTION_SIGNATURES = 1000;
35
36
  export const MAX_FUNCTION_NAME_LEN = 256;
36
37
 
@@ -65,7 +66,7 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
65
66
  return this.db.transactionAsync(callback);
66
67
  }
67
68
 
68
- public getBlockNumber(): Promise<number> {
69
+ public getBlockNumber(): Promise<BlockNumber> {
69
70
  return this.getSynchedL2BlockNumber();
70
71
  }
71
72
 
@@ -124,7 +125,7 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
124
125
  async addContractClasses(
125
126
  data: ContractClassPublic[],
126
127
  bytecodeCommitments: Fr[],
127
- blockNumber: number,
128
+ blockNumber: BlockNumber,
128
129
  ): Promise<boolean> {
129
130
  return (
130
131
  await Promise.all(
@@ -133,7 +134,7 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
133
134
  ).every(Boolean);
134
135
  }
135
136
 
136
- async deleteContractClasses(data: ContractClassPublic[], blockNumber: number): Promise<boolean> {
137
+ async deleteContractClasses(data: ContractClassPublic[], blockNumber: BlockNumber): Promise<boolean> {
137
138
  return (await Promise.all(data.map(c => this.#contractClassStore.deleteContractClasses(c, blockNumber)))).every(
138
139
  Boolean,
139
140
  );
@@ -151,13 +152,13 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
151
152
  return this.#contractClassStore.addFunctions(contractClassId, privateFunctions, utilityFunctions);
152
153
  }
153
154
 
154
- async addContractInstances(data: ContractInstanceWithAddress[], blockNumber: number): Promise<boolean> {
155
+ async addContractInstances(data: ContractInstanceWithAddress[], blockNumber: BlockNumber): Promise<boolean> {
155
156
  return (await Promise.all(data.map(c => this.#contractInstanceStore.addContractInstance(c, blockNumber)))).every(
156
157
  Boolean,
157
158
  );
158
159
  }
159
160
 
160
- async deleteContractInstances(data: ContractInstanceWithAddress[], _blockNumber: number): Promise<boolean> {
161
+ async deleteContractInstances(data: ContractInstanceWithAddress[], _blockNumber: BlockNumber): Promise<boolean> {
161
162
  return (await Promise.all(data.map(c => this.#contractInstanceStore.deleteContractInstance(c)))).every(Boolean);
162
163
  }
163
164
 
@@ -196,14 +197,22 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
196
197
  * @param blocksToUnwind - The number of blocks we are to unwind
197
198
  * @returns True if the operation is successful
198
199
  */
199
- unwindBlocks(from: number, blocksToUnwind: number): Promise<boolean> {
200
+ unwindBlocks(from: BlockNumber, blocksToUnwind: number): Promise<boolean> {
200
201
  return this.#blockStore.unwindBlocks(from, blocksToUnwind);
201
202
  }
202
203
 
203
- getPublishedBlock(number: number): Promise<PublishedL2Block | undefined> {
204
+ getPublishedBlock(number: BlockNumber): Promise<PublishedL2Block | undefined> {
204
205
  return this.#blockStore.getBlock(number);
205
206
  }
206
207
 
208
+ getPublishedBlockByHash(blockHash: Fr): Promise<PublishedL2Block | undefined> {
209
+ return this.#blockStore.getBlockByHash(L2BlockHash.fromField(blockHash));
210
+ }
211
+
212
+ getPublishedBlockByArchive(archive: Fr): Promise<PublishedL2Block | undefined> {
213
+ return this.#blockStore.getBlockByArchive(archive);
214
+ }
215
+
207
216
  /**
208
217
  * Gets up to `limit` amount of L2 blocks starting from `from`.
209
218
  *
@@ -211,7 +220,7 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
211
220
  * @param limit - The number of blocks to return.
212
221
  * @returns The requested L2 blocks
213
222
  */
214
- getPublishedBlocks(start: number, limit: number): Promise<PublishedL2Block[]> {
223
+ getPublishedBlocks(start: BlockNumber, limit: number): Promise<PublishedL2Block[]> {
215
224
  return toArray(this.#blockStore.getBlocks(start, limit));
216
225
  }
217
226
 
@@ -222,10 +231,18 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
222
231
  * @param limit - The number of blocks to return.
223
232
  * @returns The requested L2 blocks
224
233
  */
225
- getBlockHeaders(start: number, limit: number): Promise<BlockHeader[]> {
234
+ getBlockHeaders(start: BlockNumber, limit: number): Promise<BlockHeader[]> {
226
235
  return toArray(this.#blockStore.getBlockHeaders(start, limit));
227
236
  }
228
237
 
238
+ getBlockHeaderByHash(blockHash: Fr): Promise<BlockHeader | undefined> {
239
+ return this.#blockStore.getBlockHeaderByHash(L2BlockHash.fromField(blockHash));
240
+ }
241
+
242
+ getBlockHeaderByArchive(archive: Fr): Promise<BlockHeader | undefined> {
243
+ return this.#blockStore.getBlockHeaderByArchive(archive);
244
+ }
245
+
229
246
  /**
230
247
  * Gets a tx effect.
231
248
  * @param txHash - The hash of the tx corresponding to the tx effect.
@@ -283,22 +300,12 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
283
300
  }
284
301
 
285
302
  /**
286
- * Gets L1 to L2 message (to be) included in a given block.
287
- * @param blockNumber - L2 block number to get messages for.
303
+ * Gets L1 to L2 message (to be) included in a given checkpoint.
304
+ * @param checkpointNumber - Checkpoint number to get messages for.
288
305
  * @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found).
289
306
  */
290
- getL1ToL2Messages(blockNumber: number): Promise<Fr[]> {
291
- return this.#messageStore.getL1ToL2Messages(blockNumber);
292
- }
293
-
294
- /**
295
- * Retrieves all private logs from up to `limit` blocks, starting from the block number `from`.
296
- * @param from - The block number from which to begin retrieving logs.
297
- * @param limit - The maximum number of blocks to retrieve logs from.
298
- * @returns An array of private logs from the specified range of blocks.
299
- */
300
- getPrivateLogs(from: number, limit: number): Promise<PrivateLog[]> {
301
- return this.#logStore.getPrivateLogs(from, limit);
307
+ getL1ToL2Messages(checkpointNumber: CheckpointNumber): Promise<Fr[]> {
308
+ return this.#messageStore.getL1ToL2Messages(checkpointNumber);
302
309
  }
303
310
 
304
311
  /**
@@ -346,15 +353,15 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
346
353
  * Gets the number of the latest L2 block processed.
347
354
  * @returns The number of the latest L2 block processed.
348
355
  */
349
- getSynchedL2BlockNumber(): Promise<number> {
356
+ getSynchedL2BlockNumber(): Promise<BlockNumber> {
350
357
  return this.#blockStore.getSynchedL2BlockNumber();
351
358
  }
352
359
 
353
- getProvenL2BlockNumber(): Promise<number> {
360
+ getProvenL2BlockNumber(): Promise<BlockNumber> {
354
361
  return this.#blockStore.getProvenL2BlockNumber();
355
362
  }
356
363
 
357
- async setProvenL2BlockNumber(blockNumber: number) {
364
+ async setProvenL2BlockNumber(blockNumber: BlockNumber) {
358
365
  await this.#blockStore.setProvenL2BlockNumber(blockNumber);
359
366
  }
360
367
 
@@ -384,8 +391,8 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
384
391
  return this.db.estimateSize();
385
392
  }
386
393
 
387
- public rollbackL1ToL2MessagesToL2Block(targetBlockNumber: number): Promise<void> {
388
- return this.#messageStore.rollbackL1ToL2MessagesToL2Block(targetBlockNumber);
394
+ public rollbackL1ToL2MessagesToCheckpoint(targetCheckpointNumber: CheckpointNumber): Promise<void> {
395
+ return this.#messageStore.rollbackL1ToL2MessagesToCheckpoint(targetCheckpointNumber);
389
396
  }
390
397
 
391
398
  public iterateL1ToL2Messages(range: CustomRange<bigint> = {}): AsyncIterableIterator<InboxMessage> {
@@ -395,4 +402,12 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
395
402
  public removeL1ToL2Messages(startIndex: bigint): Promise<void> {
396
403
  return this.#messageStore.removeL1ToL2Messages(startIndex);
397
404
  }
405
+
406
+ public getPendingChainValidationStatus(): Promise<ValidateBlockResult | undefined> {
407
+ return this.#blockStore.getPendingChainValidationStatus();
408
+ }
409
+
410
+ public setPendingChainValidationStatus(status: ValidateBlockResult | undefined): Promise<void> {
411
+ return this.#blockStore.setPendingChainValidationStatus(status);
412
+ }
398
413
  }