@aztec/archiver 0.0.1-commit.f5d02921e → 0.0.1-commit.f7ea82942

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 (71) hide show
  1. package/README.md +12 -6
  2. package/dest/archiver.d.ts +5 -3
  3. package/dest/archiver.d.ts.map +1 -1
  4. package/dest/archiver.js +15 -4
  5. package/dest/config.d.ts +3 -1
  6. package/dest/config.d.ts.map +1 -1
  7. package/dest/config.js +13 -2
  8. package/dest/errors.d.ts +17 -1
  9. package/dest/errors.d.ts.map +1 -1
  10. package/dest/errors.js +22 -0
  11. package/dest/factory.d.ts +1 -1
  12. package/dest/factory.d.ts.map +1 -1
  13. package/dest/factory.js +2 -1
  14. package/dest/index.d.ts +3 -2
  15. package/dest/index.d.ts.map +1 -1
  16. package/dest/index.js +2 -1
  17. package/dest/l1/data_retrieval.d.ts +19 -10
  18. package/dest/l1/data_retrieval.d.ts.map +1 -1
  19. package/dest/l1/data_retrieval.js +25 -32
  20. package/dest/l1/validate_historical_logs.d.ts +23 -0
  21. package/dest/l1/validate_historical_logs.d.ts.map +1 -0
  22. package/dest/l1/validate_historical_logs.js +108 -0
  23. package/dest/modules/data_store_updater.d.ts +12 -5
  24. package/dest/modules/data_store_updater.d.ts.map +1 -1
  25. package/dest/modules/data_store_updater.js +13 -3
  26. package/dest/modules/instrumentation.d.ts +7 -2
  27. package/dest/modules/instrumentation.d.ts.map +1 -1
  28. package/dest/modules/instrumentation.js +22 -6
  29. package/dest/modules/l1_synchronizer.d.ts +6 -2
  30. package/dest/modules/l1_synchronizer.d.ts.map +1 -1
  31. package/dest/modules/l1_synchronizer.js +213 -124
  32. package/dest/store/block_store.d.ts +11 -3
  33. package/dest/store/block_store.d.ts.map +1 -1
  34. package/dest/store/block_store.js +88 -6
  35. package/dest/store/kv_archiver_store.d.ts +11 -9
  36. package/dest/store/kv_archiver_store.d.ts.map +1 -1
  37. package/dest/store/kv_archiver_store.js +9 -7
  38. package/dest/store/l2_tips_cache.d.ts +1 -1
  39. package/dest/store/l2_tips_cache.d.ts.map +1 -1
  40. package/dest/store/l2_tips_cache.js +2 -2
  41. package/dest/store/log_store.d.ts +1 -1
  42. package/dest/store/log_store.d.ts.map +1 -1
  43. package/dest/store/log_store.js +2 -4
  44. package/dest/store/message_store.d.ts +3 -3
  45. package/dest/store/message_store.d.ts.map +1 -1
  46. package/dest/store/message_store.js +9 -10
  47. package/dest/test/fake_l1_state.d.ts +14 -3
  48. package/dest/test/fake_l1_state.d.ts.map +1 -1
  49. package/dest/test/fake_l1_state.js +55 -10
  50. package/dest/test/noop_l1_archiver.d.ts +1 -1
  51. package/dest/test/noop_l1_archiver.d.ts.map +1 -1
  52. package/dest/test/noop_l1_archiver.js +4 -2
  53. package/package.json +13 -13
  54. package/src/archiver.ts +28 -6
  55. package/src/config.ts +14 -1
  56. package/src/errors.ts +34 -0
  57. package/src/factory.ts +1 -0
  58. package/src/index.ts +2 -1
  59. package/src/l1/data_retrieval.ts +36 -45
  60. package/src/l1/validate_historical_logs.ts +140 -0
  61. package/src/modules/data_store_updater.ts +27 -3
  62. package/src/modules/instrumentation.ts +27 -7
  63. package/src/modules/l1_synchronizer.ts +274 -148
  64. package/src/store/block_store.ts +112 -4
  65. package/src/store/kv_archiver_store.ts +18 -10
  66. package/src/store/l2_tips_cache.ts +8 -2
  67. package/src/store/log_store.ts +2 -5
  68. package/src/store/message_store.ts +10 -12
  69. package/src/structs/inbox_message.ts +1 -1
  70. package/src/test/fake_l1_state.ts +75 -13
  71. package/src/test/noop_l1_archiver.ts +3 -1
@@ -48,7 +48,9 @@ import { updateRollingHash } from '../structs/inbox_message.js';
48
48
  canPruneResult;
49
49
  // Computed from checkpoints based on L1 block visibility
50
50
  pendingCheckpointNumber;
51
- // The L1 block number reported as "finalized" (defaults to the start block)
51
+ // The L1 block number reported as "finalized" (defaults to the start block).
52
+ // `undefined` simulates the startup window on a fresh devnet where
53
+ // `getBlock({ blockTag: 'finalized' })` fails with "finalized block not found".
52
54
  finalizedL1BlockNumber;
53
55
  constructor(config){
54
56
  this.config = config;
@@ -161,7 +163,10 @@ import { updateRollingHash } from '../structs/inbox_message.js';
161
163
  this.l1BlockNumber = blockNumber;
162
164
  this.updatePendingCheckpointNumber();
163
165
  }
