@aztec/archiver 0.0.1-commit.8afd444 → 0.0.1-commit.8ee97c858

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 (92) hide show
  1. package/dest/archiver.d.ts +7 -5
  2. package/dest/archiver.d.ts.map +1 -1
  3. package/dest/archiver.js +62 -111
  4. package/dest/config.d.ts +3 -3
  5. package/dest/config.d.ts.map +1 -1
  6. package/dest/config.js +2 -1
  7. package/dest/errors.d.ts +21 -9
  8. package/dest/errors.d.ts.map +1 -1
  9. package/dest/errors.js +27 -14
  10. package/dest/factory.d.ts +3 -4
  11. package/dest/factory.d.ts.map +1 -1
  12. package/dest/factory.js +24 -20
  13. package/dest/index.d.ts +2 -1
  14. package/dest/index.d.ts.map +1 -1
  15. package/dest/index.js +1 -0
  16. package/dest/l1/bin/retrieve-calldata.js +36 -33
  17. package/dest/l1/calldata_retriever.d.ts +73 -50
  18. package/dest/l1/calldata_retriever.d.ts.map +1 -1
  19. package/dest/l1/calldata_retriever.js +190 -259
  20. package/dest/l1/data_retrieval.d.ts +9 -9
  21. package/dest/l1/data_retrieval.d.ts.map +1 -1
  22. package/dest/l1/data_retrieval.js +21 -19
  23. package/dest/l1/spire_proposer.d.ts +5 -5
  24. package/dest/l1/spire_proposer.d.ts.map +1 -1
  25. package/dest/l1/spire_proposer.js +9 -17
  26. package/dest/modules/data_source_base.d.ts +12 -7
  27. package/dest/modules/data_source_base.d.ts.map +1 -1
  28. package/dest/modules/data_source_base.js +33 -77
  29. package/dest/modules/data_store_updater.d.ts +22 -7
  30. package/dest/modules/data_store_updater.d.ts.map +1 -1
  31. package/dest/modules/data_store_updater.js +70 -30
  32. package/dest/modules/instrumentation.d.ts +15 -2
  33. package/dest/modules/instrumentation.d.ts.map +1 -1
  34. package/dest/modules/instrumentation.js +19 -2
  35. package/dest/modules/l1_synchronizer.d.ts +5 -8
  36. package/dest/modules/l1_synchronizer.d.ts.map +1 -1
  37. package/dest/modules/l1_synchronizer.js +50 -15
  38. package/dest/store/block_store.d.ts +29 -26
  39. package/dest/store/block_store.d.ts.map +1 -1
  40. package/dest/store/block_store.js +130 -78
  41. package/dest/store/kv_archiver_store.d.ts +40 -13
  42. package/dest/store/kv_archiver_store.d.ts.map +1 -1
  43. package/dest/store/kv_archiver_store.js +48 -13
  44. package/dest/store/l2_tips_cache.d.ts +19 -0
  45. package/dest/store/l2_tips_cache.d.ts.map +1 -0
  46. package/dest/store/l2_tips_cache.js +89 -0
  47. package/dest/store/log_store.d.ts +6 -3
  48. package/dest/store/log_store.d.ts.map +1 -1
  49. package/dest/store/log_store.js +148 -51
  50. package/dest/store/message_store.d.ts +5 -1
  51. package/dest/store/message_store.d.ts.map +1 -1
  52. package/dest/store/message_store.js +14 -1
  53. package/dest/test/fake_l1_state.d.ts +13 -1
  54. package/dest/test/fake_l1_state.d.ts.map +1 -1
  55. package/dest/test/fake_l1_state.js +95 -23
  56. package/dest/test/mock_archiver.d.ts +1 -1
  57. package/dest/test/mock_archiver.d.ts.map +1 -1
  58. package/dest/test/mock_archiver.js +3 -2
  59. package/dest/test/mock_l2_block_source.d.ts +21 -5
  60. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  61. package/dest/test/mock_l2_block_source.js +132 -86
  62. package/dest/test/mock_structs.d.ts +4 -1
  63. package/dest/test/mock_structs.d.ts.map +1 -1
  64. package/dest/test/mock_structs.js +13 -1
  65. package/dest/test/noop_l1_archiver.d.ts +4 -1
  66. package/dest/test/noop_l1_archiver.d.ts.map +1 -1
  67. package/dest/test/noop_l1_archiver.js +5 -1
  68. package/package.json +13 -13
  69. package/src/archiver.ts +74 -131
  70. package/src/config.ts +8 -1
  71. package/src/errors.ts +40 -24
  72. package/src/factory.ts +34 -17
  73. package/src/index.ts +1 -0
  74. package/src/l1/README.md +25 -68
  75. package/src/l1/bin/retrieve-calldata.ts +46 -39
  76. package/src/l1/calldata_retriever.ts +249 -379
  77. package/src/l1/data_retrieval.ts +23 -25
  78. package/src/l1/spire_proposer.ts +7 -15
  79. package/src/modules/data_source_base.ts +64 -98
  80. package/src/modules/data_store_updater.ts +72 -31
  81. package/src/modules/instrumentation.ts +29 -2
  82. package/src/modules/l1_synchronizer.ts +61 -24
  83. package/src/store/block_store.ts +157 -105
  84. package/src/store/kv_archiver_store.ts +73 -15
  85. package/src/store/l2_tips_cache.ts +89 -0
  86. package/src/store/log_store.ts +219 -58
  87. package/src/store/message_store.ts +20 -1
  88. package/src/test/fake_l1_state.ts +125 -26
  89. package/src/test/mock_archiver.ts +3 -2
  90. package/src/test/mock_l2_block_source.ts +173 -81
  91. package/src/test/mock_structs.ts +20 -6
  92. package/src/test/noop_l1_archiver.ts +7 -1
