@aztec/archiver 0.72.1 → 0.74.0

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 (62) hide show
  1. package/dest/archiver/archiver.d.ts +2 -2
  2. package/dest/archiver/archiver.d.ts.map +1 -1
  3. package/dest/archiver/archiver.js +31 -16
  4. package/dest/archiver/archiver_store.d.ts +2 -2
  5. package/dest/archiver/archiver_store.d.ts.map +1 -1
  6. package/dest/archiver/archiver_store_test_suite.d.ts +1 -1
  7. package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
  8. package/dest/archiver/archiver_store_test_suite.js +14 -14
  9. package/dest/archiver/config.d.ts +1 -1
  10. package/dest/archiver/config.d.ts.map +1 -1
  11. package/dest/archiver/config.js +4 -4
  12. package/dest/archiver/data_retrieval.d.ts +3 -2
  13. package/dest/archiver/data_retrieval.d.ts.map +1 -1
  14. package/dest/archiver/data_retrieval.js +83 -16
  15. package/dest/archiver/errors.d.ts +4 -0
  16. package/dest/archiver/errors.d.ts.map +1 -0
  17. package/dest/archiver/errors.js +6 -0
  18. package/dest/archiver/kv_archiver_store/block_store.d.ts +16 -16
  19. package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
  20. package/dest/archiver/kv_archiver_store/block_store.js +53 -53
  21. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +5 -5
  22. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +1 -1
  23. package/dest/archiver/kv_archiver_store/contract_class_store.js +13 -12
  24. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +3 -3
  25. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +1 -1
  26. package/dest/archiver/kv_archiver_store/contract_instance_store.js +3 -3
  27. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +3 -7
  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 +39 -61
  30. package/dest/archiver/kv_archiver_store/log_store.d.ts +5 -5
  31. package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
  32. package/dest/archiver/kv_archiver_store/log_store.js +54 -53
  33. package/dest/archiver/kv_archiver_store/message_store.d.ts +6 -6
  34. package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
  35. package/dest/archiver/kv_archiver_store/message_store.js +16 -16
  36. package/dest/archiver/kv_archiver_store/nullifier_store.d.ts +2 -2
  37. package/dest/archiver/kv_archiver_store/nullifier_store.d.ts.map +1 -1
  38. package/dest/archiver/kv_archiver_store/nullifier_store.js +31 -22
  39. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +2 -2
  40. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +1 -1
  41. package/dest/archiver/memory_archiver_store/memory_archiver_store.js +24 -22
  42. package/dest/factory.js +7 -7
  43. package/dest/test/mock_l2_block_source.d.ts +2 -2
  44. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  45. package/dest/test/mock_l2_block_source.js +12 -9
  46. package/package.json +12 -12
  47. package/src/archiver/archiver.ts +38 -18
  48. package/src/archiver/archiver_store.ts +1 -1
  49. package/src/archiver/archiver_store_test_suite.ts +17 -14
  50. package/src/archiver/config.ts +4 -4
  51. package/src/archiver/data_retrieval.ts +108 -12
  52. package/src/archiver/errors.ts +5 -0
  53. package/src/archiver/kv_archiver_store/block_store.ts +66 -67
  54. package/src/archiver/kv_archiver_store/contract_class_store.ts +17 -15
  55. package/src/archiver/kv_archiver_store/contract_instance_store.ts +5 -5
  56. package/src/archiver/kv_archiver_store/kv_archiver_store.ts +43 -62
  57. package/src/archiver/kv_archiver_store/log_store.ts +79 -71
  58. package/src/archiver/kv_archiver_store/message_store.ts +22 -22
  59. package/src/archiver/kv_archiver_store/nullifier_store.ts +48 -30
  60. package/src/archiver/memory_archiver_store/memory_archiver_store.ts +44 -43
  61. package/src/factory.ts +10 -8
  62. package/src/test/mock_l2_block_source.ts +18 -16
@@ -7,17 +7,18 @@ import {
7
7
  type UnconstrainedFunctionWithMembershipProof,
8
8
  Vector,
9
9
  } from '@aztec/circuits.js';
10
+ import { toArray } from '@aztec/foundation/iterable';
10
11
  import { BufferReader, numToUInt8, serializeToBuffer } from '@aztec/foundation/serialize';
11
- import { type AztecKVStore, type AztecMap } from '@aztec/kv-store';
12
+ import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
12
13
 
13
14
  /**
14
15
  * LMDB implementation of the ArchiverDataStore interface.
15
16
  */
