@aztec/archiver 0.16.0 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dest/archiver/archiver.d.ts +3 -6
  2. package/dest/archiver/archiver.d.ts.map +1 -1
  3. package/dest/archiver/archiver.js +25 -46
  4. package/dest/archiver/archiver_store.d.ts +10 -161
  5. package/dest/archiver/archiver_store.d.ts.map +1 -1
  6. package/dest/archiver/archiver_store.js +2 -328
  7. package/dest/archiver/archiver_store_test_suite.d.ts +8 -0
  8. package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -0
  9. package/dest/archiver/archiver_store_test_suite.js +478 -0
  10. package/dest/archiver/data_retrieval.d.ts +3 -4
  11. package/dest/archiver/data_retrieval.d.ts.map +1 -1
  12. package/dest/archiver/data_retrieval.js +1 -1
  13. package/dest/archiver/eth_log_handlers.d.ts +3 -4
  14. package/dest/archiver/eth_log_handlers.d.ts.map +1 -1
  15. package/dest/archiver/eth_log_handlers.js +7 -6
  16. package/dest/archiver/index.d.ts +3 -0
  17. package/dest/archiver/index.d.ts.map +1 -1
  18. package/dest/archiver/index.js +3 -1
  19. package/dest/archiver/lmdb_archiver_store.d.ts +125 -0
  20. package/dest/archiver/lmdb_archiver_store.d.ts.map +1 -0
  21. package/dest/archiver/lmdb_archiver_store.js +545 -0
  22. package/dest/archiver/{l1_to_l2_message_store.d.ts → memory_archiver_store/l1_to_l2_message_store.d.ts} +6 -2
  23. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts.map +1 -0
  24. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.js +91 -0
  25. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +163 -0
  26. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +1 -0
  27. package/dest/archiver/memory_archiver_store/memory_archiver_store.js +338 -0
  28. package/dest/index.js +3 -4
  29. package/package.json +7 -6
  30. package/src/archiver/archiver.ts +40 -53
  31. package/src/archiver/archiver_store.ts +16 -373
  32. package/src/archiver/archiver_store_test_suite.ts +638 -0
  33. package/src/archiver/data_retrieval.ts +5 -6
  34. package/src/archiver/eth_log_handlers.ts +23 -16
  35. package/src/archiver/index.ts +3 -0
  36. package/src/archiver/lmdb_archiver_store.ts +728 -0
  37. package/src/archiver/{l1_to_l2_message_store.ts → memory_archiver_store/l1_to_l2_message_store.ts} +23 -3
  38. package/src/archiver/memory_archiver_store/memory_archiver_store.ts +399 -0
  39. package/src/index.ts +1 -2
  40. package/dest/archiver/l1_to_l2_message_store.d.ts.map +0 -1
  41. package/dest/archiver/l1_to_l2_message_store.js +0 -72
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/archiver",
3
- "version": "0.16.0",
3
+ "version": "0.16.1",
4
4
  "type": "module",
5
5
  "exports": "./dest/index.js",
6
6
  "typedocOptions": {
@@ -34,13 +34,14 @@
34
34
  "rootDir": "./src"
35
35
  },
