@aztec/archiver 0.76.4 → 0.77.0-testnet-ignition.21

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 (91) hide show
  1. package/README.md +1 -1
  2. package/dest/archiver/archiver.d.ts +22 -10
  3. package/dest/archiver/archiver.d.ts.map +1 -1
  4. package/dest/archiver/archiver.js +762 -713
  5. package/dest/archiver/archiver_store.d.ts +20 -7
  6. package/dest/archiver/archiver_store.d.ts.map +1 -1
  7. package/dest/archiver/archiver_store.js +4 -2
  8. package/dest/archiver/archiver_store_test_suite.d.ts +2 -2
  9. package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
  10. package/dest/archiver/archiver_store_test_suite.js +398 -227
  11. package/dest/archiver/config.d.ts +1 -1
  12. package/dest/archiver/config.d.ts.map +1 -1
  13. package/dest/archiver/config.js +10 -12
  14. package/dest/archiver/data_retrieval.d.ts +17 -14
  15. package/dest/archiver/data_retrieval.d.ts.map +1 -1
  16. package/dest/archiver/data_retrieval.js +90 -88
  17. package/dest/archiver/errors.js +1 -2
  18. package/dest/archiver/index.d.ts +1 -1
  19. package/dest/archiver/index.d.ts.map +1 -1
  20. package/dest/archiver/index.js +0 -1
  21. package/dest/archiver/instrumentation.d.ts +3 -1
  22. package/dest/archiver/instrumentation.d.ts.map +1 -1
  23. package/dest/archiver/instrumentation.js +37 -17
  24. package/dest/archiver/kv_archiver_store/block_store.d.ts +5 -3
  25. package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
  26. package/dest/archiver/kv_archiver_store/block_store.js +125 -130
  27. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +2 -1
  28. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +1 -1
  29. package/dest/archiver/kv_archiver_store/contract_class_store.js +45 -37
  30. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +10 -2
  31. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +1 -1
  32. package/dest/archiver/kv_archiver_store/contract_instance_store.js +54 -15
  33. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +16 -9
  34. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
  35. package/dest/archiver/kv_archiver_store/kv_archiver_store.js +143 -160
  36. package/dest/archiver/kv_archiver_store/log_store.d.ts +5 -3
  37. package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
  38. package/dest/archiver/kv_archiver_store/log_store.js +296 -255
  39. package/dest/archiver/kv_archiver_store/message_store.d.ts +3 -3
  40. package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
  41. package/dest/archiver/kv_archiver_store/message_store.js +45 -50
  42. package/dest/archiver/kv_archiver_store/nullifier_store.d.ts +2 -2
  43. package/dest/archiver/kv_archiver_store/nullifier_store.d.ts.map +1 -1
  44. package/dest/archiver/kv_archiver_store/nullifier_store.js +36 -43
  45. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts +2 -2
  46. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts.map +1 -1
  47. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.js +17 -26
  48. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +16 -7
  49. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +1 -1
  50. package/dest/archiver/memory_archiver_store/memory_archiver_store.js +287 -247
  51. package/dest/archiver/structs/data_retrieval.js +5 -2
  52. package/dest/archiver/structs/published.js +1 -2
  53. package/dest/factory.d.ts +20 -6
  54. package/dest/factory.d.ts.map +1 -1
  55. package/dest/factory.js +54 -30
  56. package/dest/index.js +0 -1
  57. package/dest/rpc/index.d.ts +2 -1
  58. package/dest/rpc/index.d.ts.map +1 -1
  59. package/dest/rpc/index.js +8 -4
  60. package/dest/test/index.js +0 -1
  61. package/dest/test/mock_archiver.d.ts +3 -2
  62. package/dest/test/mock_archiver.d.ts.map +1 -1
  63. package/dest/test/mock_archiver.js +8 -13
  64. package/dest/test/mock_l1_to_l2_message_source.d.ts +2 -2
  65. package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
  66. package/dest/test/mock_l1_to_l2_message_source.js +4 -4
  67. package/dest/test/mock_l2_block_source.d.ts +5 -3
  68. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  69. package/dest/test/mock_l2_block_source.js +71 -68
  70. package/package.json +15 -16
  71. package/src/archiver/archiver.ts +149 -89
  72. package/src/archiver/archiver_store.ts +27 -27
  73. package/src/archiver/archiver_store_test_suite.ts +22 -15
  74. package/src/archiver/config.ts +1 -1
  75. package/src/archiver/data_retrieval.ts +32 -44
  76. package/src/archiver/index.ts +1 -1
  77. package/src/archiver/instrumentation.ts +11 -1
  78. package/src/archiver/kv_archiver_store/block_store.ts +10 -4
  79. package/src/archiver/kv_archiver_store/contract_class_store.ts +9 -9
  80. package/src/archiver/kv_archiver_store/contract_instance_store.ts +81 -3
  81. package/src/archiver/kv_archiver_store/kv_archiver_store.ts +44 -29
  82. package/src/archiver/kv_archiver_store/log_store.ts +56 -32
  83. package/src/archiver/kv_archiver_store/message_store.ts +4 -3
  84. package/src/archiver/kv_archiver_store/nullifier_store.ts +3 -2
  85. package/src/archiver/memory_archiver_store/l1_to_l2_message_store.ts +3 -3
  86. package/src/archiver/memory_archiver_store/memory_archiver_store.ts +110 -57
  87. package/src/factory.ts +44 -25
  88. package/src/rpc/index.ts +2 -6
  89. package/src/test/mock_archiver.ts +3 -2
  90. package/src/test/mock_l1_to_l2_message_source.ts +2 -2
  91. package/src/test/mock_l2_block_source.ts +16 -15
