@aztec/archiver 0.71.0 → 0.73.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 (70) hide show
  1. package/dest/archiver/archiver.d.ts +6 -6
  2. package/dest/archiver/archiver.d.ts.map +1 -1
  3. package/dest/archiver/archiver.js +35 -20
  4. package/dest/archiver/archiver_store.d.ts +6 -6
  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 +103 -65
  9. package/dest/archiver/config.d.ts +2 -2
  10. package/dest/archiver/config.d.ts.map +1 -1
  11. package/dest/archiver/config.js +5 -5
  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 +69 -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 +7 -11
  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 +41 -63
  30. package/dest/archiver/kv_archiver_store/log_store.d.ts +8 -8
  31. package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
  32. package/dest/archiver/kv_archiver_store/log_store.js +122 -89
  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 +9 -9
  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 +72 -71
  42. package/dest/factory.js +8 -8
  43. package/dest/rpc/index.d.ts +1 -1
  44. package/dest/rpc/index.d.ts.map +1 -1
  45. package/dest/rpc/index.js +5 -5
  46. package/dest/test/mock_archiver.d.ts +1 -1
  47. package/dest/test/mock_archiver.d.ts.map +1 -1
  48. package/dest/test/mock_archiver.js +2 -1
  49. package/dest/test/mock_l2_block_source.d.ts +3 -3
  50. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  51. package/dest/test/mock_l2_block_source.js +14 -11
  52. package/package.json +13 -13
  53. package/src/archiver/archiver.ts +46 -25
  54. package/src/archiver/archiver_store.ts +6 -5
  55. package/src/archiver/archiver_store_test_suite.ts +113 -77
  56. package/src/archiver/config.ts +6 -6
  57. package/src/archiver/data_retrieval.ts +94 -12
  58. package/src/archiver/errors.ts +5 -0
  59. package/src/archiver/kv_archiver_store/block_store.ts +66 -67
  60. package/src/archiver/kv_archiver_store/contract_class_store.ts +17 -15
  61. package/src/archiver/kv_archiver_store/contract_instance_store.ts +5 -5
  62. package/src/archiver/kv_archiver_store/kv_archiver_store.ts +48 -66
  63. package/src/archiver/kv_archiver_store/log_store.ts +167 -112
  64. package/src/archiver/kv_archiver_store/message_store.ts +22 -22
  65. package/src/archiver/kv_archiver_store/nullifier_store.ts +48 -30
  66. package/src/archiver/memory_archiver_store/memory_archiver_store.ts +100 -96
  67. package/src/factory.ts +11 -9
  68. package/src/rpc/index.ts +4 -4
  69. package/src/test/mock_archiver.ts +1 -0
  70. package/src/test/mock_l2_block_source.ts +20 -18
@@ -1,19 +1,24 @@
1
1
  import {
2
2
  ContractClass2BlockL2Logs,
3
+ ExtendedPublicLog,
3
4
  ExtendedUnencryptedL2Log,
4
- type GetUnencryptedLogsResponse,
5
+ type GetContractClassLogsResponse,
6
+ type GetPublicLogsResponse,
5
7
  type L2Block,
6
8
  type LogFilter,
7
9
  LogId,
8
10
  TxScopedL2Log,
9
- UnencryptedL2BlockL2Logs,
10
- type UnencryptedL2Log,
11
+ UnencryptedL2Log,
11
12
  } from '@aztec/circuit-types';
12
- import { Fr, PrivateLog } from '@aztec/circuits.js';
13
- import { INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX } from '@aztec/circuits.js/constants';
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';
14
19
  import { createLogger } from '@aztec/foundation/log';
15
- import { BufferReader } from '@aztec/foundation/serialize';
16
- import { type AztecKVStore, type AztecMap } from '@aztec/kv-store';
20
+ import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize';
21
+ import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
17
22
 
18
23
  import { type BlockStore } from './block_store.js';
19
24
 
@@ -21,19 +26,19 @@ import { type BlockStore } from './block_store.js';
21
26
  * A store for logs
