@aztec/archiver 0.26.6 → 0.27.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 (49) hide show
  1. package/README.md +2 -3
  2. package/dest/archiver/archiver.d.ts +12 -16
  3. package/dest/archiver/archiver.d.ts.map +1 -1
  4. package/dest/archiver/archiver.js +38 -36
  5. package/dest/archiver/archiver_store.d.ts +18 -21
  6. package/dest/archiver/archiver_store.d.ts.map +1 -1
  7. package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
  8. package/dest/archiver/archiver_store_test_suite.js +46 -90
  9. package/dest/archiver/config.d.ts.map +1 -1
  10. package/dest/archiver/config.js +2 -5
  11. package/dest/archiver/data_retrieval.d.ts +10 -12
  12. package/dest/archiver/data_retrieval.d.ts.map +1 -1
  13. package/dest/archiver/data_retrieval.js +23 -22
  14. package/dest/archiver/eth_log_handlers.d.ts +17 -20
  15. package/dest/archiver/eth_log_handlers.d.ts.map +1 -1
  16. package/dest/archiver/eth_log_handlers.js +35 -52
  17. package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
  18. package/dest/archiver/kv_archiver_store/block_store.js +1 -9
  19. package/dest/archiver/kv_archiver_store/contract_store.d.ts +1 -21
  20. package/dest/archiver/kv_archiver_store/contract_store.d.ts.map +1 -1
  21. package/dest/archiver/kv_archiver_store/contract_store.js +1 -36
  22. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +14 -21
  23. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
  24. package/dest/archiver/kv_archiver_store/kv_archiver_store.js +25 -28
  25. package/dest/archiver/kv_archiver_store/message_store.d.ts +11 -1
  26. package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
  27. package/dest/archiver/kv_archiver_store/message_store.js +57 -5
  28. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts +18 -1
  29. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts.map +1 -1
  30. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.js +48 -1
  31. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +18 -21
  32. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +1 -1
  33. package/dest/archiver/memory_archiver_store/memory_archiver_store.js +32 -45
  34. package/dest/index.d.ts.map +1 -1
  35. package/dest/index.js +15 -3
  36. package/package.json +9 -9
  37. package/src/archiver/archiver.ts +46 -46
  38. package/src/archiver/archiver_store.ts +21 -24
  39. package/src/archiver/archiver_store_test_suite.ts +54 -115
  40. package/src/archiver/config.ts +0 -4
  41. package/src/archiver/data_retrieval.ts +30 -35
  42. package/src/archiver/eth_log_handlers.ts +42 -74
  43. package/src/archiver/kv_archiver_store/block_store.ts +0 -10
  44. package/src/archiver/kv_archiver_store/contract_store.ts +1 -44
  45. package/src/archiver/kv_archiver_store/kv_archiver_store.ts +26 -31
  46. package/src/archiver/kv_archiver_store/message_store.ts +60 -3
  47. package/src/archiver/memory_archiver_store/l1_to_l2_message_store.ts +48 -1
  48. package/src/archiver/memory_archiver_store/memory_archiver_store.ts +36 -48
  49. package/src/index.ts +15 -2
@@ -1,18 +1,18 @@
1
- import { Body, ExtendedContractData, L1ToL2Message } from '@aztec/circuit-types';
1
+ import { Body, L1ToL2Message, NewInboxLeaf } from '@aztec/circuit-types';
2
2
  import { AppendOnlyTreeSnapshot, Fr, Header } from '@aztec/circuits.js';
3
3
  import { EthAddress } from '@aztec/foundation/eth-address';
4
4
 
5
5
  import { PublicClient } from 'viem';
6
6
 
7
7
  import {
8
- getContractDeploymentLogs,
9
8
  getL1ToL2MessageCancelledLogs,
10
9
  getL2BlockProcessedLogs,
10
+ getLeafInsertedLogs,
11
11
  getPendingL1ToL2MessageLogs,
12
12
  getTxsPublishedLogs,
13
13
  processCancelledL1ToL2MessagesLogs,
14
- processContractDeploymentLogs,
15
14
  processL2BlockProcessedLogs,
15
+ processLeafInsertedLogs,
16
16
  processPendingL1ToL2MessageAddedLogs,
17
17
  processTxsPublishedLogs,
18
18
  } from './eth_log_handlers.js';
@@ -116,78 +116,72 @@ export async function retrieveBlockBodiesFromAvailabilityOracle(
116
116
  }
117
117
 
