@aztec/archiver 4.0.0-nightly.20260112 → 4.0.0-nightly.20260114

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 (68) hide show
  1. package/README.md +139 -22
  2. package/dest/archiver/archive_source_base.d.ts +75 -0
  3. package/dest/archiver/archive_source_base.d.ts.map +1 -0
  4. package/dest/archiver/archive_source_base.js +202 -0
  5. package/dest/archiver/archiver.d.ts +32 -168
  6. package/dest/archiver/archiver.d.ts.map +1 -1
  7. package/dest/archiver/archiver.js +123 -613
  8. package/dest/archiver/archiver_store_updates.d.ts +38 -0
  9. package/dest/archiver/archiver_store_updates.d.ts.map +1 -0
  10. package/dest/archiver/archiver_store_updates.js +212 -0
  11. package/dest/archiver/config.js +2 -2
  12. package/dest/archiver/index.d.ts +3 -2
  13. package/dest/archiver/index.d.ts.map +1 -1
  14. package/dest/archiver/index.js +2 -0
  15. package/dest/archiver/kv_archiver_store/block_store.d.ts +12 -5
  16. package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
  17. package/dest/archiver/kv_archiver_store/block_store.js +23 -4
  18. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +1 -1
  19. package/dest/archiver/kv_archiver_store/contract_class_store.js +1 -1
  20. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +1 -1
  21. package/dest/archiver/kv_archiver_store/contract_instance_store.js +1 -1
  22. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +173 -12
  23. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
  24. package/dest/archiver/kv_archiver_store/kv_archiver_store.js +159 -48
  25. package/dest/archiver/l1/calldata_retriever.d.ts +2 -2
  26. package/dest/archiver/l1/calldata_retriever.d.ts.map +1 -1
  27. package/dest/archiver/l1/calldata_retriever.js +2 -2
  28. package/dest/archiver/l1/data_retrieval.d.ts +9 -11
  29. package/dest/archiver/l1/data_retrieval.d.ts.map +1 -1
  30. package/dest/archiver/l1/data_retrieval.js +32 -51
  31. package/dest/archiver/l1/validate_trace.js +1 -1
  32. package/dest/archiver/test/fake_l1_state.d.ts +173 -0
  33. package/dest/archiver/test/fake_l1_state.d.ts.map +1 -0
  34. package/dest/archiver/test/fake_l1_state.js +364 -0
  35. package/dest/archiver/validation.d.ts +4 -4
  36. package/dest/archiver/validation.d.ts.map +1 -1
  37. package/dest/archiver/validation.js +1 -1
  38. package/dest/test/mock_l1_to_l2_message_source.d.ts +2 -2
  39. package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
  40. package/dest/test/mock_l1_to_l2_message_source.js +12 -3
  41. package/dest/test/mock_l2_block_source.d.ts +8 -4
  42. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  43. package/dest/test/mock_l2_block_source.js +65 -19
  44. package/package.json +13 -13
  45. package/src/archiver/archive_source_base.ts +339 -0
  46. package/src/archiver/archiver.ts +166 -815
  47. package/src/archiver/archiver_store_updates.ts +321 -0
  48. package/src/archiver/config.ts +2 -2
  49. package/src/archiver/index.ts +2 -1
  50. package/src/archiver/kv_archiver_store/block_store.ts +36 -8
  51. package/src/archiver/kv_archiver_store/contract_class_store.ts +1 -1
  52. package/src/archiver/kv_archiver_store/contract_instance_store.ts +1 -1
  53. package/src/archiver/kv_archiver_store/kv_archiver_store.ts +177 -11
  54. package/src/archiver/l1/calldata_retriever.ts +2 -2
  55. package/src/archiver/l1/data_retrieval.ts +51 -68
  56. package/src/archiver/l1/validate_trace.ts +1 -1
  57. package/src/archiver/test/fake_l1_state.ts +561 -0
  58. package/src/archiver/validation.ts +6 -6
  59. package/src/test/mock_l1_to_l2_message_source.ts +10 -4
  60. package/src/test/mock_l2_block_source.ts +76 -18
  61. package/dest/archiver/archiver_store.d.ts +0 -308
  62. package/dest/archiver/archiver_store.d.ts.map +0 -1
  63. package/dest/archiver/archiver_store.js +0 -4
  64. package/dest/archiver/archiver_store_test_suite.d.ts +0 -8
  65. package/dest/archiver/archiver_store_test_suite.d.ts.map +0 -1
  66. package/dest/archiver/archiver_store_test_suite.js +0 -2770
  67. package/src/archiver/archiver_store.ts +0 -372
  68. package/src/archiver/archiver_store_test_suite.ts +0 -2843
@@ -371,7 +371,7 @@ function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
371
371
  return (_apply_decs_2203_r = applyDecs2203RFactory())(targetClass, memberDecs, classDecs, parentClass);
372
372
  }
373
373
  var _dec, _dec1, _dec2, _dec3, _dec4, _initProto;
