@aztec/archiver 0.8.9 → 0.8.11

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.
@@ -3,13 +3,19 @@ import { AztecAddress } from '@aztec/foundation/aztec-address';
3
3
  import {
4
4
  ContractData,
5
5
  ExtendedContractData,
6
+ ExtendedUnencryptedL2Log,
7
+ GetUnencryptedLogsResponse,
6
8
  INITIAL_L2_BLOCK_NUM,
7
9
  L1ToL2Message,
8
10
  L2Block,
11
+ L2BlockContext,
9
12
  L2BlockL2Logs,
10
13
  L2Tx,
14
+ LogFilter,
15
+ LogId,
11
16
  LogType,
12
17
  TxHash,
18
+ UnencryptedL2Log,
13
19
  } from '@aztec/types';
14
20
 
15
21
  import { L1ToL2MessageStore, PendingL1ToL2MessageStore } from './l1_to_l2_message_store.js';
@@ -24,7 +30,7 @@ export interface ArchiverDataStore {
24
30
  * @param blocks - The L2 blocks to be added to the store.
25
31
  * @returns True if the operation is successful.
26
32
  */
27
- addL2Blocks(blocks: L2Block[]): Promise<boolean>;
33
+ addBlocks(blocks: L2Block[]): Promise<boolean>;
28
34
 
29
35
  /**
30
36
  * Gets up to `limit` amount of L2 blocks starting from `from`.
@@ -32,7 +38,7 @@ export interface ArchiverDataStore {
32
38
  * @param limit - The number of blocks to return.
33
39
  * @returns The requested L2 blocks.
34
40
  */
35
- getL2Blocks(from: number, limit: number): Promise<L2Block[]>;
41
+ getBlocks(from: number, limit: number): Promise<L2Block[]>;
36
42
 
37
43
  /**
38
44
  * Gets an l2 tx.
@@ -94,6 +100,13 @@ export interface ArchiverDataStore {
94
100
  */
95
101
  getLogs(from: number, limit: number, logType: LogType): Promise<L2BlockL2Logs[]>;
96
102
 
103
+ /**
104
+ * Gets unencrypted logs based on the provided filter.
105
+ * @param filter - The filter to apply to the logs.
106
+ * @returns The requested logs.
107
+ */
108
+ getUnencryptedLogs(filter: LogFilter): Promise<GetUnencryptedLogsResponse>;
109
+
97
110
  /**
98
111
  * Add new extended contract data from an L2 block to the store's list.
99
112
  * @param data - List of contracts' data to be added.
@@ -137,12 +150,6 @@ export interface ArchiverDataStore {
137
150
  * @returns The number of the latest L2 block processed.
138
151
  */
139
152
  getBlockNumber(): Promise<number>;
140
-
141
- /**
142
- * Gets the length of L2 blocks in store.
143
- * @returns The length of L2 Blocks stored.
144
- */
145
- getBlocksLength(): number;
146
153
  }
147
154
 
148
155
  /**
@@ -152,7 +159,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
152
159
  /**
153
160
  * An array containing all the L2 blocks that have been fetched so far.
154
161
  */
155
- private l2Blocks: L2Block[] = [];
162
+ private l2BlockContexts: L2BlockContext[] = [];
156
163
 
157
164
  /**
158
165
  * An array containing all the L2 Txs in the L2 blocks that have been fetched so far.
@@ -163,13 +170,13 @@ export class MemoryArchiverStore implements ArchiverDataStore {
163
170
  * An array containing all the encrypted logs that have been fetched so far.
164
171
  * Note: Index in the "outer" array equals to (corresponding L2 block's number - INITIAL_L2_BLOCK_NUM).
165
172
  */
166
- private encryptedLogs: L2BlockL2Logs[] = [];
173
+ private encryptedLogsPerBlock: L2BlockL2Logs[] = [];
167
174
 
168
175
  /**
169
176
  * An array containing all the unencrypted logs that have been fetched so far.
170
177
  * Note: Index in the "outer" array equals to (corresponding L2 block's number - INITIAL_L2_BLOCK_NUM).
171
178
  */