118
118
  /**
119
- * Fetches new contract data.
119
+ * Fetch new pending L1 to L2 messages.
120
120
  * @param publicClient - The viem public client to use for transaction retrieval.
121
- * @param contractDeploymentEmitterAddress - The address of the contract deployment emitter contract.
121
+ * @param inboxAddress - The address of the inbox contract to fetch messages from.
122
122
  * @param blockUntilSynced - If true, blocks until the archiver has fully synced.
123
123
  * @param searchStartBlock - The block number to use for starting the search.
124
124
  * @param searchEndBlock - The highest block number that we should search up to.
125
- * @param blockNumberToBodyHash - A mapping from block number to relevant body hash.
126
- * @returns An array of ExtendedContractData and their equivalent L2 Block number along with the next eth block to search from..
125
+ * @returns An array of L1ToL2Message and next eth block to search from.
127
126
  */
128
- export async function retrieveNewContractData(
127
+ export async function retrieveNewPendingL1ToL2Messages(
129
128
  publicClient: PublicClient,
130
- contractDeploymentEmitterAddress: EthAddress,
129
+ inboxAddress: EthAddress,
131
130
  blockUntilSynced: boolean,
132
131
  searchStartBlock: bigint,
133
132
  searchEndBlock: bigint,
134
- blockNumberToBodyHash: { [key: number]: Buffer | undefined },
135
- ): Promise<DataRetrieval<[ExtendedContractData[], number]>> {
136
- let retrievedNewContracts: [ExtendedContractData[], number][] = [];
133
+ ): Promise<DataRetrieval<[L1ToL2Message, bigint]>> {
134
+ const retrievedNewL1ToL2Messages: [L1ToL2Message, bigint][] = [];
137
135
  do {
138
136
  if (searchStartBlock > searchEndBlock) {
139
137
  break;
140
138
  }
141
- const contractDataLogs = await getContractDeploymentLogs(
139
+ const newL1ToL2MessageLogs = await getPendingL1ToL2MessageLogs(
142
140
  publicClient,
143
- contractDeploymentEmitterAddress,
141
+ inboxAddress,
144
142
  searchStartBlock,
145
143
  searchEndBlock,
146
144
  );
147
- if (contractDataLogs.length === 0) {
145
+ if (newL1ToL2MessageLogs.length === 0) {
148
146
  break;
149
147
  }
150
- const newContracts = processContractDeploymentLogs(blockNumberToBodyHash, contractDataLogs);
151
- retrievedNewContracts = retrievedNewContracts.concat(newContracts);
152
- searchStartBlock = (contractDataLogs.findLast(cd => !!cd)?.blockNumber || searchStartBlock) + 1n;
148
+ const newL1ToL2Messages = processPendingL1ToL2MessageAddedLogs(newL1ToL2MessageLogs);
149
+ retrievedNewL1ToL2Messages.push(...newL1ToL2Messages);
150
+ // handles the case when there are no new messages:
151
+ searchStartBlock = (newL1ToL2MessageLogs.findLast(msgLog => !!msgLog)?.blockNumber || searchStartBlock) + 1n;
153
152
  } while (blockUntilSynced && searchStartBlock <= searchEndBlock);
154
- return { nextEthBlockNumber: searchStartBlock, retrievedData: retrievedNewContracts };
153
+ return { nextEthBlockNumber: searchStartBlock, retrievedData: retrievedNewL1ToL2Messages };
155
154
  }
156
155
 
157
156
  /**
158
- * Fetch new pending L1 to L2 messages.
157
+ * Fetch new L1 to L2 messages.
159
158
  * @param publicClient - The viem public client to use for transaction retrieval.
160
- * @param inboxAddress - The address of the inbox contract to fetch messages from.
159
+ * @param newInboxAddress - The address of the inbox contract to fetch messages from.
161
160
  * @param blockUntilSynced - If true, blocks until the archiver has fully synced.
162
161
  * @param searchStartBlock - The block number to use for starting the search.
163
162
  * @param searchEndBlock - The highest block number that we should search up to.
164
- * @returns An array of L1ToL2Message and next eth block to search from.
163
+ * @returns An array of NewInboxLeaf and next eth block to search from.
165
164
  */
166
- export async function retrieveNewPendingL1ToL2Messages(
165
+ export async function retrieveNewL1ToL2Messages(
167
166
  publicClient: PublicClient,
168
- inboxAddress: EthAddress,
167
+ newInboxAddress: EthAddress,
169
168
  blockUntilSynced: boolean,
170
169
  searchStartBlock: bigint,
171
170
  searchEndBlock: bigint,
172
- ): Promise<DataRetrieval<[L1ToL2Message, bigint]>> {
173
- const retrievedNewL1ToL2Messages: [L1ToL2Message, bigint][] = [];
171
+ ): Promise<DataRetrieval<NewInboxLeaf>> {
172
+ const retrievedNewL1ToL2Messages: NewInboxLeaf[] = [];
174
173
  do {
175
174
  if (searchStartBlock > searchEndBlock) {
176
175
  break;
177
176
  }
178
- const newL1ToL2MessageLogs = await getPendingL1ToL2MessageLogs(
179
- publicClient,
180
- inboxAddress,
181
- searchStartBlock,
182
- searchEndBlock,
183
- );
184
- if (newL1ToL2MessageLogs.length === 0) {
177
+ const leafInsertedLogs = await getLeafInsertedLogs(publicClient, newInboxAddress, searchStartBlock, searchEndBlock);
178
+ if (leafInsertedLogs.length === 0) {
185
179
  break;
186
180
  }
187
- const newL1ToL2Messages = processPendingL1ToL2MessageAddedLogs(newL1ToL2MessageLogs);
181
+ const newL1ToL2Messages = processLeafInsertedLogs(leafInsertedLogs);
188
182
  retrievedNewL1ToL2Messages.push(...newL1ToL2Messages);
189
183
  // handles the case when there are no new messages:
190
- searchStartBlock = (newL1ToL2MessageLogs.findLast(msgLog => !!msgLog)?.blockNumber || searchStartBlock) + 1n;
184
+ searchStartBlock = (leafInsertedLogs.findLast(msgLog => !!msgLog)?.blockNumber || searchStartBlock) + 1n;
191
185
  } while (blockUntilSynced && searchStartBlock <= searchEndBlock);
192
186
  return { nextEthBlockNumber: searchStartBlock, retrievedData: retrievedNewL1ToL2Messages };
193
187
  }
@@ -200,6 +194,7 @@ export async function retrieveNewPendingL1ToL2Messages(
200
194
  * @param searchStartBlock - The block number to use for starting the search.
201
195
  * @param searchEndBlock - The highest block number that we should search up to.
202
196
  * @returns An array of entry keys that were cancelled and next eth block to search from.
197
+ * TODO(#4492): Nuke the following when purging the old inbox
203
198
  */
204
199
  export async function retrieveNewCancelledL1ToL2Messages(
205
200
  publicClient: PublicClient,
@@ -1,21 +1,29 @@
1
- import {
2
- Body,
3
- ContractData,
4
- EncodedContractFunction,
5
- ExtendedContractData,
6
- L1Actor,
7
- L1ToL2Message,
8
- L2Actor,
9
- } from '@aztec/circuit-types';
1
+ import { Body, L1Actor, L1ToL2Message, L2Actor, NewInboxLeaf } from '@aztec/circuit-types';
10
2
  import { AppendOnlyTreeSnapshot, Header } from '@aztec/circuits.js';
11
3
  import { AztecAddress } from '@aztec/foundation/aztec-address';
12
4
  import { EthAddress } from '@aztec/foundation/eth-address';
13
5
  import { Fr } from '@aztec/foundation/fields';
14
- import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize';
15
- import { AvailabilityOracleAbi, ContractDeploymentEmitterAbi, InboxAbi, RollupAbi } from '@aztec/l1-artifacts';
6
+ import { numToUInt32BE } from '@aztec/foundation/serialize';
7
+ import { AvailabilityOracleAbi, InboxAbi, NewInboxAbi, RollupAbi } from '@aztec/l1-artifacts';
16
8
 
17
9
  import { Hex, Log, PublicClient, decodeFunctionData, getAbiItem, getAddress, hexToBytes } from 'viem';
18
10
 
11
+ /**
12
+ * Processes newly received LeafInserted (L1 to L2) logs.
13
+ * @param logs - LeafInserted logs.
14
+ * @returns Array of all processed LeafInserted logs
15
+ */
16
+ export function processLeafInsertedLogs(
17
+ logs: Log<bigint, number, false, undefined, true, typeof NewInboxAbi, 'LeafInserted'>[],
18
+ ): NewInboxLeaf[] {
19
+ const leaves: NewInboxLeaf[] = [];
20
+ for (const log of logs) {
21
+ const { blockNumber, index, value } = log.args;
22
+ leaves.push(new NewInboxLeaf(blockNumber, index, Buffer.from(hexToBytes(value))));
23
+ }
24
+ return leaves;
25
+ }
26
+
19
27
  /**
20
28
  * Processes newly received MessageAdded (L1 to L2) logs.
21
29
  * @param logs - MessageAdded logs.
@@ -227,24 +235,24 @@ export function getTxsPublishedLogs(
227
235
  }
228
236
 
229
237
  /**
230
- * Gets relevant `ContractDeployment` logs from chain.
238
+ * Get relevant `MessageAdded` logs emitted by Inbox on chain.
231
239
  * @param publicClient - The viem public client to use for transaction retrieval.
232
- * @param contractDeploymentEmitterAddress - The address of the L2 contract deployment emitter contract.
240
+ * @param inboxAddress - The address of the inbox contract.
233
241
  * @param fromBlock - First block to get logs from (inclusive).
234
242
  * @param toBlock - Last block to get logs from (inclusive).
235
- * @returns An array of `ContractDeployment` logs.
243
+ * @returns An array of `MessageAdded` logs.
236
244
  */
237
- export function getContractDeploymentLogs(
245
+ export function getPendingL1ToL2MessageLogs(
238
246
  publicClient: PublicClient,
239
- contractDeploymentEmitterAddress: EthAddress,
247
+ inboxAddress: EthAddress,
240
248
  fromBlock: bigint,
241
249
  toBlock: bigint,
242
- ): Promise<Log<bigint, number, false, undefined, true, typeof ContractDeploymentEmitterAbi, 'ContractDeployment'>[]> {
250
+ ): Promise<Log<bigint, number, false, undefined, true, typeof InboxAbi, 'MessageAdded'>[]> {
243
251
  return publicClient.getLogs({
244
- address: getAddress(contractDeploymentEmitterAddress.toString()),
252
+ address: getAddress(inboxAddress.toString()),
245
253
  event: getAbiItem({
246
- abi: ContractDeploymentEmitterAbi,
247
- name: 'ContractDeployment',
254
+ abi: InboxAbi,
255
+ name: 'MessageAdded',
248
256
  }),
249
257
  fromBlock,
250
258
  toBlock: toBlock + 1n, // the toBlock argument in getLogs is exclusive
@@ -252,64 +260,24 @@ export function getContractDeploymentLogs(
252
260
  }
253
261
 
254
262
  /**
255
- * Processes newly received ContractDeployment logs.
256
- * @param blockNumberToBodyHash - A mapping from block number to relevant body hash.
257
- * @param logs - ContractDeployment logs.
258
- * @returns The set of retrieved extended contract data items.
259
- */
260
- export function processContractDeploymentLogs(
261
- blockNumberToBodyHash: { [key: number]: Buffer | undefined },
262
- logs: Log<bigint, number, false, undefined, true, typeof ContractDeploymentEmitterAbi, 'ContractDeployment'>[],
263
- ): [ExtendedContractData[], number][] {
264
- const extendedContractData: [ExtendedContractData[], number][] = [];
265
- for (let i = 0; i < logs.length; i++) {
266
- const log = logs[i];
267
- const l2BlockNum = Number(log.args.l2BlockNum);
268
- const blockHash = Buffer.from(hexToBytes(log.args.l2BlockHash));
269
- const expectedBlockHash = blockNumberToBodyHash[l2BlockNum];
270
- if (expectedBlockHash === undefined || !blockHash.equals(expectedBlockHash)) {
271
- continue;
272
- }
273
- const publicFnsReader = BufferReader.asReader(Buffer.from(log.args.acir.slice(2), 'hex'));
274
- const contractClassId = Fr.fromBuffer(Buffer.from(hexToBytes(log.args.contractClassId)));
275
- const saltedInitializationHash = Fr.fromBuffer(Buffer.from(hexToBytes(log.args.saltedInitializationHash)));
276
- const publicKeyHash = Fr.fromBuffer(Buffer.from(hexToBytes(log.args.publicKeyHash)));
277
-
278
- const contractData = new ExtendedContractData(
279
- new ContractData(AztecAddress.fromString(log.args.aztecAddress), EthAddress.fromString(log.args.portalAddress)),
280
- publicFnsReader.readVector(EncodedContractFunction),
281
- contractClassId,
282
- saltedInitializationHash,
283
- publicKeyHash,
284
- );
285
- if (extendedContractData[i]) {
286
- extendedContractData[i][0].push(contractData);
287
- } else {
288
- extendedContractData[i] = [[contractData], l2BlockNum];
289
- }
290
- }
291
- return extendedContractData;
292
- }
293
-
294
- /**
295
- * Get relevant `MessageAdded` logs emitted by Inbox on chain.
263
+ * Get relevant `L1ToL2MessageCancelled` logs emitted by Inbox on chain when pending messages are cancelled
296
264
  * @param publicClient - The viem public client to use for transaction retrieval.
297
265
  * @param inboxAddress - The address of the inbox contract.
298
266
  * @param fromBlock - First block to get logs from (inclusive).
299
267
  * @param toBlock - Last block to get logs from (inclusive).
300
- * @returns An array of `MessageAdded` logs.
268
+ * @returns An array of `L1ToL2MessageCancelled` logs.
301
269
  */
302
- export function getPendingL1ToL2MessageLogs(
270
+ export function getL1ToL2MessageCancelledLogs(
303
271
  publicClient: PublicClient,
304
272
  inboxAddress: EthAddress,
305
273
  fromBlock: bigint,
306
274
  toBlock: bigint,
307
- ): Promise<Log<bigint, number, false, undefined, true, typeof InboxAbi, 'MessageAdded'>[]> {
275
+ ): Promise<Log<bigint, number, false, undefined, true, typeof InboxAbi, 'L1ToL2MessageCancelled'>[]> {
308
276
  return publicClient.getLogs({
309
277
  address: getAddress(inboxAddress.toString()),
310
278
  event: getAbiItem({
311
279
  abi: InboxAbi,
312
- name: 'MessageAdded',
280
+ name: 'L1ToL2MessageCancelled',
313
281
  }),
314
282
  fromBlock,
315
283
  toBlock: toBlock + 1n, // the toBlock argument in getLogs is exclusive
@@ -317,24 +285,24 @@ export function getPendingL1ToL2MessageLogs(
317
285
  }
318
286
 
319
287
  /**
320
- * Get relevant `L1ToL2MessageCancelled` logs emitted by Inbox on chain when pending messages are cancelled
288
+ * Get relevant `LeafInserted` logs emitted by NewInbox on chain.
321
289
  * @param publicClient - The viem public client to use for transaction retrieval.
322
- * @param inboxAddress - The address of the inbox contract.
290
+ * @param newInboxAddress - The address of the new inbox contract.
323
291
  * @param fromBlock - First block to get logs from (inclusive).
324
292
  * @param toBlock - Last block to get logs from (inclusive).
325
- * @returns An array of `L1ToL2MessageCancelled` logs.
293
+ * @returns An array of `LeafInserted` logs.
326
294
  */
327
- export function getL1ToL2MessageCancelledLogs(
295
+ export function getLeafInsertedLogs(
328
296
  publicClient: PublicClient,
329
- inboxAddress: EthAddress,
297
+ newInboxAddress: EthAddress,
330
298
  fromBlock: bigint,
331
299
  toBlock: bigint,
332
- ): Promise<Log<bigint, number, false, undefined, true, typeof InboxAbi, 'L1ToL2MessageCancelled'>[]> {
300
+ ): Promise<Log<bigint, number, false, undefined, true, typeof NewInboxAbi, 'LeafInserted'>[]> {
333
301
  return publicClient.getLogs({
334
- address: getAddress(inboxAddress.toString()),
302
+ address: getAddress(newInboxAddress.toString()),
335
303
  event: getAbiItem({
336
- abi: InboxAbi,
337
- name: 'L1ToL2MessageCancelled',
304
+ abi: NewInboxAbi,
305
+ name: 'LeafInserted',
338
306
  }),
339
307
  fromBlock,
340
308
  toBlock: toBlock + 1n, // the toBlock argument in getLogs is exclusive
@@ -55,16 +55,6 @@ export class BlockStore {
55
55
  block.getTxs().forEach((tx, i) => {
56
56
  void this.#txIndex.set(tx.txHash.toString(), [block.number, i]);
57
57
  });
58
-
59
- block.body.txEffects
60
- .flatMap(txEffect => txEffect.contractData)
61
- .forEach((contractData, i) => {
62
- if (contractData.contractAddress.isZero()) {
63
- return;
64
- }
65
-
66
- void this.#contractIndex.set(contractData.contractAddress.toString(), [block.number, i]);
67
- });
68
58
  }
69
59
 
70
60
  return true;
@@ -1,4 +1,4 @@
1
- import { ContractData, ExtendedContractData } from '@aztec/circuit-types';
1
+ import { ExtendedContractData } from '@aztec/circuit-types';
2
2
  import { AztecAddress } from '@aztec/foundation/aztec-address';
3
3
  import { createDebugLogger } from '@aztec/foundation/log';
4
4
  import { AztecKVStore, AztecMap } from '@aztec/kv-store';
@@ -52,47 +52,4 @@ export class ContractStore {
52
52
 
53
53
  return undefined;
54
54
  }
55
-
56
- /**
57
- * Lookup all extended contract data in an L2 block.
58
- * @param blockNumber - The block number to get all contract data from.
59
- * @returns All extended contract data in the block (if found).
60
- */
61
- getExtendedContractDataInBlock(blockNumber: number): Array<ExtendedContractData> {
62
- return (this.#extendedContractData.get(blockNumber) ?? []).map(contract =>
63
- ExtendedContractData.fromBuffer(contract),
64
- );
65
- }
66
-
67
- /**
68
- * Get basic info for an L2 contract.
69
- * Contains contract address & the ethereum portal address.
70
- * @param contractAddress - The contract data address.
71
- * @returns ContractData with the portal address (if we didn't throw an error).
72
- */
73
- getContractData(contractAddress: AztecAddress): ContractData | undefined {
74
- const [blockNumber, index] = this.#blockStore.getContractLocation(contractAddress) ?? [];
75
- if (typeof blockNumber !== 'number' || typeof index !== 'number') {
76
- return undefined;
77
- }
78
-
79
- const block = this.#blockStore.getBlock(blockNumber);
80
-
81
- if (block?.body.txEffects[index].contractData.length !== 1) {
82
- throw new Error(`Contract data at block: ${blockNumber}, tx: ${index} does not have length of 1`);
83
- }
84
-
85
- return block?.body.txEffects[index].contractData[0];
86
- }
87
-
88
- /**
89
- * Get basic info for an all L2 contracts deployed in a block.
90
- * Contains contract address & the ethereum portal address.
91
- * @param blockNumber - Number of the L2 block where contracts were deployed.
92
- * @returns ContractData with the portal address (if we didn't throw an error).
93
- */
94
- getContractDataInBlock(blockNumber: number): ContractData[] {
95
- const block = this.#blockStore.getBlock(blockNumber);
96
- return block?.body.txEffects.flatMap(txEffect => txEffect.contractData) ?? [];
97
- }
98
55
  }
@@ -1,6 +1,5 @@
1
1
  import {
2
2
  Body,
3
- ContractData,
4
3
  ExtendedContractData,
5
4
  GetUnencryptedLogsResponse,
6
5
  L1ToL2Message,
@@ -8,6 +7,7 @@ import {
8
7
  L2BlockL2Logs,
9
8
  LogFilter,
10
9
  LogType,
10
+ NewInboxLeaf,
11
11
  TxEffect,
12
12
  TxHash,
13
13
  TxReceipt,
@@ -148,6 +148,16 @@ export class KVArchiverDataStore implements ArchiverDataStore {
148
148
  return this.#logStore.addLogs(encryptedLogs, unencryptedLogs, blockNumber);
149
149
  }
150
150
 
151
+ /**
152
+ * Append new L1 to L2 messages to the store.
153
+ * @param messages - The L1 to L2 messages to be added to the store.
154
+ * @param lastMessageL1BlockNumber - The L1 block number in which the last message was emitted.
155
+ * @returns True if the operation is successful.
156
+ */
157
+ addNewL1ToL2Messages(messages: NewInboxLeaf[], lastMessageL1BlockNumber: bigint): Promise<boolean> {
158
+ return Promise.resolve(this.#messageStore.addNewL1ToL2Messages(messages, lastMessageL1BlockNumber));
159
+ }
160
+
151
161
  /**
152
162
  * Append new pending L1 to L2 messages to the store.
153
163
  * @param messages - The L1 to L2 messages to be added to the store.
@@ -201,6 +211,19 @@ export class KVArchiverDataStore implements ArchiverDataStore {
201
211
  }
202
212
  }
203
213
 
214
+ /**
215
+ * Gets new L1 to L2 message (to be) included in a given block.
216
+ * @param blockNumber - L2 block number to get messages for.
217
+ * @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found).
218
+ */
219
+ getNewL1ToL2Messages(blockNumber: bigint): Promise<Buffer[]> {
220
+ try {
221
+ return Promise.resolve(this.#messageStore.getNewL1ToL2Messages(blockNumber));
222
+ } catch (err) {
223
+ return Promise.reject(err);
224
+ }
225
+ }
226
+
204
227
  /**
205
228
  * Gets up to `limit` amount of logs starting from `from`.
206
229
  * @param start - Number of the L2 block to which corresponds the first logs to be returned.
@@ -248,35 +271,6 @@ export class KVArchiverDataStore implements ArchiverDataStore {
248
271
  return Promise.resolve(this.#contractStore.getExtendedContractData(contractAddress));
249
272
  }
250
273
 
251
- /**
252
- * Lookup all extended contract data in an L2 block.
253
- * @param blockNumber - The block number to get all contract data from.
254
- * @returns All extended contract data in the block (if found).
255
- */
256
- getExtendedContractDataInBlock(blockNumber: number): Promise<ExtendedContractData[]> {
257
- return Promise.resolve(Array.from(this.#contractStore.getExtendedContractDataInBlock(blockNumber)));
258
- }
259
-
260
- /**
261
- * Get basic info for an L2 contract.
262
- * Contains contract address & the ethereum portal address.
263
- * @param contractAddress - The contract data address.
264
- * @returns ContractData with the portal address (if we didn't throw an error).
265
- */
266
- getContractData(contractAddress: AztecAddress): Promise<ContractData | undefined> {
267
- return Promise.resolve(this.#contractStore.getContractData(contractAddress));
268
- }
269
-
270
- /**
271
- * Get basic info for an all L2 contracts deployed in a block.
272
- * Contains contract address & the ethereum portal address.
273
- * @param blockNumber - Number of the L2 block where contracts were deployed.
274
- * @returns ContractData with the portal address (if we didn't throw an error).
275
- */
276
- getContractDataInBlock(blockNumber: number): Promise<ContractData[]> {
277
- return Promise.resolve(Array.from(this.#contractStore.getContractDataInBlock(blockNumber)));
278
- }
279
-
280
274
  /**
281
275
  * Gets the number of the latest L2 block processed.
282
276
  * @returns The number of the latest L2 block processed.
@@ -290,10 +284,11 @@ export class KVArchiverDataStore implements ArchiverDataStore {
290
284
  */
291
285
  getL1BlockNumber(): Promise<ArchiverL1SynchPoint> {
292
286
  const addedBlock = this.#blockStore.getL1BlockNumber();
293
- const { addedMessages, cancelledMessages } = this.#messageStore.getL1BlockNumber();
287
+ const { addedMessages, cancelledMessages, newMessages } = this.#messageStore.getL1BlockNumber();
294
288
  return Promise.resolve({
295
289
  addedBlock,
296
290
  addedMessages,
291
+ newMessages,
297
292
  cancelledMessages,
298
293
  });
299
294
  }
@@ -1,5 +1,5 @@
1
- import { L1ToL2Message } from '@aztec/circuit-types';
2
- import { Fr } from '@aztec/circuits.js';
1
+ import { L1ToL2Message, NewInboxLeaf } from '@aztec/circuit-types';
2
+ import { Fr, L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/circuits.js';
3
3
  import { createDebugLogger } from '@aztec/foundation/log';
4
4
  import { AztecCounter, AztecKVStore, AztecMap, AztecSingleton } from '@aztec/kv-store';
5
5
 
@@ -19,16 +19,23 @@ type Message = {
19
19
  * LMDB implementation of the ArchiverDataStore interface.
20
20
  */
21
21
  export class MessageStore {
22
- #messages: AztecMap<string, Message>;
22
+ #newMessages: AztecMap<string, Buffer>;
23
+ #lastL1BlockNewMessages: AztecSingleton<bigint>;
24
+ // TODO(#4492): Nuke the following when purging the old inbox
23
25
  #pendingMessagesByFee: AztecCounter<[number, string]>;
26
+ #messages: AztecMap<string, Message>;
24
27
  #lastL1BlockAddingMessages: AztecSingleton<bigint>;
25
28
  #lastL1BlockCancellingMessages: AztecSingleton<bigint>;
26
29
 
27
30
  #log = createDebugLogger('aztec:archiver:message_store');
28
31
 
32
+ #l1ToL2MessagesSubtreeSize = 2 ** L1_TO_L2_MSG_SUBTREE_HEIGHT;
33
+
29
34
  constructor(private db: AztecKVStore) {
35
+ this.#newMessages = db.openMap('archiver_l1_to_l2_new_messages');
30
36
  this.#messages = db.openMap('archiver_l1_to_l2_messages');
31
37
  this.#pendingMessagesByFee = db.openCounter('archiver_messages_by_fee');
38
+ this.#lastL1BlockNewMessages = db.openSingleton('archiver_last_l1_block_new_messages');
32
39
  this.#lastL1BlockAddingMessages = db.openSingleton('archiver_last_l1_block_adding_messages');
33
40
  this.#lastL1BlockCancellingMessages = db.openSingleton('archiver_last_l1_block_cancelling_messages');
34
41
  }
@@ -39,11 +46,40 @@ export class MessageStore {
39
46
  */
40
47
  getL1BlockNumber() {
41
48
  return {
49
+ newMessages: this.#lastL1BlockNewMessages.get() ?? 0n,
50
+ // TODO(#4492): Nuke the following when purging the old inbox
42
51
  addedMessages: this.#lastL1BlockAddingMessages.get() ?? 0n,
43
52
  cancelledMessages: this.#lastL1BlockCancellingMessages.get() ?? 0n,
44
53
  };
45
54
  }
46
55
 
56
+ /**
57
+ * Append new L1 to L2 messages to the store.
58
+ * @param messages - The L1 to L2 messages to be added to the store.
59
+ * @param lastMessageL1BlockNumber - The L1 block number in which the last message was emitted.
60
+ * @returns True if the operation is successful.
61
+ */
62
+ addNewL1ToL2Messages(messages: NewInboxLeaf[], lastMessageL1BlockNumber: bigint): Promise<boolean> {
63
+ return this.db.transaction(() => {
64
+ const lastL1BlockNumber = this.#lastL1BlockNewMessages.get() ?? 0n;
65
+ if (lastL1BlockNumber >= lastMessageL1BlockNumber) {
66
+ return false;
67
+ }
68
+
69
+ void this.#lastL1BlockNewMessages.set(lastMessageL1BlockNumber);
70
+
71
+ for (const message of messages) {
72
+ if (message.index >= this.#l1ToL2MessagesSubtreeSize) {
73
+ throw new Error(`Message index ${message.index} out of subtree range`);
74
+ }
75
+ const key = `${message.blockNumber}-${message.index}`;
76
+ void this.#newMessages.setIfNotExists(key, message.leaf);
77
+ }
78
+
79
+ return true;
80
+ });
81
+ }
82
+
47
83
  /**
48
84
  * Append new pending L1 to L2 messages to the store.
49
85
  * @param messages - The L1 to L2 messages to be added to the store.
@@ -171,4 +207,25 @@ export class MessageStore {
171
207
 
172
208
  return entryKeys;
173
209
  }
210
+
211
+ getNewL1ToL2Messages(blockNumber: bigint): Buffer[] {
212
+ const messages: Buffer[] = [];
213
+ let undefinedMessageFound = false;
214
+ for (let messageIndex = 0; messageIndex < this.#l1ToL2MessagesSubtreeSize; messageIndex++) {
215
+ // This is inefficient but probably fine for now.
216
+ const key = `${blockNumber}-${messageIndex}`;
217
+ const message = this.#newMessages.get(key);
218
+ if (message) {
219
+ if (undefinedMessageFound) {
220
+ throw new Error(`L1 to L2 message gap found in block ${blockNumber}`);
221
+ }
222
+ messages.push(message);
223
+ } else {
224
+ undefinedMessageFound = true;
225
+ // We continue iterating over messages here to verify that there are no more messages after the undefined one.
226
+ // --> If this was the case this would imply there is some issue with log fetching.
227
+ }
228
+ }
229
+ return messages;
230
+ }
174
231
  }
@@ -1,6 +1,53 @@
1
- import { L1ToL2Message } from '@aztec/circuit-types';
1
+ import { L1ToL2Message, NewInboxLeaf } from '@aztec/circuit-types';
2
+ import { L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/circuits.js/constants';
2
3
  import { Fr } from '@aztec/foundation/fields';
3
4
 
5
+ /**
6
+ * A simple in-memory implementation of an L1 to L2 message store
7
+ * that handles message duplication.
8
+ * TODO(#4492): Clean this up
9
+ */
10
+ export class NewL1ToL2MessageStore {
11
+ /**
12
+ * A map containing the entry key to the corresponding L1 to L2
13
+ * messages (and the number of times the message has been seen).
14
+ */
15
+ protected store: Map<string, Buffer> = new Map();
16
+
17
+ #l1ToL2MessagesSubtreeSize = 2 ** L1_TO_L2_MSG_SUBTREE_HEIGHT;
18
+
19
+ constructor() {}
20
+
21
+ addMessage(message: NewInboxLeaf) {
22
+ if (message.index >= this.#l1ToL2MessagesSubtreeSize) {
23
+ throw new Error(`Message index ${message.index} out of subtree range`);
24
+ }
25
+ const key = `${message.blockNumber}-${message.index}`;
26
+ this.store.set(key, message.leaf);
27
+ }
28
+
29
+ getMessages(blockNumber: bigint): Buffer[] {
30
+ const messages: Buffer[] = [];
31
+ let undefinedMessageFound = false;
32
+ for (let messageIndex = 0; messageIndex < this.#l1ToL2MessagesSubtreeSize; messageIndex++) {
33
+ // This is inefficient but probably fine for now.
34
+ const key = `${blockNumber}-${messageIndex}`;
35
+ const message = this.store.get(key);
36
+ if (message) {
37
+ if (undefinedMessageFound) {
38
+ throw new Error(`L1 to L2 message gap found in block ${blockNumber}`);
39
+ }
40
+ messages.push(message);
41
+ } else {
42
+ undefinedMessageFound = true;
43
+ // We continue iterating over messages here to verify that there are no more messages after the undefined one.
44
+ // --> If this was the case this would imply there is some issue with log fetching.
45
+ }
46
+ }
47
+ return messages;
48
+ }
49
+ }
50
+
4
51
  /**
5
52
  * A simple in-memory implementation of an L1 to L2 message store
6
53
  * that handles message duplication.