374
- import { GENESIS_BLOCK_HEADER_HASH } from '@aztec/constants';
374
+ import { GENESIS_BLOCK_HEADER_HASH, INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
375
375
  import { EpochCache } from '@aztec/epoch-cache';
376
376
  import { createEthereumChain } from '@aztec/ethereum/chain';
377
377
  import { BlockTagTooOldError, InboxContract, RollupContract } from '@aztec/ethereum/contracts';
@@ -380,23 +380,21 @@ import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
380
380
  import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
381
381
  import { merge, pick } from '@aztec/foundation/collection';
382
382
  import { Fr } from '@aztec/foundation/curves/bn254';
383
+ import { EthAddress } from '@aztec/foundation/eth-address';
383
384
  import { createLogger } from '@aztec/foundation/log';
384
385
  import { promiseWithResolvers } from '@aztec/foundation/promise';
385
386
  import { RunningPromise, makeLoggingErrorHandler } from '@aztec/foundation/running-promise';
386
387
  import { count } from '@aztec/foundation/string';
387
388
  import { DateProvider, Timer, elapsed } from '@aztec/foundation/timer';
388
389
  import { isDefined } from '@aztec/foundation/types';
389
- import { ContractClassPublishedEvent, PrivateFunctionBroadcastedEvent, UtilityFunctionBroadcastedEvent } from '@aztec/protocol-contracts/class-registry';
390
- import { ContractInstancePublishedEvent, ContractInstanceUpdatedEvent } from '@aztec/protocol-contracts/instance-registry';
391
- import { CommitteeAttestation, L2Block, L2BlockSourceEvents, PublishedL2Block } from '@aztec/stdlib/block';
392
- import { Checkpoint, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
393
- import { computePublicBytecodeCommitment, isValidPrivateFunctionMembershipProof, isValidUtilityFunctionMembershipProof } from '@aztec/stdlib/contract';
390
+ import { GENESIS_CHECKPOINT_HEADER_HASH, L2BlockSourceEvents } from '@aztec/stdlib/block';
394
391
  import { getEpochAtSlot, getEpochNumberAtTimestamp, getSlotAtTimestamp, getSlotRangeForEpoch, getTimestampRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
395
392
  import { computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
396
393
  import { execInSpan, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
397
394
  import { EventEmitter } from 'events';
398
- import groupBy from 'lodash.groupby';
399
395
  import { createPublicClient, fallback, http } from 'viem';
396
+ import { ArchiveSourceBase } from './archive_source_base.js';
397
+ import { addBlocksWithContractData, addCheckpointsWithContractData, unwindCheckpointsWithContractData } from './archiver_store_updates.js';
400
398
  import { InitialCheckpointNumberNotSequentialError, NoBlobBodiesFoundError } from './errors.js';
401
399
  import { ArchiverInstrumentation } from './instrumentation.js';
402
400
  import { retrieveCheckpointsFromRollup, retrieveL1ToL2Message, retrieveL1ToL2Messages, retrievedToPublishedCheckpoint } from './l1/data_retrieval.js';
@@ -406,7 +404,7 @@ function mapArchiverConfig(config) {
406
404
  return {
407
405
  pollingIntervalMs: config.archiverPollingIntervalMS,
408
406
  batchSize: config.archiverBatchSize,
409
- skipValidateBlockAttestations: config.skipValidateBlockAttestations,
407
+ skipValidateCheckpointAttestations: config.skipValidateCheckpointAttestations,
410
408
  maxAllowedEthClientDriftSeconds: config.maxAllowedEthClientDriftSeconds,
411
409
  ethereumAllowNoDebugHosts: config.ethereumAllowNoDebugHosts
412
410
  };
@@ -416,9 +414,11 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
416
414
  * Pulls checkpoints in a non-blocking manner and provides interface for their retrieval.
417
415
  * Responsible for handling robust L1 polling so that other components do not need to
418
416
  * concern themselves with it.
419
- */ export class Archiver extends EventEmitter {
417
+ */ export class Archiver extends ArchiveSourceBase {
420
418
  publicClient;
421
419
  debugClient;
420
+ rollup;
421
+ inbox;
422
422
  l1Addresses;
423
423
  dataStore;
424
424
  config;
@@ -457,10 +457,8 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
457
457
  ]
458
458
  ], []));
459
459
  }
460
+ /** Event emitter for archiver events (L2BlockProven, L2PruneDetected, etc). */ events;
460
461
  /** A loop in which we will be continually fetching new checkpoints. */ runningPromise;
461
- rollup;
462
- inbox;
463
- store;
464
462
  l1BlockNumber;
465
463
  l1Timestamp;
466
464
  initialSyncComplete;
@@ -471,18 +469,20 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
471
469
  * Creates a new instance of the Archiver.
472
470
  * @param publicClient - A client for interacting with the Ethereum node.
473
471
  * @param debugClient - A client for interacting with the Ethereum node for debug/trace methods.
474
- * @param rollupAddress - Ethereum address of the rollup contract.
475
- * @param inboxAddress - Ethereum address of the inbox contract.
476
- * @param registryAddress - Ethereum address of the registry contract.
477
- * @param pollingIntervalMs - The interval for polling for L1 logs (in milliseconds).
478
- * @param store - An archiver data store for storage & retrieval of blocks, encrypted logs & contract data.
472
+ * @param rollup - Rollup contract instance.
473
+ * @param inbox - Inbox contract instance.
474
+ * @param l1Addresses - L1 contract addresses (registry, governance proposer, slash factory, slashing proposer).
475
+ * @param dataStore - An archiver data store for storage & retrieval of blocks, encrypted logs & contract data.
476
+ * @param config - Archiver configuration options.
477
+ * @param blobClient - Client for retrieving blob data.
478
+ * @param epochCache - Cache for epoch-related data.
479
+ * @param dateProvider - Provider for current date/time.
480
+ * @param instrumentation - Instrumentation for metrics and tracing.
481
+ * @param l1constants - L1 rollup constants.
479
482
  * @param log - A logger.
480
- */ constructor(publicClient, debugClient, l1Addresses, dataStore, config, blobClient, epochCache, dateProvider, instrumentation, l1constants, log = createLogger('archiver')){
481
- super(), this.publicClient = publicClient, this.debugClient = debugClient, this.l1Addresses = l1Addresses, this.dataStore = dataStore, this.config = config, this.blobClient = blobClient, this.epochCache = epochCache, this.dateProvider = dateProvider, this.instrumentation = instrumentation, this.l1constants = l1constants, this.log = log, this.initialSyncComplete = (_initProto(this), false), this.blockQueue = [];
483
+ */ constructor(publicClient, debugClient, rollup, inbox, l1Addresses, dataStore, config, blobClient, epochCache, dateProvider, instrumentation, l1constants, log = createLogger('archiver')){
484
+ super(dataStore), this.publicClient = publicClient, this.debugClient = debugClient, this.rollup = rollup, this.inbox = inbox, this.l1Addresses = l1Addresses, this.dataStore = dataStore, this.config = config, this.blobClient = blobClient, this.epochCache = epochCache, this.dateProvider = dateProvider, this.instrumentation = instrumentation, this.l1constants = l1constants, this.log = log, this.events = (_initProto(this), new EventEmitter()), this.initialSyncComplete = false, this.blockQueue = [];
482
485
  this.tracer = instrumentation.tracer;
483
- this.store = new ArchiverStoreHelper(dataStore);
484
- this.rollup = new RollupContract(publicClient, l1Addresses.rollupAddress);
485
- this.inbox = new InboxContract(publicClient, l1Addresses.inboxAddress);
486
486
  this.initialSyncPromise = promiseWithResolvers();
487
487
  // Running promise starts with a small interval inbetween runs, so all iterations needed for the initial sync
488
488
  // are done as fast as possible. This then gets updated once the initial sync completes.
@@ -513,6 +513,7 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
513
513
  pollingInterval: config.viemPollingIntervalMS
514
514
  });
515
515
  const rollup = new RollupContract(publicClient, config.l1Contracts.rollupAddress);
516
+ const inbox = new InboxContract(publicClient, config.l1Contracts.inboxAddress);
516
517
  const [l1StartBlock, l1GenesisTime, proofSubmissionEpochs, genesisArchiveRoot, slashingProposerAddress] = await Promise.all([
517
518
  rollup.getL1StartBlock(),
518
519
  rollup.getL1GenesisTime(),
@@ -543,7 +544,7 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
543
544
  }, mapArchiverConfig(config));
544
545
  const epochCache = deps.epochCache ?? await EpochCache.create(config.l1Contracts.rollupAddress, config, deps);
545
546
  const telemetry = deps.telemetry ?? getTelemetryClient();
546
- const archiver = new Archiver(publicClient, debugClient, {
547
+ const archiver = new Archiver(publicClient, debugClient, rollup, inbox, {
547
548
  ...config.l1Contracts,
548
549
  slashingProposerAddress
549
550
  }, archiverStore, opts, deps.blobClient, epochCache, deps.dateProvider ?? new DateProvider(), await ArchiverInstrumentation.new(telemetry, ()=>archiverStore.estimateSize()), l1Constants);
@@ -567,7 +568,7 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
567
568
  const { l1StartBlock } = this.l1constants;
568
569
  const { blocksSynchedTo = l1StartBlock, messagesSynchedTo = l1StartBlock } = await this.store.getSynchPoint();
569
570
  const currentL2Checkpoint = await this.getSynchedCheckpointNumber();
570
- this.log.info(`Starting archiver sync to rollup contract ${this.l1Addresses.rollupAddress.toString()} from L1 block ${blocksSynchedTo} and L2 checkpoint ${currentL2Checkpoint}`, {
571
+ this.log.info(`Starting archiver sync to rollup contract ${this.rollup.address} from L1 block ${blocksSynchedTo} and L2 checkpoint ${currentL2Checkpoint}`, {
571
572
  blocksSynchedTo,
572
573
  messagesSynchedTo,
573
574
  currentL2Checkpoint
@@ -615,7 +616,7 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
615
616
  // Process each block individually to properly resolve/reject each promise
616
617
  for (const { block, resolve, reject } of queuedItems){
617
618
  try {
618
- await this.store.addBlocks([
619
+ await addBlocksWithContractData(this.store, [
619
620
  block
620
621
  ]);
621
622
  this.log.debug(`Added block ${block.number} to store`);
@@ -732,9 +733,15 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
732
733
  // but the corresponding blocks have not been processed (see #12631).
733
734
  this.l1Timestamp = currentL1Timestamp;
734
735
  this.l1BlockNumber = currentL1BlockNumber;
736
+ const l1BlockNumberAtEnd = await this.publicClient.getBlockNumber();
737
+ this.log.trace(`Archiver sync iteration complete`, {
738
+ l1BlockNumberAtStart: currentL1BlockNumber,
739
+ l1TimestampAtStart: currentL1Timestamp,
740
+ l1BlockNumberAtEnd
741
+ });
735
742
  // We resolve the initial sync only once we've caught up with the latest L1 block number (with 1 block grace)
736
743
  // so if the initial sync took too long, we still go for another iteration.
737
- if (!this.initialSyncComplete && currentL1BlockNumber + 1n >= await this.publicClient.getBlockNumber()) {
744
+ if (!this.initialSyncComplete && currentL1BlockNumber + 1n >= l1BlockNumberAtEnd) {
738
745
  this.log.info(`Initial archiver sync to L1 block ${currentL1BlockNumber} complete`, {
739
746
  l1BlockNumber: currentL1BlockNumber,
740
747
  syncPoint: await this.store.getSynchPoint(),
@@ -787,13 +794,11 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
787
794
  const checkpoints = await Promise.all(checkpointPromises);
788
795
  const blockPromises = await Promise.all(checkpoints.filter(isDefined).map((cp)=>this.store.getBlocksForCheckpoint(CheckpointNumber(cp.checkpointNumber))));
789
796
  const newBlocks = blockPromises.filter(isDefined).flat();
790
- // TODO(pw/mbps): Don't convert to legacy blocks here
791
- const blocks = (await Promise.all(newBlocks.map((x)=>this.getBlock(x.number)))).filter(isDefined);
792
797
  // Emit an event for listening services to react to the chain prune
793
- this.emit(L2BlockSourceEvents.L2PruneDetected, {
798
+ this.events.emit(L2BlockSourceEvents.L2PruneDetected, {
794
799
  type: L2BlockSourceEvents.L2PruneDetected,
795
800
  epochNumber: pruneFromEpochNumber,
796
- blocks
801
+ blocks: newBlocks
797
802
  });
798
803
  this.log.debug(`L2 prune from ${provenCheckpointNumber + 1} to ${localPendingCheckpointNumber} will occur on next checkpoint submission.`);
799
804
  await this.unwindCheckpoints(localPendingCheckpointNumber, checkpointsToUnwind);
@@ -801,7 +806,7 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
801
806
  this.instrumentation.processPrune(timer.ms());
802
807
  // TODO(palla/reorg): Do we need to set the block synched L1 block number here?
803
808
  // Seems like the next iteration should handle this.
804
- // await this.store.setBlockSynchedL1BlockNumber(currentL1BlockNumber);
809
+ // await this.store.setCheckpointSynchedL1BlockNumber(currentL1BlockNumber);
805
810
  }
806
811
  return {
807
812
  rollupCanPrune
@@ -872,7 +877,7 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
872
877
  do {
873
878
  [searchStartBlock, searchEndBlock] = this.nextRange(searchEndBlock, currentL1BlockNumber);
874
879
  this.log.trace(`Retrieving L1 to L2 messages between L1 blocks ${searchStartBlock} and ${searchEndBlock}.`);
875
- const messages = await retrieveL1ToL2Messages(this.inbox.getContract(), searchStartBlock, searchEndBlock);
880
+ const messages = await retrieveL1ToL2Messages(this.inbox, searchStartBlock, searchEndBlock);
876
881
  this.log.verbose(`Retrieved ${messages.length} new L1 to L2 messages between L1 blocks ${searchStartBlock} and ${searchEndBlock}.`);
877
882
  const timer = new Timer();
878
883
  await this.store.addL1ToL2Messages(messages);
@@ -908,7 +913,7 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
908
913
  let searchEndBlock = this.l1constants.l1StartBlock - 1n;
909
914
  do {
910
915
  [searchStartBlock, searchEndBlock] = this.nextRange(searchEndBlock, currentL1BlockNumber);
911
- const message = await retrieveL1ToL2Message(this.inbox.getContract(), leaf, searchStartBlock, searchEndBlock);
916
+ const message = await retrieveL1ToL2Message(this.inbox, leaf, searchStartBlock, searchEndBlock);
912
917
  if (message) {
913
918
  return message;
914
919
  }
@@ -1017,7 +1022,7 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
1017
1022
  const provenSlotNumber = localCheckpointForDestinationProvenCheckpointNumber.header.slotNumber;
1018
1023
  const provenEpochNumber = getEpochAtSlot(provenSlotNumber, this.l1constants);
1019
1024
  const lastBlockNumberInCheckpoint = localCheckpointForDestinationProvenCheckpointNumber.startBlock + localCheckpointForDestinationProvenCheckpointNumber.numBlocks - 1;
1020
- this.emit(L2BlockSourceEvents.L2BlockProven, {
1025
+ this.events.emit(L2BlockSourceEvents.L2BlockProven, {
1021
1026
  type: L2BlockSourceEvents.L2BlockProven,
1022
1027
  blockNumber: BlockNumber(lastBlockNumberInCheckpoint),
1023
1028
  slotNumber: provenSlotNumber,
@@ -1055,7 +1060,7 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
1055
1060
  // However, in the re-org scenario, our L1 node is temporarily lying to us and we end up potentially missing checkpoints.
1056
1061
  // We must only set this block number based on actually retrieved logs.
1057
1062
  // TODO(#8621): Tackle this properly when we handle L1 Re-orgs.
1058
- // await this.store.setBlockSynchedL1BlockNumber(currentL1BlockNumber);
1063
+ // await this.store.setCheckpointSynchedL1BlockNumber(currentL1BlockNumber);
1059
1064
  this.log.debug(`No checkpoints to retrieve from ${blocksSynchedTo + 1n} to ${currentL1BlockNumber}`);
1060
1065
  return rollupStatus;
1061
1066
  }
@@ -1101,7 +1106,7 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
1101
1106
  [searchStartBlock, searchEndBlock] = this.nextRange(searchEndBlock, currentL1BlockNumber);
1102
1107
  this.log.trace(`Retrieving checkpoints from L1 block ${searchStartBlock} to ${searchEndBlock}`);
1103
1108
  // TODO(md): Retrieve from blob client then from consensus client, then from peers
1104
- const retrievedCheckpoints = await execInSpan(this.tracer, 'Archiver.retrieveCheckpointsFromRollup', ()=>retrieveCheckpointsFromRollup(this.rollup.getContract(), this.publicClient, this.debugClient, this.blobClient, searchStartBlock, searchEndBlock, this.l1Addresses, this.instrumentation, this.log, !this.initialSyncComplete));
1109
+ const retrievedCheckpoints = await execInSpan(this.tracer, 'Archiver.retrieveCheckpointsFromRollup', ()=>retrieveCheckpointsFromRollup(this.rollup, this.publicClient, this.debugClient, this.blobClient, searchStartBlock, searchEndBlock, this.l1Addresses, this.instrumentation, this.log, !this.initialSyncComplete));
1105
1110
  if (retrievedCheckpoints.length === 0) {
1106
1111
  // We are not calling `setBlockSynchedL1BlockNumber` because it may cause sync issues if based off infura.
1107
1112
  // See further details in earlier comments.
@@ -1116,7 +1121,7 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
1116
1121
  const publishedCheckpoints = await Promise.all(retrievedCheckpoints.map((b)=>retrievedToPublishedCheckpoint(b)));
1117
1122
  const validCheckpoints = [];
1118
1123
  for (const published of publishedCheckpoints){
1119
- const validationResult = this.config.skipValidateBlockAttestations ? {
1124
+ const validationResult = this.config.skipValidateCheckpointAttestations ? {
1120
1125
  valid: true
1121
1126
  } : await validateCheckpointAttestations(published, this.epochCache, this.l1constants, this.log);
1122
1127
  // Only update the validation result if it has changed, so we can keep track of the first invalid checkpoint
@@ -1124,7 +1129,7 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
1124
1129
  // There is an exception though: if a checkpoint is invalidated and replaced with another invalid checkpoint,
1125
1130
  // we need to update the validation result, since we need to be able to invalidate the new one.
1126
1131
  // See test 'chain progresses if an invalid checkpoint is invalidated with an invalid one' for more info.
1127
- if (rollupStatus.validationResult?.valid !== validationResult.valid || !rollupStatus.validationResult.valid && !validationResult.valid && rollupStatus.validationResult.block.blockNumber === validationResult.block.blockNumber) {
1132
+ if (rollupStatus.validationResult?.valid !== validationResult.valid || !rollupStatus.validationResult.valid && !validationResult.valid && rollupStatus.validationResult.checkpoint.checkpointNumber === validationResult.checkpoint.checkpointNumber) {
1128
1133
  rollupStatus.validationResult = validationResult;
1129
1134
  }
1130
1135
  if (!validationResult.valid) {
@@ -1133,9 +1138,9 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
1133
1138
  l1BlockNumber: published.l1.blockNumber,
1134
1139
  ...pick(validationResult, 'reason')
1135
1140
  });
1136
- // Emit event for invalid block detection
1137
- this.emit(L2BlockSourceEvents.InvalidAttestationsBlockDetected, {
1138
- type: L2BlockSourceEvents.InvalidAttestationsBlockDetected,
1141
+ // Emit event for invalid checkpoint detection
1142
+ this.events.emit(L2BlockSourceEvents.InvalidAttestationsCheckpointDetected, {
1143
+ type: L2BlockSourceEvents.InvalidAttestationsCheckpointDetected,
1139
1144
  validationResult
1140
1145
  });
1141
1146
  continue;
@@ -1173,7 +1178,7 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
1173
1178
  const { previousCheckpointNumber, newCheckpointNumber } = err;
1174
1179
  const previousCheckpoint = previousCheckpointNumber ? await this.store.getCheckpointData(CheckpointNumber(previousCheckpointNumber)) : undefined;
1175
1180
  const updatedL1SyncPoint = previousCheckpoint?.l1.blockNumber ?? this.l1constants.l1StartBlock;
1176
- await this.store.setBlockSynchedL1BlockNumber(updatedL1SyncPoint);
1181
+ await this.store.setCheckpointSynchedL1BlockNumber(updatedL1SyncPoint);
1177
1182
  this.log.warn(`Attempting to insert checkpoint ${newCheckpointNumber} with previous block ${previousCheckpointNumber}. Rolling back L1 sync point to ${updatedL1SyncPoint} to try and fetch the missing blocks.`, {
1178
1183
  previousCheckpointNumber,
1179
1184
  newCheckpointNumber,
@@ -1232,7 +1237,7 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
1232
1237
  currentL1BlockNumber,
1233
1238
  ...status
1234
1239
  });
1235
- await this.store.setBlockSynchedL1BlockNumber(targetL1BlockNumber);
1240
+ await this.store.setCheckpointSynchedL1BlockNumber(targetL1BlockNumber);
1236
1241
  } else {
1237
1242
  this.log.trace(`No new checkpoints behind L1 sync point to retrieve.`, {
1238
1243
  latestLocalCheckpointNumber,
@@ -1268,7 +1273,7 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
1268
1273
  });
1269
1274
  }
1270
1275
  getRollupAddress() {
1271
- return Promise.resolve(this.l1Addresses.rollupAddress);
1276
+ return Promise.resolve(EthAddress.fromString(this.rollup.address));
1272
1277
  }
1273
1278
  getRegistryAddress() {
1274
1279
  return Promise.resolve(this.l1Addresses.registryAddress);
@@ -1382,7 +1387,7 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
1382
1387
  return this.store.setProvenCheckpointNumber(checkpointNumber);
1383
1388
  }
1384
1389
  unwindCheckpoints(from, checkpointsToUnwind) {
1385
- return this.store.unwindCheckpoints(from, checkpointsToUnwind);
1390
+ return unwindCheckpointsWithContractData(this.store, from, checkpointsToUnwind);
1386
1391
  }
1387
1392
  async getLastBlockNumberInCheckpoint(checkpointNumber) {
1388
1393
  const checkpointData = await this.store.getCheckpointData(checkpointNumber);
@@ -1392,178 +1397,105 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
1392
1397
  return BlockNumber(checkpointData.startBlock + checkpointData.numBlocks - 1);
1393
1398
  }
1394
1399
  addCheckpoints(checkpoints, pendingChainValidationStatus) {
1395
- return this.store.addCheckpoints(checkpoints, pendingChainValidationStatus);
1396
- }
1397
- getBlockHeaderByHash(blockHash) {
1398
- return this.store.getBlockHeaderByHash(blockHash);
1399
- }
1400
- getBlockHeaderByArchive(archive) {
1401
- return this.store.getBlockHeaderByArchive(archive);
1402
- }
1403
- /**
1404
- * Gets an l2 block.
1405
- * @param number - The block number to return.
1406
- * @returns The requested L2 block.
1407
- */ async getL2BlockNew(number) {
1408
- // If the number provided is -ve, then return the latest block.
1409
- if (number < 0) {
1410
- number = await this.store.getSynchedL2BlockNumber();
1411
- }
1412
- if (number === 0) {
1413
- return undefined;
1414
- }
1415
- const publishedBlock = await this.store.store.getBlock(number);
1416
- return publishedBlock;
1417
- }
1418
- async getBlockHeader(number) {
1419
- if (number === 'latest') {
1420
- number = await this.store.getSynchedL2BlockNumber();
1421
- }
1422
- if (number === 0) {
1423
- return undefined;
1424
- }
1425
- const headers = await this.store.getBlockHeaders(number, 1);
1426
- return headers.length === 0 ? undefined : headers[0];
1427
- }
1428
- getCheckpointedBlock(number) {
1429
- return this.store.getCheckpointedBlock(number);
1430
- }
1431
- getCheckpointedBlockByHash(blockHash) {
1432
- return this.store.getCheckpointedBlockByHash(blockHash);
1433
- }
1434
- getProvenBlockNumber() {
1435
- return this.store.getProvenBlockNumber();
1436
- }
1437
- getCheckpointedBlockByArchive(archive) {
1438
- return this.store.getCheckpointedBlockByArchive(archive);
1439
- }
1440
- getTxEffect(txHash) {
1441
- return this.store.getTxEffect(txHash);
1442
- }
1443
- getSettledTxReceipt(txHash) {
1444
- return this.store.getSettledTxReceipt(txHash);
1445
- }
1446
- getPrivateLogsByTags(tags) {
1447
- return this.store.getPrivateLogsByTags(tags);
1448
- }
1449
- getPublicLogsByTagsFromContract(contractAddress, tags) {
1450
- return this.store.getPublicLogsByTagsFromContract(contractAddress, tags);
1451
- }
1452
- /**
1453
- * Gets public logs based on the provided filter.
1454
- * @param filter - The filter to apply to the logs.
1455
- * @returns The requested logs.
1456
- */ getPublicLogs(filter) {
1457
- return this.store.getPublicLogs(filter);
1458
- }
1459
- /**
1460
- * Gets contract class logs based on the provided filter.
1461
- * @param filter - The filter to apply to the logs.
1462
- * @returns The requested logs.
1463
- */ getContractClassLogs(filter) {
1464
- return this.store.getContractClassLogs(filter);
1465
- }
1466
- /**
1467
- * Gets the number of the latest L2 block processed by the block source implementation.
1468
- * This includes both checkpointed and uncheckpointed blocks.
1469
- * @returns The number of the latest L2 block processed by the block source implementation.
1470
- */ getBlockNumber() {
1471
- return this.store.getLatestBlockNumber();
1472
- }
1473
- getContractClass(id) {
1474
- return this.store.getContractClass(id);
1475
- }
1476
- getBytecodeCommitment(id) {
1477
- return this.store.getBytecodeCommitment(id);
1478
- }
1479
- async getContract(address, maybeTimestamp) {
1480
- let timestamp;
1481
- if (maybeTimestamp === undefined) {
1482
- const latestBlockHeader = await this.getBlockHeader('latest');
1483
- // If we get undefined block header, it means that the archiver has not yet synced any block so we default to 0.
1484
- timestamp = latestBlockHeader ? latestBlockHeader.globalVariables.timestamp : 0n;
1485
- } else {
1486
- timestamp = maybeTimestamp;
1487
- }
1488
- return this.store.getContractInstance(address, timestamp);
1489
- }
1490
- /**
1491
- * Gets L1 to L2 message (to be) included in a given checkpoint.
1492
- * @param checkpointNumber - Checkpoint number to get messages for.
1493
- * @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found).
1494
- */ getL1ToL2Messages(checkpointNumber) {
1495
- return this.store.getL1ToL2Messages(checkpointNumber);
1496
- }
1497
- /**
1498
- * Gets the L1 to L2 message index in the L1 to L2 message tree.
1499
- * @param l1ToL2Message - The L1 to L2 message.
1500
- * @returns The index of the L1 to L2 message in the L1 to L2 message tree (undefined if not found).
1501
- */ getL1ToL2MessageIndex(l1ToL2Message) {
1502
- return this.store.getL1ToL2MessageIndex(l1ToL2Message);
1503
- }
1504
- getContractClassIds() {
1505
- return this.store.getContractClassIds();
1400
+ return addCheckpointsWithContractData(this.store, checkpoints, pendingChainValidationStatus);
1506
1401
  }
1507
- registerContractFunctionSignatures(signatures) {
1508
- return this.store.registerContractFunctionSignatures(signatures);
1509
- }
1510
- getDebugFunctionName(address, selector) {
1511
- return this.store.getDebugFunctionName(address, selector);
1512
- }
1513
- async getPendingChainValidationStatus() {
1514
- return await this.store.getPendingChainValidationStatus() ?? {
1515
- valid: true
1516
- };
1517
- }
1518
- isPendingChainInvalid() {
1519
- return this.getPendingChainValidationStatus().then((status)=>!status.valid);
1402
+ getCheckpointedBlockNumber() {
1403
+ return this.store.getCheckpointedL2BlockNumber();
1520
1404
  }
1521
1405
  async getL2Tips() {
1522
- const [latestBlockNumber, provenBlockNumber] = await Promise.all([
1406
+ const [latestBlockNumber, provenBlockNumber, checkpointedBlockNumber] = await Promise.all([
1523
1407
  this.getBlockNumber(),
1524
- this.getProvenBlockNumber()
1408
+ this.getProvenBlockNumber(),
1409
+ this.getCheckpointedBlockNumber()
1525
1410
  ]);
1526
1411
  // TODO(#13569): Compute proper finalized block number based on L1 finalized block.
1527
1412
  // We just force it 2 epochs worth of proven data for now.
1528
1413
  // NOTE: update end-to-end/src/e2e_epochs/epochs_empty_blocks.test.ts as that uses finalized blocks in computations
1529
1414
  const finalizedBlockNumber = BlockNumber(Math.max(provenBlockNumber - this.l1constants.epochDuration * 2, 0));
1530
- const [latestBlockHeader, provenBlockHeader, finalizedBlockHeader] = await Promise.all([
1531
- latestBlockNumber > 0 ? this.getBlockHeader(latestBlockNumber) : undefined,
1532
- provenBlockNumber > 0 ? this.getBlockHeader(provenBlockNumber) : undefined,
1533
- finalizedBlockNumber > 0 ? this.getBlockHeader(finalizedBlockNumber) : undefined
1415
+ const beforeInitialblockNumber = BlockNumber(INITIAL_L2_BLOCK_NUM - 1);
1416
+ // Get the latest block header and checkpointed blocks for proven, finalised and checkpointed blocks
1417
+ const [latestBlockHeader, provenCheckpointedBlock, finalizedCheckpointedBlock, checkpointedBlock] = await Promise.all([
1418
+ latestBlockNumber > beforeInitialblockNumber ? this.getBlockHeader(latestBlockNumber) : undefined,
1419
+ provenBlockNumber > beforeInitialblockNumber ? this.getCheckpointedBlock(provenBlockNumber) : undefined,
1420
+ finalizedBlockNumber > beforeInitialblockNumber ? this.getCheckpointedBlock(finalizedBlockNumber) : undefined,
1421
+ checkpointedBlockNumber > beforeInitialblockNumber ? this.getCheckpointedBlock(checkpointedBlockNumber) : undefined
1534
1422
  ]);
1535
- if (latestBlockNumber > 0 && !latestBlockHeader) {
1423
+ if (latestBlockNumber > beforeInitialblockNumber && !latestBlockHeader) {
1536
1424
  throw new Error(`Failed to retrieve latest block header for block ${latestBlockNumber}`);
1537
1425
  }
1538
- if (provenBlockNumber > 0 && !provenBlockHeader) {
1539
- throw new Error(`Failed to retrieve proven block header for block ${provenBlockNumber} (latest block is ${latestBlockNumber})`);
1426
+ // Checkpointed blocks must exist for proven, finalized and checkpointed tips if they are beyond the initial block number.
1427
+ if (checkpointedBlockNumber > beforeInitialblockNumber && !checkpointedBlock?.block.header) {
1428
+ throw new Error(`Failed to retrieve checkpointed block header for block ${checkpointedBlockNumber} (latest block is ${latestBlockNumber})`);
1429
+ }
1430
+ if (provenBlockNumber > beforeInitialblockNumber && !provenCheckpointedBlock?.block.header) {
1431
+ throw new Error(`Failed to retrieve proven checkpointed for block ${provenBlockNumber} (latest block is ${latestBlockNumber})`);
1540
1432
  }
1541
- if (finalizedBlockNumber > 0 && !finalizedBlockHeader) {
1433
+ if (finalizedBlockNumber > beforeInitialblockNumber && !finalizedCheckpointedBlock?.block.header) {
1542
1434
  throw new Error(`Failed to retrieve finalized block header for block ${finalizedBlockNumber} (latest block is ${latestBlockNumber})`);
1543
1435
  }
1544
1436
  const latestBlockHeaderHash = await latestBlockHeader?.hash() ?? GENESIS_BLOCK_HEADER_HASH;
1545
- const provenBlockHeaderHash = await provenBlockHeader?.hash() ?? GENESIS_BLOCK_HEADER_HASH;
1546
- const finalizedBlockHeaderHash = await finalizedBlockHeader?.hash() ?? GENESIS_BLOCK_HEADER_HASH;
1547
- return {
1548
- latest: {
1437
+ const provenBlockHeaderHash = await provenCheckpointedBlock?.block.header?.hash() ?? GENESIS_BLOCK_HEADER_HASH;
1438
+ const finalizedBlockHeaderHash = await finalizedCheckpointedBlock?.block.header?.hash() ?? GENESIS_BLOCK_HEADER_HASH;
1439
+ const checkpointedBlockHeaderHash = await checkpointedBlock?.block.header?.hash() ?? GENESIS_BLOCK_HEADER_HASH;
1440
+ // Now attempt to retrieve checkpoints for proven, finalised and checkpointed blocks
1441
+ const [[provenBlockCheckpoint], [finalizedBlockCheckpoint], [checkpointedBlockCheckpoint]] = await Promise.all([
1442
+ provenCheckpointedBlock !== undefined ? await this.getPublishedCheckpoints(provenCheckpointedBlock?.checkpointNumber, 1) : [
1443
+ undefined
1444
+ ],
1445
+ finalizedCheckpointedBlock !== undefined ? await this.getPublishedCheckpoints(finalizedCheckpointedBlock?.checkpointNumber, 1) : [
1446
+ undefined
1447
+ ],
1448
+ checkpointedBlock !== undefined ? await this.getPublishedCheckpoints(checkpointedBlock?.checkpointNumber, 1) : [
1449
+ undefined
1450
+ ]
1451
+ ]);
1452
+ const initialcheckpointId = {
1453
+ number: CheckpointNumber.ZERO,
1454
+ hash: GENESIS_CHECKPOINT_HEADER_HASH.toString()
1455
+ };
1456
+ const makeCheckpointId = (checkpoint)=>{
1457
+ if (checkpoint === undefined) {
1458
+ return initialcheckpointId;
1459
+ }
1460
+ return {
1461
+ number: checkpoint.checkpoint.number,
1462
+ hash: checkpoint.checkpoint.hash().toString()
1463
+ };
1464
+ };
1465
+ const l2Tips = {
1466
+ proposed: {
1549
1467
  number: latestBlockNumber,
1550
1468
  hash: latestBlockHeaderHash.toString()
1551
1469
  },
1552
1470
  proven: {
1553
- number: provenBlockNumber,
1554
- hash: provenBlockHeaderHash.toString()
1471
+ block: {
1472
+ number: provenBlockNumber,
1473
+ hash: provenBlockHeaderHash.toString()
1474
+ },
1475
+ checkpoint: makeCheckpointId(provenBlockCheckpoint)
1555
1476
  },
1556
1477
  finalized: {
1557
- number: finalizedBlockNumber,
1558
- hash: finalizedBlockHeaderHash.toString()
1478
+ block: {
1479
+ number: finalizedBlockNumber,
1480
+ hash: finalizedBlockHeaderHash.toString()
1481
+ },
1482
+ checkpoint: makeCheckpointId(finalizedBlockCheckpoint)
1483
+ },
1484
+ checkpointed: {
1485
+ block: {
1486
+ number: checkpointedBlockNumber,
1487
+ hash: checkpointedBlockHeaderHash.toString()
1488
+ },
1489
+ checkpoint: makeCheckpointId(checkpointedBlockCheckpoint)
1559
1490
  }
1560
1491
  };
1492
+ return l2Tips;
1561
1493
  }
1562
1494
  async rollbackTo(targetL2BlockNumber) {
1563
1495
  // TODO(pw/mbps): This still assumes 1 block per checkpoint
1564
1496
  const currentBlocks = await this.getL2Tips();
1565
- const currentL2Block = currentBlocks.latest.number;
1566
- const currentProvenBlock = currentBlocks.proven.number;
1497
+ const currentL2Block = currentBlocks.proposed.number;
1498
+ const currentProvenBlock = currentBlocks.proven.block.number;
1567
1499
  if (targetL2BlockNumber >= currentL2Block) {
1568
1500
  throw new Error(`Target L2 block ${targetL2BlockNumber} must be less than current L2 block ${currentL2Block}`);
1569
1501
  }
@@ -1576,11 +1508,11 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
1576
1508
  const targetCheckpointNumber = CheckpointNumber.fromBlockNumber(targetL2BlockNumber);
1577
1509
  const targetL1BlockHash = await this.getL1BlockHash(targetL1BlockNumber);
1578
1510
  this.log.info(`Unwinding ${blocksToUnwind} checkpoints from L2 block ${currentL2Block}`);
1579
- await this.store.unwindCheckpoints(CheckpointNumber(currentL2Block), blocksToUnwind);
1511
+ await unwindCheckpointsWithContractData(this.store, CheckpointNumber(currentL2Block), blocksToUnwind);
1580
1512
  this.log.info(`Unwinding L1 to L2 messages to checkpoint ${targetCheckpointNumber}`);
1581
1513
  await this.store.rollbackL1ToL2MessagesToCheckpoint(targetCheckpointNumber);
1582
1514
  this.log.info(`Setting L1 syncpoints to ${targetL1BlockNumber}`);
1583
- await this.store.setBlockSynchedL1BlockNumber(targetL1BlockNumber);
1515
+ await this.store.setCheckpointSynchedL1BlockNumber(targetL1BlockNumber);
1584
1516
  await this.store.setMessageSynchedL1Block({
1585
1517
  l1BlockNumber: targetL1BlockNumber,
1586
1518
  l1BlockHash: targetL1BlockHash
@@ -1595,19 +1527,6 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
1595
1527
  // await this.store.setFinalizedL2BlockNumber(0);
1596
1528
  // }
1597
1529
  }
1598
- async getPublishedCheckpoints(checkpointNumber, limit) {
1599
- const checkpoints = await this.store.getRangeOfCheckpoints(checkpointNumber, limit);
1600
- const blocks = (await Promise.all(checkpoints.map((ch)=>this.store.getBlocksForCheckpoint(ch.checkpointNumber)))).filter(isDefined);
1601
- const fullCheckpoints = [];
1602
- for(let i = 0; i < checkpoints.length; i++){
1603
- const blocksForCheckpoint = blocks[i];
1604
- const checkpoint = checkpoints[i];
1605
- const fullCheckpoint = new Checkpoint(checkpoint.archive, checkpoint.header, blocksForCheckpoint, checkpoint.checkpointNumber);
1606
- const publishedCheckpoint = new PublishedCheckpoint(fullCheckpoint, checkpoint.l1, checkpoint.attestations.map((x)=>CommitteeAttestation.fromBuffer(x)));
1607
- fullCheckpoints.push(publishedCheckpoint);
1608
- }
1609
- return fullCheckpoints;
1610
- }
1611
1530
  async getCheckpointsForEpoch(epochNumber) {
1612
1531
  const [start, end] = getSlotRangeForEpoch(epochNumber, this.l1constants);
1613
1532
  const checkpoints = [];
@@ -1625,413 +1544,4 @@ _dec = trackSpan('Archiver.syncFromL1'), _dec1 = trackSpan('Archiver.sync'), _de
1625
1544
  }
1626
1545
  return checkpoints.reverse();
1627
1546
  }
1628
- /* Legacy APIs */ async getPublishedBlockByHash(blockHash) {
1629
- const checkpointedBlock = await this.store.getCheckpointedBlockByHash(blockHash);
1630
- return this.buildOldBlockFromCheckpointedBlock(checkpointedBlock);
1631
- }
1632
- async getPublishedBlockByArchive(archive) {
1633
- const checkpointedBlock = await this.store.getCheckpointedBlockByArchive(archive);
1634
- return this.buildOldBlockFromCheckpointedBlock(checkpointedBlock);
1635
- }
1636
- /**
1637
- * Gets up to `limit` amount of L2 blocks starting from `from`.
1638
- * @param from - Number of the first block to return (inclusive).
1639
- * @param limit - The number of blocks to return.
1640
- * @param proven - If true, only return blocks that have been proven.
1641
- * @returns The requested L2 blocks.
1642
- */ async getBlocks(from, limit, proven) {
1643
- const publishedBlocks = await this.getPublishedBlocks(from, limit, proven);
1644
- return publishedBlocks.map((x)=>x.block);
1645
- }
1646
- async getPublishedBlocks(from, limit, proven) {
1647
- const checkpoints = await this.store.getRangeOfCheckpoints(CheckpointNumber(from), limit);
1648
- const provenCheckpointNumber = await this.getProvenCheckpointNumber();
1649
- const blocks = (await Promise.all(checkpoints.map((ch)=>this.store.getBlocksForCheckpoint(ch.checkpointNumber)))).filter(isDefined);
1650
- const olbBlocks = [];
1651
- for(let i = 0; i < checkpoints.length; i++){
1652
- const blockForCheckpoint = blocks[i][0];
1653
- const checkpoint = checkpoints[i];
1654
- if (checkpoint.checkpointNumber > provenCheckpointNumber && proven === true) {
1655
- continue;
1656
- }
1657
- const oldCheckpoint = new Checkpoint(blockForCheckpoint.archive, checkpoint.header, [
1658
- blockForCheckpoint
1659
- ], checkpoint.checkpointNumber);
1660
- const oldBlock = L2Block.fromCheckpoint(oldCheckpoint);
1661
- const publishedBlock = new PublishedL2Block(oldBlock, checkpoint.l1, checkpoint.attestations.map((x)=>CommitteeAttestation.fromBuffer(x)));
1662
- olbBlocks.push(publishedBlock);
1663
- }
1664
- return olbBlocks;
1665
- }
1666
- async buildOldBlockFromCheckpointedBlock(checkpointedBlock) {
1667
- if (!checkpointedBlock) {
1668
- return undefined;
1669
- }
1670
- const checkpoint = await this.store.getCheckpointData(checkpointedBlock.checkpointNumber);
1671
- if (!checkpoint) {
1672
- return checkpoint;
1673
- }
1674
- const fullCheckpoint = new Checkpoint(checkpointedBlock?.block.archive, checkpoint?.header, [
1675
- checkpointedBlock.block
1676
- ], checkpoint.checkpointNumber);
1677
- const oldBlock = L2Block.fromCheckpoint(fullCheckpoint);
1678
- const published = new PublishedL2Block(oldBlock, checkpoint.l1, checkpoint.attestations.map((x)=>CommitteeAttestation.fromBuffer(x)));
1679
- return published;
1680
- }
1681
- async getBlock(number) {
1682
- // If the number provided is -ve, then return the latest block.
1683
- if (number < 0) {
1684
- number = await this.store.getSynchedL2BlockNumber();
1685
- }
1686
- if (number === 0) {
1687
- return undefined;
1688
- }
1689
- const publishedBlocks = await this.getPublishedBlocks(number, 1);
1690
- if (publishedBlocks.length === 0) {
1691
- return undefined;
1692
- }
1693
- return publishedBlocks[0].block;
1694
- }
1695
- }
1696
- var Operation = /*#__PURE__*/ function(Operation) {
1697
- Operation[Operation["Store"] = 0] = "Store";
1698
- Operation[Operation["Delete"] = 1] = "Delete";
1699
- return Operation;
1700
- }(Operation || {});
1701
- /**
1702
- * A helper class that we use to deal with some of the logic needed when adding blocks.
1703
- *
1704
- * I would have preferred to not have this type. But it is useful for handling the logic that any
1705
- * store would need to include otherwise while exposing fewer functions and logic directly to the archiver.
1706
- */ export class ArchiverStoreHelper {
1707
- store;
1708
- #log;
1709
- constructor(store){
1710
- this.store = store;
1711
- this.#log = createLogger('archiver:block-helper');
1712
- }
1713
- /**
1714
- * Extracts and stores contract classes out of ContractClassPublished events emitted by the class registry contract.
1715
- * @param allLogs - All logs emitted in a bunch of blocks.
1716
- */ async #updatePublishedContractClasses(allLogs, blockNum, operation) {
1717
- const contractClassPublishedEvents = allLogs.filter((log)=>ContractClassPublishedEvent.isContractClassPublishedEvent(log)).map((log)=>ContractClassPublishedEvent.fromLog(log));
1718
- const contractClasses = await Promise.all(contractClassPublishedEvents.map((e)=>e.toContractClassPublic()));
1719
- if (contractClasses.length > 0) {
1720
- contractClasses.forEach((c)=>this.#log.verbose(`${Operation[operation]} contract class ${c.id.toString()}`));
1721
- if (operation == 0) {
1722
- // TODO: Will probably want to create some worker threads to compute these bytecode commitments as they are expensive
1723
- const commitments = await Promise.all(contractClasses.map((c)=>computePublicBytecodeCommitment(c.packedBytecode)));
1724
- return await this.store.addContractClasses(contractClasses, commitments, blockNum);
1725
- } else if (operation == 1) {
1726
- return await this.store.deleteContractClasses(contractClasses, blockNum);
1727
- }
1728
- }
1729
- return true;
1730
- }
1731
- /**
1732
- * Extracts and stores contract instances out of ContractInstancePublished events emitted by the canonical deployer contract.
1733
- * @param allLogs - All logs emitted in a bunch of blocks.
1734
- */ async #updateDeployedContractInstances(allLogs, blockNum, operation) {
1735
- const contractInstances = allLogs.filter((log)=>ContractInstancePublishedEvent.isContractInstancePublishedEvent(log)).map((log)=>ContractInstancePublishedEvent.fromLog(log)).map((e)=>e.toContractInstance());
1736
- if (contractInstances.length > 0) {
1737
- contractInstances.forEach((c)=>this.#log.verbose(`${Operation[operation]} contract instance at ${c.address.toString()}`));
1738
- if (operation == 0) {
1739
- return await this.store.addContractInstances(contractInstances, blockNum);
1740
- } else if (operation == 1) {
1741
- return await this.store.deleteContractInstances(contractInstances, blockNum);
1742
- }
1743
- }
1744
- return true;
1745
- }
1746
- /**
1747
- * Extracts and stores contract instances out of ContractInstancePublished events emitted by the canonical deployer contract.
1748
- * @param allLogs - All logs emitted in a bunch of blocks.
1749
- * @param timestamp - Timestamp at which the updates were scheduled.
1750
- * @param operation - The operation to perform on the contract instance updates (Store or Delete).
1751
- */ async #updateUpdatedContractInstances(allLogs, timestamp, operation) {
1752
- const contractUpdates = allLogs.filter((log)=>ContractInstanceUpdatedEvent.isContractInstanceUpdatedEvent(log)).map((log)=>ContractInstanceUpdatedEvent.fromLog(log)).map((e)=>e.toContractInstanceUpdate());
1753
- if (contractUpdates.length > 0) {
1754
- contractUpdates.forEach((c)=>this.#log.verbose(`${Operation[operation]} contract instance update at ${c.address.toString()}`));
1755
- if (operation == 0) {
1756
- return await this.store.addContractInstanceUpdates(contractUpdates, timestamp);
1757
- } else if (operation == 1) {
1758
- return await this.store.deleteContractInstanceUpdates(contractUpdates, timestamp);
1759
- }
1760
- }
1761
- return true;
1762
- }
1763
- /**
1764
- * Stores the functions that were broadcasted individually
1765
- *
1766
- * @dev Beware that there is not a delete variant of this, since they are added to contract classes
1767
- * and will be deleted as part of the class if needed.
1768
- *
1769
- * @param allLogs - The logs from the block
1770
- * @param _blockNum - The block number
1771
- * @returns
1772
- */ async #storeBroadcastedIndividualFunctions(allLogs, _blockNum) {
1773
- // Filter out private and utility function broadcast events
1774
- const privateFnEvents = allLogs.filter((log)=>PrivateFunctionBroadcastedEvent.isPrivateFunctionBroadcastedEvent(log)).map((log)=>PrivateFunctionBroadcastedEvent.fromLog(log));
1775
- const utilityFnEvents = allLogs.filter((log)=>UtilityFunctionBroadcastedEvent.isUtilityFunctionBroadcastedEvent(log)).map((log)=>UtilityFunctionBroadcastedEvent.fromLog(log));
1776
- // Group all events by contract class id
1777
- for (const [classIdString, classEvents] of Object.entries(groupBy([
1778
- ...privateFnEvents,
1779
- ...utilityFnEvents
1780
- ], (e)=>e.contractClassId.toString()))){
1781
- const contractClassId = Fr.fromHexString(classIdString);
1782
- const contractClass = await this.getContractClass(contractClassId);
1783
- if (!contractClass) {
1784
- this.#log.warn(`Skipping broadcasted functions as contract class ${contractClassId.toString()} was not found`);
1785
- continue;
1786
- }
1787
- // Split private and utility functions, and filter out invalid ones
1788
- const allFns = classEvents.map((e)=>e.toFunctionWithMembershipProof());
1789
- const privateFns = allFns.filter((fn)=>'utilityFunctionsTreeRoot' in fn);
1790
- const utilityFns = allFns.filter((fn)=>'privateFunctionsArtifactTreeRoot' in fn);
1791
- const privateFunctionsWithValidity = await Promise.all(privateFns.map(async (fn)=>({
1792
- fn,
1793
- valid: await isValidPrivateFunctionMembershipProof(fn, contractClass)
1794
- })));
1795
- const validPrivateFns = privateFunctionsWithValidity.filter(({ valid })=>valid).map(({ fn })=>fn);
1796
- const utilityFunctionsWithValidity = await Promise.all(utilityFns.map(async (fn)=>({
1797
- fn,
1798
- valid: await isValidUtilityFunctionMembershipProof(fn, contractClass)
1799
- })));
1800
- const validUtilityFns = utilityFunctionsWithValidity.filter(({ valid })=>valid).map(({ fn })=>fn);
1801
- const validFnCount = validPrivateFns.length + validUtilityFns.length;
1802
- if (validFnCount !== allFns.length) {
1803
- this.#log.warn(`Skipping ${allFns.length - validFnCount} invalid functions`);
1804
- }
1805
- // Store the functions in the contract class in a single operation
1806
- if (validFnCount > 0) {
1807
- this.#log.verbose(`Storing ${validFnCount} functions for contract class ${contractClassId.toString()}`);
1808
- }
1809
- return await this.store.addFunctions(contractClassId, validPrivateFns, validUtilityFns);
1810
- }
1811
- return true;
1812
- }
1813
- async addBlockDataToDB(block) {
1814
- const contractClassLogs = block.body.txEffects.flatMap((txEffect)=>txEffect.contractClassLogs);
1815
- // ContractInstancePublished event logs are broadcast in privateLogs.
1816
- const privateLogs = block.body.txEffects.flatMap((txEffect)=>txEffect.privateLogs);
1817
- const publicLogs = block.body.txEffects.flatMap((txEffect)=>txEffect.publicLogs);
1818
- return (await Promise.all([
1819
- this.#updatePublishedContractClasses(contractClassLogs, block.number, 0),
1820
- this.#updateDeployedContractInstances(privateLogs, block.number, 0),
1821
- this.#updateUpdatedContractInstances(publicLogs, block.header.globalVariables.timestamp, 0),
1822
- this.#storeBroadcastedIndividualFunctions(contractClassLogs, block.number)
1823
- ])).every(Boolean);
1824
- }
1825
- addBlocks(blocks, pendingChainValidationStatus) {
1826
- // Add the blocks to the store. Store will throw if the blocks are not in order, there are gaps,
1827
- // or if the previous block is not in the store.
1828
- return this.store.transactionAsync(async ()=>{
1829
- await this.store.addBlocks(blocks);
1830
- const opResults = await Promise.all([
1831
- // Update the pending chain validation status if provided
1832
- pendingChainValidationStatus && this.store.setPendingChainValidationStatus(pendingChainValidationStatus),
1833
- // Add any logs emitted during the retrieved blocks
1834
- this.store.addLogs(blocks),
1835
- // Unroll all logs emitted during the retrieved blocks and extract any contract classes and instances from them
1836
- ...blocks.map((block)=>{
1837
- return this.addBlockDataToDB(block);
1838
- })
1839
- ]);
1840
- return opResults.every(Boolean);
1841
- });
1842
- }
1843
- addCheckpoints(checkpoints, pendingChainValidationStatus) {
1844
- // Add the blocks to the store. Store will throw if the blocks are not in order, there are gaps,
1845
- // or if the previous block is not in the store.
1846
- return this.store.transactionAsync(async ()=>{
1847
- await this.store.addCheckpoints(checkpoints);
1848
- const allBlocks = checkpoints.flatMap((ch)=>ch.checkpoint.blocks);
1849
- const opResults = await Promise.all([
1850
- // Update the pending chain validation status if provided
1851
- pendingChainValidationStatus && this.store.setPendingChainValidationStatus(pendingChainValidationStatus),
1852
- // Add any logs emitted during the retrieved blocks
1853
- this.store.addLogs(allBlocks),
1854
- // Unroll all logs emitted during the retrieved blocks and extract any contract classes and instances from them
1855
- ...allBlocks.map((block)=>{
1856
- return this.addBlockDataToDB(block);
1857
- })
1858
- ]);
1859
- return opResults.every(Boolean);
1860
- });
1861
- }
1862
- async unwindCheckpoints(from, checkpointsToUnwind) {
1863
- if (checkpointsToUnwind <= 0) {
1864
- throw new Error(`Cannot unwind ${checkpointsToUnwind} blocks`);
1865
- }
1866
- const last = await this.getSynchedCheckpointNumber();
1867
- if (from != last) {
1868
- throw new Error(`Cannot unwind checkpoints from checkpoint ${from} when the last checkpoint is ${last}`);
1869
- }
1870
- const blocks = [];
1871
- const lastCheckpointNumber = from + checkpointsToUnwind - 1;
1872
- for(let checkpointNumber = from; checkpointNumber <= lastCheckpointNumber; checkpointNumber++){
1873
- const blocksForCheckpoint = await this.store.getBlocksForCheckpoint(checkpointNumber);
1874
- if (!blocksForCheckpoint) {
1875
- continue;
1876
- }
1877
- blocks.push(...blocksForCheckpoint);
1878
- }
1879
- const opResults = await Promise.all([
1880
- // Prune rolls back to the last proven block, which is by definition valid
1881
- this.store.setPendingChainValidationStatus({
1882
- valid: true
1883
- }),
1884
- // Unroll all logs emitted during the retrieved blocks and extract any contract classes and instances from them
1885
- ...blocks.map(async (block)=>{
1886
- const contractClassLogs = block.body.txEffects.flatMap((txEffect)=>txEffect.contractClassLogs);
1887
- // ContractInstancePublished event logs are broadcast in privateLogs.
1888
- const privateLogs = block.body.txEffects.flatMap((txEffect)=>txEffect.privateLogs);
1889
- const publicLogs = block.body.txEffects.flatMap((txEffect)=>txEffect.publicLogs);
1890
- return (await Promise.all([
1891
- this.#updatePublishedContractClasses(contractClassLogs, block.number, 1),
1892
- this.#updateDeployedContractInstances(privateLogs, block.number, 1),
1893
- this.#updateUpdatedContractInstances(publicLogs, block.header.globalVariables.timestamp, 1)
1894
- ])).every(Boolean);
1895
- }),
1896
- this.store.deleteLogs(blocks),
1897
- this.store.unwindCheckpoints(from, checkpointsToUnwind)
1898
- ]);
1899
- return opResults.every(Boolean);
1900
- }
1901
- getCheckpointData(checkpointNumber) {
1902
- return this.store.getCheckpointData(checkpointNumber);
1903
- }
1904
- getRangeOfCheckpoints(from, limit) {
1905
- return this.store.getRangeOfCheckpoints(from, limit);
1906
- }
1907
- getCheckpointedL2BlockNumber() {
1908
- return this.store.getCheckpointedL2BlockNumber();
1909
- }
1910
- getSynchedCheckpointNumber() {
1911
- return this.store.getSynchedCheckpointNumber();
1912
- }
1913
- setCheckpointSynchedL1BlockNumber(l1BlockNumber) {
1914
- return this.store.setCheckpointSynchedL1BlockNumber(l1BlockNumber);
1915
- }
1916
- getCheckpointedBlock(number) {
1917
- return this.store.getCheckpointedBlock(number);
1918
- }
1919
- getCheckpointedBlockByHash(blockHash) {
1920
- return this.store.getCheckpointedBlockByHash(blockHash);
1921
- }
1922
- getCheckpointedBlockByArchive(archive) {
1923
- return this.store.getCheckpointedBlockByArchive(archive);
1924
- }
1925
- getBlockHeaders(from, limit) {
1926
- return this.store.getBlockHeaders(from, limit);
1927
- }
1928
- getBlockHeaderByHash(blockHash) {
1929
- return this.store.getBlockHeaderByHash(blockHash);
1930
- }
1931
- getBlockHeaderByArchive(archive) {
1932
- return this.store.getBlockHeaderByArchive(archive);
1933
- }
1934
- getBlockByHash(blockHash) {
1935
- return this.store.getBlockByHash(blockHash);
1936
- }
1937
- getBlockByArchive(archive) {
1938
- return this.store.getBlockByArchive(archive);
1939
- }
1940
- getLatestBlockNumber() {
1941
- return this.store.getLatestBlockNumber();
1942
- }
1943
- getBlocksForCheckpoint(checkpointNumber) {
1944
- return this.store.getBlocksForCheckpoint(checkpointNumber);
1945
- }
1946
- getTxEffect(txHash) {
1947
- return this.store.getTxEffect(txHash);
1948
- }
1949
- getSettledTxReceipt(txHash) {
1950
- return this.store.getSettledTxReceipt(txHash);
1951
- }
1952
- addL1ToL2Messages(messages) {
1953
- return this.store.addL1ToL2Messages(messages);
1954
- }
1955
- getL1ToL2Messages(checkpointNumber) {
1956
- return this.store.getL1ToL2Messages(checkpointNumber);
1957
- }
1958
- getL1ToL2MessageIndex(l1ToL2Message) {
1959
- return this.store.getL1ToL2MessageIndex(l1ToL2Message);
1960
- }
1961
- getPrivateLogsByTags(tags) {
1962
- return this.store.getPrivateLogsByTags(tags);
1963
- }
1964
- getPublicLogsByTagsFromContract(contractAddress, tags) {
1965
- return this.store.getPublicLogsByTagsFromContract(contractAddress, tags);
1966
- }
1967
- getPublicLogs(filter) {
1968
- return this.store.getPublicLogs(filter);
1969
- }
1970
- getContractClassLogs(filter) {
1971
- return this.store.getContractClassLogs(filter);
1972
- }
1973
- getSynchedL2BlockNumber() {
1974
- return this.store.getCheckpointedL2BlockNumber();
1975
- }
1976
- getProvenCheckpointNumber() {
1977
- return this.store.getProvenCheckpointNumber();
1978
- }
1979
- getProvenBlockNumber() {
1980
- return this.store.getProvenBlockNumber();
1981
- }
1982
- setProvenCheckpointNumber(checkpointNumber) {
1983
- return this.store.setProvenCheckpointNumber(checkpointNumber);
1984
- }
1985
- setBlockSynchedL1BlockNumber(l1BlockNumber) {
1986
- return this.store.setCheckpointSynchedL1BlockNumber(l1BlockNumber);
1987
- }
1988
- setMessageSynchedL1Block(l1Block) {
1989
- return this.store.setMessageSynchedL1Block(l1Block);
1990
- }
1991
- getSynchPoint() {
1992
- return this.store.getSynchPoint();
1993
- }
1994
- getContractClass(id) {
1995
- return this.store.getContractClass(id);
1996
- }
1997
- getBytecodeCommitment(contractClassId) {
1998
- return this.store.getBytecodeCommitment(contractClassId);
1999
- }
2000
- getContractInstance(address, timestamp) {
2001
- return this.store.getContractInstance(address, timestamp);
2002
- }
2003
- getContractClassIds() {
2004
- return this.store.getContractClassIds();
2005
- }
2006
- registerContractFunctionSignatures(signatures) {
2007
- return this.store.registerContractFunctionSignatures(signatures);
2008
- }
2009
- getDebugFunctionName(address, selector) {
2010
- return this.store.getDebugFunctionName(address, selector);
2011
- }
2012
- getTotalL1ToL2MessageCount() {
2013
- return this.store.getTotalL1ToL2MessageCount();
2014
- }
2015
- estimateSize() {
2016
- return this.store.estimateSize();
2017
- }
2018
- rollbackL1ToL2MessagesToCheckpoint(targetCheckpointNumber) {
2019
- return this.store.rollbackL1ToL2MessagesToCheckpoint(targetCheckpointNumber);
2020
- }
2021
- iterateL1ToL2Messages(range = {}) {
2022
- return this.store.iterateL1ToL2Messages(range);
2023
- }
2024
- removeL1ToL2Messages(startIndex) {
2025
- return this.store.removeL1ToL2Messages(startIndex);
2026
- }
2027
- getLastL1ToL2Message() {
2028
- return this.store.getLastL1ToL2Message();
2029
- }
2030
- getPendingChainValidationStatus() {
2031
- return this.store.getPendingChainValidationStatus();
2032
- }
2033
- setPendingChainValidationStatus(status) {
2034
- this.#log.debug(`Setting pending chain validation status to valid ${status?.valid}`, status);
2035
- return this.store.setPendingChainValidationStatus(status);
2036
- }
2037
1547
  }