@@ -1,29 +1,31 @@
1
1
  import { Blob, BlobDeserializationError } from '@aztec/blob-lib';
2
- import { type BlobSinkClientInterface } from '@aztec/blob-sink/client';
3
- import { Body, InboxLeaf, L2Block } from '@aztec/circuit-types';
4
- import { AppendOnlyTreeSnapshot, BlockHeader, Fr, Proof } from '@aztec/circuits.js';
2
+ import type { BlobSinkClientInterface } from '@aztec/blob-sink/client';
3
+ import type { EpochProofPublicInputArgs, ViemPublicClient } from '@aztec/ethereum';
5
4
  import { asyncPool } from '@aztec/foundation/async-pool';
6
- import { type EthAddress } from '@aztec/foundation/eth-address';
7
- import { type ViemSignature } from '@aztec/foundation/eth-signature';
5
+ import type { EthAddress } from '@aztec/foundation/eth-address';
6
+ import type { ViemSignature } from '@aztec/foundation/eth-signature';
7
+ import { Fr } from '@aztec/foundation/fields';
8
8
  import { type Logger, createLogger } from '@aztec/foundation/log';
9
9
  import { numToUInt32BE } from '@aztec/foundation/serialize';
10
10
  import { ForwarderAbi, type InboxAbi, RollupAbi } from '@aztec/l1-artifacts';
11
+ import { Body, L2Block } from '@aztec/stdlib/block';
12
+ import { InboxLeaf } from '@aztec/stdlib/messaging';
13
+ import { Proof } from '@aztec/stdlib/proofs';
14
+ import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
15
+ import { BlockHeader } from '@aztec/stdlib/tx';
11
16
 
12
17
  import {
13
- type Chain,
14
18
  type GetContractEventsReturnType,
15
19
  type GetContractReturnType,
16
20
  type Hex,
17
- type HttpTransport,
18
- type PublicClient,
19
21
  decodeFunctionData,
20
22
  getAbiItem,
21
23
  hexToBytes,
22
24
  } from 'viem';
23
25
 
24
26
  import { NoBlobBodiesFoundError } from './errors.js';
25
- import { type DataRetrieval } from './structs/data_retrieval.js';
26
- import { type L1Published, type L1PublishedData } from './structs/published.js';
27
+ import type { DataRetrieval } from './structs/data_retrieval.js';
28
+ import type { L1Published, L1PublishedData } from './structs/published.js';
27
29
 
28
30
  /**
29
31
  * Fetches new L2 blocks.
@@ -35,8 +37,8 @@ import { type L1Published, type L1PublishedData } from './structs/published.js';
35
37
  * @returns An array of block; as well as the next eth block to search from.
36
38
  */
37
39
  export async function retrieveBlocksFromRollup(
38
- rollup: GetContractReturnType<typeof RollupAbi, PublicClient<HttpTransport, Chain>>,
39
- publicClient: PublicClient,
40
+ rollup: GetContractReturnType<typeof RollupAbi, ViemPublicClient>,
41
+ publicClient: ViemPublicClient,
40
42
  blobSinkClient: BlobSinkClientInterface,
41
43
  searchStartBlock: bigint,
42
44
  searchEndBlock: bigint,
@@ -76,7 +78,9 @@ export async function retrieveBlocksFromRollup(
76
78
  retrievedBlocks.push(...newBlocks);
77
79
  searchStartBlock = lastLog.blockNumber! + 1n;
78
80
  } while (searchStartBlock <= searchEndBlock);
79
- return retrievedBlocks;
81
+
82
+ // The asyncpool from processL2BlockProposedLogs will not necessarily return the blocks in order, so we sort them before returning.
83
+ return retrievedBlocks.sort((a, b) => Number(a.l1.blockNumber - b.l1.blockNumber));
80
84
  }
81
85
 
82
86
  /**
@@ -87,8 +91,8 @@ export async function retrieveBlocksFromRollup(
87
91
  * @returns - An array blocks.
88
92
  */