164
- /** Sets the L1 block number that will be reported as "finalized". */ setFinalizedL1BlockNumber(blockNumber) {
166
+ /**
167
+ * Sets the L1 block number that will be reported as "finalized". Pass `undefined` to
168
+ * simulate a chain that does not yet have a finalized block (devnet startup).
169
+ */ setFinalizedL1BlockNumber(blockNumber) {
165
170
  this.finalizedL1BlockNumber = blockNumber;
166
171
  }
167
172
  /** Marks a checkpoint as proven. Updates provenCheckpointNumber. */ markCheckpointAsProven(checkpointNumber) {
@@ -194,6 +199,19 @@ import { updateRollingHash } from '../structs/inbox_message.js';
194
199
  this.updatePendingCheckpointNumber();
195
200
  }
196
201
  /**
202
+ * Moves a checkpoint to a different L1 block number (simulates L1 reorg that
203
+ * re-includes the same checkpoint transaction in a different block).
204
+ * The checkpoint content stays the same — only the L1 metadata changes.
205
+ * Auto-updates pending status.
206
+ */ moveCheckpointToL1Block(checkpointNumber, newL1BlockNumber) {
207
+ for (const cpData of this.checkpoints){
208
+ if (cpData.checkpointNumber === checkpointNumber) {
209
+ cpData.l1BlockNumber = newL1BlockNumber;
210
+ }
211
+ }
212
+ this.updatePendingCheckpointNumber();
213
+ }
214
+ /**
197
215
  * Removes messages after a given total index (simulates L1 reorg).
198
216
  * Auto-updates rolling hash.
199
217
  */ removeMessagesAfter(totalIndex) {
@@ -279,21 +297,26 @@ import { updateRollingHash } from '../structs/inbox_message.js';
279
297
  }
280
298
  /** Creates mock InboxContract that reads from this fake state. */ createMockInboxContract(_publicClient) {
281
299
  const mockInbox = mock();
282
- mockInbox.getState.mockImplementation(()=>{
300
+ mockInbox.getState.mockImplementation((opts = {})=>{
301
+ // Filter messages visible at the given block number (or all if not specified)
302
+ const blockNumber = opts.blockNumber ?? this.l1BlockNumber;
303
+ const visibleMessages = this.messages.filter((m)=>m.l1BlockNumber <= blockNumber);
283
304
  // treeInProgress must be > any sealed checkpoint. On L1, a checkpoint can only be proposed
284
305
  // after its messages are sealed, so treeInProgress > checkpointNumber for all published checkpoints.
285
- const maxFromMessages = this.messages.length > 0 ? Math.max(...this.messages.map((m)=>Number(m.checkpointNumber))) + 1 : 0;
286
- const maxFromCheckpoints = this.checkpoints.length > 0 ? Math.max(...this.checkpoints.filter((cp)=>!cp.pruned).map((cp)=>Number(cp.checkpointNumber))) + 1 : 0;
306
+ const maxFromMessages = visibleMessages.length > 0 ? Math.max(...visibleMessages.map((m)=>Number(m.checkpointNumber))) + 1 : 0;
307
+ const maxFromCheckpoints = this.checkpoints.length > 0 ? Math.max(...this.checkpoints.filter((cp)=>!cp.pruned && cp.l1BlockNumber <= blockNumber).map((cp)=>Number(cp.checkpointNumber)), 0) + 1 : 0;
287
308
  const treeInProgress = Math.max(maxFromMessages, maxFromCheckpoints, INITIAL_CHECKPOINT_NUMBER);
309
+ // Compute rolling hash only for visible messages
310
+ const rollingHash = visibleMessages.length > 0 ? visibleMessages[visibleMessages.length - 1].rollingHash : Buffer16.ZERO;
288
311
  return Promise.resolve({
289
- messagesRollingHash: this.messagesRollingHash,
290
- totalMessagesInserted: BigInt(this.messages.length),
312
+ messagesRollingHash: rollingHash,
313
+ totalMessagesInserted: BigInt(visibleMessages.length),
291
314
  treeInProgress: BigInt(treeInProgress)
292
315
  });
293
316
  });
294
317
  // Mock the wrapper methods for fetching message events
295
318
  mockInbox.getMessageSentEvents.mockImplementation((fromBlock, toBlock)=>Promise.resolve(this.getMessageSentLogs(fromBlock, toBlock)));
296
- mockInbox.getMessageSentEventByHash.mockImplementation((hash, fromBlock, toBlock)=>Promise.resolve(this.getMessageSentLogs(fromBlock, toBlock, hash)));
319
+ mockInbox.getMessageSentEventByHash.mockImplementation((msgHash, aroundL1BlockNumber)=>Promise.resolve(this.getMessageSentLogByHash(msgHash, aroundL1BlockNumber)));
297
320
  return mockInbox;
298
321
  }
299
322
  /** Creates mock PublicClient that reads from this fake state. */ createMockPublicClient() {
@@ -303,6 +326,11 @@ import { updateRollingHash } from '../structs/inbox_message.js';
303
326
  publicClient.getBlock.mockImplementation(async (args = {})=>{
304
327
  let blockNum;
305
328
  if (args.blockTag === 'finalized') {
329
+ if (this.finalizedL1BlockNumber === undefined) {
330
+ throw Object.assign(new Error('finalized block not found'), {
331
+ details: 'finalized block not found'
332
+ });
333
+ }
306
334
  blockNum = this.finalizedL1BlockNumber;
307
335
  } else {
308
336
  blockNum = args.blockNumber ?? await publicClient.getBlockNumber();
@@ -319,8 +347,8 @@ import { updateRollingHash } from '../structs/inbox_message.js';
319
347
  }
320
348
  /** Creates mock BlobClient that reads from this fake state. */ createMockBlobClient() {
321
349
  const blobClient = mock();
322
- // The blockId is the transaction's blockHash, which we set to the checkpoint's archive root
323
- blobClient.getBlobSidecar.mockImplementation((blockId)=>Promise.resolve(this.checkpoints.find((cpData)=>cpData.checkpoint.archive.root.toString() === blockId)?.blobs ?? []));
350
+ // The blockId is the L1 block hash, which we derive from the L1 block number
351
+ blobClient.getBlobSidecar.mockImplementation((blockId)=>Promise.resolve(this.checkpoints.find((cpData)=>Buffer32.fromBigInt(cpData.l1BlockNumber).toString() === blockId)?.blobs ?? []));
324
352
  blobClient.testSources.mockResolvedValue(undefined);
325
353
  return blobClient;
326
354
  }
@@ -371,6 +399,23 @@ import { updateRollingHash } from '../structs/inbox_message.js';
371
399
  }
372
400
  }));
373
401
  }
402
+ getMessageSentLogByHash(msgHash, aroundL1BlockNumber) {
403
+ const msg = this.messages.find((msg)=>msg.leaf.toString() === msgHash && msg.l1BlockNumber >= aroundL1BlockNumber - 5n && msg.l1BlockNumber <= aroundL1BlockNumber + 5n);
404
+ if (!msg) {
405
+ return undefined;
406
+ }
407
+ return {
408
+ l1BlockNumber: msg.l1BlockNumber,
409
+ l1BlockHash: Buffer32.fromBigInt(msg.l1BlockNumber),
410
+ l1TransactionHash: `0x${msg.l1BlockNumber.toString(16)}`,
411
+ args: {
412
+ checkpointNumber: msg.checkpointNumber,
413
+ index: msg.index,
414
+ leaf: msg.leaf,
415
+ rollingHash: msg.rollingHash
416
+ }
417
+ };
418
+ }
374
419
  async makeRollupTx(checkpoint, signers) {
375
420
  const attestations = signers.map((signer)=>makeCheckpointAttestationFromCheckpoint(checkpoint, signer)).map((attestation)=>CommitteeAttestation.fromSignature(attestation.signature)).map((committeeAttestation)=>committeeAttestation.toViem());
376
421
  const header = checkpoint.header.toViem();
@@ -23,4 +23,4 @@ export declare class NoopL1Archiver extends Archiver {
23
23
  export declare function createNoopL1Archiver(dataStore: KVArchiverDataStore, l1Constants: L1RollupConstants & {
24
24
  genesisArchiveRoot: Fr;
25
25
  }, telemetry?: TelemetryClient): Promise<NoopL1Archiver>;
26
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9vcF9sMV9hcmNoaXZlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Rlc3Qvbm9vcF9sMV9hcmNoaXZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFN0QsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBSXBELE9BQU8sS0FBSyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDckUsT0FBTyxFQUFFLEtBQUssZUFBZSxFQUFtQyxNQUFNLHlCQUF5QixDQUFDO0FBS2hHLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUMxQyxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUV4RSxPQUFPLEtBQUssRUFBRSxtQkFBbUIsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBeUJ6RTs7OztHQUlHO0FBQ0gscUJBQWEsY0FBZSxTQUFRLFFBQVE7SUFDMUMsWUFDRSxTQUFTLEVBQUUsbUJBQW1CLEVBQzlCLFdBQVcsRUFBRSxpQkFBaUIsR0FBRztRQUFFLGtCQUFrQixFQUFFLEVBQUUsQ0FBQTtLQUFFLEVBQzNELGVBQWUsRUFBRSx1QkFBdUIsRUF1Q3pDO0lBRUQsbURBQW1EO0lBQ25DLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLE9BQU8sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBSWhFO0lBRUQsNkVBQTZFO0lBQzdELHFCQUFxQixJQUFJLE9BQU8sQ0FBQyxVQUFVLEdBQUcsU0FBUyxDQUFDLENBRXZFO0NBQ0Y7QUFFRCxtRUFBbUU7QUFDbkUsd0JBQXNCLG9CQUFvQixDQUN4QyxTQUFTLEVBQUUsbUJBQW1CLEVBQzlCLFdBQVcsRUFBRSxpQkFBaUIsR0FBRztJQUFFLGtCQUFrQixFQUFFLEVBQUUsQ0FBQTtDQUFFLEVBQzNELFNBQVMsR0FBRSxlQUFzQyxHQUNoRCxPQUFPLENBQUMsY0FBYyxDQUFDLENBR3pCIn0=
26
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9vcF9sMV9hcmNoaXZlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Rlc3Qvbm9vcF9sMV9hcmNoaXZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFN0QsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBSXBELE9BQU8sS0FBSyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDckUsT0FBTyxFQUFFLEtBQUssZUFBZSxFQUFtQyxNQUFNLHlCQUF5QixDQUFDO0FBS2hHLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUMxQyxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUV4RSxPQUFPLEtBQUssRUFBRSxtQkFBbUIsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBeUJ6RTs7OztHQUlHO0FBQ0gscUJBQWEsY0FBZSxTQUFRLFFBQVE7SUFDMUMsWUFDRSxTQUFTLEVBQUUsbUJBQW1CLEVBQzlCLFdBQVcsRUFBRSxpQkFBaUIsR0FBRztRQUFFLGtCQUFrQixFQUFFLEVBQUUsQ0FBQTtLQUFFLEVBQzNELGVBQWUsRUFBRSx1QkFBdUIsRUF5Q3pDO0lBRUQsbURBQW1EO0lBQ25DLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLE9BQU8sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBSWhFO0lBRUQsNkVBQTZFO0lBQzdELHFCQUFxQixJQUFJLE9BQU8sQ0FBQyxVQUFVLEdBQUcsU0FBUyxDQUFDLENBRXZFO0NBQ0Y7QUFFRCxtRUFBbUU7QUFDbkUsd0JBQXNCLG9CQUFvQixDQUN4QyxTQUFTLEVBQUUsbUJBQW1CLEVBQzlCLFdBQVcsRUFBRSxpQkFBaUIsR0FBRztJQUFFLGtCQUFrQixFQUFFLEVBQUUsQ0FBQTtDQUFFLEVBQzNELFNBQVMsR0FBRSxlQUFzQyxHQUNoRCxPQUFPLENBQUMsY0FBYyxDQUFDLENBR3pCIn0=
@@ -1 +1 @@
1
- {"version":3,"file":"noop_l1_archiver.d.ts","sourceRoot":"","sources":["../../src/test/noop_l1_archiver.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAE7D,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAIpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,KAAK,eAAe,EAAmC,MAAM,yBAAyB,CAAC;AAKhG,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAExE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAyBzE;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,QAAQ;IAC1C,YACE,SAAS,EAAE,mBAAmB,EAC9B,WAAW,EAAE,iBAAiB,GAAG;QAAE,kBAAkB,EAAE,EAAE,CAAA;KAAE,EAC3D,eAAe,EAAE,uBAAuB,EAuCzC;IAED,mDAAmD;IACnC,KAAK,CAAC,iBAAiB,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhE;IAED,6EAA6E;IAC7D,qBAAqB,IAAI,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAEvE;CACF;AAED,mEAAmE;AACnE,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,mBAAmB,EAC9B,WAAW,EAAE,iBAAiB,GAAG;IAAE,kBAAkB,EAAE,EAAE,CAAA;CAAE,EAC3D,SAAS,GAAE,eAAsC,GAChD,OAAO,CAAC,cAAc,CAAC,CAGzB"}
1
+ {"version":3,"file":"noop_l1_archiver.d.ts","sourceRoot":"","sources":["../../src/test/noop_l1_archiver.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAE7D,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAIpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,KAAK,eAAe,EAAmC,MAAM,yBAAyB,CAAC;AAKhG,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAExE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAyBzE;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,QAAQ;IAC1C,YACE,SAAS,EAAE,mBAAmB,EAC9B,WAAW,EAAE,iBAAiB,GAAG;QAAE,kBAAkB,EAAE,EAAE,CAAA;KAAE,EAC3D,eAAe,EAAE,uBAAuB,EAyCzC;IAED,mDAAmD;IACnC,KAAK,CAAC,iBAAiB,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhE;IAED,6EAA6E;IAC7D,qBAAqB,IAAI,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAEvE;CACF;AAED,mEAAmE;AACnE,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,mBAAmB,EAC9B,WAAW,EAAE,iBAAiB,GAAG;IAAE,kBAAkB,EAAE,EAAE,CAAA;CAAE,EAC3D,SAAS,GAAE,eAAsC,GAChD,OAAO,CAAC,cAAc,CAAC,CAGzB"}
@@ -42,16 +42,18 @@ import { ArchiverInstrumentation } from '../modules/instrumentation.js';
42
42
  const events = new EventEmitter();
43
43
  const synchronizer = new NoopL1Synchronizer(instrumentation.tracer);
44
44
  super(publicClient, debugClient, rollup, {
45
+ rollupAddress: EthAddress.ZERO,
45
46
  registryAddress: EthAddress.ZERO,
47
+ inboxAddress: EthAddress.ZERO,
46
48
  governanceProposerAddress: EthAddress.ZERO,
47
- slashFactoryAddress: EthAddress.ZERO,
48
49
  slashingProposerAddress: EthAddress.ZERO
49
50
  }, dataStore, {
50
51
  pollingIntervalMs: 1000,
51
52
  batchSize: 100,
52
53
  skipValidateCheckpointAttestations: true,
53
54
  maxAllowedEthClientDriftSeconds: 300,
54
- ethereumAllowNoDebugHosts: true
55
+ ethereumAllowNoDebugHosts: true,
56
+ skipHistoricalLogsCheck: true
55
57
  }, blobClient, instrumentation, {
56
58
  ...l1Constants,
57
59
  l1StartBlockHash: Buffer32.random()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/archiver",
3
- "version": "0.0.1-commit.f5d02921e",
3
+ "version": "0.0.1-commit.f7ea82942",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js",
@@ -65,18 +65,18 @@
65
65
  ]
66
66
  },
67
67
  "dependencies": {
68
- "@aztec/blob-client": "0.0.1-commit.f5d02921e",
69
- "@aztec/blob-lib": "0.0.1-commit.f5d02921e",
70
- "@aztec/constants": "0.0.1-commit.f5d02921e",
71
- "@aztec/epoch-cache": "0.0.1-commit.f5d02921e",
72
- "@aztec/ethereum": "0.0.1-commit.f5d02921e",
73
- "@aztec/foundation": "0.0.1-commit.f5d02921e",
74
- "@aztec/kv-store": "0.0.1-commit.f5d02921e",
75
- "@aztec/l1-artifacts": "0.0.1-commit.f5d02921e",
76
- "@aztec/noir-protocol-circuits-types": "0.0.1-commit.f5d02921e",
77
- "@aztec/protocol-contracts": "0.0.1-commit.f5d02921e",
78
- "@aztec/stdlib": "0.0.1-commit.f5d02921e",
79
- "@aztec/telemetry-client": "0.0.1-commit.f5d02921e",
68
+ "@aztec/blob-client": "0.0.1-commit.f7ea82942",
69
+ "@aztec/blob-lib": "0.0.1-commit.f7ea82942",
70
+ "@aztec/constants": "0.0.1-commit.f7ea82942",
71
+ "@aztec/epoch-cache": "0.0.1-commit.f7ea82942",
72
+ "@aztec/ethereum": "0.0.1-commit.f7ea82942",
73
+ "@aztec/foundation": "0.0.1-commit.f7ea82942",
74
+ "@aztec/kv-store": "0.0.1-commit.f7ea82942",
75
+ "@aztec/l1-artifacts": "0.0.1-commit.f7ea82942",
76
+ "@aztec/noir-protocol-circuits-types": "0.0.1-commit.f7ea82942",
77
+ "@aztec/protocol-contracts": "0.0.1-commit.f7ea82942",
78
+ "@aztec/stdlib": "0.0.1-commit.f7ea82942",
79
+ "@aztec/telemetry-client": "0.0.1-commit.f7ea82942",
80
80
  "lodash.groupby": "^4.6.0",
81
81
  "lodash.omit": "^4.5.0",
82
82
  "tslib": "^2.5.0",
package/src/archiver.ts CHANGED
@@ -11,7 +11,7 @@ import { EthAddress } from '@aztec/foundation/eth-address';
11
11
  import { type Logger, createLogger } from '@aztec/foundation/log';
12
12
  import { type PromiseWithResolvers, promiseWithResolvers } from '@aztec/foundation/promise';
13
13
  import { RunningPromise, makeLoggingErrorHandler } from '@aztec/foundation/running-promise';
14
- import { DateProvider } from '@aztec/foundation/timer';
14
+ import { DateProvider, elapsed } from '@aztec/foundation/timer';
15
15
  import {
16
16
  type ArchiverEmitter,
17
17
  L2Block,
@@ -31,6 +31,7 @@ import { type TelemetryClient, type Traceable, type Tracer, trackSpan } from '@a
31
31
 
32
32
  import { type ArchiverConfig, mapArchiverConfig } from './config.js';
33
33
  import { BlockAlreadyCheckpointedError, NoBlobBodiesFoundError } from './errors.js';
34
+ import { validateAndLogHistoricalLogsAvailability } from './l1/validate_historical_logs.js';
34
35
  import { validateAndLogTraceAvailability } from './l1/validate_trace.js';
35
36
  import { ArchiverDataSourceBase } from './modules/data_source_base.js';
36
37
  import { ArchiverDataStoreUpdater } from './modules/data_store_updater.js';
@@ -85,13 +86,15 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
85
86
 
86
87
  public readonly tracer: Tracer;
87
88
 
89
+ private readonly instrumentation: ArchiverInstrumentation;
90
+
88
91
  /**
89
92
  * Creates a new instance of the Archiver.
90
93
  * @param publicClient - A client for interacting with the Ethereum node.
91
94
  * @param debugClient - A client for interacting with the Ethereum node for debug/trace methods.
92
95
  * @param rollup - Rollup contract instance.
93
96
  * @param inbox - Inbox contract instance.
94
- * @param l1Addresses - L1 contract addresses (registry, governance proposer, slash factory, slashing proposer).
97
+ * @param l1Addresses - L1 contract addresses (registry, governance proposer, slashing proposer).
95
98
  * @param dataStore - An archiver data store for storage & retrieval of blocks, encrypted logs & contract data.
96
99
  * @param config - Archiver configuration options.
97
100
  * @param blobClient - Client for retrieving blob data.
@@ -106,8 +109,10 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
106
109
  private readonly rollup: RollupContract,
107
110
  private readonly l1Addresses: Pick<
108
111
  L1ContractAddresses,
109
- 'registryAddress' | 'governanceProposerAddress' | 'slashFactoryAddress'
110
- > & { slashingProposerAddress: EthAddress },
112
+ 'rollupAddress' | 'registryAddress' | 'inboxAddress' | 'governanceProposerAddress'
113
+ > & {
114
+ slashingProposerAddress: EthAddress;
115
+ },
111
116
  readonly dataStore: KVArchiverDataStore,
112
117
  private config: {
113
118
  pollingIntervalMs: number;
@@ -115,6 +120,7 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
115
120
  skipValidateCheckpointAttestations?: boolean;
116
121
  maxAllowedEthClientDriftSeconds: number;
117
122
  ethereumAllowNoDebugHosts?: boolean;
123
+ skipHistoricalLogsCheck?: boolean;
118
124
  },
119
125
  private readonly blobClient: BlobClientInterface,
120
126
  instrumentation: ArchiverInstrumentation,
@@ -130,6 +136,7 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
130
136
  super(dataStore, l1Constants);
131
137
 
132
138
  this.tracer = instrumentation.tracer;
139
+ this.instrumentation = instrumentation;
133
140
  this.initialSyncPromise = promiseWithResolvers();
134
141
  this.synchronizer = synchronizer;
135
142
  this.events = events;
@@ -170,6 +177,17 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
170
177
  this.config.ethereumAllowNoDebugHosts ?? false,
171
178
  this.log.getBindings(),
172
179
  );
180
+ await validateAndLogHistoricalLogsAvailability(
181
+ this.publicClient,
182
+ {
183
+ rollupAddress: this.l1Addresses.rollupAddress,
184
+ inboxAddress: this.l1Addresses.inboxAddress,
185
+ registryAddress: this.l1Addresses.registryAddress,
186
+ governanceProposerAddress: this.l1Addresses.governanceProposerAddress,
187
+ },
188
+ this.config.skipHistoricalLogsCheck ?? false,
189
+ this.log.getBindings(),
190
+ );
173
191
 
174
192
  // Log initial state for the archiver
175
193
  const { l1StartBlock } = this.l1Constants;
@@ -245,7 +263,8 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
245
263
  }
246
264
 
247
265
  try {
248
- await this.updater.addProposedBlock(block);
266
+ const [durationMs] = await elapsed(() => this.updater.addProposedBlock(block));
267
+ this.instrumentation.processNewProposedBlock(durationMs, block);
249
268
  this.log.debug(`Added block ${block.number} to store`);
250
269
  resolve();
251
270
  } catch (err: any) {
@@ -490,7 +509,10 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
490
509
  await this.store.rollbackL1ToL2MessagesToCheckpoint(targetCheckpointNumber);
491
510
  this.log.info(`Setting L1 syncpoints to ${targetL1BlockNumber}`);
492
511
  await this.store.setCheckpointSynchedL1BlockNumber(targetL1BlockNumber);
493
- await this.store.setMessageSynchedL1Block({ l1BlockNumber: targetL1BlockNumber, l1BlockHash: targetL1BlockHash });
512
+ await this.store.setMessageSyncState(
513
+ { l1BlockNumber: targetL1BlockNumber, l1BlockHash: targetL1BlockHash },
514
+ undefined,
515
+ );
494
516
  if (targetL2BlockNumber < currentProvenBlock) {
495
517
  this.log.info(`Rolling back proven L2 checkpoint to ${targetCheckpointNumber}`);
496
518
  await this.updater.setProvenCheckpointNumber(targetCheckpointNumber);
package/src/config.ts CHANGED
@@ -50,13 +50,17 @@ export const archiverConfigMappings: ConfigMappingsType<ArchiverConfig> = {
50
50
  },
51
51
  archiverStoreMapSizeKb: {
52
52
  env: 'ARCHIVER_STORE_MAP_SIZE_KB',
53
- parseEnv: (val: string | undefined) => (val ? +val : undefined),
53
+ parseEnv: (val: string) => +val,
54
54
  description: 'The maximum possible size of the archiver DB in KB. Overwrites the general dataStoreMapSizeKb.',
55
55
  },
56
56
  skipValidateCheckpointAttestations: {
57
57
  description: 'Skip validating checkpoint attestations (for testing purposes only)',
58
58
  ...booleanConfigHelper(false),
59
59
  },
60
+ skipPromoteProposedCheckpointDuringL1Sync: {
61
+ description: 'Skip promoting proposed checkpoints during L1 sync (for testing purposes only)',
62
+ ...booleanConfigHelper(false),
63
+ },
60
64
  maxAllowedEthClientDriftSeconds: {
61
65
  env: 'MAX_ALLOWED_ETH_CLIENT_DRIFT_SECONDS',
62
66
  description: 'Maximum allowed drift in seconds between the Ethereum client and current time.',
@@ -67,6 +71,13 @@ export const archiverConfigMappings: ConfigMappingsType<ArchiverConfig> = {
67
71
  description: 'Whether to allow starting the archiver without debug/trace method support on Ethereum hosts',
68
72
  ...booleanConfigHelper(true),
69
73
  },
74
+ archiverSkipHistoricalLogsCheck: {
75
+ env: 'ARCHIVER_SKIP_HISTORICAL_LOGS_CHECK',
76
+ description:
77
+ 'Skip the startup check that probes the L1 RPC for historical Rollup contract logs. ' +
78
+ 'Set to true to bypass the check when the connected RPC node is known to prune old logs.',
79
+ ...booleanConfigHelper(false),
80
+ },
70
81
  ...chainConfigMappings,
71
82
  ...l1ReaderConfigMappings,
72
83
  viemPollingIntervalMS: {
@@ -96,7 +107,9 @@ export function mapArchiverConfig(config: Partial<ArchiverConfig>) {
96
107
  pollingIntervalMs: config.archiverPollingIntervalMS,
97
108
  batchSize: config.archiverBatchSize,
98
109
  skipValidateCheckpointAttestations: config.skipValidateCheckpointAttestations,
110
+ skipPromoteProposedCheckpointDuringL1Sync: config.skipPromoteProposedCheckpointDuringL1Sync,
99
111
  maxAllowedEthClientDriftSeconds: config.maxAllowedEthClientDriftSeconds,
100
112
  ethereumAllowNoDebugHosts: config.ethereumAllowNoDebugHosts,
113
+ skipHistoricalLogsCheck: config.archiverSkipHistoricalLogsCheck,
101
114
  };
102
115
  }
package/src/errors.ts CHANGED
@@ -132,6 +132,40 @@ export class ProposedCheckpointNotSequentialError extends Error {
132
132
  }
133
133
  }
134
134
 
135
+ /** Thrown when attempting to promote a proposed checkpoint but no proposed checkpoint exists in the store. */
136
+ export class NoProposedCheckpointToPromoteError extends Error {
137
+ constructor() {
138
+ super('Cannot promote proposed checkpoint: no proposed checkpoint exists');
139
+ this.name = 'NoProposedCheckpointToPromoteError';
140
+ }
141
+ }
142
+
143
+ /** Thrown when the archive root of the proposed checkpoint does not match the expected one. */
144
+ export class ProposedCheckpointArchiveRootMismatchError extends Error {
145
+ constructor(
146
+ public readonly expectedArchiveRoot: Fr,
147
+ public readonly actualArchiveRoot: Fr,
148
+ ) {
149
+ super(
150
+ `Cannot promote proposed checkpoint: archive root mismatch (expected ${expectedArchiveRoot}, got ${actualArchiveRoot})`,
151
+ );
152
+ this.name = 'ProposedCheckpointArchiveRootMismatchError';
153
+ }
154
+ }
155
+
156
+ /** Thrown when the proposed checkpoint does not directly follow the latest confirmed checkpoint. */
157
+ export class ProposedCheckpointPromotionNotSequentialError extends Error {
158
+ constructor(
159
+ public readonly proposedCheckpointNumber: number,
160
+ public readonly latestCheckpointNumber: number,
161
+ ) {
162
+ super(
163
+ `Cannot promote proposed checkpoint: not sequential (latest ${latestCheckpointNumber}, proposed ${proposedCheckpointNumber})`,
164
+ );
165
+ this.name = 'ProposedCheckpointPromotionNotSequentialError';
166
+ }
167
+ }
168
+
135
169
  /** Thrown when a proposed block conflicts with an already checkpointed block (different content). */
136
170
  export class CannotOverwriteCheckpointedBlockError extends Error {
137
171
  constructor(
package/src/factory.ts CHANGED
@@ -121,6 +121,7 @@ export async function createArchiver(
121
121
  batchSize: 100,
122
122
  maxAllowedEthClientDriftSeconds: 300,
123
123
  ethereumAllowNoDebugHosts: false,
124
+ skipHistoricalLogsCheck: false,
124
125
  },
125
126
  mapArchiverConfig(config),
126
127
  );
package/src/index.ts CHANGED
@@ -10,4 +10,5 @@ export { KVArchiverDataStore, ARCHIVER_DB_VERSION } from './store/kv_archiver_st
10
10
  export { ContractInstanceStore } from './store/contract_instance_store.js';
11
11
  export { L2TipsCache } from './store/l2_tips_cache.js';
12
12
 
13
- export { retrieveCheckpointsFromRollup, retrieveL2ProofVerifiedEvents } from './l1/data_retrieval.js';
13
+ export { retrieveL2ProofVerifiedEvents } from './l1/data_retrieval.js';
14
+ export { CalldataRetriever } from './l1/calldata_retriever.js';
@@ -35,18 +35,28 @@ import type { DataRetrieval } from '../structs/data_retrieval.js';
35
35
  import type { InboxMessage } from '../structs/inbox_message.js';
36
36
  import { CalldataRetriever } from './calldata_retriever.js';
37
37
 
38
- export type RetrievedCheckpoint = {
38
+ type RetrievedCheckpointBase = {
39
39
  checkpointNumber: CheckpointNumber;
40
40
  archiveRoot: Fr;
41
41
  feeAssetPriceModifier: bigint;
42
42
  header: CheckpointHeader;
43
- checkpointBlobData: CheckpointBlobData;
44
43
  l1: L1PublishedData;
45
44
  chainId: Fr;
46
45
  version: Fr;
47
46
  attestations: CommitteeAttestation[];
48
47
  };
49
48
 
49
+ /** Checkpoint data as retrieved from L1 calldata and blob data. */
50
+ export type RetrievedCheckpoint = RetrievedCheckpointBase & { checkpointBlobData: CheckpointBlobData };
51
+
52
+ /** Checkpoint data retrieved from L1 calldata only, without blob data. */
53
+ export type RetrievedCheckpointFromCalldata = RetrievedCheckpointBase & {
54
+ /** Versioned blob hashes from the checkpoint proposed event. */
55
+ blobHashes: Buffer[];
56
+ /** Parent beacon block root from the L1 block, used for blob fetching. */
57
+ parentBeaconBlockRoot: string | undefined;
58
+ };
59
+
50
60
  export async function retrievedToPublishedCheckpoint({
51
61
  checkpointNumber,
52
62
  archiveRoot,
@@ -137,31 +147,27 @@ export async function retrievedToPublishedCheckpoint({
137
147
  }
138
148
 
139
149
  /**
140
- * Fetches new checkpoints.
150
+ * Fetches checkpoint calldata from the rollup contract without fetching blob data.
151
+ * Returns RetrievedCheckpointFromCalldata objects that preserve the information needed for deferred blob fetching.
141
152
  * @param rollup - The rollup contract wrapper.
142
153
  * @param publicClient - The viem public client to use for transaction retrieval.
143
154
  * @param debugClient - The viem debug client to use for trace/debug RPC methods (optional).
144
- * @param blobClient - The blob client client for fetching blob data.
145
155
  * @param searchStartBlock - The block number to use for starting the search.
146
156
  * @param searchEndBlock - The highest block number that we should search up to.
147
- * @param contractAddresses - The contract addresses (governanceProposerAddress, slashFactoryAddress, slashingProposerAddress).
148
157
  * @param instrumentation - The archiver instrumentation instance.
149
158
  * @param logger - The logger instance.
150
- * @param isHistoricalSync - Whether this is a historical sync.
151
- * @returns An array of retrieved checkpoints.
159
+ * @returns An array of calldata-only checkpoints.
152
160
  */
153
- export async function retrieveCheckpointsFromRollup(
161
+ export async function retrieveCheckpointCalldataFromRollup(
154
162
  rollup: RollupContract,
155
163
  publicClient: ViemPublicClient,
156
164
  debugClient: ViemPublicDebugClient,
157
- blobClient: BlobClientInterface,
158
165
  searchStartBlock: bigint,
159
166
  searchEndBlock: bigint,
160
167
  instrumentation: ArchiverInstrumentation,
161
168
  logger: Logger = createLogger('archiver'),
162
- isHistoricalSync: boolean = false,
163
- ): Promise<RetrievedCheckpoint[]> {
164
- const retrievedCheckpoints: RetrievedCheckpoint[] = [];
169
+ ): Promise<RetrievedCheckpointFromCalldata[]> {
170
+ const retrievedCheckpoints: RetrievedCheckpointFromCalldata[] = [];
165
171
 
166
172
  let rollupConstants: { chainId: Fr; version: Fr; targetCommitteeSize: number } | undefined;
167
173
 
@@ -197,46 +203,39 @@ export async function retrieveCheckpointsFromRollup(
197
203
  rollup,
198
204
  publicClient,
199
205
  debugClient,
200
- blobClient,
201
206
  checkpointProposedLogs,
202
207
  rollupConstants,
203
208
  instrumentation,
204
209
  logger,
205
- isHistoricalSync,
206
210
  );
207
211
  retrievedCheckpoints.push(...newCheckpoints);
208
212
  searchStartBlock = lastLog.l1BlockNumber + 1n;
209
213
  } while (searchStartBlock <= searchEndBlock);
210
214
 
211
- // The asyncPool from processCheckpointProposedLogs will not necessarily return the checkpoints in order, so we sort them before returning.
212
215
  return retrievedCheckpoints.sort((a, b) => Number(a.l1.blockNumber - b.l1.blockNumber));
213
216
  }
214
217
 
215
218
  /**
216
- * Processes newly received CheckpointProposed logs.
219
+ * Processes CheckpointProposed logs, fetching only calldata (no blobs).
217
220
  * @param rollup - The rollup contract wrapper.
218
221
  * @param publicClient - The viem public client to use for transaction retrieval.
219
222
  * @param debugClient - The viem debug client to use for trace/debug RPC methods (optional).
220
- * @param blobClient - The blob client client for fetching blob data.
221
223
  * @param logs - CheckpointProposed logs.
222
224
  * @param rollupConstants - The rollup constants (chainId, version, targetCommitteeSize).
223
225
  * @param instrumentation - The archiver instrumentation instance.
224
226
  * @param logger - The logger instance.
225
- * @param isHistoricalSync - Whether this is a historical sync.
226
- * @returns An array of retrieved checkpoints.
227
+ * @returns An array of calldata-only checkpoints.
227
228
  */
228
229
  async function processCheckpointProposedLogs(
229
230
  rollup: RollupContract,
230
231
  publicClient: ViemPublicClient,
231
232
  debugClient: ViemPublicDebugClient,
232
- blobClient: BlobClientInterface,
233
233
  logs: CheckpointProposedLog[],
234
234
  { chainId, version, targetCommitteeSize }: { chainId: Fr; version: Fr; targetCommitteeSize: number },
235
235
  instrumentation: ArchiverInstrumentation,
236
236
  logger: Logger,
237
- isHistoricalSync: boolean,
238
- ): Promise<RetrievedCheckpoint[]> {
239
- const retrievedCheckpoints: RetrievedCheckpoint[] = [];
237
+ ): Promise<RetrievedCheckpointFromCalldata[]> {
238
+ const retrievedCheckpoints: RetrievedCheckpointFromCalldata[] = [];
240
239
  const calldataRetriever = new CalldataRetriever(
241
240
  publicClient,
242
241
  debugClient,
@@ -252,7 +251,6 @@ async function processCheckpointProposedLogs(
252
251
  const archiveFromChain = await rollup.archiveAt(checkpointNumber);
253
252
  const blobHashes = log.args.versionedBlobHashes;
254
253
 
255
- // The value from the event and contract will match only if the checkpoint is in the chain.
256
254
  if (archive.equals(archiveFromChain)) {
257
255
  const expectedHashes = {
258
256
  attestationsHash: log.args.attestationsHash.toString() as Hex,
@@ -268,19 +266,16 @@ async function processCheckpointProposedLogs(
268
266
  const { timestamp, parentBeaconBlockRoot } = await getL1Block(publicClient, log.l1BlockNumber);
269
267
  const l1 = new L1PublishedData(log.l1BlockNumber, timestamp, log.l1BlockHash.toString());
270
268
 
271
- const checkpointBlobData = await getCheckpointBlobDataFromBlobs(
272
- blobClient,
273
- checkpoint.blockHash,
269
+ retrievedCheckpoints.push({
270
+ ...checkpoint,
271
+ l1,
272
+ chainId,
273
+ version,
274
274
  blobHashes,
275
- checkpointNumber,
276
- logger,
277
- isHistoricalSync,
278
275
  parentBeaconBlockRoot,
279
- timestamp,
280
- );
276
+ });
281
277
 
282
- retrievedCheckpoints.push({ ...checkpoint, checkpointBlobData, l1, chainId, version });
283
- logger.trace(`Retrieved checkpoint ${checkpointNumber} from L1 tx ${log.l1TransactionHash}`, {
278
+ logger.trace(`Retrieved checkpoint calldata ${checkpointNumber} from L1 tx ${log.l1TransactionHash}`, {
284
279
  l1BlockNumber: log.l1BlockNumber,
285
280
  checkpointNumber,
286
281
  archive: archive.toString(),
@@ -344,14 +339,10 @@ export async function getCheckpointBlobDataFromBlobs(
344
339
  /** Given an L1 to L2 message, retrieves its corresponding event from the Inbox within a specific block range. */
345
340
  export async function retrieveL1ToL2Message(
346
341
  inbox: InboxContract,
347
- leaf: Fr,
348
- fromBlock: bigint,
349
- toBlock: bigint,
342
+ message: InboxMessage,
350
343
  ): Promise<InboxMessage | undefined> {
351
- const logs = await inbox.getMessageSentEventByHash(leaf.toString(), fromBlock, toBlock);
352
-
353
- const messages = mapLogsInboxMessage(logs);
354
- return messages.length > 0 ? messages[0] : undefined;
344
+ const log = await inbox.getMessageSentEventByHash(message.leaf.toString(), message.l1BlockNumber);
345
+ return log && mapLogInboxMessage(log);
355
346
  }
356
347
 
357
348
  /**
@@ -374,22 +365,22 @@ export async function retrieveL1ToL2Messages(
374
365
  break;
375
366
  }
376
367
 
377
- retrievedL1ToL2Messages.push(...mapLogsInboxMessage(messageSentLogs));
368
+ retrievedL1ToL2Messages.push(...messageSentLogs.map(mapLogInboxMessage));
378
369
  searchStartBlock = messageSentLogs.at(-1)!.l1BlockNumber + 1n;
379
370
  }
380
371
 
381
372
  return retrievedL1ToL2Messages;
382
373
  }
383
374
 
384
- function mapLogsInboxMessage(logs: MessageSentLog[]): InboxMessage[] {
385
- return logs.map(log => ({
375
+ function mapLogInboxMessage(log: MessageSentLog): InboxMessage {
376
+ return {
386
377
  index: log.args.index,
387
378
  leaf: log.args.leaf,
388
379
  l1BlockNumber: log.l1BlockNumber,
389
380
  l1BlockHash: log.l1BlockHash,
390
381
  checkpointNumber: log.args.checkpointNumber,
391
382
  rollingHash: log.args.rollingHash,
392
- }));
383
+ };
393
384
  }
394
385
 
395
386
  /** Retrieves L2ProofVerified events from the rollup contract. */