172
- private unencryptedLogs: L2BlockL2Logs[] = [];
179
+ private unencryptedLogsPerBlock: L2BlockL2Logs[] = [];
173
180
 
174
181
  /**
175
182
  * A sparse array containing all the extended contract data that have been fetched so far.
@@ -192,15 +199,18 @@ export class MemoryArchiverStore implements ArchiverDataStore {
192
199
  */
193
200
  private pendingL1ToL2Messages: PendingL1ToL2MessageStore = new PendingL1ToL2MessageStore();
194
201
 
195
- constructor() {}
202
+ constructor(
203
+ /** The max number of logs that can be obtained in 1 "getUnencryptedLogs" call. */
204
+ public readonly maxLogs: number,
205
+ ) {}
196
206
 
197
207
  /**
198
208
  * Append new blocks to the store's list.
199
209
  * @param blocks - The L2 blocks to be added to the store.
200
210
  * @returns True if the operation is successful (always in this implementation).
201
211
  */
202
- public addL2Blocks(blocks: L2Block[]): Promise<boolean> {
203
- this.l2Blocks.push(...blocks);
212
+ public addBlocks(blocks: L2Block[]): Promise<boolean> {
213
+ this.l2BlockContexts.push(...blocks.map(block => new L2BlockContext(block)));
204
214
  this.l2Txs.push(...blocks.flatMap(b => b.getTxs()));
205
215
  return Promise.resolve(true);
206
216
  }
@@ -212,7 +222,9 @@ export class MemoryArchiverStore implements ArchiverDataStore {
212
222
  * @returns True if the operation is successful.
213
223
  */
214
224
  addLogs(data: L2BlockL2Logs[], logType: LogType): Promise<boolean> {
215
- logType === LogType.ENCRYPTED ? this.encryptedLogs.push(...data) : this.unencryptedLogs.push(...data);
225
+ logType === LogType.ENCRYPTED
226
+ ? this.encryptedLogsPerBlock.push(...data)
227
+ : this.unencryptedLogsPerBlock.push(...data);
216
228
  return Promise.resolve(true);
217
229
  }
218
230
 
@@ -281,18 +293,21 @@ export class MemoryArchiverStore implements ArchiverDataStore {
281
293
  * @param from - Number of the first block to return (inclusive).
282
294
  * @param limit - The number of blocks to return.
283
295
  * @returns The requested L2 blocks.
296
+ * @remarks When "from" is smaller than genesis block number, blocks from the beginning are returned.
284
297
  */
285
- public getL2Blocks(from: number, limit: number): Promise<L2Block[]> {
298
+ public getBlocks(from: number, limit: number): Promise<L2Block[]> {
286
299
  // Return an empty array if we are outside of range
287
300
  if (limit < 1) {
288
- throw new Error(`Invalid block range from: ${from}, limit: ${limit}`);
301
+ throw new Error(`Invalid limit: ${limit}`);
289
302
  }
290
- if (from < INITIAL_L2_BLOCK_NUM || from > this.l2Blocks.length) {
303
+
304
+ const fromIndex = Math.max(from - INITIAL_L2_BLOCK_NUM, 0);
305
+ if (fromIndex >= this.l2BlockContexts.length) {
291
306
  return Promise.resolve([]);
292
307
  }
293
- const startIndex = from - INITIAL_L2_BLOCK_NUM;
294
- const endIndex = startIndex + limit;
295
- return Promise.resolve(this.l2Blocks.slice(startIndex, endIndex));
308
+
309
+ const toIndex = fromIndex + limit;
310
+ return Promise.resolve(this.l2BlockContexts.slice(fromIndex, toIndex).map(blockContext => blockContext.block));
296
311
  }
297
312
 
298
313
  /**
@@ -336,9 +351,9 @@ export class MemoryArchiverStore implements ArchiverDataStore {
336
351
  */
337
352
  getLogs(from: number, limit: number, logType: LogType): Promise<L2BlockL2Logs[]> {
338
353
  if (from < INITIAL_L2_BLOCK_NUM || limit < 1) {
339
- throw new Error(`Invalid block range from: ${from}, limit: ${limit}`);
354
+ throw new Error(`Invalid limit: ${limit}`);
340
355
  }
341
- const logs = logType === LogType.ENCRYPTED ? this.encryptedLogs : this.unencryptedLogs;
356
+ const logs = logType === LogType.ENCRYPTED ? this.encryptedLogsPerBlock : this.unencryptedLogsPerBlock;
342
357
  if (from > logs.length) {
343
358
  return Promise.resolve([]);
344
359
  }
@@ -347,6 +362,90 @@ export class MemoryArchiverStore implements ArchiverDataStore {
347
362
  return Promise.resolve(logs.slice(startIndex, endIndex));
348
363
  }
349
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
+
350
449
  /**
351
450
  * Get the extended contract data for this contract.
352
451
  * @param contractAddress - The contract data address.
@@ -363,7 +462,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
363
462
  * @returns All extended contract data in the block (if found).
364
463
  */
365
464
  public getExtendedContractDataInBlock(blockNum: number): Promise<ExtendedContractData[]> {
366
- if (blockNum > this.l2Blocks.length) {
465
+ if (blockNum > this.l2BlockContexts.length) {
367
466
  return Promise.resolve([]);
368
467
  }
369
468
  return Promise.resolve(this.extendedContractDataByBlock[blockNum] || []);
@@ -379,8 +478,8 @@ export class MemoryArchiverStore implements ArchiverDataStore {
379
478
  if (contractAddress.isZero()) {
380
479
  return Promise.resolve(undefined);
381
480
  }
382
- for (const block of this.l2Blocks) {
383
- for (const contractData of block.newContractData) {
481
+ for (const blockContext of this.l2BlockContexts) {
482
+ for (const contractData of blockContext.block.newContractData) {
384
483
  if (contractData.contractAddress.equals(contractAddress)) {
385
484
  return Promise.resolve(contractData);
386
485
  }
@@ -396,10 +495,10 @@ export class MemoryArchiverStore implements ArchiverDataStore {
396
495
  * @returns ContractData with the portal address (if we didn't throw an error).
397
496
  */
398
497
  public getContractDataInBlock(l2BlockNum: number): Promise<ContractData[] | undefined> {
399
- if (l2BlockNum > this.l2Blocks.length) {
498
+ if (l2BlockNum > this.l2BlockContexts.length) {
400
499
  return Promise.resolve([]);
401
500
  }
402
- const block = this.l2Blocks[l2BlockNum];
501
+ const block = this.l2BlockContexts[l2BlockNum].block;
403
502
  return Promise.resolve(block.newContractData);
404
503
  }
405
504
 
@@ -408,15 +507,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
408
507
  * @returns The number of the latest L2 block processed.
409
508
  */
410
509
  public getBlockNumber(): Promise<number> {
411
- if (this.l2Blocks.length === 0) return Promise.resolve(INITIAL_L2_BLOCK_NUM - 1);
412
- return Promise.resolve(this.l2Blocks[this.l2Blocks.length - 1].number);
413
- }
414
-
415
- /**
416
- * Gets the length of L2 blocks in store.
417
- * @returns The length of L2 Blocks array.
418
- */
419
- public getBlocksLength(): number {
420
- return this.l2Blocks.length;
510
+ if (this.l2BlockContexts.length === 0) return Promise.resolve(INITIAL_L2_BLOCK_NUM - 1);
511
+ return Promise.resolve(this.l2BlockContexts[this.l2BlockContexts.length - 1].block.number);
421
512
  }
422
513
  }
@@ -32,11 +32,6 @@ export interface ArchiverConfig {
32
32
  */
33
33
  viemPollingIntervalMS?: number;
34
34
 
35
- /**
36
- * Eth block from which we start scanning for L2Blocks.
37
- */
38
- searchStartBlock: number;
39
-
40
35
  /**
41
36
  * The deployed L1 contract addresses
42
37
  */
@@ -46,6 +41,9 @@ export interface ArchiverConfig {
46
41
  * Optional dir to store data. If omitted will store in memory.
47
42
  */
48
43
  dataDirectory?: string;
44
+
45
+ /** The max number of logs that can be obtained in 1 "getUnencryptedLogs" call. */
46
+ maxLogs?: number;
49
47
  }
50
48
 
51
49
  /**
@@ -60,9 +58,9 @@ export function getConfigEnvVars(): ArchiverConfig {
60
58
  ARCHIVER_VIEM_POLLING_INTERVAL_MS,
61
59
  ROLLUP_CONTRACT_ADDRESS,
62
60
  CONTRACT_DEPLOYMENT_EMITTER_ADDRESS,
63
- SEARCH_START_BLOCK,
64
61
  API_KEY,
65
62
  INBOX_CONTRACT_ADDRESS,
63
+ OUTBOX_CONTRACT_ADDRESS,
66
64
  REGISTRY_CONTRACT_ADDRESS,
67
65
  DATA_DIRECTORY,
68
66
  } = process.env;
@@ -71,7 +69,7 @@ export function getConfigEnvVars(): ArchiverConfig {
71
69
  rollupAddress: ROLLUP_CONTRACT_ADDRESS ? EthAddress.fromString(ROLLUP_CONTRACT_ADDRESS) : EthAddress.ZERO,
72
70
  registryAddress: REGISTRY_CONTRACT_ADDRESS ? EthAddress.fromString(REGISTRY_CONTRACT_ADDRESS) : EthAddress.ZERO,
73
71
  inboxAddress: INBOX_CONTRACT_ADDRESS ? EthAddress.fromString(INBOX_CONTRACT_ADDRESS) : EthAddress.ZERO,
74
- outboxAddress: EthAddress.ZERO,
72
+ outboxAddress: OUTBOX_CONTRACT_ADDRESS ? EthAddress.fromString(OUTBOX_CONTRACT_ADDRESS) : EthAddress.ZERO,
75
73
  contractDeploymentEmitterAddress: CONTRACT_DEPLOYMENT_EMITTER_ADDRESS
76
74
  ? EthAddress.fromString(CONTRACT_DEPLOYMENT_EMITTER_ADDRESS)
77
75
  : EthAddress.ZERO,
@@ -81,7 +79,6 @@ export function getConfigEnvVars(): ArchiverConfig {
81
79
  rpcUrl: ETHEREUM_HOST || 'http://127.0.0.1:8545/',
82
80
  archiverPollingIntervalMS: ARCHIVER_POLLING_INTERVAL_MS ? +ARCHIVER_POLLING_INTERVAL_MS : 1_000,
83
81
  viemPollingIntervalMS: ARCHIVER_VIEM_POLLING_INTERVAL_MS ? +ARCHIVER_VIEM_POLLING_INTERVAL_MS : 1_000,
84
- searchStartBlock: SEARCH_START_BLOCK ? +SEARCH_START_BLOCK : 0,
85
82
  apiKey: API_KEY,
86
83
  l1Contracts: addresses,
87
84
  dataDirectory: DATA_DIRECTORY,
package/src/index.ts CHANGED
@@ -17,14 +17,14 @@ const log = createDebugLogger('aztec:archiver');
17
17
  // eslint-disable-next-line require-await
18
18
  async function main() {
19
19
  const config = getConfigEnvVars();
20
- const { rpcUrl, l1Contracts, searchStartBlock } = config;
20
+ const { rpcUrl, l1Contracts } = config;
21
21
 
22
22
  const publicClient = createPublicClient({
23
23
  chain: localhost,
24
24
  transport: http(rpcUrl),
25
25
  });
26
26
 
27
- const archiverStore = new MemoryArchiverStore();
27
+ const archiverStore = new MemoryArchiverStore(1000);
28
28
 
29
29
  const archiver = new Archiver(
30
30
  publicClient,
@@ -32,7 +32,7 @@ async function main() {
32
32
  l1Contracts.inboxAddress,
33
33
  l1Contracts.registryAddress,
34
34
  l1Contracts.contractDeploymentEmitterAddress,
35
- searchStartBlock,
35
+ 0, // searchStartBlock
36
36
  archiverStore,
37
37
  );
38
38