22
27
  */
23
28
  export class LogStore {
24
- #logsByTag: AztecMap<string, Buffer[]>;
25
- #logTagsByBlock: AztecMap<number, string[]>;
26
- #privateLogsByBlock: AztecMap<number, Buffer>;
27
- #unencryptedLogsByBlock: AztecMap<number, Buffer>;
28
- #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>;
29
34
  #logsMaxPageSize: number;
30
35
  #log = createLogger('archiver:log_store');
31
36
 
32
- constructor(private db: AztecKVStore, private blockStore: BlockStore, logsMaxPageSize: number = 1000) {
37
+ constructor(private db: AztecAsyncKVStore, private blockStore: BlockStore, logsMaxPageSize: number = 1000) {
33
38
  this.#logsByTag = db.openMap('archiver_tagged_logs_by_tag');
34
39
  this.#logTagsByBlock = db.openMap('archiver_log_tags_by_block');
35
40
  this.#privateLogsByBlock = db.openMap('archiver_private_logs_by_block');
36
- this.#unencryptedLogsByBlock = db.openMap('archiver_unencrypted_logs_by_block');
41
+ this.#publicLogsByBlock = db.openMap('archiver_public_logs_by_block');
37
42
  this.#contractClassLogsByBlock = db.openMap('archiver_contract_class_logs_by_block');
38
43
 
39
44
  this.#logsMaxPageSize = logsMaxPageSize;
@@ -70,39 +75,46 @@ export class LogStore {
70
75
  const dataStartIndexForBlock =
71
76
  block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
72
77
  block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
73
- block.body.unencryptedLogs.txLogs.forEach((txLogs, txIndex) => {
74
- const txHash = block.body.txEffects[txIndex].txHash;
78
+ block.body.txEffects.forEach((txEffect, txIndex) => {
79
+ const txHash = txEffect.txHash;
75
80
  const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
76
- const logs = txLogs.unrollLogs();
77
- logs.forEach(log => {
78
- if (log.data.length < 32 * 33) {
79
- // TODO remove when #9835 and #9836 are fixed
80
- this.#log.warn(`Skipping unencrypted log with insufficient data length: ${log.data.length}`);
81
+ txEffect.publicLogs.forEach(log => {
82
+ // Check that each log stores 2 lengths in its first field. If not, it's not a tagged log:
83
+ const firstFieldBuf = log.log[0].toBuffer();
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]]
89
+ this.#log.warn(`Skipping public log with invalid first field: ${log.log[0]}`);
81
90
  return;
82
91
  }
83
- try {
84
- // TODO remove when #9835 and #9836 are fixed. The partial note logs are emitted as bytes, but encoded as Fields.
85
- // This means that for every 32 bytes of payload, we only have 1 byte of data.
86
- // Also, the tag is not stored in the first 32 bytes of the log, (that's the length of public fields now) but in the next 32.
87
- const correctedBuffer = Buffer.alloc(32);
88
- const initialOffset = 32;
89
- for (let i = 0; i < 32; i++) {
90
- const byte = Fr.fromBuffer(
91
- log.data.subarray(i * 32 + initialOffset, i * 32 + 32 + initialOffset),
92
- ).toNumber();
93
- correctedBuffer.writeUInt8(byte, i);
94
- }
95
- const tag = new Fr(correctedBuffer);
96
-
97
- this.#log.debug(`Found tagged unencrypted log with tag ${tag.toString()} in block ${block.number}`);
98
- const currentLogs = taggedLogs.get(tag.toString()) ?? [];
99
- currentLogs.push(
100
- new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, /* isFromPublic */ true, log.data).toBuffer(),
101
- );
102
- taggedLogs.set(tag.toString(), currentLogs);
103
- } catch (err) {
104
- this.#log.warn(`Failed to add tagged log to store: ${err}`);
92
+ // Check that the length values line up with the log contents
93
+ const publicValuesLength = firstFieldBuf.subarray(-5).readUint16BE();
94
+ const privateValuesLength = firstFieldBuf.subarray(-5).readUint16BE(3);
95
+ // Add 1 for the first field holding lengths
96
+ const totalLogLength = 1 + publicValuesLength + privateValuesLength;
97
+ // Note that zeroes can be valid log values, so we can only assert that we do not go over the given length
98
+ if (totalLogLength > PUBLIC_LOG_DATA_SIZE_IN_FIELDS || log.log.slice(totalLogLength).find(f => !f.isZero())) {
99
+ this.#log.warn(`Skipping invalid tagged public log with first field: ${log.log[0]}`);
100
+ return;
105
101
  }
102
+
103
+ // The first elt stores lengths as above => tag is in fields[1]
104
+ const tag = log.log[1];
105
+
106
+ this.#log.debug(`Found tagged public log with tag ${tag.toString()} in block ${block.number}`);
107
+ const currentLogs = taggedLogs.get(tag.toString()) ?? [];
108
+ currentLogs.push(
109
+ new TxScopedL2Log(
110
+ txHash,
111
+ dataStartIndexForTx,
112
+ block.number,
113
+ /* isFromPublic */ true,
114
+ log.toBuffer(),
115
+ ).toBuffer(),
116
+ );
117
+ taggedLogs.set(tag.toString(), currentLogs);
106
118
  });
107
119
  });
108
120
  return taggedLogs;
@@ -113,7 +125,7 @@ export class LogStore {
113
125
  * @param blocks - The blocks for which to add the logs.
114
126
  * @returns True if the operation is successful.
115
127
  */
116
- async addLogs(blocks: L2Block[]): Promise<boolean> {
128
+ addLogs(blocks: L2Block[]): Promise<boolean> {
117
129
  const taggedLogsToAdd = blocks
118
130
  .flatMap(block => [this.#extractTaggedLogsFromPrivate(block), this.#extractTaggedLogsFromPublic(block)])
119
131
  .reduce((acc, val) => {
@@ -124,55 +136,73 @@ export class LogStore {
124
136
  return acc;
125
137
  });
126
138
  const tagsToUpdate = Array.from(taggedLogsToAdd.keys());
127
- const currentTaggedLogs = await this.db.transaction(() =>
128
- tagsToUpdate.map(tag => ({ tag, logBuffers: this.#logsByTag.get(tag) })),
129
- );
130
- currentTaggedLogs.forEach(taggedLogBuffer => {
131
- if (taggedLogBuffer.logBuffers && taggedLogBuffer.logBuffers.length > 0) {
132
- taggedLogsToAdd.set(
133
- taggedLogBuffer.tag,
134
- taggedLogBuffer.logBuffers!.concat(taggedLogsToAdd.get(taggedLogBuffer.tag)!),
135
- );
136
- }
137
- });
138
- return this.db.transaction(() => {
139
- 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) {
140
153
  const tagsInBlock = [];
141
154
  for (const [tag, logs] of taggedLogsToAdd.entries()) {
142
- void this.#logsByTag.set(tag, logs);
155
+ await this.#logsByTag.set(tag, logs);
143
156
  tagsInBlock.push(tag);
144
157
  }
145
- void this.#logTagsByBlock.set(block.number, tagsInBlock);
158
+ await this.#logTagsByBlock.set(block.number, tagsInBlock);
146
159
 
147
160
  const privateLogsInBlock = block.body.txEffects
148
161
  .map(txEffect => txEffect.privateLogs)
149
162
  .flat()
150
163
  .map(log => log.toBuffer());
151
- void this.#privateLogsByBlock.set(block.number, Buffer.concat(privateLogsInBlock));
152
-
153
- void this.#unencryptedLogsByBlock.set(block.number, block.body.unencryptedLogs.toBuffer());
154
- void this.#contractClassLogsByBlock.set(block.number, block.body.contractClassLogs.toBuffer());
155
- });
164
+ await this.#privateLogsByBlock.set(block.number, Buffer.concat(privateLogsInBlock));
165
+
166
+ const publicLogsInBlock = block.body.txEffects
167
+ .map((txEffect, txIndex) =>
168
+ [
169
+ numToUInt32BE(txIndex),
170
+ numToUInt32BE(txEffect.publicLogs.length),
171
+ txEffect.publicLogs.map(log => log.toBuffer()),
172
+ ].flat(),
173
+ )
174
+ .flat();
175
+
176
+ await this.#publicLogsByBlock.set(block.number, Buffer.concat(publicLogsInBlock));
177
+ await this.#contractClassLogsByBlock.set(block.number, block.body.contractClassLogs.toBuffer());
178
+ }
156
179
 
157
180
  return true;
158
181
  });
159
182
  }
160
183
 
161
- async deleteLogs(blocks: L2Block[]): Promise<boolean> {
162
- const tagsToDelete = await this.db.transaction(() => {
163
- return blocks.flatMap(block => this.#logTagsByBlock.get(block.number)?.map(tag => tag.toString()) ?? []);
164
- });
165
- return this.db.transaction(() => {
166
- blocks.forEach(block => {
167
- void this.#privateLogsByBlock.delete(block.number);
168
- void this.#unencryptedLogsByBlock.delete(block.number);
169
- void this.#logTagsByBlock.delete(block.number);
170
- });
171
-
172
- tagsToDelete.forEach(tag => {
173
- void this.#logsByTag.delete(tag.toString());
174
- });
175
-
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())));
176
206
  return true;
177
207
  });
178
208
  }
@@ -183,9 +213,9 @@ export class LogStore {
183
213
  * @param limit - The maximum number of blocks to retrieve logs from.
184
214
  * @returns An array of private logs from the specified range of blocks.
185
215
  */
186
- getPrivateLogs(start: number, limit: number) {
216
+ async getPrivateLogs(start: number, limit: number): Promise<PrivateLog[]> {
187
217
  const logs = [];
188
- for (const buffer of this.#privateLogsByBlock.values({ start, limit })) {
218
+ for await (const buffer of this.#privateLogsByBlock.valuesAsync({ start, limit })) {
189
219
  const reader = new BufferReader(buffer);
190
220
  while (reader.remainingBytes() > 0) {
191
221
  logs.push(reader.readObject(PrivateLog));
@@ -200,51 +230,59 @@ export class LogStore {
200
230
  * @returns For each received tag, an array of matching logs is returned. An empty array implies no logs match
201
231
  * that tag.
202
232
  */
203
- getLogsByTags(tags: Fr[]): Promise<TxScopedL2Log[][]> {
204
- return this.db.transaction(() =>
205
- tags
206
- .map(tag => this.#logsByTag.get(tag.toString()))
207
- .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)) ?? [],
208
237
  );
209
238
  }
210
239
 
211
240
  /**
212
- * Gets unencrypted logs based on the provided filter.
241
+ * Gets public logs based on the provided filter.
213
242
  * @param filter - The filter to apply to the logs.
214
243
  * @returns The requested logs.
215
244
  */
216
- getUnencryptedLogs(filter: LogFilter): GetUnencryptedLogsResponse {
245
+ getPublicLogs(filter: LogFilter): Promise<GetPublicLogsResponse> {
217
246
  if (filter.afterLog) {
218
- return this.#filterUnencryptedLogsBetweenBlocks(filter);
247
+ return this.#filterPublicLogsBetweenBlocks(filter);
219
248
  } else if (filter.txHash) {
220
- return this.#filterUnencryptedLogsOfTx(filter);
249
+ return this.#filterPublicLogsOfTx(filter);
221
250
  } else {
222
- return this.#filterUnencryptedLogsBetweenBlocks(filter);
251
+ return this.#filterPublicLogsBetweenBlocks(filter);
223
252
  }
224
253
  }
225
254
 
226
- #filterUnencryptedLogsOfTx(filter: LogFilter): GetUnencryptedLogsResponse {
255
+ async #filterPublicLogsOfTx(filter: LogFilter): Promise<GetPublicLogsResponse> {
227
256
  if (!filter.txHash) {
228
257
  throw new Error('Missing txHash');
229
258
  }
230
259
 
231
- const [blockNumber, txIndex] = this.blockStore.getTxLocation(filter.txHash) ?? [];
260
+ const [blockNumber, txIndex] = (await this.blockStore.getTxLocation(filter.txHash)) ?? [];
232
261
  if (typeof blockNumber !== 'number' || typeof txIndex !== 'number') {
233
262
  return { logs: [], maxLogsHit: false };
234
263
  }
235
264
 
236
- const buffer = this.#unencryptedLogsByBlock.get(blockNumber) ?? Buffer.alloc(0);
237
- const unencryptedLogsInBlock = UnencryptedL2BlockL2Logs.fromBuffer(buffer);
265
+ const buffer = (await this.#publicLogsByBlock.getAsync(blockNumber)) ?? Buffer.alloc(0);
266
+ const publicLogsInBlock: [PublicLog[]] = [[]];
267
+ const reader = new BufferReader(buffer);
268
+ while (reader.remainingBytes() > 0) {
269
+ const indexOfTx = reader.readNumber();
270
+ const numLogsInTx = reader.readNumber();
271
+ publicLogsInBlock[indexOfTx] = [];
272
+ for (let i = 0; i < numLogsInTx; i++) {
273
+ publicLogsInBlock[indexOfTx].push(reader.readObject(PublicLog));
274
+ }
275
+ }
238
276
 
239
- const txLogs = unencryptedLogsInBlock.txLogs[txIndex].unrollLogs();
277
+ const txLogs = publicLogsInBlock[txIndex];
240
278
 
241
- const logs: ExtendedUnencryptedL2Log[] = [];
279
+ const logs: ExtendedPublicLog[] = [];
242
280
  const maxLogsHit = this.#accumulateLogs(logs, blockNumber, txIndex, txLogs, filter);
243
281
 
244
282
  return { logs, maxLogsHit };
245
283
  }
246
284
 
247
- #filterUnencryptedLogsBetweenBlocks(filter: LogFilter): GetUnencryptedLogsResponse {
285
+ async #filterPublicLogsBetweenBlocks(filter: LogFilter): Promise<GetPublicLogsResponse> {
248
286
  const start =
249
287
  filter.afterLog?.blockNumber ?? Math.max(filter.fromBlock ?? INITIAL_L2_BLOCK_NUM, INITIAL_L2_BLOCK_NUM);
250
288
  const end = filter.toBlock;
@@ -256,13 +294,22 @@ export class LogStore {
256
294
  };
257
295
  }
258
296
 
259
- const logs: ExtendedUnencryptedL2Log[] = [];
297
+ const logs: ExtendedPublicLog[] = [];
260
298
 
261
299
  let maxLogsHit = false;
262
- loopOverBlocks: for (const [blockNumber, logBuffer] of this.#unencryptedLogsByBlock.entries({ start, end })) {
263
- const unencryptedLogsInBlock = UnencryptedL2BlockL2Logs.fromBuffer(logBuffer);
264
- for (let txIndex = filter.afterLog?.txIndex ?? 0; txIndex < unencryptedLogsInBlock.txLogs.length; txIndex++) {
265
- const txLogs = unencryptedLogsInBlock.txLogs[txIndex].unrollLogs();
300
+ loopOverBlocks: for await (const [blockNumber, logBuffer] of this.#publicLogsByBlock.entriesAsync({ start, end })) {
301
+ const publicLogsInBlock: [PublicLog[]] = [[]];
302
+ const reader = new BufferReader(logBuffer);
303
+ while (reader.remainingBytes() > 0) {
304
+ const indexOfTx = reader.readNumber();
305
+ const numLogsInTx = reader.readNumber();
306
+ publicLogsInBlock[indexOfTx] = [];
307
+ for (let i = 0; i < numLogsInTx; i++) {
308
+ publicLogsInBlock[indexOfTx].push(reader.readObject(PublicLog));
309
+ }
310
+ }
311
+ for (let txIndex = filter.afterLog?.txIndex ?? 0; txIndex < publicLogsInBlock.length; txIndex++) {
312
+ const txLogs = publicLogsInBlock[txIndex];
266
313
  maxLogsHit = this.#accumulateLogs(logs, blockNumber, txIndex, txLogs, filter);
267
314
  if (maxLogsHit) {
268
315
  this.#log.debug(`Max logs hit at block ${blockNumber}`);
@@ -279,7 +326,7 @@ export class LogStore {
279
326
  * @param filter - The filter to apply to the logs.
280
327
  * @returns The requested logs.
281
328
  */
282
- getContractClassLogs(filter: LogFilter): GetUnencryptedLogsResponse {
329
+ getContractClassLogs(filter: LogFilter): Promise<GetContractClassLogsResponse> {
283
330
  if (filter.afterLog) {
284
331
  return this.#filterContractClassLogsBetweenBlocks(filter);
285
332
  } else if (filter.txHash) {
@@ -289,16 +336,16 @@ export class LogStore {
289
336
  }
290
337
  }
291
338
 
292
- #filterContractClassLogsOfTx(filter: LogFilter): GetUnencryptedLogsResponse {
339
+ async #filterContractClassLogsOfTx(filter: LogFilter): Promise<GetContractClassLogsResponse> {
293
340
  if (!filter.txHash) {
294
341
  throw new Error('Missing txHash');
295
342
  }
296
343
 
297
- const [blockNumber, txIndex] = this.blockStore.getTxLocation(filter.txHash) ?? [];
344
+ const [blockNumber, txIndex] = (await this.blockStore.getTxLocation(filter.txHash)) ?? [];
298
345
  if (typeof blockNumber !== 'number' || typeof txIndex !== 'number') {
299
346
  return { logs: [], maxLogsHit: false };
300
347
  }
301
- const contractClassLogsBuffer = this.#contractClassLogsByBlock.get(blockNumber);
348
+ const contractClassLogsBuffer = await this.#contractClassLogsByBlock.getAsync(blockNumber);
302
349
  const contractClassLogsInBlock = contractClassLogsBuffer
303
350
  ? ContractClass2BlockL2Logs.fromBuffer(contractClassLogsBuffer)
304
351
  : new ContractClass2BlockL2Logs([]);
@@ -310,7 +357,7 @@ export class LogStore {
310
357
  return { logs, maxLogsHit };
311
358
  }
312
359
 
313
- #filterContractClassLogsBetweenBlocks(filter: LogFilter): GetUnencryptedLogsResponse {
360
+ async #filterContractClassLogsBetweenBlocks(filter: LogFilter): Promise<GetContractClassLogsResponse> {
314
361
  const start =
315
362
  filter.afterLog?.blockNumber ?? Math.max(filter.fromBlock ?? INITIAL_L2_BLOCK_NUM, INITIAL_L2_BLOCK_NUM);
316
363
  const end = filter.toBlock;
@@ -325,7 +372,10 @@ export class LogStore {
325
372
  const logs: ExtendedUnencryptedL2Log[] = [];
326
373
 
327
374
  let maxLogsHit = false;
328
- 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
+ })) {
329
379
  const contractClassLogsInBlock = ContractClass2BlockL2Logs.fromBuffer(logBuffer);
330
380
  for (let txIndex = filter.afterLog?.txIndex ?? 0; txIndex < contractClassLogsInBlock.txLogs.length; txIndex++) {
331
381
  const txLogs = contractClassLogsInBlock.txLogs[txIndex].unrollLogs();
@@ -341,10 +391,10 @@ export class LogStore {
341
391
  }
342
392
 
343
393
  #accumulateLogs(
344
- results: ExtendedUnencryptedL2Log[],
394
+ results: (ExtendedUnencryptedL2Log | ExtendedPublicLog)[],
345
395
  blockNumber: number,
346
396
  txIndex: number,
347
- txLogs: UnencryptedL2Log[],
397
+ txLogs: (UnencryptedL2Log | PublicLog)[],
348
398
  filter: LogFilter,
349
399
  ): boolean {
350
400
  let maxLogsHit = false;
@@ -352,7 +402,12 @@ export class LogStore {
352
402
  for (; logIndex < txLogs.length; logIndex++) {
353
403
  const log = txLogs[logIndex];
354
404
  if (!filter.contractAddress || log.contractAddress.equals(filter.contractAddress)) {
355
- results.push(new ExtendedUnencryptedL2Log(new LogId(blockNumber, txIndex, logIndex), log));
405
+ if (log instanceof UnencryptedL2Log) {
406
+ results.push(new ExtendedUnencryptedL2Log(new LogId(blockNumber, txIndex, logIndex), log));
407
+ } else {
408
+ results.push(new ExtendedPublicLog(new LogId(blockNumber, txIndex, logIndex), log));
409
+ }
410
+
356
411
  if (results.length >= this.#logsMaxPageSize) {
357
412
  maxLogsHit = true;
358
413
  break;
@@ -1,7 +1,7 @@
1
1
  import { InboxLeaf } from '@aztec/circuit-types';
2
2
  import { Fr, L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/circuits.js';
3
3
  import { createLogger } from '@aztec/foundation/log';
4
- import { type AztecKVStore, type AztecMap, type AztecSingleton } from '@aztec/kv-store';
4
+ import type { AztecAsyncKVStore, AztecAsyncMap, AztecAsyncSingleton } from '@aztec/kv-store';
5
5
 
6
6
  import { type DataRetrieval } from '../structs/data_retrieval.js';
7
7
 
@@ -9,36 +9,36 @@ import { type DataRetrieval } from '../structs/data_retrieval.js';
9
9
  * LMDB implementation of the ArchiverDataStore interface.
10
10
  */
11
11
  export class MessageStore {
12
- #l1ToL2Messages: AztecMap<string, Buffer>;
13
- #l1ToL2MessageIndices: AztecMap<string, bigint>;
14
- #lastSynchedL1Block: AztecSingleton<bigint>;
15
- #totalMessageCount: AztecSingleton<bigint>;
12
+ #l1ToL2Messages: AztecAsyncMap<string, Buffer>;
13
+ #l1ToL2MessageIndices: AztecAsyncMap<string, bigint>;
14
+ #lastSynchedL1Block: AztecAsyncSingleton<bigint>;
15
+ #totalMessageCount: AztecAsyncSingleton<bigint>;
16
16
 
17
17
  #log = createLogger('archiver:message_store');
18
18
 
19
19
  #l1ToL2MessagesSubtreeSize = 2 ** L1_TO_L2_MSG_SUBTREE_HEIGHT;
20
20
 
21
- constructor(private db: AztecKVStore) {
21
+ constructor(private db: AztecAsyncKVStore) {
22
22
  this.#l1ToL2Messages = db.openMap('archiver_l1_to_l2_messages');
23
23
  this.#l1ToL2MessageIndices = db.openMap('archiver_l1_to_l2_message_indices');
24
24
  this.#lastSynchedL1Block = db.openSingleton('archiver_last_l1_block_new_messages');
25
25
  this.#totalMessageCount = db.openSingleton('archiver_l1_to_l2_message_count');
26
26
  }
27
27
 
28
- getTotalL1ToL2MessageCount(): bigint {
29
- return this.#totalMessageCount.get() ?? 0n;
28
+ async getTotalL1ToL2MessageCount(): Promise<bigint> {
29
+ return (await this.#totalMessageCount.getAsync()) ?? 0n;
30
30
  }
31
31
 
32
32
  /**
33
33
  * Gets the last L1 block number that emitted new messages.
34
34
  * @returns The last L1 block number processed
35
35
  */
36
- getSynchedL1BlockNumber(): bigint | undefined {
37
- return this.#lastSynchedL1Block.get();
36
+ getSynchedL1BlockNumber(): Promise<bigint | undefined> {
37
+ return this.#lastSynchedL1Block.getAsync();
38
38
  }
39
39
 
40
- setSynchedL1BlockNumber(l1BlockNumber: bigint) {
41
- void this.#lastSynchedL1Block.set(l1BlockNumber);
40
+ async setSynchedL1BlockNumber(l1BlockNumber: bigint): Promise<void> {
41
+ await this.#lastSynchedL1Block.set(l1BlockNumber);
42
42
  }
43
43
 
44
44
  /**
@@ -47,22 +47,22 @@ export class MessageStore {
47
47
  * @returns True if the operation is successful.
48
48
  */
49
49
  addL1ToL2Messages(messages: DataRetrieval<InboxLeaf>): Promise<boolean> {
50
- return this.db.transaction(() => {
51
- const lastL1BlockNumber = this.#lastSynchedL1Block.get() ?? 0n;
50
+ return this.db.transactionAsync(async () => {
51
+ const lastL1BlockNumber = (await this.#lastSynchedL1Block.getAsync()) ?? 0n;
52
52
  if (lastL1BlockNumber >= messages.lastProcessedL1BlockNumber) {
53
53
  return false;
54
54
  }
55
55
 
56
- void this.#lastSynchedL1Block.set(messages.lastProcessedL1BlockNumber);
56
+ await this.#lastSynchedL1Block.set(messages.lastProcessedL1BlockNumber);
57
57
 
58
58
  for (const message of messages.retrievedData) {
59
59
  const key = `${message.index}`;
60
- void this.#l1ToL2Messages.set(key, message.leaf.toBuffer());
61
- void this.#l1ToL2MessageIndices.set(message.leaf.toString(), message.index);
60
+ await this.#l1ToL2Messages.set(key, message.leaf.toBuffer());
61
+ await this.#l1ToL2MessageIndices.set(message.leaf.toString(), message.index);
62
62
  }
63
63
 
64
- const lastTotalMessageCount = this.getTotalL1ToL2MessageCount();
65
- void this.#totalMessageCount.set(lastTotalMessageCount + BigInt(messages.retrievedData.length));
64
+ const lastTotalMessageCount = await this.getTotalL1ToL2MessageCount();
65
+ await this.#totalMessageCount.set(lastTotalMessageCount + BigInt(messages.retrievedData.length));
66
66
 
67
67
  return true;
68
68
  });
@@ -74,17 +74,17 @@ export class MessageStore {
74
74
  * @returns The index of the L1 to L2 message in the L1 to L2 message tree (undefined if not found).
75
75
  */
76
76
  getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise<bigint | undefined> {
77
- return Promise.resolve(this.#l1ToL2MessageIndices.get(l1ToL2Message.toString()));
77
+ return this.#l1ToL2MessageIndices.getAsync(l1ToL2Message.toString());
78
78
  }
79
79
 
80
- getL1ToL2Messages(blockNumber: bigint): Fr[] {
80
+ async getL1ToL2Messages(blockNumber: bigint): Promise<Fr[]> {
81
81
  const messages: Fr[] = [];
82
82
  let undefinedMessageFound = false;
83
83
  const startIndex = Number(InboxLeaf.smallestIndexFromL2Block(blockNumber));
84
84
  for (let i = startIndex; i < startIndex + this.#l1ToL2MessagesSubtreeSize; i++) {
85
85
  // This is inefficient but probably fine for now.
86
86
  const key = `${i}`;
87
- const message = this.#l1ToL2Messages.get(key);
87
+ const message = await this.#l1ToL2Messages.getAsync(key);
88
88
  if (message) {
89
89
  if (undefinedMessageFound) {
90
90
  throw new Error(`L1 to L2 message gap found in block ${blockNumber}`);