16
17
  export class ContractClassStore {
17
- #contractClasses: AztecMap<string, Buffer>;
18
- #bytecodeCommitments: AztecMap<string, Buffer>;
18
+ #contractClasses: AztecAsyncMap<string, Buffer>;
19
+ #bytecodeCommitments: AztecAsyncMap<string, Buffer>;
19
20
 
20
- constructor(private db: AztecKVStore) {
21
+ constructor(private db: AztecAsyncKVStore) {
21
22
  this.#contractClasses = db.openMap('archiver_contract_classes');
22
23
  this.#bytecodeCommitments = db.openMap('archiver_bytecode_commitments');
23
24
  }
@@ -35,25 +36,25 @@ export class ContractClassStore {
35
36
  }
36
37
 
37
38
  async deleteContractClasses(contractClass: ContractClassPublic, blockNumber: number): Promise<void> {
38
- const restoredContractClass = this.#contractClasses.get(contractClass.id.toString());
39
+ const restoredContractClass = await this.#contractClasses.getAsync(contractClass.id.toString());
39
40
  if (restoredContractClass && deserializeContractClassPublic(restoredContractClass).l2BlockNumber >= blockNumber) {
40
41
  await this.#contractClasses.delete(contractClass.id.toString());
41
42
  await this.#bytecodeCommitments.delete(contractClass.id.toString());
42
43
  }
43
44
  }
44
45
 
45
- getContractClass(id: Fr): ContractClassPublic | undefined {
46
- const contractClass = this.#contractClasses.get(id.toString());
46
+ async getContractClass(id: Fr): Promise<ContractClassPublic | undefined> {
47
+ const contractClass = await this.#contractClasses.getAsync(id.toString());
47
48
  return contractClass && { ...deserializeContractClassPublic(contractClass), id };
48
49
  }
49
50
 
50
- getBytecodeCommitment(id: Fr): Fr | undefined {
51
- const value = this.#bytecodeCommitments.get(id.toString());
51
+ async getBytecodeCommitment(id: Fr): Promise<Fr | undefined> {
52
+ const value = await this.#bytecodeCommitments.getAsync(id.toString());
52
53
  return value === undefined ? undefined : Fr.fromBuffer(value);
53
54
  }
54
55
 
55
- getContractClassIds(): Fr[] {
56
- return Array.from(this.#contractClasses.keys()).map(key => Fr.fromHexString(key));
56
+ async getContractClassIds(): Promise<Fr[]> {
57
+ return (await toArray(this.#contractClasses.keysAsync())).map(key => Fr.fromHexString(key));
57
58
  }
58
59
 
59
60
  async addFunctions(
@@ -61,8 +62,8 @@ export class ContractClassStore {
61
62
  newPrivateFunctions: ExecutablePrivateFunctionWithMembershipProof[],
62
63
  newUnconstrainedFunctions: UnconstrainedFunctionWithMembershipProof[],
63
64
  ): Promise<boolean> {
64
- await this.db.transaction(() => {
65
- const existingClassBuffer = this.#contractClasses.get(contractClassId.toString());
65
+ await this.db.transactionAsync(async () => {
66
+ const existingClassBuffer = await this.#contractClasses.getAsync(contractClassId.toString());
66
67
  if (!existingClassBuffer) {
67
68
  throw new Error(`Unknown contract class ${contractClassId} when adding private functions to store`);
68
69
  }
@@ -83,9 +84,10 @@ export class ContractClassStore {
83
84
  ),
84
85
  ],
85
86
  };
86
- void this.#contractClasses.set(contractClassId.toString(), serializeContractClassPublic(updatedClass));
87
+ await this.#contractClasses.set(contractClassId.toString(), serializeContractClassPublic(updatedClass));
87
88
  });
88
- return Promise.resolve(true);
89
+
90
+ return true;
89
91
  }
90
92
  }
91
93
 
@@ -1,13 +1,13 @@
1
1
  import { type AztecAddress, type ContractInstanceWithAddress, SerializableContractInstance } from '@aztec/circuits.js';
2
- import { type AztecKVStore, type AztecMap } from '@aztec/kv-store';
2
+ import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
3
3
 
4
4
  /**
5
5
  * LMDB implementation of the ArchiverDataStore interface.
6
6
  */
7
7
  export class ContractInstanceStore {
8
- #contractInstances: AztecMap<string, Buffer>;
8
+ #contractInstances: AztecAsyncMap<string, Buffer>;
9
9
 
10
- constructor(db: AztecKVStore) {
10
+ constructor(db: AztecAsyncKVStore) {
11
11
  this.#contractInstances = db.openMap('archiver_contract_instances');
12
12
  }
13
13
 
@@ -22,8 +22,8 @@ export class ContractInstanceStore {
22
22
  return this.#contractInstances.delete(contractInstance.address.toString());
23
23
  }
24
24
 
25
- getContractInstance(address: AztecAddress): ContractInstanceWithAddress | undefined {
26
- const contractInstance = this.#contractInstances.get(address.toString());
25
+ async getContractInstance(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {
26
+ const contractInstance = await this.#contractInstances.getAsync(address.toString());
27
27
  return contractInstance && SerializableContractInstance.fromBuffer(contractInstance).withAddress(address);
28
28
  }
29
29
  }
@@ -20,8 +20,9 @@ import {
20
20
  } from '@aztec/circuits.js';
21
21
  import { FunctionSelector } from '@aztec/foundation/abi';
22
22
  import { type AztecAddress } from '@aztec/foundation/aztec-address';
23
+ import { toArray } from '@aztec/foundation/iterable';
23
24
  import { createLogger } from '@aztec/foundation/log';
24
- import { type AztecKVStore } from '@aztec/kv-store';
25
+ import { type AztecAsyncKVStore, type StoreSize } from '@aztec/kv-store';
25
26
 
26
27
  import { type ArchiverDataStore, type ArchiverL1SynchPoint } from '../archiver_store.js';
27
28
  import { type DataRetrieval } from '../structs/data_retrieval.js';
@@ -47,7 +48,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
47
48
 
48
49
  #log = createLogger('archiver:data-store');
49
50
 
50
- constructor(private db: AztecKVStore, logsMaxPageSize: number = 1000) {
51
+ constructor(private db: AztecAsyncKVStore, logsMaxPageSize: number = 1000) {
51
52
  this.#blockStore = new BlockStore(db);
52
53
  this.#logStore = new LogStore(db, this.#blockStore, logsMaxPageSize);
53
54
  this.#messageStore = new MessageStore(db);
@@ -63,30 +64,28 @@ export class KVArchiverDataStore implements ArchiverDataStore {
63
64
  return Promise.resolve(this.functionNames.get(selector.toString()));
64
65
  }
65
66
 
66
- registerContractFunctionSignatures(_address: AztecAddress, signatures: string[]): Promise<void> {
67
+ async registerContractFunctionSignatures(_address: AztecAddress, signatures: string[]): Promise<void> {
67
68
  for (const sig of signatures) {
68
69
  try {
69
- const selector = FunctionSelector.fromSignature(sig);
70
+ const selector = await FunctionSelector.fromSignature(sig);
70
71
  this.functionNames.set(selector.toString(), sig.slice(0, sig.indexOf('(')));
71
72
  } catch {
72
73
  this.#log.warn(`Failed to parse signature: ${sig}. Ignoring`);
73
74
  }
74
75
  }
75
-
76
- return Promise.resolve();
77
76
  }
78
77
 
79
78
  getContractClass(id: Fr): Promise<ContractClassPublic | undefined> {
80
- return Promise.resolve(this.#contractClassStore.getContractClass(id));
79
+ return this.#contractClassStore.getContractClass(id);
81
80
  }
82
81
 
83
82
  getContractClassIds(): Promise<Fr[]> {
84
- return Promise.resolve(this.#contractClassStore.getContractClassIds());
83
+ return this.#contractClassStore.getContractClassIds();
85
84
  }
86
85
 
87
86
  getContractInstance(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {
88
87
  const contract = this.#contractInstanceStore.getContractInstance(address);
89
- return Promise.resolve(contract);
88
+ return contract;
90
89
  }
91
90
 
92
91
  async addContractClasses(
@@ -108,7 +107,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
108
107
  }
109
108
 
110
109
  getBytecodeCommitment(contractClassId: Fr): Promise<Fr | undefined> {
111
- return Promise.resolve(this.#contractClassStore.getBytecodeCommitment(contractClassId));
110
+ return this.#contractClassStore.getBytecodeCommitment(contractClassId);
112
111
  }
113
112
 
114
113
  addFunctions(
@@ -155,12 +154,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
155
154
  * @returns The requested L2 blocks
156
155
  */
157
156
  getBlocks(start: number, limit: number): Promise<L1Published<L2Block>[]> {
158
- try {
159
- return Promise.resolve(Array.from(this.#blockStore.getBlocks(start, limit)));
160
- } catch (err) {
161
- // this function is sync so if any errors are thrown we need to make sure they're passed on as rejected Promises
162
- return Promise.reject(err);
163
- }
157
+ return toArray(this.#blockStore.getBlocks(start, limit));
164
158
  }
165
159
 
166
160
  /**
@@ -171,12 +165,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
171
165
  * @returns The requested L2 blocks
172
166
  */
173
167
  getBlockHeaders(start: number, limit: number): Promise<BlockHeader[]> {
174
- try {
175
- return Promise.resolve(Array.from(this.#blockStore.getBlockHeaders(start, limit)));
176
- } catch (err) {
177
- // this function is sync so if any errors are thrown we need to make sure they're passed on as rejected Promises
178
- return Promise.reject(err);
179
- }
168
+ return toArray(this.#blockStore.getBlockHeaders(start, limit));
180
169
  }
181
170
 
182
171
  /**
@@ -185,7 +174,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
185
174
  * @returns The requested tx effect (or undefined if not found).
186
175
  */
187
176
  getTxEffect(txHash: TxHash) {
188
- return Promise.resolve(this.#blockStore.getTxEffect(txHash));
177
+ return this.#blockStore.getTxEffect(txHash);
189
178
  }
190
179
 
191
180
  /**
@@ -194,7 +183,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
194
183
  * @returns The requested tx receipt (or undefined if not found).
195
184
  */
196
185
  getSettledTxReceipt(txHash: TxHash): Promise<TxReceipt | undefined> {
197
- return Promise.resolve(this.#blockStore.getSettledTxReceipt(txHash));
186
+ return this.#blockStore.getSettledTxReceipt(txHash);
198
187
  }
199
188
 
200
189
  /**
@@ -228,7 +217,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
228
217
  }
229
218
 
230
219
  getTotalL1ToL2MessageCount(): Promise<bigint> {
231
- return Promise.resolve(this.#messageStore.getTotalL1ToL2MessageCount());
220
+ return this.#messageStore.getTotalL1ToL2MessageCount();
232
221
  }
233
222
 
234
223
  /**
@@ -237,7 +226,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
237
226
  * @returns True if the operation is successful.
238
227
  */
239
228
  addL1ToL2Messages(messages: DataRetrieval<InboxLeaf>): Promise<boolean> {
240
- return Promise.resolve(this.#messageStore.addL1ToL2Messages(messages));
229
+ return this.#messageStore.addL1ToL2Messages(messages);
241
230
  }
242
231
 
243
232
  /**
@@ -246,7 +235,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
246
235
  * @returns The index of the L1 to L2 message in the L1 to L2 message tree (undefined if not found).
247
236
  */
248
237
  getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise<bigint | undefined> {
249
- return Promise.resolve(this.#messageStore.getL1ToL2MessageIndex(l1ToL2Message));
238
+ return this.#messageStore.getL1ToL2MessageIndex(l1ToL2Message);
250
239
  }
251
240
 
252
241
  /**
@@ -255,11 +244,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
255
244
  * @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found).
256
245
  */
257
246
  getL1ToL2Messages(blockNumber: bigint): Promise<Fr[]> {
258
- try {
259
- return Promise.resolve(this.#messageStore.getL1ToL2Messages(blockNumber));
260
- } catch (err) {
261
- return Promise.reject(err);
262
- }
247
+ return this.#messageStore.getL1ToL2Messages(blockNumber);
263
248
  }
264
249
 
265
250
  /**
@@ -269,11 +254,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
269
254
  * @returns An array of private logs from the specified range of blocks.
270
255
  */
271
256
  getPrivateLogs(from: number, limit: number): Promise<PrivateLog[]> {
272
- try {
273
- return Promise.resolve(Array.from(this.#logStore.getPrivateLogs(from, limit)));
274
- } catch (err) {
275
- return Promise.reject(err);
276
- }
257
+ return this.#logStore.getPrivateLogs(from, limit);
277
258
  }
278
259
 
279
260
  /**
@@ -297,7 +278,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
297
278
  */
298
279
  getPublicLogs(filter: LogFilter): Promise<GetPublicLogsResponse> {
299
280
  try {
300
- return Promise.resolve(this.#logStore.getPublicLogs(filter));
281
+ return this.#logStore.getPublicLogs(filter);
301
282
  } catch (err) {
302
283
  return Promise.reject(err);
303
284
  }
@@ -310,7 +291,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
310
291
  */
311
292
  getContractClassLogs(filter: LogFilter): Promise<GetContractClassLogsResponse> {
312
293
  try {
313
- return Promise.resolve(this.#logStore.getContractClassLogs(filter));
294
+ return this.#logStore.getContractClassLogs(filter);
314
295
  } catch (err) {
315
296
  return Promise.reject(err);
316
297
  }
@@ -321,48 +302,48 @@ export class KVArchiverDataStore implements ArchiverDataStore {
321
302
  * @returns The number of the latest L2 block processed.
322
303
  */
323
304
  getSynchedL2BlockNumber(): Promise<number> {
324
- return Promise.resolve(this.#blockStore.getSynchedL2BlockNumber());
305
+ return this.#blockStore.getSynchedL2BlockNumber();
325
306
  }
326
307
 
327
308
  getProvenL2BlockNumber(): Promise<number> {
328
- return Promise.resolve(this.#blockStore.getProvenL2BlockNumber());
309
+ return this.#blockStore.getProvenL2BlockNumber();
329
310
  }
330
311
 
331
312
  getProvenL2EpochNumber(): Promise<number | undefined> {
332
- return Promise.resolve(this.#blockStore.getProvenL2EpochNumber());
313
+ return this.#blockStore.getProvenL2EpochNumber();
333
314
  }
334
315
 
335
- setProvenL2BlockNumber(blockNumber: number) {
336
- this.#blockStore.setProvenL2BlockNumber(blockNumber);
337
- return Promise.resolve();
316
+ async setProvenL2BlockNumber(blockNumber: number) {
317
+ await this.#blockStore.setProvenL2BlockNumber(blockNumber);
338
318
  }
339
319
 
340
- setProvenL2EpochNumber(epochNumber: number) {
341
- this.#blockStore.setProvenL2EpochNumber(epochNumber);
342
- return Promise.resolve();
320
+ async setProvenL2EpochNumber(epochNumber: number) {
321
+ await this.#blockStore.setProvenL2EpochNumber(epochNumber);
343
322
  }
344
323
 
345
- setBlockSynchedL1BlockNumber(l1BlockNumber: bigint) {
346
- this.#blockStore.setSynchedL1BlockNumber(l1BlockNumber);
347
- return Promise.resolve();
324
+ async setBlockSynchedL1BlockNumber(l1BlockNumber: bigint) {
325
+ await this.#blockStore.setSynchedL1BlockNumber(l1BlockNumber);
348
326
  }
349
327
 
350
- setMessageSynchedL1BlockNumber(l1BlockNumber: bigint) {
351
- this.#messageStore.setSynchedL1BlockNumber(l1BlockNumber);
352
- return Promise.resolve();
328
+ async setMessageSynchedL1BlockNumber(l1BlockNumber: bigint) {
329
+ await this.#messageStore.setSynchedL1BlockNumber(l1BlockNumber);
353
330
  }
354
331
 
355
332
  /**
356
333
  * Gets the last L1 block number processed by the archiver
357
334
  */
358
- getSynchPoint(): Promise<ArchiverL1SynchPoint> {
359
- return Promise.resolve({
360
- blocksSynchedTo: this.#blockStore.getSynchedL1BlockNumber(),
361
- messagesSynchedTo: this.#messageStore.getSynchedL1BlockNumber(),
362
- });
363
- }
364
-
365
- public estimateSize(): { mappingSize: number; actualSize: number; numItems: number } {
335
+ async getSynchPoint(): Promise<ArchiverL1SynchPoint> {
336
+ const [blocksSynchedTo, messagesSynchedTo] = await Promise.all([
337
+ this.#blockStore.getSynchedL1BlockNumber(),
338
+ this.#messageStore.getSynchedL1BlockNumber(),
339
+ ]);
340
+ return {
341
+ blocksSynchedTo,
342
+ messagesSynchedTo,
343
+ };
344
+ }
345
+
346
+ public estimateSize(): Promise<StoreSize> {
366
347
  return this.db.estimateSize();
367
348
  }
368
349
  }
@@ -18,7 +18,7 @@ import {
18
18
  } from '@aztec/circuits.js/constants';
19
19
  import { createLogger } from '@aztec/foundation/log';
20
20
  import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize';
21
- import { type AztecKVStore, type AztecMap } from '@aztec/kv-store';
21
+ import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
22
22
 
23
23
  import { type BlockStore } from './block_store.js';
24
24
 
@@ -26,15 +26,15 @@ import { type BlockStore } from './block_store.js';
26
26
  * A store for logs
27
27
  */
28
28
  export class LogStore {
29
- #logsByTag: AztecMap<string, Buffer[]>;
30
- #logTagsByBlock: AztecMap<number, string[]>;
31
- #privateLogsByBlock: AztecMap<number, Buffer>;
32
- #publicLogsByBlock: AztecMap<number, Buffer>;
33
- #contractClassLogsByBlock: AztecMap<number, Buffer>;
29
+ #logsByTag: AztecAsyncMap<string, Buffer[]>;
30
+ #logTagsByBlock: AztecAsyncMap<number, string[]>;
31
+ #privateLogsByBlock: AztecAsyncMap<number, Buffer>;
32
+ #publicLogsByBlock: AztecAsyncMap<number, Buffer>;
33
+ #contractClassLogsByBlock: AztecAsyncMap<number, Buffer>;
34
34
  #logsMaxPageSize: number;
35
35
  #log = createLogger('archiver:log_store');
36
36
 
37
- constructor(private db: AztecKVStore, private blockStore: BlockStore, logsMaxPageSize: number = 1000) {
37
+ constructor(private db: AztecAsyncKVStore, private blockStore: BlockStore, logsMaxPageSize: number = 1000) {
38
38
  this.#logsByTag = db.openMap('archiver_tagged_logs_by_tag');
39
39
  this.#logTagsByBlock = db.openMap('archiver_log_tags_by_block');
40
40
  this.#privateLogsByBlock = db.openMap('archiver_private_logs_by_block');
@@ -79,21 +79,19 @@ export class LogStore {
79
79
  const txHash = txEffect.txHash;
80
80
  const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
81
81
  txEffect.publicLogs.forEach(log => {
82
- // Check that each log stores 3 lengths in its first field. If not, it's not a tagged log:
82
+ // Check that each log stores 2 lengths in its first field. If not, it's not a tagged log:
83
83
  const firstFieldBuf = log.log[0].toBuffer();
84
- if (
85
- !firstFieldBuf.subarray(0, 24).equals(Buffer.alloc(24)) ||
86
- firstFieldBuf[26] !== 0 ||
87
- firstFieldBuf[29] !== 0
88
- ) {
89
- // See parseLogFromPublic - the first field of a tagged log is 8 bytes structured:
90
- // [ publicLen[0], publicLen[1], 0, privateLen[0], privateLen[1], 0, ciphertextLen[0], ciphertextLen[1]]
84
+ // See macros/note/mod/ and see how finalization_log[0] is constructed, to understand this monstrosity. (It wasn't me).
85
+ // Search the codebase for "disgusting encoding" to see other hardcoded instances of this encoding, that you might need to change if you ever find yourself here.
86
+ if (!firstFieldBuf.subarray(0, 27).equals(Buffer.alloc(27)) || firstFieldBuf[29] !== 0) {
87
+ // See parseLogFromPublic - the first field of a tagged log is 5 bytes structured:
88
+ // [ publicLen[0], publicLen[1], 0, privateLen[0], privateLen[1]]
91
89
  this.#log.warn(`Skipping public log with invalid first field: ${log.log[0]}`);
92
90
  return;
93
91
  }
94
92
  // Check that the length values line up with the log contents
95
- const publicValuesLength = firstFieldBuf.subarray(-8).readUint16BE();
96
- const privateValuesLength = firstFieldBuf.subarray(-8).readUint16BE(3);
93
+ const publicValuesLength = firstFieldBuf.subarray(-5).readUint16BE();
94
+ const privateValuesLength = firstFieldBuf.subarray(-5).readUint16BE(3);
97
95
  // Add 1 for the first field holding lengths
98
96
  const totalLogLength = 1 + publicValuesLength + privateValuesLength;
99
97
  // Note that zeroes can be valid log values, so we can only assert that we do not go over the given length
@@ -127,7 +125,7 @@ export class LogStore {
127
125
  * @param blocks - The blocks for which to add the logs.
128
126
  * @returns True if the operation is successful.
129
127
  */
130
- async addLogs(blocks: L2Block[]): Promise<boolean> {
128
+ addLogs(blocks: L2Block[]): Promise<boolean> {
131
129
  const taggedLogsToAdd = blocks
132
130
  .flatMap(block => [this.#extractTaggedLogsFromPrivate(block), this.#extractTaggedLogsFromPublic(block)])
133
131
  .reduce((acc, val) => {
@@ -138,31 +136,32 @@ export class LogStore {
138
136
  return acc;
139
137
  });
140
138
  const tagsToUpdate = Array.from(taggedLogsToAdd.keys());
141
- const currentTaggedLogs = await this.db.transaction(() =>
142
- tagsToUpdate.map(tag => ({ tag, logBuffers: this.#logsByTag.get(tag) })),
143
- );
144
- currentTaggedLogs.forEach(taggedLogBuffer => {
145
- if (taggedLogBuffer.logBuffers && taggedLogBuffer.logBuffers.length > 0) {
146
- taggedLogsToAdd.set(
147
- taggedLogBuffer.tag,
148
- taggedLogBuffer.logBuffers!.concat(taggedLogsToAdd.get(taggedLogBuffer.tag)!),
149
- );
150
- }
151
- });
152
- return this.db.transaction(() => {
153
- blocks.forEach(block => {
139
+
140
+ return this.db.transactionAsync(async () => {
141
+ const currentTaggedLogs = await Promise.all(
142
+ tagsToUpdate.map(async tag => ({ tag, logBuffers: await this.#logsByTag.getAsync(tag) })),
143
+ );
144
+ currentTaggedLogs.forEach(taggedLogBuffer => {
145
+ if (taggedLogBuffer.logBuffers && taggedLogBuffer.logBuffers.length > 0) {
146
+ taggedLogsToAdd.set(
147
+ taggedLogBuffer.tag,
148
+ taggedLogBuffer.logBuffers!.concat(taggedLogsToAdd.get(taggedLogBuffer.tag)!),
149
+ );
150
+ }
151
+ });
152
+ for (const block of blocks) {
154
153
  const tagsInBlock = [];
155
154
  for (const [tag, logs] of taggedLogsToAdd.entries()) {
156
- void this.#logsByTag.set(tag, logs);
155
+ await this.#logsByTag.set(tag, logs);
157
156
  tagsInBlock.push(tag);
158
157
  }
159
- void this.#logTagsByBlock.set(block.number, tagsInBlock);
158
+ await this.#logTagsByBlock.set(block.number, tagsInBlock);
160
159
 
161
160
  const privateLogsInBlock = block.body.txEffects
162
161
  .map(txEffect => txEffect.privateLogs)
163
162
  .flat()
164
163
  .map(log => log.toBuffer());
165
- void this.#privateLogsByBlock.set(block.number, Buffer.concat(privateLogsInBlock));
164
+ await this.#privateLogsByBlock.set(block.number, Buffer.concat(privateLogsInBlock));
166
165
 
167
166
  const publicLogsInBlock = block.body.txEffects
168
167
  .map((txEffect, txIndex) =>
@@ -174,29 +173,36 @@ export class LogStore {
174
173
  )
175
174
  .flat();
176
175
 
177
- void this.#publicLogsByBlock.set(block.number, Buffer.concat(publicLogsInBlock));
178
- void this.#contractClassLogsByBlock.set(block.number, block.body.contractClassLogs.toBuffer());
179
- });
176
+ await this.#publicLogsByBlock.set(block.number, Buffer.concat(publicLogsInBlock));
177
+ await this.#contractClassLogsByBlock.set(block.number, block.body.contractClassLogs.toBuffer());
178
+ }
180
179
 
181
180
  return true;
182
181
  });
183
182
  }
184
183
 
185
- async deleteLogs(blocks: L2Block[]): Promise<boolean> {
186
- const tagsToDelete = await this.db.transaction(() => {
187
- return blocks.flatMap(block => this.#logTagsByBlock.get(block.number)?.map(tag => tag.toString()) ?? []);
188
- });
189
- return this.db.transaction(() => {
190
- blocks.forEach(block => {
191
- void this.#privateLogsByBlock.delete(block.number);
192
- void this.#publicLogsByBlock.delete(block.number);
193
- void this.#logTagsByBlock.delete(block.number);
194
- });
195
-
196
- tagsToDelete.forEach(tag => {
197
- void this.#logsByTag.delete(tag.toString());
198
- });
199
-
184
+ deleteLogs(blocks: L2Block[]): Promise<boolean> {
185
+ return this.db.transactionAsync(async () => {
186
+ const tagsToDelete = (
187
+ await Promise.all(
188
+ blocks.map(async block => {
189
+ const tags = await this.#logTagsByBlock.getAsync(block.number);
190
+ return tags ?? [];
191
+ }),
192
+ )
193
+ ).flat();
194
+
195
+ await Promise.all(
196
+ blocks.map(block =>
197
+ Promise.all([
198
+ this.#privateLogsByBlock.delete(block.number),
199
+ this.#publicLogsByBlock.delete(block.number),
200
+ this.#logTagsByBlock.delete(block.number),
201
+ ]),
202
+ ),
203
+ );
204
+
205
+ await Promise.all(tagsToDelete.map(tag => this.#logsByTag.delete(tag.toString())));
200
206
  return true;
201
207
  });
202
208
  }
@@ -207,9 +213,9 @@ export class LogStore {
207
213
  * @param limit - The maximum number of blocks to retrieve logs from.
208
214
  * @returns An array of private logs from the specified range of blocks.
209
215
  */
210
- getPrivateLogs(start: number, limit: number) {
216
+ async getPrivateLogs(start: number, limit: number): Promise<PrivateLog[]> {
211
217
  const logs = [];
212
- for (const buffer of this.#privateLogsByBlock.values({ start, limit })) {
218
+ for await (const buffer of this.#privateLogsByBlock.valuesAsync({ start, limit })) {
213
219
  const reader = new BufferReader(buffer);
214
220
  while (reader.remainingBytes() > 0) {
215
221
  logs.push(reader.readObject(PrivateLog));
@@ -224,11 +230,10 @@ export class LogStore {
224
230
  * @returns For each received tag, an array of matching logs is returned. An empty array implies no logs match
225
231
  * that tag.
226
232
  */
227
- getLogsByTags(tags: Fr[]): Promise<TxScopedL2Log[][]> {
228
- return this.db.transaction(() =>
229
- tags
230
- .map(tag => this.#logsByTag.get(tag.toString()))
231
- .map(noteLogBuffers => noteLogBuffers?.map(noteLogBuffer => TxScopedL2Log.fromBuffer(noteLogBuffer)) ?? []),
233
+ async getLogsByTags(tags: Fr[]): Promise<TxScopedL2Log[][]> {
234
+ const logs = await Promise.all(tags.map(tag => this.#logsByTag.getAsync(tag.toString())));
235
+ return logs.map(
236
+ noteLogBuffers => noteLogBuffers?.map(noteLogBuffer => TxScopedL2Log.fromBuffer(noteLogBuffer)) ?? [],
232
237
  );
233
238
  }
234
239
 
@@ -237,7 +242,7 @@ export class LogStore {
237
242
  * @param filter - The filter to apply to the logs.
238
243
  * @returns The requested logs.
239
244
  */
240
- getPublicLogs(filter: LogFilter): GetPublicLogsResponse {
245
+ getPublicLogs(filter: LogFilter): Promise<GetPublicLogsResponse> {
241
246
  if (filter.afterLog) {
242
247
  return this.#filterPublicLogsBetweenBlocks(filter);
243
248
  } else if (filter.txHash) {
@@ -247,17 +252,17 @@ export class LogStore {
247
252
  }
248
253
  }
249
254
 
250
- #filterPublicLogsOfTx(filter: LogFilter): GetPublicLogsResponse {
255
+ async #filterPublicLogsOfTx(filter: LogFilter): Promise<GetPublicLogsResponse> {
251
256
  if (!filter.txHash) {
252
257
  throw new Error('Missing txHash');
253
258
  }
254
259
 
255
- const [blockNumber, txIndex] = this.blockStore.getTxLocation(filter.txHash) ?? [];
260
+ const [blockNumber, txIndex] = (await this.blockStore.getTxLocation(filter.txHash)) ?? [];
256
261
  if (typeof blockNumber !== 'number' || typeof txIndex !== 'number') {
257
262
  return { logs: [], maxLogsHit: false };
258
263
  }
259
264
 
260
- const buffer = this.#publicLogsByBlock.get(blockNumber) ?? Buffer.alloc(0);
265
+ const buffer = (await this.#publicLogsByBlock.getAsync(blockNumber)) ?? Buffer.alloc(0);
261
266
  const publicLogsInBlock: [PublicLog[]] = [[]];
262
267
  const reader = new BufferReader(buffer);
263
268
  while (reader.remainingBytes() > 0) {
@@ -277,7 +282,7 @@ export class LogStore {
277
282
  return { logs, maxLogsHit };
278
283
  }
279
284
 
280
- #filterPublicLogsBetweenBlocks(filter: LogFilter): GetPublicLogsResponse {
285
+ async #filterPublicLogsBetweenBlocks(filter: LogFilter): Promise<GetPublicLogsResponse> {
281
286
  const start =
282
287
  filter.afterLog?.blockNumber ?? Math.max(filter.fromBlock ?? INITIAL_L2_BLOCK_NUM, INITIAL_L2_BLOCK_NUM);
283
288
  const end = filter.toBlock;
@@ -292,7 +297,7 @@ export class LogStore {
292
297
  const logs: ExtendedPublicLog[] = [];
293
298
 
294
299
  let maxLogsHit = false;
295
- loopOverBlocks: for (const [blockNumber, logBuffer] of this.#publicLogsByBlock.entries({ start, end })) {
300
+ loopOverBlocks: for await (const [blockNumber, logBuffer] of this.#publicLogsByBlock.entriesAsync({ start, end })) {
296
301
  const publicLogsInBlock: [PublicLog[]] = [[]];
297
302
  const reader = new BufferReader(logBuffer);
298
303
  while (reader.remainingBytes() > 0) {
@@ -321,7 +326,7 @@ export class LogStore {
321
326
  * @param filter - The filter to apply to the logs.
322
327
  * @returns The requested logs.
323
328
  */
324
- getContractClassLogs(filter: LogFilter): GetContractClassLogsResponse {
329
+ getContractClassLogs(filter: LogFilter): Promise<GetContractClassLogsResponse> {
325
330
  if (filter.afterLog) {
326
331
  return this.#filterContractClassLogsBetweenBlocks(filter);
327
332
  } else if (filter.txHash) {
@@ -331,16 +336,16 @@ export class LogStore {
331
336
  }
332
337
  }
333
338
 
334
- #filterContractClassLogsOfTx(filter: LogFilter): GetContractClassLogsResponse {
339
+ async #filterContractClassLogsOfTx(filter: LogFilter): Promise<GetContractClassLogsResponse> {
335
340
  if (!filter.txHash) {
336
341
  throw new Error('Missing txHash');
337
342
  }
338
343
 
339
- const [blockNumber, txIndex] = this.blockStore.getTxLocation(filter.txHash) ?? [];
344
+ const [blockNumber, txIndex] = (await this.blockStore.getTxLocation(filter.txHash)) ?? [];
340
345
  if (typeof blockNumber !== 'number' || typeof txIndex !== 'number') {
341
346
  return { logs: [], maxLogsHit: false };
342
347
  }
343
- const contractClassLogsBuffer = this.#contractClassLogsByBlock.get(blockNumber);
348
+ const contractClassLogsBuffer = await this.#contractClassLogsByBlock.getAsync(blockNumber);
344
349
  const contractClassLogsInBlock = contractClassLogsBuffer
345
350
  ? ContractClass2BlockL2Logs.fromBuffer(contractClassLogsBuffer)
346
351
  : new ContractClass2BlockL2Logs([]);
@@ -352,7 +357,7 @@ export class LogStore {
352
357
  return { logs, maxLogsHit };
353
358
  }
354
359
 
355
- #filterContractClassLogsBetweenBlocks(filter: LogFilter): GetContractClassLogsResponse {
360
+ async #filterContractClassLogsBetweenBlocks(filter: LogFilter): Promise<GetContractClassLogsResponse> {
356
361
  const start =
357
362
  filter.afterLog?.blockNumber ?? Math.max(filter.fromBlock ?? INITIAL_L2_BLOCK_NUM, INITIAL_L2_BLOCK_NUM);
358
363
  const end = filter.toBlock;
@@ -367,7 +372,10 @@ export class LogStore {
367
372
  const logs: ExtendedUnencryptedL2Log[] = [];
368
373
 
369
374
  let maxLogsHit = false;
370
- loopOverBlocks: for (const [blockNumber, logBuffer] of this.#contractClassLogsByBlock.entries({ start, end })) {
375
+ loopOverBlocks: for await (const [blockNumber, logBuffer] of this.#contractClassLogsByBlock.entriesAsync({
376
+ start,
377
+ end,
378
+ })) {
371
379
  const contractClassLogsInBlock = ContractClass2BlockL2Logs.fromBuffer(logBuffer);
372
380
  for (let txIndex = filter.afterLog?.txIndex ?? 0; txIndex < contractClassLogsInBlock.txLogs.length; txIndex++) {
373
381
  const txLogs = contractClassLogsInBlock.txLogs[txIndex].unrollLogs();