36
36
  "dependencies": {
37
- "@aztec/circuits.js": "0.16.0",
38
- "@aztec/ethereum": "0.16.0",
39
- "@aztec/foundation": "0.16.0",
40
- "@aztec/l1-artifacts": "0.16.0",
41
- "@aztec/types": "0.16.0",
37
+ "@aztec/circuits.js": "0.16.1",
38
+ "@aztec/ethereum": "0.16.1",
39
+ "@aztec/foundation": "0.16.1",
40
+ "@aztec/l1-artifacts": "0.16.1",
41
+ "@aztec/types": "0.16.1",
42
42
  "@types/lodash.omit": "^4.5.7",
43
43
  "debug": "^4.3.4",
44
+ "lmdb": "^2.9.1",
44
45
  "lodash.omit": "^4.5.0",
45
46
  "tsc-watch": "^6.0.0",
46
47
  "tslib": "^2.5.0",
@@ -6,7 +6,6 @@ import { EthAddress } from '@aztec/foundation/eth-address';
6
6
  import { Fr } from '@aztec/foundation/fields';
7
7
  import { DebugLogger, createDebugLogger } from '@aztec/foundation/log';
8
8
  import { RunningPromise } from '@aztec/foundation/running-promise';
9
- import { RegistryAbi } from '@aztec/l1-artifacts';
10
9
  import {
11
10
  ContractData,
12
11
  ContractDataSource,
@@ -26,9 +25,9 @@ import {
26
25
  } from '@aztec/types';
27
26
 
28
27
  import omit from 'lodash.omit';
29
- import { Chain, HttpTransport, PublicClient, createPublicClient, getContract, http } from 'viem';
28
+ import { Chain, HttpTransport, PublicClient, createPublicClient, http } from 'viem';
30
29
 
31
- import { ArchiverDataStore, MemoryArchiverStore } from './archiver_store.js';
30
+ import { ArchiverDataStore } from './archiver_store.js';
32
31
  import { ArchiverConfig } from './config.js';
33
32
  import {
34
33
  retrieveBlocks,
@@ -53,11 +52,6 @@ export class Archiver implements L2BlockSource, L2LogsSource, ContractDataSource
53
52
  */
54
53
  private nextL2BlockFromL1Block = 0n;
55
54
 
56
- /**
57
- * Last Processed Block Number
58
- */
59
- private lastProcessedL1BlockNumber = 0n;
60
-
61
55
  /**
62
56
  * Use this to track logged block in order to avoid repeating the same message.
63
57
  */
@@ -81,22 +75,23 @@ export class Archiver implements L2BlockSource, L2LogsSource, ContractDataSource
81
75
  private readonly inboxAddress: EthAddress,
82
76
  private readonly registryAddress: EthAddress,
83
77
  private readonly contractDeploymentEmitterAddress: EthAddress,
84
- searchStartBlock: number,
85
78
  private readonly store: ArchiverDataStore,
86
79
  private readonly pollingIntervalMs = 10_000,
87
80
  private readonly log: DebugLogger = createDebugLogger('aztec:archiver'),
88
- ) {
89
- this.nextL2BlockFromL1Block = BigInt(searchStartBlock);
90
- this.lastProcessedL1BlockNumber = BigInt(searchStartBlock);
91
- }
81
+ ) {}
92
82
 
93
83
  /**
94
84
  * Creates a new instance of the Archiver and blocks until it syncs from chain.
95
85
  * @param config - The archiver's desired configuration.
86
+ * @param archiverStore - The backing store for the archiver.
96
87
  * @param blockUntilSynced - If true, blocks until the archiver has fully synced.
97
88
  * @returns - An instance of the archiver.
98
89
  */
99
- public static async createAndSync(config: ArchiverConfig, blockUntilSynced = true): Promise<Archiver> {
90
+ public static async createAndSync(
91
+ config: ArchiverConfig,
92
+ archiverStore: ArchiverDataStore,
93
+ blockUntilSynced = true,
94
+ ): Promise<Archiver> {
100
95
  const chain = createEthereumChain(config.rpcUrl, config.apiKey);
101
96
  const publicClient = createPublicClient({
102
97
  chain: chain.chainInfo,
@@ -104,23 +99,12 @@ export class Archiver implements L2BlockSource, L2LogsSource, ContractDataSource
104
99
  pollingInterval: config.viemPollingIntervalMS,
105
100
  });
106
101
 
107
- // ask the registry for the block number when the rollup was deployed
108
- // this is the block from which archiver has to search from
109
- const registryContract = getContract({
110
- address: config.l1Contracts.registryAddress.toString(),
111
- abi: RegistryAbi,
112
- publicClient,
113
- });
114
- const searchStartBlock = Number((await registryContract.read.getCurrentSnapshot()).blockNumber);
115
-
116
- const archiverStore = new MemoryArchiverStore(config.maxLogs ?? 1000);
117
102
  const archiver = new Archiver(
118
103
  publicClient,
119
104
  config.l1Contracts.rollupAddress,
120
105
  config.l1Contracts.inboxAddress,
121
106
  config.l1Contracts.registryAddress,
122
107
  config.l1Contracts.contractDeploymentEmitterAddress,
123
- searchStartBlock,
124
108
  archiverStore,
125
109
  config.archiverPollingIntervalMS,
126
110
  );
@@ -152,7 +136,12 @@ export class Archiver implements L2BlockSource, L2LogsSource, ContractDataSource
152
136
  */
153
137
  private async sync(blockUntilSynced: boolean) {
154
138
  const currentL1BlockNumber = await this.publicClient.getBlockNumber();
155
- if (currentL1BlockNumber <= this.lastProcessedL1BlockNumber) {
139
+ // this makes the archiver more resilient to eventually-consistent eth providers like Infura
140
+ // it _will_ process the same L1 blocks over and over again until the L2 chain advances
141
+ // one thing to handle now is that we will process the same L1 to L2 messages over and over again
142
+ // so the store needs to account for that.
143
+ const lastProcessedL1BlockNumber = await this.store.getL1BlockNumber();
144
+ if (currentL1BlockNumber <= lastProcessedL1BlockNumber) {
156
145
  // reducing logs, otherwise this gets triggered on every loop (1s)
157
146
  if (currentL1BlockNumber !== this.lastLoggedL1BlockNumber) {
158
147
  this.log(`No new blocks to process, current block number: ${currentL1BlockNumber}`);
@@ -169,14 +158,14 @@ export class Archiver implements L2BlockSource, L2LogsSource, ContractDataSource
169
158
  * to ensure that data is read exactly once.
170
159
  *
171
160
  * The first is the problem of eventually consistent ETH service providers like Infura.
172
- * We are not currently handling this correctly in the case of L1 to L2 messages and we will
173
- * want to re-visit L2 Block and contract data retrieval at a later stage. This is not
174
- * currently a problem but will need to be addressed before a mainnet release.
161
+ * We currently read from the last L1 block that we saw emit an L2 block. This could mean
162
+ * that the archiver ends up looking at the same L1 block multiple times (e.g. if we last saw
163
+ * an L2 block emitted at L1 block 10, we'd constantly ask for L1 blocks from 11 onwards until
164
+ * we see another L2 block). For this to work message and block processing need to be idempotent.
165
+ * We should re-visit this before mainnet launch.
175
166
  *
176
167
  * The second is that in between the various calls to L1, the block number can move meaning some
177
168
  * of the following calls will return data for blocks that were not present during earlier calls.
178
- * This is a problem for example when setting the last block number marker for L1 to L2 messages -
179
- * this.lastProcessedBlockNumber = currentBlockNumber;
180
169
  * It's possible that we actually received messages in block currentBlockNumber + 1 meaning the next time
181
170
  * we do this sync we get the same message again. Additionally, the call to get cancelled L1 to L2 messages
182
171
  * could read from a block not present when retrieving pending messages. If a message was added and cancelled
@@ -195,14 +184,14 @@ export class Archiver implements L2BlockSource, L2LogsSource, ContractDataSource
195
184
  this.publicClient,
196
185
  this.inboxAddress,
197
186
  blockUntilSynced,
198
- this.lastProcessedL1BlockNumber + 1n, // + 1 to prevent re-including messages from the last processed block
187
+ lastProcessedL1BlockNumber + 1n, // + 1 to prevent re-including messages from the last processed block
199
188
  currentL1BlockNumber,
200
189
  );
201
190
  const retrievedCancelledL1ToL2Messages = await retrieveNewCancelledL1ToL2Messages(
202
191
  this.publicClient,
203
192
  this.inboxAddress,
204
193
  blockUntilSynced,
205
- this.lastProcessedL1BlockNumber + 1n,
194
+ lastProcessedL1BlockNumber + 1n,
206
195
  currentL1BlockNumber,
207
196
  );
208
197
 
@@ -215,8 +204,6 @@ export class Archiver implements L2BlockSource, L2LogsSource, ContractDataSource
215
204
  this.log('Removing pending l1 to l2 messages from store where messages were cancelled');
216
205
  await this.store.cancelPendingL1ToL2Messages(retrievedCancelledL1ToL2Messages.retrievedData);
217
206
 
218
- this.lastProcessedL1BlockNumber = currentL1BlockNumber;
219
-
220
207
  // ********** Events that are processed per block **********
221
208
 
222
209
  // Read all data from chain and then write to our stores at the end
@@ -252,26 +239,22 @@ export class Archiver implements L2BlockSource, L2LogsSource, ContractDataSource
252
239
 
253
240
  this.log(`Retrieved ${retrievedBlocks.retrievedData.length} block(s) from chain`);
254
241
 
255
- // store encrypted logs from L2 Blocks that we have retrieved
256
- const encryptedLogs = retrievedBlocks.retrievedData.map(block => {
257
- return block.newEncryptedLogs!;
258
- });
259
- await this.store.addLogs(encryptedLogs, LogType.ENCRYPTED);
260
-
261
- // store unencrypted logs from L2 Blocks that we have retrieved
262
- const unencryptedLogs = retrievedBlocks.retrievedData.map(block => {
263
- return block.newUnencryptedLogs!;
264
- });
265
- await this.store.addLogs(unencryptedLogs, LogType.UNENCRYPTED);
242
+ await Promise.all(
243
+ retrievedBlocks.retrievedData.map(block =>
244
+ this.store.addLogs(block.newEncryptedLogs, block.newUnencryptedLogs, block.number),
245
+ ),
246
+ );
266
247
 
267
248
  // store contracts for which we have retrieved L2 blocks
268
249
  const lastKnownL2BlockNum = retrievedBlocks.retrievedData[retrievedBlocks.retrievedData.length - 1].number;
269
- retrievedContracts.retrievedData.forEach(async ([contracts, l2BlockNum], index) => {
270
- this.log(`Retrieved extended contract data for l2 block number: ${index}`);
271
- if (l2BlockNum <= lastKnownL2BlockNum) {
272
- await this.store.addExtendedContractData(contracts, l2BlockNum);
273
- }
274
- });
250
+ await Promise.all(
251
+ retrievedContracts.retrievedData.map(async ([contracts, l2BlockNum]) => {
252
+ this.log(`Retrieved extended contract data for l2 block number: ${l2BlockNum}`);
253
+ if (l2BlockNum <= lastKnownL2BlockNum) {
254
+ await this.store.addExtendedContractData(contracts, l2BlockNum);
255
+ }
256
+ }),
257
+ );
275
258
 
276
259
  // from retrieved L2Blocks, confirm L1 to L2 messages that have been published
277
260
  // from each l2block fetch all messageKeys in a flattened array:
@@ -285,7 +268,11 @@ export class Archiver implements L2BlockSource, L2LogsSource, ContractDataSource
285
268
  retrievedBlocks.retrievedData.map(block => {
286
269
  // Ensure we pad the L1 to L2 message array to the full size before storing.
287
270
  block.newL1ToL2Messages = padArrayEnd(block.newL1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
288
- return L2Block.fromFields(omit(block, ['newEncryptedLogs', 'newUnencryptedLogs']), block.getBlockHash());
271
+ return L2Block.fromFields(
272
+ omit(block, ['newEncryptedLogs', 'newUnencryptedLogs']),
273
+ block.getBlockHash(),
274
+ block.getL1BlockNumber(),
275
+ );
289
276
  }),
290
277
  );
291
278
 
@@ -1,25 +1,20 @@
1
- import { Fr, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/circuits.js';
1
+ import { Fr } from '@aztec/circuits.js';
2
2
  import { AztecAddress } from '@aztec/foundation/aztec-address';
3
3
  import {
4
+ CancelledL1ToL2Message,
4
5
  ContractData,
5
6
  ExtendedContractData,
6
- ExtendedUnencryptedL2Log,
7
7
  GetUnencryptedLogsResponse,
8
- INITIAL_L2_BLOCK_NUM,
9
8
  L1ToL2Message,
10
9
  L2Block,
11
- L2BlockContext,
12
10
  L2BlockL2Logs,
13
11
  L2Tx,
14
12
  LogFilter,
15
- LogId,
16
13
  LogType,
14
+ PendingL1ToL2Message,
17
15
  TxHash,
18
- UnencryptedL2Log,
19
16
  } from '@aztec/types';
20
17
 
21
- import { L1ToL2MessageStore, PendingL1ToL2MessageStore } from './l1_to_l2_message_store.js';
22
-
23
18
  /**
24
19
  * Interface describing a data store to be used by the archiver to store all its relevant data
25
20
  * (blocks, encrypted logs, aztec contract data extended contract data).
@@ -49,25 +44,30 @@ export interface ArchiverDataStore {
49
44
 
50
45
  /**
51
46
  * Append new logs to the store's list.
52
- * @param data - The logs to be added to the store.
53
- * @param logType - The type of the logs to be added to the store.
47
+ * @param encryptedLogs - The encrypted logs to be added to the store.
48
+ * @param unencryptedLogs - The unencrypted logs to be added to the store.
49
+ * @param blockNumber - The block for which to add the logs.
54
50
  * @returns True if the operation is successful.
55
51
  */
56
- addLogs(data: L2BlockL2Logs[], logType: LogType): Promise<boolean>;
52
+ addLogs(
53
+ encryptedLogs: L2BlockL2Logs | undefined,
54
+ unencryptedLogs: L2BlockL2Logs | undefined,
55
+ blockNumber: number,
56
+ ): Promise<boolean>;
57
57
 
58
58
  /**
59
59
  * Append new pending L1 to L2 messages to the store.
60
60
  * @param messages - The L1 to L2 messages to be added to the store.
61
61
  * @returns True if the operation is successful.
62
62
  */
63
- addPendingL1ToL2Messages(messages: L1ToL2Message[]): Promise<boolean>;
63
+ addPendingL1ToL2Messages(messages: PendingL1ToL2Message[]): Promise<boolean>;
64
64
 
65
65
  /**
66
66
  * Remove pending L1 to L2 messages from the store (if they were cancelled).
67
- * @param messageKeys - The message keys to be removed from the store.
67
+ * @param message - The message keys to be removed from the store.
68
68
  * @returns True if the operation is successful.
69
69
  */
70
- cancelPendingL1ToL2Messages(messageKeys: Fr[]): Promise<boolean>;
70
+ cancelPendingL1ToL2Messages(message: CancelledL1ToL2Message[]): Promise<boolean>;
71
71
 
72
72
  /**
73
73
  * Messages that have been published in an L2 block are confirmed.
@@ -150,366 +150,9 @@ export interface ArchiverDataStore {
150
150
  * @returns The number of the latest L2 block processed.
151
151
  */
152
152
  getBlockNumber(): Promise<number>;
153
- }
154
-
155
- /**
156
- * Simple, in-memory implementation of an archiver data store.
157
- */
158
- export class MemoryArchiverStore implements ArchiverDataStore {
159
- /**
160
- * An array containing all the L2 blocks that have been fetched so far.
161
- */
162
- private l2BlockContexts: L2BlockContext[] = [];
163
-
164
- /**
165
- * An array containing all the L2 Txs in the L2 blocks that have been fetched so far.
166
- */
167
- private l2Txs: L2Tx[] = [];
168
-
169
- /**
170
- * An array containing all the encrypted logs that have been fetched so far.
171
- * Note: Index in the "outer" array equals to (corresponding L2 block's number - INITIAL_L2_BLOCK_NUM).
172
- */
173
- private encryptedLogsPerBlock: L2BlockL2Logs[] = [];
174
-
175
- /**
176
- * An array containing all the unencrypted logs that have been fetched so far.
177
- * Note: Index in the "outer" array equals to (corresponding L2 block's number - INITIAL_L2_BLOCK_NUM).
178
- */
179
- private unencryptedLogsPerBlock: L2BlockL2Logs[] = [];
180
-
181
- /**
182
- * A sparse array containing all the extended contract data that have been fetched so far.
183
- */
184
- private extendedContractDataByBlock: (ExtendedContractData[] | undefined)[] = [];
185
-
186
- /**
187
- * A mapping of contract address to extended contract data.
188
- */
189
- private extendedContractData: Map<string, ExtendedContractData> = new Map();
190
-
191
- /**
192
- * Contains all the confirmed L1 to L2 messages (i.e. messages that were consumed in an L2 block)
193
- * It is a map of entryKey to the corresponding L1 to L2 message and the number of times it has appeared
194
- */
195
- private confirmedL1ToL2Messages: L1ToL2MessageStore = new L1ToL2MessageStore();
196
-
197
- /**
198
- * Contains all the pending L1 to L2 messages (accounts for duplication of messages)
199
- */
200
- private pendingL1ToL2Messages: PendingL1ToL2MessageStore = new PendingL1ToL2MessageStore();
201
-
202
- constructor(
203
- /** The max number of logs that can be obtained in 1 "getUnencryptedLogs" call. */
204
- public readonly maxLogs: number,
205
- ) {}
206
-
207
- /**
208
- * Append new blocks to the store's list.
209
- * @param blocks - The L2 blocks to be added to the store.
210
- * @returns True if the operation is successful (always in this implementation).
211
- */
212
- public addBlocks(blocks: L2Block[]): Promise<boolean> {
213
- this.l2BlockContexts.push(...blocks.map(block => new L2BlockContext(block)));
214
- this.l2Txs.push(...blocks.flatMap(b => b.getTxs()));
215
- return Promise.resolve(true);
216
- }
217
153
 
218
154
  /**
219
- * Append new logs to the store's list.
220
- * @param data - The logs to be added to the store.
221
- * @param logType - The type of the logs to be added to the store.
222
- * @returns True if the operation is successful.
223
- */
224
- addLogs(data: L2BlockL2Logs[], logType: LogType): Promise<boolean> {
225
- logType === LogType.ENCRYPTED
226
- ? this.encryptedLogsPerBlock.push(...data)
227
- : this.unencryptedLogsPerBlock.push(...data);
228
- return Promise.resolve(true);
229
- }
230
-
231
- /**
232
- * Append new pending L1 to L2 messages to the store.
233
- * @param messages - The L1 to L2 messages to be added to the store.
234
- * @returns True if the operation is successful (always in this implementation).
235
- */
236
- public addPendingL1ToL2Messages(messages: L1ToL2Message[]): Promise<boolean> {
237
- for (const msg of messages) {
238
- this.pendingL1ToL2Messages.addMessage(msg.entryKey!, msg);
239
- }
240
- return Promise.resolve(true);
241
- }
242
-
243
- /**
244
- * Remove pending L1 to L2 messages from the store (if they were cancelled).
245
- * @param messageKeys - The message keys to be removed from the store.
246
- * @returns True if the operation is successful (always in this implementation).
247
- */
248
- public cancelPendingL1ToL2Messages(messageKeys: Fr[]): Promise<boolean> {
249
- messageKeys.forEach(messageKey => {
250
- this.pendingL1ToL2Messages.removeMessage(messageKey);
251
- });
252
- return Promise.resolve(true);
253
- }
254
-
255
- /**
256
- * Messages that have been published in an L2 block are confirmed.
257
- * Add them to the confirmed store, also remove them from the pending store.
258
- * @param messageKeys - The message keys to be removed from the store.
259
- * @returns True if the operation is successful (always in this implementation).
260
- */
261
- public confirmL1ToL2Messages(messageKeys: Fr[]): Promise<boolean> {
262
- messageKeys.forEach(messageKey => {
263
- this.confirmedL1ToL2Messages.addMessage(messageKey, this.pendingL1ToL2Messages.getMessage(messageKey)!);
264
- this.pendingL1ToL2Messages.removeMessage(messageKey);
265
- });
266
- return Promise.resolve(true);
267
- }
268
-
269
- /**
270
- * Store new extended contract data from an L2 block to the store's list.
271
- * @param data - List of contracts' data to be added.
272
- * @param blockNum - Number of the L2 block the contract data was deployed in.
273
- * @returns True if the operation is successful (always in this implementation).
274
- */
275
- public addExtendedContractData(data: ExtendedContractData[], blockNum: number): Promise<boolean> {
276
- // Add to the contracts mapping
277
- for (const contractData of data) {
278
- const key = contractData.contractData.contractAddress.toString();
279
- this.extendedContractData.set(key, contractData);
280
- }
281
-
282
- // Add the index per block
283
- if (this.extendedContractDataByBlock[blockNum]?.length) {
284
- this.extendedContractDataByBlock[blockNum]?.push(...data);
285
- } else {
286
- this.extendedContractDataByBlock[blockNum] = [...data];
287
- }
288
- return Promise.resolve(true);
289
- }
290
-
291
- /**
292
- * Gets up to `limit` amount of L2 blocks starting from `from`.
293
- * @param from - Number of the first block to return (inclusive).
294
- * @param limit - The number of blocks to return.
295
- * @returns The requested L2 blocks.
296
- * @remarks When "from" is smaller than genesis block number, blocks from the beginning are returned.
297
- */
298
- public getBlocks(from: number, limit: number): Promise<L2Block[]> {
299
- // Return an empty array if we are outside of range
300
- if (limit < 1) {
301
- throw new Error(`Invalid limit: ${limit}`);
302
- }
303
-
304
- const fromIndex = Math.max(from - INITIAL_L2_BLOCK_NUM, 0);
305
- if (fromIndex >= this.l2BlockContexts.length) {
306
- return Promise.resolve([]);
307
- }
308
-
309
- const toIndex = fromIndex + limit;
310
- return Promise.resolve(this.l2BlockContexts.slice(fromIndex, toIndex).map(blockContext => blockContext.block));
311
- }
312
-
313
- /**
314
- * Gets an l2 tx.
315
- * @param txHash - The txHash of the l2 tx.
316
- * @returns The requested L2 tx.
317
- */
318
- public getL2Tx(txHash: TxHash): Promise<L2Tx | undefined> {
319
- const l2Tx = this.l2Txs.find(tx => tx.txHash.equals(txHash));
320
- return Promise.resolve(l2Tx);
321
- }
322
-
323
- /**
324
- * Gets up to `limit` amount of pending L1 to L2 messages, sorted by fee
325
- * @param limit - The number of messages to return (by default NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).
326
- * @returns The requested L1 to L2 message keys.
327
- */
328
- public getPendingL1ToL2MessageKeys(limit: number = NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP): Promise<Fr[]> {
329
- return Promise.resolve(this.pendingL1ToL2Messages.getMessageKeys(limit));
330
- }
331
-
332
- /**
333
- * Gets the confirmed L1 to L2 message corresponding to the given message key.
334
- * @param messageKey - The message key to look up.
335
- * @returns The requested L1 to L2 message or throws if not found.
336
- */
337
- public getConfirmedL1ToL2Message(messageKey: Fr): Promise<L1ToL2Message> {
338
- const message = this.confirmedL1ToL2Messages.getMessage(messageKey);
339
- if (!message) {
340
- throw new Error(`L1 to L2 Message with key ${messageKey.toString()} not found in the confirmed messages store`);
341
- }
342
- return Promise.resolve(message);
343
- }
344
-
345
- /**
346
- * Gets up to `limit` amount of logs starting from `from`.
347
- * @param from - Number of the L2 block to which corresponds the first logs to be returned.
348
- * @param limit - The number of logs to return.
349
- * @param logType - Specifies whether to return encrypted or unencrypted logs.
350
- * @returns The requested logs.
351
- */
352
- getLogs(from: number, limit: number, logType: LogType): Promise<L2BlockL2Logs[]> {
353
- if (from < INITIAL_L2_BLOCK_NUM || limit < 1) {
354
- throw new Error(`Invalid limit: ${limit}`);
355
- }
356
- const logs = logType === LogType.ENCRYPTED ? this.encryptedLogsPerBlock : this.unencryptedLogsPerBlock;
357
- if (from > logs.length) {
358
- return Promise.resolve([]);
359
- }
360
- const startIndex = from - INITIAL_L2_BLOCK_NUM;
361
- const endIndex = startIndex + limit;
362
- return Promise.resolve(logs.slice(startIndex, endIndex));
363
- }
364
-
365
- /**
366
- * Gets unencrypted logs based on the provided filter.
367
- * @param filter - The filter to apply to the logs.
368
- * @returns The requested logs.
369
- * @remarks Works by doing an intersection of all params in the filter.
370
- */
371
- getUnencryptedLogs(filter: LogFilter): Promise<GetUnencryptedLogsResponse> {
372
- let txHash: TxHash | undefined;
373
- let fromBlockIndex = 0;
374
- let toBlockIndex = this.unencryptedLogsPerBlock.length;
375
- let txIndexInBlock = 0;
376
- let logIndexInTx = 0;
377
-
378
- if (filter.afterLog) {
379
- // Continuation parameter is set --> tx hash is ignored
380
- if (filter.fromBlock == undefined || filter.fromBlock <= filter.afterLog.blockNumber) {
381
- fromBlockIndex = filter.afterLog.blockNumber - INITIAL_L2_BLOCK_NUM;
382
- txIndexInBlock = filter.afterLog.txIndex;
383
- logIndexInTx = filter.afterLog.logIndex + 1; // We want to start from the next log
384
- } else {
385
- fromBlockIndex = filter.fromBlock - INITIAL_L2_BLOCK_NUM;
386
- }
387
- } else {
388
- txHash = filter.txHash;
389
-
390
- if (filter.fromBlock !== undefined) {
391
- fromBlockIndex = filter.fromBlock - INITIAL_L2_BLOCK_NUM;
392
- }
393
- }
394
-
395
- if (filter.toBlock !== undefined) {
396
- toBlockIndex = filter.toBlock - INITIAL_L2_BLOCK_NUM;
397
- }
398
-
399
- // Ensure the indices are within block array bounds
400
- fromBlockIndex = Math.max(fromBlockIndex, 0);
401
- toBlockIndex = Math.min(toBlockIndex, this.unencryptedLogsPerBlock.length);
402
-
403
- if (fromBlockIndex > this.unencryptedLogsPerBlock.length || toBlockIndex < fromBlockIndex || toBlockIndex <= 0) {
404
- return Promise.resolve({
405
- logs: [],
406
- maxLogsHit: false,
407
- });
408
- }
409
-
410
- const contractAddress = filter.contractAddress;
411
- const selector = filter.selector;
412
-
413
- const logs: ExtendedUnencryptedL2Log[] = [];
414
-
415
- for (; fromBlockIndex < toBlockIndex; fromBlockIndex++) {
416
- const blockContext = this.l2BlockContexts[fromBlockIndex];
417
- const blockLogs = this.unencryptedLogsPerBlock[fromBlockIndex];
418
- for (; txIndexInBlock < blockLogs.txLogs.length; txIndexInBlock++) {
419
- const txLogs = blockLogs.txLogs[txIndexInBlock].unrollLogs().map(log => UnencryptedL2Log.fromBuffer(log));
420
- for (; logIndexInTx < txLogs.length; logIndexInTx++) {
421
- const log = txLogs[logIndexInTx];
422
- if (
423
- (!txHash || blockContext.getTxHash(txIndexInBlock).equals(txHash)) &&
424
- (!contractAddress || log.contractAddress.equals(contractAddress)) &&
425
- (!selector || log.selector.equals(selector))
426
- ) {
427
- logs.push(
428
- new ExtendedUnencryptedL2Log(new LogId(blockContext.block.number, txIndexInBlock, logIndexInTx), log),
429
- );
430
- if (logs.length === this.maxLogs) {
431
- return Promise.resolve({
432
- logs,
433
- maxLogsHit: true,
434
- });
435
- }
436
- }
437
- }
438
- logIndexInTx = 0;
439
- }
440
- txIndexInBlock = 0;
441
- }
442
-
443
- return Promise.resolve({
444
- logs,
445
- maxLogsHit: false,
446
- });
447
- }
448
-
449
- /**
450
- * Get the extended contract data for this contract.
451
- * @param contractAddress - The contract data address.
452
- * @returns The extended contract data or undefined if not found.
453
- */
454
- getExtendedContractData(contractAddress: AztecAddress): Promise<ExtendedContractData | undefined> {
455
- const result = this.extendedContractData.get(contractAddress.toString());
456
- return Promise.resolve(result);
457
- }
458
-
459
- /**
460
- * Lookup all contract data in an L2 block.
461
- * @param blockNum - The block number to get all contract data from.
462
- * @returns All extended contract data in the block (if found).
463
- */
464
- public getExtendedContractDataInBlock(blockNum: number): Promise<ExtendedContractData[]> {
465
- if (blockNum > this.l2BlockContexts.length) {
466
- return Promise.resolve([]);
467
- }
468
- return Promise.resolve(this.extendedContractDataByBlock[blockNum] || []);
469
- }
470
-
471
- /**
472
- * Get basic info for an L2 contract.
473
- * Contains contract address & the ethereum portal address.
474
- * @param contractAddress - The contract data address.
475
- * @returns ContractData with the portal address (if we didn't throw an error).
476
- */
477
- public getContractData(contractAddress: AztecAddress): Promise<ContractData | undefined> {
478
- if (contractAddress.isZero()) {
479
- return Promise.resolve(undefined);
480
- }
481
- for (const blockContext of this.l2BlockContexts) {
482
- for (const contractData of blockContext.block.newContractData) {
483
- if (contractData.contractAddress.equals(contractAddress)) {
484
- return Promise.resolve(contractData);
485
- }
486
- }
487
- }
488
- return Promise.resolve(undefined);
489
- }
490
-
491
- /**
492
- * Get basic info for an all L2 contracts deployed in a block.
493
- * Contains contract address & the ethereum portal address.
494
- * @param l2BlockNum - Number of the L2 block where contracts were deployed.
495
- * @returns ContractData with the portal address (if we didn't throw an error).
496
- */
497
- public getContractDataInBlock(l2BlockNum: number): Promise<ContractData[] | undefined> {
498
- if (l2BlockNum > this.l2BlockContexts.length) {
499
- return Promise.resolve([]);
500
- }
501
- const block = this.l2BlockContexts[l2BlockNum].block;
502
- return Promise.resolve(block.newContractData);
503
- }
504
-
505
- /**
506
- * Gets the number of the latest L2 block processed.
507
- * @returns The number of the latest L2 block processed.
155
+ * Gets the number of the latest L1 block processed.
508
156
  */
509
- public getBlockNumber(): Promise<number> {
510
- if (this.l2BlockContexts.length === 0) {
511
- return Promise.resolve(INITIAL_L2_BLOCK_NUM - 1);
512
- }
513
- return Promise.resolve(this.l2BlockContexts[this.l2BlockContexts.length - 1].block.number);
514
- }
157
+ getL1BlockNumber(): Promise<bigint>;
515
158
  }