89
93
  export async function processL2BlockProposedLogs(
90
- rollup: GetContractReturnType<typeof RollupAbi, PublicClient<HttpTransport, Chain>>,
91
- publicClient: PublicClient,
94
+ rollup: GetContractReturnType<typeof RollupAbi, ViemPublicClient>,
95
+ publicClient: ViemPublicClient,
92
96
  blobSinkClient: BlobSinkClientInterface,
93
97
  logs: GetContractEventsReturnType<typeof RollupAbi, 'L2BlockProposed'>,
94
98
  logger: Logger,
@@ -130,7 +134,7 @@ export async function processL2BlockProposedLogs(
130
134
  return retrievedBlocks;
131
135
  }
132
136
 
133
- export async function getL1BlockTime(publicClient: PublicClient, blockNumber: bigint): Promise<bigint> {
137
+ export async function getL1BlockTime(publicClient: ViemPublicClient, blockNumber: bigint): Promise<bigint> {
134
138
  const block = await publicClient.getBlock({ blockNumber, includeTransactions: false });
135
139
  return block.timestamp;
136
140
  }
@@ -196,7 +200,7 @@ function extractRollupProposeCalldata(forwarderData: Hex, rollupAddress: Hex): H
196
200
  * @returns L2 block from the calldata, deserialized
197
201
  */
198
202
  async function getBlockFromRollupTx(
199
- publicClient: PublicClient,
203
+ publicClient: ViemPublicClient,
200
204
  blobSinkClient: BlobSinkClientInterface,
201
205
  txHash: `0x${string}`,
202
206
  blobHashes: Buffer[], // WORKTODO(md): buffer32?
@@ -216,8 +220,7 @@ async function getBlockFromRollupTx(
216
220
  throw new Error(`Unexpected rollup method called ${rollupFunctionName}`);
217
221
  }
218
222
 
219
- // TODO(#9101): 'bodyHex' will be removed from below
220
- const [decodedArgs, , bodyHex, blobInputs] = rollupArgs! as readonly [
223
+ const [decodedArgs, , blobInputs] = rollupArgs! as readonly [
221
224
  {
222
225
  header: Hex;
223
226
  archive: Hex;
@@ -229,7 +232,6 @@ async function getBlockFromRollupTx(
229
232
  },
230
233
  ViemSignature[],
231
234
  Hex,
232
- Hex,
233
235
  ];
234
236
 
235
237
  const header = BlockHeader.fromBuffer(Buffer.from(hexToBytes(decodedArgs.header)));
@@ -238,8 +240,6 @@ async function getBlockFromRollupTx(
238
240
  throw new NoBlobBodiesFoundError(Number(l2BlockNum));
239
241
  }
240
242
 
241
- // TODO(#9101): Once calldata is removed, we can remove this field encoding and update
242
- // Body.fromBlobFields to accept blob buffers directly
243
243
  let blockFields: Fr[];
244
244
  try {
245
245
  blockFields = Blob.toEncodedFields(blobBodies);
@@ -252,22 +252,10 @@ async function getBlockFromRollupTx(
252
252
  throw err;
253
253
  }
254
254
 
255
- // TODO(#9101): Retreiving the block body from calldata is a temporary soln before we have
256
- // either a beacon chain client or link to some blob store. Web2 is ok because we will
257
- // verify the block body vs the blob as below.
258
- const blockBody = Body.fromBuffer(Buffer.from(hexToBytes(bodyHex)));
259
-
260
- // TODO(#9101): The below reconstruction is currently redundant, but once we extract blobs will be the way to construct blocks.
261
- // The blob source will give us blockFields, and we must construct the body from them:
262
- // TODO(#8954): When logs are refactored into fields, we won't need to inject them here.
263
- const reconstructedBlock = Body.fromBlobFields(blockFields, blockBody.contractClassLogs);
264
-
265
- if (!reconstructedBlock.toBuffer().equals(blockBody.toBuffer())) {
266
- // TODO(#9101): Remove below check (without calldata there will be nothing to check against)
267
- throw new Error(`Block reconstructed from blob fields does not match`);
268
- }
255
+ // The blob source gives us blockFields, and we must construct the body from them:
256
+ const blockBody = Body.fromBlobFields(blockFields);
269
257
 
270
- // TODO(#9101): Once we stop publishing calldata, we will still need the blobCheck below to ensure that the block we are building does correspond to the blob fields
258
+ // TODO: Will this ever throw now that we do not get blocks from calldata at all?
271
259
  const blobCheck = await Blob.getBlobs(blockFields);
272
260
  if (Blob.getEthBlobEvaluationInputs(blobCheck) !== blobInputs) {
273
261
  // NB: We can just check the blobhash here, which is the first 32 bytes of blobInputs
@@ -305,7 +293,7 @@ async function getBlockFromRollupTx(
305
293
  * @returns An array of InboxLeaf and next eth block to search from.
306
294
  */
307
295
  export async function retrieveL1ToL2Messages(
308
- inbox: GetContractReturnType<typeof InboxAbi, PublicClient<HttpTransport, Chain>>,
296
+ inbox: GetContractReturnType<typeof InboxAbi, ViemPublicClient>,
309
297
  searchStartBlock: bigint,
310
298
  searchEndBlock: bigint,
311
299
  ): Promise<DataRetrieval<InboxLeaf>> {
@@ -342,7 +330,7 @@ export async function retrieveL1ToL2Messages(
342
330
 
343
331
  /** Retrieves L2ProofVerified events from the rollup contract. */
344
332
  export async function retrieveL2ProofVerifiedEvents(
345
- publicClient: PublicClient,
333
+ publicClient: ViemPublicClient,
346
334
  rollupAddress: EthAddress,
347
335
  searchStartBlock: bigint,
348
336
  searchEndBlock?: bigint,
@@ -365,7 +353,7 @@ export async function retrieveL2ProofVerifiedEvents(
365
353
 
366
354
  /** Retrieve submitted proofs from the rollup contract */
367
355
  export async function retrieveL2ProofsFromRollup(
368
- publicClient: PublicClient,
356
+ publicClient: ViemPublicClient,
369
357
  rollupAddress: EthAddress,
370
358
  searchStartBlock: bigint,
371
359
  searchEndBlock?: bigint,
@@ -401,7 +389,7 @@ export type SubmitBlockProof = {
401
389
  * @returns L2 block metadata (header and archive) from the calldata, deserialized
402
390
  */
403
391
  export async function getProofFromSubmitProofTx(
404
- publicClient: PublicClient,
392
+ publicClient: ViemPublicClient,
405
393
  txHash: `0x${string}`,
406
394
  expectedProverId: Fr,
407
395
  ): Promise<SubmitBlockProof> {
@@ -418,7 +406,7 @@ export async function getProofFromSubmitProofTx(
418
406
  {
419
407
  start: bigint;
420
408
  end: bigint;
421
- args: readonly [Hex, Hex, Hex, Hex, Hex, Hex, Hex];
409
+ args: EpochProofPublicInputArgs;
422
410
  fees: readonly Hex[];
423
411
  aggregationObject: Hex;
424
412
  proof: Hex;
@@ -426,8 +414,8 @@ export async function getProofFromSubmitProofTx(
426
414
  ];
427
415
 
428
416
  aggregationObject = Buffer.from(hexToBytes(decodedArgs.aggregationObject));
429
- proverId = Fr.fromHexString(decodedArgs.args[6]);
430
- archiveRoot = Fr.fromHexString(decodedArgs.args[1]);
417
+ proverId = Fr.fromHexString(decodedArgs.args.proverId);
418
+ archiveRoot = Fr.fromHexString(decodedArgs.args.endArchive);
431
419
  proof = Proof.fromBuffer(Buffer.from(hexToBytes(decodedArgs.proof)));
432
420
  } else {
433
421
  throw new Error(`Unexpected proof method called ${functionName}`);
@@ -2,6 +2,6 @@ export * from './archiver.js';
2
2
  export * from './config.js';
3
3
  export { type L1Published, type L1PublishedData } from './structs/published.js';
4
4
  export { MemoryArchiverStore } from './memory_archiver_store/memory_archiver_store.js';
5
- export { ArchiverDataStore } from './archiver_store.js';
5
+ export type { ArchiverDataStore } from './archiver_store.js';
6
6
  export { KVArchiverDataStore } from './kv_archiver_store/kv_archiver_store.js';
7
7
  export { ContractInstanceStore } from './kv_archiver_store/contract_instance_store.js';
@@ -1,5 +1,5 @@
1
- import { type L2Block } from '@aztec/circuit-types';
2
1
  import { createLogger } from '@aztec/foundation/log';
2
+ import type { L2Block } from '@aztec/stdlib/block';
3
3
  import {
4
4
  Attributes,
5
5
  type Gauge,
@@ -20,6 +20,7 @@ export class ArchiverInstrumentation {
20
20
  private txCount: UpDownCounter;
21
21
  private syncDuration: Histogram;
22
22
  private l1BlocksSynced: UpDownCounter;
23
+ private l1BlockHeight: Gauge;
23
24
  private proofsSubmittedDelay: Histogram;
24
25
  private proofsSubmittedCount: UpDownCounter;
25
26
  private dbMetrics: LmdbMetrics;
@@ -62,6 +63,11 @@ export class ArchiverInstrumentation {
62
63
  valueType: ValueType.INT,
63
64
  });
64
65
 
66
+ this.l1BlockHeight = meter.createGauge(Metrics.ARCHIVER_L1_BLOCK_HEIGHT, {
67
+ description: 'The height of the latest L1 block processed by the archiver',
68
+ valueType: ValueType.INT,
69
+ });
70
+
65
71
  this.dbMetrics = new LmdbMetrics(
66
72
  meter,
67
73
  {
@@ -119,4 +125,8 @@ export class ArchiverInstrumentation {
119
125
  });
120
126
  }
121
127
  }
128
+
129
+ public updateL1BlockHeight(blockNumber: bigint) {
130
+ this.l1BlockHeight.record(Number(blockNumber));
131
+ }
122
132
  }
@@ -1,10 +1,15 @@
1
- import { Body, type InBlock, L2Block, L2BlockHash, type TxEffect, type TxHash, TxReceipt } from '@aztec/circuit-types';
2
- import { AppendOnlyTreeSnapshot, type AztecAddress, BlockHeader, INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js';
1
+ import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
3
2
  import { toArray } from '@aztec/foundation/iterable';
4
3
  import { createLogger } from '@aztec/foundation/log';
5
4
  import type { AztecAsyncKVStore, AztecAsyncMap, AztecAsyncSingleton, Range } from '@aztec/kv-store';
5
+ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
6
+ import { Body, type InBlock, L2Block, L2BlockHash } from '@aztec/stdlib/block';
7
+ import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
8
+ import { BlockHeader, TxEffect, TxHash, TxReceipt } from '@aztec/stdlib/tx';
6
9
 
7
- import { type L1Published, type L1PublishedData } from '../structs/published.js';
10
+ import type { L1Published, L1PublishedData } from '../structs/published.js';
11
+
12
+ export { type TxEffect, type TxHash, TxReceipt } from '@aztec/stdlib/tx';
8
13
 
9
14
  type BlockIndexValue = [blockNumber: number, index: number];
10
15
 
@@ -101,7 +106,8 @@ export class BlockStore {
101
106
  const block = await this.getBlock(blockNumber);
102
107
 
103
108
  if (block === undefined) {
104
- throw new Error(`Cannot remove block ${blockNumber} from the store, we don't have it`);
109
+ this.#log.warn(`Cannot remove block ${blockNumber} from the store since we don't have it`);
110
+ continue;
105
111
  }
106
112
  await this.#blocks.delete(block.data.number);
107
113
  await Promise.all(block.data.body.txEffects.map(tx => this.#txIndex.delete(tx.txHash.toString())));
@@ -1,15 +1,15 @@
1
- import {
2
- type ContractClassPublic,
3
- type ContractClassPublicWithBlockNumber,
4
- type ExecutablePrivateFunctionWithMembershipProof,
5
- Fr,
6
- FunctionSelector,
7
- type UnconstrainedFunctionWithMembershipProof,
8
- Vector,
9
- } from '@aztec/circuits.js';
1
+ import { Fr } from '@aztec/foundation/fields';
10
2
  import { toArray } from '@aztec/foundation/iterable';
11
3
  import { BufferReader, numToUInt8, serializeToBuffer } from '@aztec/foundation/serialize';
12
4
  import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
5
+ import { FunctionSelector } from '@aztec/stdlib/abi';
6
+ import type {
7
+ ContractClassPublic,
8
+ ContractClassPublicWithBlockNumber,
9
+ ExecutablePrivateFunctionWithMembershipProof,
10
+ UnconstrainedFunctionWithMembershipProof,
11
+ } from '@aztec/stdlib/contract';
12
+ import { Vector } from '@aztec/stdlib/types';
13
13
 
14
14
  /**
15
15
  * LMDB implementation of the ArchiverDataStore interface.
@@ -1,14 +1,25 @@
1
- import { type AztecAddress, type ContractInstanceWithAddress, SerializableContractInstance } from '@aztec/circuits.js';
1
+ import type { Fr } from '@aztec/foundation/fields';
2
2
  import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
3
+ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
4
+ import {
5
+ type ContractInstanceUpdateWithAddress,
6
+ type ContractInstanceWithAddress,
7
+ SerializableContractInstance,
8
+ SerializableContractInstanceUpdate,
9
+ } from '@aztec/stdlib/contract';
10
+
11
+ type ContractInstanceUpdateKey = [string, number] | [string, number, number];
3
12
 
4
13
  /**
5
14
  * LMDB implementation of the ArchiverDataStore interface.
6
15
  */
7
16
  export class ContractInstanceStore {
8
17
  #contractInstances: AztecAsyncMap<string, Buffer>;
18
+ #contractInstanceUpdates: AztecAsyncMap<ContractInstanceUpdateKey, Buffer>;
9
19
 
10
20
  constructor(db: AztecAsyncKVStore) {
11
21
  this.#contractInstances = db.openMap('archiver_contract_instances');
22
+ this.#contractInstanceUpdates = db.openMap('archiver_contract_instance_updates');
12
23
  }
13
24
 
14
25
  addContractInstance(contractInstance: ContractInstanceWithAddress): Promise<void> {
@@ -22,8 +33,75 @@ export class ContractInstanceStore {
22
33
  return this.#contractInstances.delete(contractInstance.address.toString());
23
34
  }
24
35
 
25
- async getContractInstance(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {
36
+ getUpdateKey(contractAddress: AztecAddress, blockNumber: number, logIndex?: number): ContractInstanceUpdateKey {
37
+ if (logIndex === undefined) {
38
+ return [contractAddress.toString(), blockNumber];
39
+ } else {
40
+ return [contractAddress.toString(), blockNumber, logIndex];
41
+ }
42
+ }
43
+
44
+ addContractInstanceUpdate(
45
+ contractInstanceUpdate: ContractInstanceUpdateWithAddress,
46
+ blockNumber: number,
47
+ logIndex: number,
48
+ ): Promise<void> {
49
+ return this.#contractInstanceUpdates.set(
50
+ this.getUpdateKey(contractInstanceUpdate.address, blockNumber, logIndex),
51
+ new SerializableContractInstanceUpdate(contractInstanceUpdate).toBuffer(),
52
+ );
53
+ }
54
+
55
+ deleteContractInstanceUpdate(
56
+ contractInstanceUpdate: ContractInstanceUpdateWithAddress,
57
+ blockNumber: number,
58
+ logIndex: number,
59
+ ): Promise<void> {
60
+ return this.#contractInstanceUpdates.delete(
61
+ this.getUpdateKey(contractInstanceUpdate.address, blockNumber, logIndex),
62
+ );
63
+ }
64
+
65
+ async getCurrentContractInstanceClassId(
66
+ address: AztecAddress,
67
+ blockNumber: number,
68
+ originalClassId: Fr,
69
+ ): Promise<Fr> {
70
+ // We need to find the last update before the given block number
71
+ const queryResult = await this.#contractInstanceUpdates
72
+ .valuesAsync({
73
+ reverse: true,
74
+ end: this.getUpdateKey(address, blockNumber + 1), // No update can match this key since it doesn't have a log index. We want the highest key <= blockNumber
75
+ limit: 1,
76
+ })
77
+ .next();
78
+ if (queryResult.done) {
79
+ return originalClassId;
80
+ }
81
+
82
+ const serializedUpdate = queryResult.value;
83
+ const update = SerializableContractInstanceUpdate.fromBuffer(serializedUpdate);
84
+ if (blockNumber < update.blockOfChange) {
85
+ return update.prevContractClassId.isZero() ? originalClassId : update.prevContractClassId;
86
+ }
87
+ return update.newContractClassId;
88
+ }
89
+
90
+ async getContractInstance(
91
+ address: AztecAddress,
92
+ blockNumber: number,
93
+ ): Promise<ContractInstanceWithAddress | undefined> {
26
94
  const contractInstance = await this.#contractInstances.getAsync(address.toString());
27
- return contractInstance && SerializableContractInstance.fromBuffer(contractInstance).withAddress(address);
95
+ if (!contractInstance) {
96
+ return undefined;
97
+ }
98
+
99
+ const instance = SerializableContractInstance.fromBuffer(contractInstance).withAddress(address);
100
+ instance.currentContractClassId = await this.getCurrentContractInstanceClassId(
101
+ address,
102
+ blockNumber,
103
+ instance.originalContractClassId,
104
+ );
105
+ return instance;
28
106
  }
29
107
  }
@@ -1,32 +1,25 @@
1
- import {
2
- type GetContractClassLogsResponse,
3
- type GetPublicLogsResponse,
4
- type InBlock,
5
- type InboxLeaf,
6
- type L2Block,
7
- type LogFilter,
8
- type TxHash,
9
- type TxReceipt,
10
- type TxScopedL2Log,
11
- } from '@aztec/circuit-types';
12
- import {
13
- type BlockHeader,
14
- type ContractClassPublic,
15
- type ContractInstanceWithAddress,
16
- type ExecutablePrivateFunctionWithMembershipProof,
17
- type Fr,
18
- type PrivateLog,
19
- type UnconstrainedFunctionWithMembershipProof,
20
- } from '@aztec/circuits.js';
21
- import { FunctionSelector } from '@aztec/foundation/abi';
22
- import { type AztecAddress } from '@aztec/foundation/aztec-address';
1
+ import type { Fr } from '@aztec/foundation/fields';
23
2
  import { toArray } from '@aztec/foundation/iterable';
24
3
  import { createLogger } from '@aztec/foundation/log';
25
- import { type AztecAsyncKVStore, type StoreSize } from '@aztec/kv-store';
26
-
27
- import { type ArchiverDataStore, type ArchiverL1SynchPoint } from '../archiver_store.js';
28
- import { type DataRetrieval } from '../structs/data_retrieval.js';
29
- import { type L1Published } from '../structs/published.js';
4
+ import type { AztecAsyncKVStore, StoreSize } from '@aztec/kv-store';
5
+ import { FunctionSelector } from '@aztec/stdlib/abi';
6
+ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
7
+ import type { InBlock, L2Block } from '@aztec/stdlib/block';
8
+ import type {
9
+ ContractClassPublic,
10
+ ContractInstanceUpdateWithAddress,
11
+ ContractInstanceWithAddress,
12
+ ExecutablePrivateFunctionWithMembershipProof,
13
+ UnconstrainedFunctionWithMembershipProof,
14
+ } from '@aztec/stdlib/contract';
15
+ import type { GetContractClassLogsResponse, GetPublicLogsResponse } from '@aztec/stdlib/interfaces/client';
16
+ import { type LogFilter, PrivateLog, type TxScopedL2Log } from '@aztec/stdlib/logs';
17
+ import type { InboxLeaf } from '@aztec/stdlib/messaging';
18
+ import type { BlockHeader, TxHash, TxReceipt } from '@aztec/stdlib/tx';
19
+
20
+ import type { ArchiverDataStore, ArchiverL1SynchPoint } from '../archiver_store.js';
21
+ import type { DataRetrieval } from '../structs/data_retrieval.js';
22
+ import type { L1Published } from '../structs/published.js';
30
23
  import { BlockStore } from './block_store.js';
31
24
  import { ContractClassStore } from './contract_class_store.js';
32
25
  import { ContractInstanceStore } from './contract_instance_store.js';
@@ -83,8 +76,8 @@ export class KVArchiverDataStore implements ArchiverDataStore {
83
76
  return this.#contractClassStore.getContractClassIds();
84
77
  }
85
78
 
86
- getContractInstance(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {
87
- const contract = this.#contractInstanceStore.getContractInstance(address);
79
+ async getContractInstance(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {
80
+ const contract = this.#contractInstanceStore.getContractInstance(address, await this.getSynchedL2BlockNumber());
88
81
  return contract;
89
82
  }
90
83
 
@@ -126,6 +119,28 @@ export class KVArchiverDataStore implements ArchiverDataStore {
126
119
  return (await Promise.all(data.map(c => this.#contractInstanceStore.deleteContractInstance(c)))).every(Boolean);
127
120
  }
128
121
 
122
+ async addContractInstanceUpdates(data: ContractInstanceUpdateWithAddress[], blockNumber: number): Promise<boolean> {
123
+ return (
124
+ await Promise.all(
125
+ data.map((update, logIndex) =>
126
+ this.#contractInstanceStore.addContractInstanceUpdate(update, blockNumber, logIndex),
127
+ ),
128
+ )
129
+ ).every(Boolean);
130
+ }
131
+ async deleteContractInstanceUpdates(
132
+ data: ContractInstanceUpdateWithAddress[],
133
+ blockNumber: number,
134
+ ): Promise<boolean> {
135
+ return (
136
+ await Promise.all(
137
+ data.map((update, logIndex) =>
138
+ this.#contractInstanceStore.deleteContractInstanceUpdate(update, blockNumber, logIndex),
139
+ ),
140
+ )
141
+ ).every(Boolean);
142
+ }
143
+
129
144
  /**
130
145
  * Append new blocks to the store's list.
131
146
  * @param blocks - The L2 blocks to be added to the store and the last processed L1 block.
@@ -1,26 +1,22 @@
1
+ import { INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX, PUBLIC_LOG_DATA_SIZE_IN_FIELDS } from '@aztec/constants';
2
+ import type { Fr } from '@aztec/foundation/fields';
3
+ import { createLogger } from '@aztec/foundation/log';
4
+ import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize';
5
+ import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
6
+ import type { L2Block } from '@aztec/stdlib/block';
7
+ import type { GetContractClassLogsResponse, GetPublicLogsResponse } from '@aztec/stdlib/interfaces/client';
1
8
  import {
2
- ContractClass2BlockL2Logs,
9
+ ContractClassLog,
10
+ ExtendedContractClassLog,
3
11
  ExtendedPublicLog,
4
- ExtendedUnencryptedL2Log,
5
- type GetContractClassLogsResponse,
6
- type GetPublicLogsResponse,
7
- type L2Block,
8
12
  type LogFilter,
9
13
  LogId,
14
+ PrivateLog,
15
+ PublicLog,
10
16
  TxScopedL2Log,
11
- UnencryptedL2Log,
12
- } from '@aztec/circuit-types';
13
- import { type Fr, PrivateLog, PublicLog } from '@aztec/circuits.js';
14
- import {
15
- INITIAL_L2_BLOCK_NUM,
16
- MAX_NOTE_HASHES_PER_TX,
17
- PUBLIC_LOG_DATA_SIZE_IN_FIELDS,
18
- } from '@aztec/circuits.js/constants';
19
- import { createLogger } from '@aztec/foundation/log';
20
- import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize';
21
- import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
17
+ } from '@aztec/stdlib/logs';
22
18
 
23
- import { type BlockStore } from './block_store.js';
19
+ import type { BlockStore } from './block_store.js';
24
20
 
25
21
  /**
26
22
  * A store for logs
@@ -173,8 +169,18 @@ export class LogStore {
173
169
  )
174
170
  .flat();
175
171
 
172
+ const contractClassLogsInBlock = block.body.txEffects
173
+ .map((txEffect, txIndex) =>
174
+ [
175
+ numToUInt32BE(txIndex),
176
+ numToUInt32BE(txEffect.contractClassLogs.length),
177
+ txEffect.contractClassLogs.map(log => log.toBuffer()),
178
+ ].flat(),
179
+ )
180
+ .flat();
181
+
176
182
  await this.#publicLogsByBlock.set(block.number, Buffer.concat(publicLogsInBlock));
177
- await this.#contractClassLogsByBlock.set(block.number, block.body.contractClassLogs.toBuffer());
183
+ await this.#contractClassLogsByBlock.set(block.number, Buffer.concat(contractClassLogsInBlock));
178
184
  }
179
185
 
180
186
  return true;
@@ -345,13 +351,22 @@ export class LogStore {
345
351
  if (typeof blockNumber !== 'number' || typeof txIndex !== 'number') {
346
352
  return { logs: [], maxLogsHit: false };
347
353
  }
348
- const contractClassLogsBuffer = await this.#contractClassLogsByBlock.getAsync(blockNumber);
349
- const contractClassLogsInBlock = contractClassLogsBuffer
350
- ? ContractClass2BlockL2Logs.fromBuffer(contractClassLogsBuffer)
351
- : new ContractClass2BlockL2Logs([]);
352
- const txLogs = contractClassLogsInBlock.txLogs[txIndex].unrollLogs();
354
+ const contractClassLogsBuffer = (await this.#contractClassLogsByBlock.getAsync(blockNumber)) ?? Buffer.alloc(0);
355
+ const contractClassLogsInBlock: [ContractClassLog[]] = [[]];
353
356
 
354
- const logs: ExtendedUnencryptedL2Log[] = [];
357
+ const reader = new BufferReader(contractClassLogsBuffer);
358
+ while (reader.remainingBytes() > 0) {
359
+ const indexOfTx = reader.readNumber();
360
+ const numLogsInTx = reader.readNumber();
361
+ contractClassLogsInBlock[indexOfTx] = [];
362
+ for (let i = 0; i < numLogsInTx; i++) {
363
+ contractClassLogsInBlock[indexOfTx].push(reader.readObject(ContractClassLog));
364
+ }
365
+ }
366
+
367
+ const txLogs = contractClassLogsInBlock[txIndex];
368
+
369
+ const logs: ExtendedContractClassLog[] = [];
355
370
  const maxLogsHit = this.#accumulateLogs(logs, blockNumber, txIndex, txLogs, filter);
356
371
 
357
372
  return { logs, maxLogsHit };
@@ -369,16 +384,25 @@ export class LogStore {
369
384
  };
370
385
  }
371
386
 
372
- const logs: ExtendedUnencryptedL2Log[] = [];
387
+ const logs: ExtendedContractClassLog[] = [];
373
388
 
374
389
  let maxLogsHit = false;
375
390
  loopOverBlocks: for await (const [blockNumber, logBuffer] of this.#contractClassLogsByBlock.entriesAsync({
376
391
  start,
377
392
  end,
378
393
  })) {
379
- const contractClassLogsInBlock = ContractClass2BlockL2Logs.fromBuffer(logBuffer);
380
- for (let txIndex = filter.afterLog?.txIndex ?? 0; txIndex < contractClassLogsInBlock.txLogs.length; txIndex++) {
381
- const txLogs = contractClassLogsInBlock.txLogs[txIndex].unrollLogs();
394
+ const contractClassLogsInBlock: [ContractClassLog[]] = [[]];
395
+ const reader = new BufferReader(logBuffer);
396
+ while (reader.remainingBytes() > 0) {
397
+ const indexOfTx = reader.readNumber();
398
+ const numLogsInTx = reader.readNumber();
399
+ contractClassLogsInBlock[indexOfTx] = [];
400
+ for (let i = 0; i < numLogsInTx; i++) {
401
+ contractClassLogsInBlock[indexOfTx].push(reader.readObject(ContractClassLog));
402
+ }
403
+ }
404
+ for (let txIndex = filter.afterLog?.txIndex ?? 0; txIndex < contractClassLogsInBlock.length; txIndex++) {
405
+ const txLogs = contractClassLogsInBlock[txIndex];
382
406
  maxLogsHit = this.#accumulateLogs(logs, blockNumber, txIndex, txLogs, filter);
383
407
  if (maxLogsHit) {
384
408
  this.#log.debug(`Max logs hit at block ${blockNumber}`);
@@ -391,10 +415,10 @@ export class LogStore {
391
415
  }
392
416
 
393
417
  #accumulateLogs(
394
- results: (ExtendedUnencryptedL2Log | ExtendedPublicLog)[],
418
+ results: (ExtendedContractClassLog | ExtendedPublicLog)[],
395
419
  blockNumber: number,
396
420
  txIndex: number,
397
- txLogs: (UnencryptedL2Log | PublicLog)[],
421
+ txLogs: (ContractClassLog | PublicLog)[],
398
422
  filter: LogFilter,
399
423
  ): boolean {
400
424
  let maxLogsHit = false;
@@ -402,8 +426,8 @@ export class LogStore {
402
426
  for (; logIndex < txLogs.length; logIndex++) {
403
427
  const log = txLogs[logIndex];
404
428
  if (!filter.contractAddress || log.contractAddress.equals(filter.contractAddress)) {
405
- if (log instanceof UnencryptedL2Log) {
406
- results.push(new ExtendedUnencryptedL2Log(new LogId(blockNumber, txIndex, logIndex), log));
429
+ if (log instanceof ContractClassLog) {
430
+ results.push(new ExtendedContractClassLog(new LogId(blockNumber, txIndex, logIndex), log));
407
431
  } else {
408
432
  results.push(new ExtendedPublicLog(new LogId(blockNumber, txIndex, logIndex), log));
409
433
  }
@@ -1,9 +1,10 @@
1
- import { InboxLeaf } from '@aztec/circuit-types';
2
- import { Fr, L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/circuits.js';
1
+ import { L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/constants';
2
+ import { Fr } from '@aztec/foundation/fields';
3
3
  import { createLogger } from '@aztec/foundation/log';
4
4
  import type { AztecAsyncKVStore, AztecAsyncMap, AztecAsyncSingleton } from '@aztec/kv-store';
5
+ import { InboxLeaf } from '@aztec/stdlib/messaging';
5
6
 
6
- import { type DataRetrieval } from '../structs/data_retrieval.js';
7
+ import type { DataRetrieval } from '../structs/data_retrieval.js';
7
8
 
8
9
  /**
9
10
  * LMDB implementation of the ArchiverDataStore interface.
@@ -1,7 +1,8 @@
1
- import { type InBlock, type L2Block } from '@aztec/circuit-types';
2
- import { type Fr, MAX_NULLIFIERS_PER_TX } from '@aztec/circuits.js';
1
+ import { MAX_NULLIFIERS_PER_TX } from '@aztec/constants';
2
+ import type { Fr } from '@aztec/foundation/fields';
3
3
  import { createLogger } from '@aztec/foundation/log';
4
4
  import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
5
+ import type { InBlock, L2Block } from '@aztec/stdlib/block';
5
6
 
6
7
  export class NullifierStore {
7
8
  #nullifiersToBlockNumber: AztecAsyncMap<string, number>;