@@ -1,5 +1,9 @@
1
+ import type { SlotNumber } from '@aztec/foundation/branded-types';
1
2
  import { createLogger } from '@aztec/foundation/log';
2
3
  import type { L2Block } from '@aztec/stdlib/block';
4
+ import type { CheckpointData } from '@aztec/stdlib/checkpoint';
5
+ import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
6
+ import { getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
3
7
  import {
4
8
  Attributes,
5
9
  type Gauge,
@@ -17,6 +21,7 @@ export class ArchiverInstrumentation {
17
21
  public readonly tracer: Tracer;
18
22
 
19
23
  private blockHeight: Gauge;
24
+ private checkpointHeight: Gauge;
20
25
  private txCount: UpDownCounter;
21
26
  private l1BlockHeight: Gauge;
22
27
  private proofsSubmittedDelay: Histogram;
@@ -36,6 +41,8 @@ export class ArchiverInstrumentation {
36
41
 
37
42
  private blockProposalTxTargetCount: UpDownCounter;
38
43
 
44
+ private checkpointL1InclusionDelay: Histogram;
45
+
39
46
  private log = createLogger('archiver:instrumentation');
40
47
 
41
48
  private constructor(
@@ -47,6 +54,8 @@ export class ArchiverInstrumentation {
47
54
 
48
55
  this.blockHeight = meter.createGauge(Metrics.ARCHIVER_BLOCK_HEIGHT);
49
56
 
57
+ this.checkpointHeight = meter.createGauge(Metrics.ARCHIVER_CHECKPOINT_HEIGHT);
58
+
50
59
  this.l1BlockHeight = meter.createGauge(Metrics.ARCHIVER_L1_BLOCK_HEIGHT);
51
60
 
52
61
  this.txCount = createUpDownCounterWithDefault(meter, Metrics.ARCHIVER_TOTAL_TXS);
@@ -81,6 +90,8 @@ export class ArchiverInstrumentation {
81
90
  },
82
91
  );
83
92
 
93
+ this.checkpointL1InclusionDelay = meter.createHistogram(Metrics.ARCHIVER_CHECKPOINT_L1_INCLUSION_DELAY);
94
+
84
95
  this.dbMetrics = new LmdbMetrics(
85
96
  meter,
86
97
  {
@@ -105,6 +116,7 @@ export class ArchiverInstrumentation {
105
116
  public processNewBlocks(syncTimePerBlock: number, blocks: L2Block[]) {
106
117
  this.syncDurationPerBlock.record(Math.ceil(syncTimePerBlock));
107
118
  this.blockHeight.record(Math.max(...blocks.map(b => b.number)));
119
+ this.checkpointHeight.record(Math.max(...blocks.map(b => b.checkpointNumber)));
108
120
  this.syncBlockCount.add(blocks.length);
109
121
 
110
122
  for (const block of blocks) {
@@ -127,8 +139,10 @@ export class ArchiverInstrumentation {
127
139
  this.pruneDuration.record(Math.ceil(duration));
128
140
  }
129
141
 
130
- public updateLastProvenBlock(blockNumber: number) {
131
- this.blockHeight.record(blockNumber, { [Attributes.STATUS]: 'proven' });
142
+ public updateLastProvenCheckpoint(checkpoint: CheckpointData) {
143
+ const lastBlockNumberInCheckpoint = checkpoint.startBlock + checkpoint.blockCount - 1;
144
+ this.blockHeight.record(lastBlockNumberInCheckpoint, { [Attributes.STATUS]: 'proven' });
145
+ this.checkpointHeight.record(checkpoint.checkpointNumber, { [Attributes.STATUS]: 'proven' });
132
146
  }
133
147
 
134
148
  public processProofsVerified(logs: { proverId: string; l2BlockNumber: bigint; delay: bigint }[]) {
@@ -154,4 +168,17 @@ export class ArchiverInstrumentation {
154
168
  [Attributes.L1_BLOCK_PROPOSAL_USED_TRACE]: usedTrace,
155
169
  });
156
170
  }
171
+
172
+ /**
173
+ * Records L1 inclusion timing for a checkpoint observed on L1 (seconds into the L2 slot).
174
+ */
175
+ public processCheckpointL1Timing(data: {
176
+ slotNumber: SlotNumber;
177
+ l1Timestamp: bigint;
178
+ l1Constants: Pick<L1RollupConstants, 'l1GenesisTime' | 'slotDuration'>;
179
+ }): void {
180
+ const slotStartTs = getTimestampForSlot(data.slotNumber, data.l1Constants);
181
+ const inclusionDelaySeconds = Number(data.l1Timestamp - slotStartTs);
182
+ this.checkpointL1InclusionDelay.record(inclusionDelaySeconds);
183
+ }
157
184
  }
@@ -1,15 +1,14 @@
1
1
  import type { BlobClientInterface } from '@aztec/blob-client/client';
2
2
  import { EpochCache } from '@aztec/epoch-cache';
3
3
  import { InboxContract, RollupContract } from '@aztec/ethereum/contracts';
4
- import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
5
4
  import type { L1BlockId } from '@aztec/ethereum/l1-types';
6
5
  import type { ViemPublicClient, ViemPublicDebugClient } from '@aztec/ethereum/types';
6
+ import { asyncPool } from '@aztec/foundation/async-pool';
7
7
  import { maxBigint } from '@aztec/foundation/bigint';
8
8
  import { BlockNumber, CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types';
9
9
  import { Buffer32 } from '@aztec/foundation/buffer';
10
10
  import { pick } from '@aztec/foundation/collection';
11
11
  import { Fr } from '@aztec/foundation/curves/bn254';
12
- import { EthAddress } from '@aztec/foundation/eth-address';
13
12
  import { type Logger, createLogger } from '@aztec/foundation/log';
14
13
  import { count } from '@aztec/foundation/string';
15
14
  import { DateProvider, Timer, elapsed } from '@aztec/foundation/timer';
@@ -28,6 +27,7 @@ import {
28
27
  retrievedToPublishedCheckpoint,
29
28
  } from '../l1/data_retrieval.js';
30
29
  import type { KVArchiverDataStore } from '../store/kv_archiver_store.js';
30
+ import type { L2TipsCache } from '../store/l2_tips_cache.js';
31
31
  import type { InboxMessage } from '../structs/inbox_message.js';
32
32
  import { ArchiverDataStoreUpdater } from './data_store_updater.js';
33
33
  import type { ArchiverInstrumentation } from './instrumentation.js';
@@ -60,10 +60,6 @@ export class ArchiverL1Synchronizer implements Traceable {
60
60
  private readonly debugClient: ViemPublicDebugClient,
61
61
  private readonly rollup: RollupContract,
62
62
  private readonly inbox: InboxContract,
63
- private readonly l1Addresses: Pick<
64
- L1ContractAddresses,
65
- 'registryAddress' | 'governanceProposerAddress' | 'slashFactoryAddress'
66
- > & { slashingProposerAddress: EthAddress },
67
63
  private readonly store: KVArchiverDataStore,
68
64
  private config: {
69
65
  batchSize: number;
@@ -74,12 +70,18 @@ export class ArchiverL1Synchronizer implements Traceable {
74
70
  private readonly epochCache: EpochCache,
75
71
  private readonly dateProvider: DateProvider,
76
72
  private readonly instrumentation: ArchiverInstrumentation,
77
- private readonly l1Constants: L1RollupConstants & { l1StartBlockHash: Buffer32; genesisArchiveRoot: Fr },
73
+ private readonly l1Constants: L1RollupConstants & {
74
+ l1StartBlockHash: Buffer32;
75
+ genesisArchiveRoot: Fr;
76
+ },
78
77
  private readonly events: ArchiverEmitter,
79
78
  tracer: Tracer,
79
+ l2TipsCache?: L2TipsCache,
80
80
  private readonly log: Logger = createLogger('archiver:l1-sync'),
81
81
  ) {
82
- this.updater = new ArchiverDataStoreUpdater(this.store);
82
+ this.updater = new ArchiverDataStoreUpdater(this.store, l2TipsCache, {
83
+ rollupManaLimit: l1Constants.rollupManaLimit,
84
+ });
83
85
  this.tracer = tracer;
84
86
  }
85
87
 
@@ -215,6 +217,9 @@ export class ArchiverL1Synchronizer implements Traceable {
215
217
  this.instrumentation.updateL1BlockHeight(currentL1BlockNumber);
216
218
  }
217
219
 
220
+ // Update the finalized L2 checkpoint based on L1 finality.
221
+ await this.updateFinalizedCheckpoint();
222
+
218
223
  // After syncing has completed, update the current l1 block number and timestamp,
219
224
  // otherwise we risk announcing to the world that we've synced to a given point,
220
225
  // but the corresponding blocks have not been processed (see #12631).
@@ -230,6 +235,27 @@ export class ArchiverL1Synchronizer implements Traceable {
230
235
  });
231
236
  }
232
237
 
238
+ /** Query L1 for its finalized block and update the finalized checkpoint accordingly. */
239
+ private async updateFinalizedCheckpoint(): Promise<void> {
240
+ try {
241
+ const finalizedL1Block = await this.publicClient.getBlock({ blockTag: 'finalized', includeTransactions: false });
242
+ const finalizedL1BlockNumber = finalizedL1Block.number;
243
+ const finalizedCheckpointNumber = await this.rollup.getProvenCheckpointNumber({
244
+ blockNumber: finalizedL1BlockNumber,
245
+ });
246
+ const localFinalizedCheckpointNumber = await this.store.getFinalizedCheckpointNumber();
247
+ if (localFinalizedCheckpointNumber !== finalizedCheckpointNumber) {
248
+ await this.updater.setFinalizedCheckpointNumber(finalizedCheckpointNumber);
249
+ this.log.info(`Updated finalized chain to checkpoint ${finalizedCheckpointNumber}`, {
250
+ finalizedCheckpointNumber,
251
+ finalizedL1BlockNumber,
252
+ });
253
+ }
254
+ } catch (err) {
255
+ this.log.warn(`Failed to update finalized checkpoint: ${err}`);
256
+ }
257
+ }
258
+
233
259
  /** Prune all proposed local blocks that should have been checkpointed by now. */
234
260
  private async pruneUncheckpointedBlocks(currentL1Timestamp: bigint) {
235
261
  const [lastCheckpointedBlockNumber, lastProposedBlockNumber] = await Promise.all([
@@ -308,17 +334,20 @@ export class ArchiverL1Synchronizer implements Traceable {
308
334
 
309
335
  const checkpointsToUnwind = localPendingCheckpointNumber - provenCheckpointNumber;
310
336
 
311
- const checkpointPromises = Array.from({ length: checkpointsToUnwind })
312
- .fill(0)
313
- .map((_, i) => this.store.getCheckpointData(CheckpointNumber(i + pruneFrom)));
314
- const checkpoints = await Promise.all(checkpointPromises);
315
-
316
- const blockPromises = await Promise.all(
317
- checkpoints
318
- .filter(isDefined)
319
- .map(cp => this.store.getBlocksForCheckpoint(CheckpointNumber(cp.checkpointNumber))),
337
+ // Fetch checkpoints and blocks in bounded batches to avoid unbounded concurrent
338
+ // promises when the gap between local pending and proven checkpoint numbers is large.
339
+ const BATCH_SIZE = 10;
340
+ const indices = Array.from({ length: checkpointsToUnwind }, (_, i) => CheckpointNumber(i + pruneFrom));
341
+ const checkpoints = (await asyncPool(BATCH_SIZE, indices, idx => this.store.getCheckpointData(idx))).filter(
342
+ isDefined,
320
343
  );
321
- const newBlocks = blockPromises.filter(isDefined).flat();
344
+ const newBlocks = (
345
+ await asyncPool(BATCH_SIZE, checkpoints, cp =>
346
+ this.store.getBlocksForCheckpoint(CheckpointNumber(cp.checkpointNumber)),
347
+ )
348
+ )
349
+ .filter(isDefined)
350
+ .flat();
322
351
 
323
352
  // Emit an event for listening services to react to the chain prune
324
353
  this.events.emit(L2BlockSourceEvents.L2PruneUnproven, {
@@ -366,6 +395,7 @@ export class ArchiverL1Synchronizer implements Traceable {
366
395
  const localMessagesInserted = await this.store.getTotalL1ToL2MessageCount();
367
396
  const localLastMessage = await this.store.getLastL1ToL2Message();
368
397
  const remoteMessagesState = await this.inbox.getState({ blockNumber: currentL1BlockNumber });
398
+ await this.store.setInboxTreeInProgress(remoteMessagesState.treeInProgress);
369
399
 
370
400
  this.log.trace(`Retrieved remote inbox state at L1 block ${currentL1BlockNumber}.`, {
371
401
  localMessagesInserted,
@@ -550,7 +580,7 @@ export class ArchiverL1Synchronizer implements Traceable {
550
580
  if (provenCheckpointNumber === 0) {
551
581
  const localProvenCheckpointNumber = await this.store.getProvenCheckpointNumber();
552
582
  if (localProvenCheckpointNumber !== provenCheckpointNumber) {
553
- await this.store.setProvenCheckpointNumber(provenCheckpointNumber);
583
+ await this.updater.setProvenCheckpointNumber(provenCheckpointNumber);
554
584
  this.log.info(`Rolled back proven chain to checkpoint ${provenCheckpointNumber}`, { provenCheckpointNumber });
555
585
  }
556
586
  }
@@ -582,13 +612,13 @@ export class ArchiverL1Synchronizer implements Traceable {
582
612
  ) {
583
613
  const localProvenCheckpointNumber = await this.store.getProvenCheckpointNumber();
584
614
  if (localProvenCheckpointNumber !== provenCheckpointNumber) {
585
- await this.store.setProvenCheckpointNumber(provenCheckpointNumber);
615
+ await this.updater.setProvenCheckpointNumber(provenCheckpointNumber);
586
616
  this.log.info(`Updated proven chain to checkpoint ${provenCheckpointNumber}`, { provenCheckpointNumber });
587
617
  const provenSlotNumber = localCheckpointForDestinationProvenCheckpointNumber.header.slotNumber;
588
618
  const provenEpochNumber: EpochNumber = getEpochAtSlot(provenSlotNumber, this.l1Constants);
589
619
  const lastBlockNumberInCheckpoint =
590
620
  localCheckpointForDestinationProvenCheckpointNumber.startBlock +
591
- localCheckpointForDestinationProvenCheckpointNumber.numBlocks -
621
+ localCheckpointForDestinationProvenCheckpointNumber.blockCount -
592
622
  1;
593
623
 
594
624
  this.events.emit(L2BlockSourceEvents.L2BlockProven, {
@@ -597,7 +627,7 @@ export class ArchiverL1Synchronizer implements Traceable {
597
627
  slotNumber: provenSlotNumber,
598
628
  epochNumber: provenEpochNumber,
599
629
  });
600
- this.instrumentation.updateLastProvenBlock(lastBlockNumberInCheckpoint);
630
+ this.instrumentation.updateLastProvenCheckpoint(localCheckpointForDestinationProvenCheckpointNumber);
601
631
  } else {
602
632
  this.log.trace(`Proven checkpoint ${provenCheckpointNumber} already stored.`);
603
633
  }
@@ -706,7 +736,6 @@ export class ArchiverL1Synchronizer implements Traceable {
706
736
  this.blobClient,
707
737
  searchStartBlock, // TODO(palla/reorg): If the L2 reorg was due to an L1 reorg, we need to start search earlier
708
738
  searchEndBlock,
709
- this.l1Addresses,
710
739
  this.instrumentation,
711
740
  this.log,
712
741
  !initialSyncComplete, // isHistoricalSync
@@ -801,6 +830,14 @@ export class ArchiverL1Synchronizer implements Traceable {
801
830
  );
802
831
  }
803
832
 
833
+ for (const published of validCheckpoints) {
834
+ this.instrumentation.processCheckpointL1Timing({
835
+ slotNumber: published.checkpoint.header.slotNumber,
836
+ l1Timestamp: published.l1.timestamp,
837
+ l1Constants: this.l1Constants,
838
+ });
839
+ }
840
+
804
841
  try {
805
842
  const updatedValidationResult =
806
843
  rollupStatus.validationResult === initialValidationResult ? undefined : rollupStatus.validationResult;
@@ -819,7 +856,7 @@ export class ArchiverL1Synchronizer implements Traceable {
819
856
  const prunedCheckpointNumber = result.prunedBlocks[0].checkpointNumber;
820
857
  const prunedSlotNumber = result.prunedBlocks[0].header.globalVariables.slotNumber;
821
858
 
822
- this.log.warn(
859
+ this.log.info(
823
860
  `Pruned ${result.prunedBlocks.length} mismatching blocks for checkpoint ${prunedCheckpointNumber}`,
824
861
  { prunedBlocks: result.prunedBlocks.map(b => b.toBlockInfo()), prunedSlotNumber, prunedCheckpointNumber },
825
862
  );