@aztec/aztec-node 3.0.0-devnet.2 → 3.0.0-devnet.20251212

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.
@@ -9,26 +9,30 @@ import { BBCircuitVerifier, QueuedIVCVerifier, TestCircuitVerifier } from '@azte
9
9
  import { createBlobSinkClient } from '@aztec/blob-sink/client';
10
10
  import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
11
11
  import { EpochCache } from '@aztec/epoch-cache';
12
- import { RegistryContract, RollupContract, createEthereumChain, getPublicClient } from '@aztec/ethereum';
12
+ import { createEthereumChain } from '@aztec/ethereum/chain';
13
+ import { getPublicClient } from '@aztec/ethereum/client';
14
+ import { RegistryContract, RollupContract } from '@aztec/ethereum/contracts';
15
+ import { BlockNumber } from '@aztec/foundation/branded-types';
13
16
  import { compactArray, pick } from '@aztec/foundation/collection';
17
+ import { Fr } from '@aztec/foundation/curves/bn254';
14
18
  import { EthAddress } from '@aztec/foundation/eth-address';
15
- import { Fr } from '@aztec/foundation/fields';
16
19
  import { BadRequestError } from '@aztec/foundation/json-rpc';
17
20
  import { createLogger } from '@aztec/foundation/log';
18
- import { SerialQueue } from '@aztec/foundation/queue';
19
21
  import { count } from '@aztec/foundation/string';
20
22
  import { DateProvider, Timer } from '@aztec/foundation/timer';
21
23
  import { MembershipWitness } from '@aztec/foundation/trees';
22
24
  import { KeystoreManager, loadKeystores, mergeKeystores } from '@aztec/node-keystore';
23
25
  import { trySnapshotSync, uploadSnapshot } from '@aztec/node-lib/actions';
24
- import { createL1TxUtilsWithBlobsFromEthSigner } from '@aztec/node-lib/factories';
26
+ import { createForwarderL1TxUtilsFromEthSigner, createL1TxUtilsWithBlobsFromEthSigner } from '@aztec/node-lib/factories';
25
27
  import { createP2PClient, getDefaultAllowedSetupFunctions } from '@aztec/p2p';
26
28
  import { ProtocolContractAddress } from '@aztec/protocol-contracts';
27
29
  import { BlockBuilder, GlobalVariableBuilder, SequencerClient, createValidatorForAcceptingTxs } from '@aztec/sequencer-client';
28
30
  import { PublicProcessorFactory } from '@aztec/simulator/server';
29
31
  import { AttestationsBlockWatcher, EpochPruneWatcher, createSlasher } from '@aztec/slasher';
32
+ import { CollectionLimitsConfig, PublicSimulatorConfig } from '@aztec/stdlib/avm';
30
33
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
31
34
  import { L2BlockHash } from '@aztec/stdlib/block';
35
+ import { GasFees } from '@aztec/stdlib/gas';
32
36
  import { computePublicDataTreeLeafSlot } from '@aztec/stdlib/hash';
33
37
  import { AztecNodeAdminConfigSchema } from '@aztec/stdlib/interfaces/client';
34
38
  import { tryStop } from '@aztec/stdlib/interfaces/server';
@@ -69,8 +73,6 @@ import { NodeMetrics } from './node_metrics.js';
69
73
  metrics;
70
74
  // Prevent two snapshot operations to happen simultaneously
71
75
  isUploadingSnapshot;
72
- // Serial queue to ensure that we only send one tx at a time
73
- txQueue;
74
76
  tracer;
75
77
  constructor(config, p2pClient, blockSource, logsSource, contractDataSource, l1ToL2MessageSource, worldStateSynchronizer, sequencer, slasherClient, validatorsSentinel, epochPruneWatcher, l1ChainId, version, globalVariableBuilder, epochCache, packageVersion, proofVerifier, telemetry = getTelemetryClient(), log = createLogger('node')){
76
78
  this.config = config;
@@ -93,10 +95,8 @@ import { NodeMetrics } from './node_metrics.js';
93
95
  this.telemetry = telemetry;
94
96
  this.log = log;
95
97
  this.isUploadingSnapshot = false;
96
- this.txQueue = new SerialQueue();
97
98
  this.metrics = new NodeMetrics(telemetry, 'AztecNodeService');
98
99
  this.tracer = telemetry.getTracer('AztecNodeService');
99
- this.txQueue.start();
100
100
  this.log.info(`Aztec Node version: ${this.packageVersion}`);
101
101
  this.log.info(`Aztec Node started on chain 0x${l1ChainId.toString(16)}`, config.l1Contracts);
102
102
  }
@@ -182,11 +182,11 @@ import { NodeMetrics } from './node_metrics.js';
182
182
  telemetry,
183
183
  dateProvider
184
184
  }, {
185
- blockUntilSync: true
185
+ blockUntilSync: !config.skipArchiverInitialSync
186
186
  });
187
187
  // now create the merkle trees and the world state synchronizer
188
188
  const worldStateSynchronizer = await createWorldStateSynchronizer(config, archiver, options.prefilledPublicData, telemetry);
189
- const circuitVerifier = config.realProofs ? await BBCircuitVerifier.new(config) : new TestCircuitVerifier();
189
+ const circuitVerifier = config.realProofs || config.debugForceTxProofVerification ? await BBCircuitVerifier.new(config) : new TestCircuitVerifier(config.proverTestVerificationDelayMs);
190
190
  if (!config.realProofs) {
191
191
  log.warn(`Aztec node is accepting fake proofs`);
192
192
  }
@@ -241,27 +241,28 @@ import { NodeMetrics } from './node_metrics.js';
241
241
  // Start p2p. Note that it depends on world state to be running.
242
242
  await p2pClient.start();
243
243
  const validatorsSentinel = await createSentinel(epochCache, archiver, p2pClient, config);
244
- if (validatorsSentinel) {
245
- // we can run a sentinel without trying to slash.
246
- await validatorsSentinel.start();
247
- if (config.slashInactivityPenalty > 0n) {
248
- watchers.push(validatorsSentinel);
249
- }
244
+ if (validatorsSentinel && config.slashInactivityPenalty > 0n) {
245
+ watchers.push(validatorsSentinel);
250
246
  }
251
247
  let epochPruneWatcher;
252
248
  if (config.slashPrunePenalty > 0n || config.slashDataWithholdingPenalty > 0n) {
253
249
  epochPruneWatcher = new EpochPruneWatcher(archiver, archiver, epochCache, p2pClient.getTxProvider(), blockBuilder, config);
254
- await epochPruneWatcher.start();
255
250
  watchers.push(epochPruneWatcher);
256
251
  }
257
252
  // We assume we want to slash for invalid attestations unless all max penalties are set to 0
258
253
  let attestationsBlockWatcher;
259
254
  if (config.slashProposeInvalidAttestationsPenalty > 0n || config.slashAttestDescendantOfInvalidPenalty > 0n) {
260
255
  attestationsBlockWatcher = new AttestationsBlockWatcher(archiver, epochCache, config);
261
- await attestationsBlockWatcher.start();
262
256
  watchers.push(attestationsBlockWatcher);
263
257
  }
264
- log.verbose(`All Aztec Node subsystems synced`);
258
+ // Start p2p-related services once the archiver has completed sync
259
+ void archiver.waitForInitialSync().then(async ()=>{
260
+ await p2pClient.start();
261
+ await validatorsSentinel?.start();
262
+ await epochPruneWatcher?.start();
263
+ await attestationsBlockWatcher?.start();
264
+ log.info(`All p2p services started`);
265
+ }).catch((err)=>log.error('Failed to start p2p services after archiver sync', err));
265
266
  // Validator enabled, create/start relevant service
266
267
  let sequencer;
267
268
  let slasherClient;
@@ -271,7 +272,14 @@ import { NodeMetrics } from './node_metrics.js';
271
272
  const validatorAddresses = keyStoreManager ? NodeKeystoreAdapter.fromKeyStoreManager(keyStoreManager).getAddresses() : [];
272
273
  slasherClient = await createSlasher(config, config.l1Contracts, getPublicClient(config), watchers, dateProvider, epochCache, validatorAddresses, undefined);
273
274
  await slasherClient.start();
274
- const l1TxUtils = await createL1TxUtilsWithBlobsFromEthSigner(publicClient, keyStoreManager.createAllValidatorPublisherSigners(), {
275
+ const l1TxUtils = config.publisherForwarderAddress ? await createForwarderL1TxUtilsFromEthSigner(publicClient, keyStoreManager.createAllValidatorPublisherSigners(), config.publisherForwarderAddress, {
276
+ ...config,
277
+ scope: 'sequencer'
278
+ }, {
279
+ telemetry,
280
+ logger: log.createChild('l1-tx-utils'),
281
+ dateProvider
282
+ }) : await createL1TxUtilsWithBlobsFromEthSigner(publicClient, keyStoreManager.createAllValidatorPublisherSigners(), {
275
283
  ...config,
276
284
  scope: 'sequencer'
277
285
  }, {
@@ -279,9 +287,8 @@ import { NodeMetrics } from './node_metrics.js';
279
287
  logger: log.createChild('l1-tx-utils'),
280
288
  dateProvider
281
289
  });
290
+ // Create and start the sequencer client
282
291
  sequencer = await SequencerClient.new(config, {
283
- // if deps were provided, they should override the defaults,
284
- // or things that we created in this function
285
292
  ...deps,
286
293
  epochCache,
287
294
  l1TxUtils,
@@ -399,6 +406,15 @@ import { NodeMetrics } from './node_metrics.js';
399
406
  */ async getCurrentBaseFees() {
400
407
  return await this.globalVariableBuilder.getCurrentBaseFees();
401
408
  }
409
+ async getMaxPriorityFees() {
410
+ for await (const tx of this.p2pClient.iteratePendingTxs()){
411
+ return tx.getGasSettings().maxPriorityFeesPerGas;
412
+ }
413
+ return GasFees.from({
414
+ feePerDaGas: 0n,
415
+ feePerL2Gas: 0n
416
+ });
417
+ }
402
418
  /**
403
419
  * Method to fetch the latest block number synchronized by the node.
404
420
  * @returns The block number.
@@ -433,14 +449,6 @@ import { NodeMetrics } from './node_metrics.js';
433
449
  return this.contractDataSource.getContract(address);
434
450
  }
435
451
  /**
436
- * Retrieves all private logs from up to `limit` blocks, starting from the block number `from`.
437
- * @param from - The block number from which to begin retrieving logs.
438
- * @param limit - The maximum number of blocks to retrieve logs from.
439
- * @returns An array of private logs from the specified range of blocks.
440
- */ getPrivateLogs(from, limit) {
441
- return this.logsSource.getPrivateLogs(from, limit);
442
- }
443
- /**
444
452
  * Gets all logs that match any of the received tags (i.e. logs with their first field equal to a tag).
445
453
  * @param tags - The tags to filter the logs by.
446
454
  * @param logsPerTag - The maximum number of logs to return for each tag. By default no limit is set
@@ -467,7 +475,7 @@ import { NodeMetrics } from './node_metrics.js';
467
475
  * Method to submit a transaction to the p2p pool.
468
476
  * @param tx - The transaction to be submitted.
469
477
  */ async sendTx(tx) {
470
- await this.txQueue.put(()=>this.#sendTx(tx));
478
+ await this.#sendTx(tx);
471
479
  }
472
480
  async #sendTx(tx) {
473
481
  const timer = new Timer();
@@ -508,7 +516,6 @@ import { NodeMetrics } from './node_metrics.js';
508
516
  * Method to stop the aztec node.
509
517
  */ async stop() {
510
518
  this.log.info(`Stopping Aztec Node`);
511
- await this.txQueue.end();
512
519
  await tryStop(this.validatorsSentinel);
513
520
  await tryStop(this.epochPruneWatcher);
514
521
  await tryStop(this.slasherClient);
@@ -572,7 +579,7 @@ import { NodeMetrics } from './node_metrics.js';
572
579
  // Now we obtain the block hashes from the archive tree by calling await `committedDb.getLeafValue(treeId, index)`
573
580
  // (note that block number corresponds to the leaf index in the archive tree).
574
581
  const blockHashes = await Promise.all(uniqueBlockNumbers.map((blockNumber)=>{
575
- return committedDb.getLeafValue(MerkleTreeId.ARCHIVE, blockNumber);
582
+ return committedDb.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(blockNumber));
576
583
  }));
577
584
  // If any of the block hashes are undefined, we throw an error.
578
585
  for(let i = 0; i < uniqueBlockNumbers.length; i++){
@@ -580,7 +587,7 @@ import { NodeMetrics } from './node_metrics.js';
580
587
  throw new Error(`Block hash is undefined for block number ${uniqueBlockNumbers[i]}`);
581
588
  }
582
589
  }
583
- // Create InBlock objects by combining indices, blockNumbers and blockHashes and return them.
590
+ // Create DataInBlock objects by combining indices, blockNumbers and blockHashes and return them.
584
591
  return maybeIndices.map((index, i)=>{
585
592
  if (index === undefined) {
586
593
  return undefined;
@@ -595,7 +602,7 @@ import { NodeMetrics } from './node_metrics.js';
595
602
  return undefined;
596
603
  }
597
604
  return {
598
- l2BlockNumber: Number(blockNumber),
605
+ l2BlockNumber: BlockNumber(Number(blockNumber)),
599
606
  l2BlockHash: L2BlockHash.fromField(blockHash),
600
607
  data: index
601
608
  };
@@ -654,7 +661,7 @@ import { NodeMetrics } from './node_metrics.js';
654
661
  }
655
662
  async getL1ToL2MessageBlock(l1ToL2Message) {
656
663
  const messageIndex = await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message);
657
- return messageIndex ? InboxLeaf.l2BlockFromIndex(messageIndex) : undefined;
664
+ return messageIndex ? BlockNumber.fromCheckpointNumber(InboxLeaf.checkpointNumberFromIndex(messageIndex)) : undefined;
658
665
  }
659
666
  /**
660
667
  * Returns whether an L1 to L2 message is synced by archiver and if it's ready to be included in a block.
@@ -772,7 +779,7 @@ import { NodeMetrics } from './node_metrics.js';
772
779
  * Returns the currently committed block header, or the initial header if no blocks have been produced.
773
780
  * @returns The current committed block header.
774
781
  */ async getBlockHeader(blockNumber = 'latest') {
775
- return blockNumber === 0 || blockNumber === 'latest' && await this.blockSource.getBlockNumber() === 0 ? this.worldStateSynchronizer.getCommitted().getInitialHeader() : this.blockSource.getBlockHeader(blockNumber);
782
+ return blockNumber === BlockNumber.ZERO || blockNumber === 'latest' && await this.blockSource.getBlockNumber() === BlockNumber.ZERO ? this.worldStateSynchronizer.getCommitted().getInitialHeader() : this.blockSource.getBlockHeader(blockNumber === 'latest' ? blockNumber : blockNumber);
776
783
  }
777
784
  /**
778
785
  * Get a block header specified by its hash.
@@ -800,7 +807,7 @@ import { NodeMetrics } from './node_metrics.js';
800
807
  throw new BadRequestError(`Transaction total gas limit ${txGasLimit + teardownGasLimit} (${txGasLimit} + ${teardownGasLimit}) exceeds maximum gas limit ${this.config.rpcSimulatePublicMaxGasLimit} for simulation`);
801
808
  }
802
809
  const txHash = tx.getTxHash();
803
- const blockNumber = await this.blockSource.getBlockNumber() + 1;
810
+ const blockNumber = BlockNumber(await this.blockSource.getBlockNumber() + 1);
804
811
  // If sequencer is not initialized, we just set these values to zero for simulation.
805
812
  const coinbase = EthAddress.ZERO;
806
813
  const feeRecipient = AztecAddress.ZERO;
@@ -813,11 +820,17 @@ import { NodeMetrics } from './node_metrics.js';
813
820
  });
814
821
  const merkleTreeFork = await this.worldStateSynchronizer.fork();
815
822
  try {
816
- const processor = publicProcessorFactory.create(merkleTreeFork, newGlobalVariables, {
823
+ const config = PublicSimulatorConfig.from({
817
824
  skipFeeEnforcement,
818
- clientInitiatedSimulation: true,
819
- maxDebugLogMemoryReads: this.config.rpcSimulatePublicMaxDebugLogMemoryReads
825
+ collectDebugLogs: true,
826
+ collectHints: false,
827
+ collectCallMetadata: true,
828
+ collectStatistics: false,
829
+ collectionLimits: CollectionLimitsConfig.from({
830
+ maxDebugLogMemoryReads: this.config.rpcSimulatePublicMaxDebugLogMemoryReads
831
+ })
820
832
  });
833
+ const processor = publicProcessorFactory.create(merkleTreeFork, newGlobalVariables, config);
821
834
  // REFACTOR: Consider merging ProcessReturnValues into ProcessedTx
822
835
  const [processedTxs, failedTxs, _usedTxs, returns] = await processor.process([
823
836
  tx
@@ -840,7 +853,7 @@ import { NodeMetrics } from './node_metrics.js';
840
853
  const verifier = isSimulation ? undefined : this.proofVerifier;
841
854
  // We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
842
855
  const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
843
- const blockNumber = await this.blockSource.getBlockNumber() + 1;
856
+ const blockNumber = BlockNumber(await this.blockSource.getBlockNumber() + 1);
844
857
  const validator = createValidatorForAcceptingTxs(db, this.contractDataSource, verifier, {
845
858
  timestamp: nextSlotTimestamp,
846
859
  blockNumber,
@@ -901,26 +914,33 @@ import { NodeMetrics } from './node_metrics.js';
901
914
  // We break support for archiver running remotely to the node
902
915
  const archiver = this.blockSource;
903
916
  if (!('backupTo' in archiver)) {
917
+ this.metrics.recordSnapshotError();
904
918
  throw new Error('Archiver implementation does not support backups. Cannot generate snapshot.');
905
919
  }
906
920
  // Test that the archiver has done an initial sync.
907
921
  if (!archiver.isInitialSyncComplete()) {
922
+ this.metrics.recordSnapshotError();
908
923
  throw new Error(`Archiver initial sync not complete. Cannot start snapshot.`);
909
924
  }
910
925
  // And it has an L2 block hash
911
926
  const l2BlockHash = await archiver.getL2Tips().then((tips)=>tips.latest.hash);
912
927
  if (!l2BlockHash) {
928
+ this.metrics.recordSnapshotError();
913
929
  throw new Error(`Archiver has no latest L2 block hash downloaded. Cannot start snapshot.`);
914
930
  }
915
931
  if (this.isUploadingSnapshot) {
932
+ this.metrics.recordSnapshotError();
916
933
  throw new Error(`Snapshot upload already in progress. Cannot start another one until complete.`);
917
934
  }
918
935
  // Do not wait for the upload to be complete to return to the caller, but flag that an operation is in progress
919
936
  this.isUploadingSnapshot = true;
937
+ const timer = new Timer();
920
938
  void uploadSnapshot(location, this.blockSource, this.worldStateSynchronizer, this.config, this.log).then(()=>{
921
939
  this.isUploadingSnapshot = false;
940
+ this.metrics.recordSnapshot(timer.ms());
922
941
  }).catch((err)=>{
923
942
  this.isUploadingSnapshot = false;
943
+ this.metrics.recordSnapshotError();
924
944
  this.log.error(`Error uploading snapshot: ${err}`);
925
945
  });
926
946
  return Promise.resolve();
@@ -993,7 +1013,7 @@ import { NodeMetrics } from './node_metrics.js';
993
1013
  if (typeof blockNumber === 'number' && blockNumber < INITIAL_L2_BLOCK_NUM - 1) {
994
1014
  throw new Error('Invalid block number to get world state for: ' + blockNumber);
995
1015
  }
996
- let blockSyncedTo = 0;
1016
+ let blockSyncedTo = BlockNumber.ZERO;
997
1017
  try {
998
1018
  // Attempt to sync the world state if necessary
999
1019
  blockSyncedTo = await this.#syncWorldState();
@@ -1016,7 +1036,7 @@ import { NodeMetrics } from './node_metrics.js';
1016
1036
  * @returns A promise that fulfils once the world state is synced
1017
1037
  */ async #syncWorldState() {
1018
1038
  const blockSourceHeight = await this.blockSource.getBlockNumber();
1019
- return this.worldStateSynchronizer.syncImmediate(blockSourceHeight);
1039
+ return await this.worldStateSynchronizer.syncImmediate(blockSourceHeight);
1020
1040
  }
1021
1041
  }
1022
1042
  _ts_decorate([
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env -S node --no-warnings
2
2
  export {};
3
- //# sourceMappingURL=index.d.ts.map
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9iaW4vaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9
package/dest/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export * from './aztec-node/config.js';
2
2
  export * from './aztec-node/server.js';
3
- //# sourceMappingURL=index.d.ts.map
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLHdCQUF3QixDQUFDO0FBQ3ZDLGNBQWMsd0JBQXdCLENBQUMifQ==
@@ -5,4 +5,4 @@ export type SentinelConfig = {
5
5
  sentinelEnabled: boolean;
6
6
  };
7
7
  export declare const sentinelConfigMappings: ConfigMappingsType<SentinelConfig>;
8
- //# sourceMappingURL=config.d.ts.map
8
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VudGluZWwvY29uZmlnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxLQUFLLGtCQUFrQixFQUEyQyxNQUFNLDBCQUEwQixDQUFDO0FBRTVHLE1BQU0sTUFBTSxjQUFjLEdBQUc7SUFDM0IsNkJBQTZCLEVBQUUsTUFBTSxDQUFDO0lBQ3RDLCtDQUErQyxFQUFFLE1BQU0sQ0FBQztJQUN4RCxlQUFlLEVBQUUsT0FBTyxDQUFDO0NBQzFCLENBQUM7QUFFRixlQUFPLE1BQU0sc0JBQXNCLEVBQUUsa0JBQWtCLENBQUMsY0FBYyxDQTRCckUsQ0FBQyJ9
@@ -6,4 +6,4 @@ import type { SlasherConfig } from '@aztec/stdlib/interfaces/server';
6
6
  import type { SentinelConfig } from './config.js';
7
7
  import { Sentinel } from './sentinel.js';
8
8
  export declare function createSentinel(epochCache: EpochCache, archiver: L2BlockSource, p2p: P2PClient, config: SentinelConfig & DataStoreConfig & SlasherConfig, logger?: import("@aztec/foundation/log").Logger): Promise<Sentinel | undefined>;
9
- //# sourceMappingURL=factory.d.ts.map
9
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFjdG9yeS5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlbnRpbmVsL2ZhY3RvcnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFFckQsT0FBTyxLQUFLLEVBQUUsZUFBZSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFOUQsT0FBTyxLQUFLLEVBQUUsU0FBUyxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQzVDLE9BQU8sS0FBSyxFQUFFLGFBQWEsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3pELE9BQU8sS0FBSyxFQUFFLGFBQWEsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRXJFLE9BQU8sS0FBSyxFQUFFLGNBQWMsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNsRCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBR3pDLHdCQUFzQixjQUFjLENBQ2xDLFVBQVUsRUFBRSxVQUFVLEVBQ3RCLFFBQVEsRUFBRSxhQUFhLEVBQ3ZCLEdBQUcsRUFBRSxTQUFTLEVBQ2QsTUFBTSxFQUFFLGNBQWMsR0FBRyxlQUFlLEdBQUcsYUFBYSxFQUN4RCxNQUFNLHlDQUFnQyxHQUNyQyxPQUFPLENBQUMsUUFBUSxHQUFHLFNBQVMsQ0FBQyxDQWlCL0IifQ==
@@ -1,3 +1,3 @@
1
1
  export { Sentinel } from './sentinel.js';
2
2
  export type { ValidatorsStats, ValidatorStats, ValidatorStatusHistory, ValidatorStatusInSlot, } from '@aztec/stdlib/validators';
3
- //# sourceMappingURL=index.d.ts.map
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZW50aW5lbC9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRXpDLFlBQVksRUFDVixlQUFlLEVBQ2YsY0FBYyxFQUNkLHNCQUFzQixFQUN0QixxQkFBcUIsR0FDdEIsTUFBTSwwQkFBMEIsQ0FBQyJ9
@@ -1,4 +1,5 @@
1
1
  import type { EpochCache } from '@aztec/epoch-cache';
2
+ import { BlockNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
2
3
  import { EthAddress } from '@aztec/foundation/eth-address';
3
4
  import { RunningPromise } from '@aztec/foundation/running-promise';
4
5
  import { type L2TipsStore } from '@aztec/kv-store/stores';
@@ -19,10 +20,10 @@ export declare class Sentinel extends Sentinel_base implements L2BlockStreamEven
19
20
  protected runningPromise: RunningPromise;
20
21
  protected blockStream: L2BlockStream;
21
22
  protected l2TipsStore: L2TipsStore;
22
- protected initialSlot: bigint | undefined;
23
- protected lastProcessedSlot: bigint | undefined;
24
- protected slotNumberToBlock: Map<bigint, {
25
- blockNumber: number;
23
+ protected initialSlot: SlotNumber | undefined;
24
+ protected lastProcessedSlot: SlotNumber | undefined;
25
+ protected slotNumberToBlock: Map<SlotNumber, {
26
+ blockNumber: BlockNumber;
26
27
  archive: string;
27
28
  attestors: EthAddress[];
28
29
  }>;
@@ -34,15 +35,15 @@ export declare class Sentinel extends Sentinel_base implements L2BlockStreamEven
34
35
  stop(): Promise<void>;
35
36
  handleBlockStreamEvent(event: L2BlockStreamEvent): Promise<void>;
36
37
  protected handleChainProven(event: L2BlockStreamEvent): Promise<void>;
37
- protected computeProvenPerformance(epoch: bigint): Promise<ValidatorsEpochPerformance>;
38
+ protected computeProvenPerformance(epoch: EpochNumber): Promise<ValidatorsEpochPerformance>;
38
39
  /**
39
40
  * Checks if a validator has been inactive for the specified number of consecutive epochs for which we have data on it.
40
41
  * @param validator The validator address to check
41
42
  * @param currentEpoch Epochs strictly before the current one are evaluated only
42
43
  * @param requiredConsecutiveEpochs Number of consecutive epochs required for slashing
43
44
  */
44
- protected checkPastInactivity(validator: EthAddress, currentEpoch: bigint, requiredConsecutiveEpochs: number): Promise<boolean>;
45
- protected handleProvenPerformance(epoch: bigint, performance: ValidatorsEpochPerformance): Promise<void>;
45
+ protected checkPastInactivity(validator: EthAddress, currentEpoch: EpochNumber, requiredConsecutiveEpochs: number): Promise<boolean>;
46
+ protected handleProvenPerformance(epoch: EpochNumber, performance: ValidatorsEpochPerformance): Promise<void>;
46
47
  /**
47
48
  * Process data for two L2 slots ago.
48
49
  * Note that we do not process historical data, since we rely on p2p data for processing,
@@ -54,38 +55,38 @@ export declare class Sentinel extends Sentinel_base implements L2BlockStreamEven
54
55
  * We also don't move past the archiver last synced L2 slot, as we don't want to process data that is not yet available.
55
56
  * Last, we check the p2p is synced with the archiver, so it has pulled all attestations from it.
56
57
  */
57
- protected isReadyToProcess(currentSlot: bigint): Promise<bigint | false>;
58
+ protected isReadyToProcess(currentSlot: SlotNumber): Promise<SlotNumber | false>;
58
59
  /**
59
60
  * Gathers committee and proposer data for a given slot, computes slot stats,
60
61
  * and updates overall stats.
61
62
  */
62
- protected processSlot(slot: bigint): Promise<void>;
63
+ protected processSlot(slot: SlotNumber): Promise<void>;
63
64
  /** Computes activity for a given slot. */
64
- protected getSlotActivity(slot: bigint, epoch: bigint, proposer: EthAddress, committee: EthAddress[]): Promise<{
65
+ protected getSlotActivity(slot: SlotNumber, epoch: EpochNumber, proposer: EthAddress, committee: EthAddress[]): Promise<{
65
66
  [k: string]: ValidatorStatusInSlot | undefined;
66
67
  }>;
67
68
  /** Push the status for each slot for each validator. */
68
- protected updateValidators(slot: bigint, stats: Record<`0x${string}`, ValidatorStatusInSlot | undefined>): Promise<void>;
69
+ protected updateValidators(slot: SlotNumber, stats: Record<`0x${string}`, ValidatorStatusInSlot | undefined>): Promise<void>;
69
70
  /** Computes stats to be returned based on stored data. */
70
- computeStats({ fromSlot, toSlot, validators, }?: {
71
- fromSlot?: bigint;
72
- toSlot?: bigint;
71
+ computeStats({ fromSlot, toSlot, validators }?: {
72
+ fromSlot?: SlotNumber;
73
+ toSlot?: SlotNumber;
73
74
  validators?: EthAddress[];
74
75
  }): Promise<ValidatorsStats>;
75
76
  /** Computes stats for a single validator. */
76
- getValidatorStats(validatorAddress: EthAddress, fromSlot?: bigint, toSlot?: bigint): Promise<SingleValidatorStats | undefined>;
77
- protected computeStatsForValidator(address: `0x${string}`, allHistory: ValidatorStatusHistory, fromSlot?: bigint, toSlot?: bigint): ValidatorStats;
77
+ getValidatorStats(validatorAddress: EthAddress, fromSlot?: SlotNumber, toSlot?: SlotNumber): Promise<SingleValidatorStats | undefined>;
78
+ protected computeStatsForValidator(address: `0x${string}`, allHistory: ValidatorStatusHistory, fromSlot?: SlotNumber, toSlot?: SlotNumber): ValidatorStats;
78
79
  protected computeMissed(history: ValidatorStatusHistory, computeOverPrefix: ValidatorStatusType | undefined, filter: ValidatorStatusInSlot[]): {
79
80
  currentStreak: number;
80
81
  rate: number | undefined;
81
82
  count: number;
82
83
  total: number;
83
84
  };
84
- protected computeFromSlot(slot: bigint | undefined): {
85
+ protected computeFromSlot(slot: SlotNumber | undefined): {
85
86
  timestamp: bigint;
86
- slot: bigint;
87
+ slot: SlotNumber;
87
88
  date: string;
88
89
  } | undefined;
89
90
  }
90
91
  export {};
91
- //# sourceMappingURL=sentinel.d.ts.map
92
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VudGluZWwuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZW50aW5lbC9zZW50aW5lbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNyRCxPQUFPLEVBQUUsV0FBVyxFQUFFLFdBQVcsRUFBRSxVQUFVLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUV2RixPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFFM0QsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBQ25FLE9BQU8sRUFBcUIsS0FBSyxXQUFXLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUM3RSxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDNUMsT0FBTyxFQUlMLEtBQUssT0FBTyxFQUNaLEtBQUssY0FBYyxFQUNwQixNQUFNLGdCQUFnQixDQUFDO0FBQ3hCLE9BQU8sS0FBSyxFQUFFLGFBQWEsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQzNELE9BQU8sRUFDTCxLQUFLLGFBQWEsRUFDbEIsYUFBYSxFQUNiLEtBQUssa0JBQWtCLEVBQ3ZCLEtBQUsseUJBQXlCLEVBRS9CLE1BQU0scUJBQXFCLENBQUM7QUFFN0IsT0FBTyxLQUFLLEVBQ1Ysb0JBQW9CLEVBQ3BCLGNBQWMsRUFDZCxzQkFBc0IsRUFDdEIscUJBQXFCLEVBQ3JCLG1CQUFtQixFQUNuQiwwQkFBMEIsRUFDMUIsZUFBZSxFQUNoQixNQUFNLDBCQUEwQixDQUFDO0FBSWxDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxZQUFZLENBQUM7O0FBRTNDLHFCQUFhLFFBQVMsU0FBUSxhQUEyQyxZQUFXLHlCQUF5QixFQUFFLE9BQU87SUFZbEgsU0FBUyxDQUFDLFVBQVUsRUFBRSxVQUFVO0lBQ2hDLFNBQVMsQ0FBQyxRQUFRLEVBQUUsYUFBYTtJQUNq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
@@ -1 +1 @@
1
- {"version":3,"file":"sentinel.d.ts","sourceRoot":"","sources":["../../src/sentinel/sentinel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sentinel.d.ts","sourceRoot":"","sources":["../../src/sentinel/sentinel.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
1
2
  import { countWhile, filterAsync, fromEntries, getEntries, mapValues } from '@aztec/foundation/collection';
2
3
  import { EthAddress } from '@aztec/foundation/eth-address';
3
4
  import { createLogger } from '@aztec/foundation/log';
@@ -19,6 +20,7 @@ export class Sentinel extends EventEmitter {
19
20
  l2TipsStore;
20
21
  initialSlot;
21
22
  lastProcessedSlot;
23
+ // eslint-disable-next-line aztec-custom/no-non-primitive-in-collections
22
24
  slotNumberToBlock;
23
25
  constructor(epochCache, archiver, p2p, store, config, logger = createLogger('node:sentinel')){
24
26
  super(), this.epochCache = epochCache, this.archiver = archiver, this.p2p = p2p, this.store = store, this.config = config, this.logger = logger, this.slotNumberToBlock = new Map();
@@ -38,7 +40,7 @@ export class Sentinel extends EventEmitter {
38
40
  }
39
41
  /** Loads initial slot and initializes blockstream. We will not process anything at or before the initial slot. */ async init() {
40
42
  this.initialSlot = this.epochCache.getEpochAndSlotNow().slot;
41
- const startingBlock = await this.archiver.getBlockNumber();
43
+ const startingBlock = BlockNumber(await this.archiver.getBlockNumber());
42
44
  this.logger.info(`Starting validator sentinel with initial slot ${this.initialSlot} and block ${startingBlock}`);
43
45
  this.blockStream = new L2BlockStream(this.archiver, this.l2TipsStore, this, this.logger, {
44
46
  startingBlock
@@ -53,7 +55,7 @@ export class Sentinel extends EventEmitter {
53
55
  // Store mapping from slot to archive, block number, and attestors
54
56
  for (const block of event.blocks){
55
57
  this.slotNumberToBlock.set(block.block.header.getSlot(), {
56
- blockNumber: block.block.number,
58
+ blockNumber: BlockNumber(block.block.number),
57
59
  archive: block.block.archive.root.toString(),
58
60
  attestors: getAttestationInfoFromPublishedL2Block(block).filter((a)=>a.status === 'recovered-from-signature').map((a)=>a.address)
59
61
  });
@@ -74,7 +76,7 @@ export class Sentinel extends EventEmitter {
74
76
  if (event.type !== 'chain-proven') {
75
77
  return;
76
78
  }
77
- const blockNumber = event.block.number;
79
+ const blockNumber = BlockNumber(event.block.number);
78
80
  const block = await this.archiver.getBlock(blockNumber);
79
81
  if (!block) {
80
82
  this.logger.error(`Failed to get block ${blockNumber}`, {
@@ -131,13 +133,15 @@ export class Sentinel extends EventEmitter {
131
133
  }
132
134
  // Get all historical performance for this validator
133
135
  const allPerformance = await this.store.getProvenPerformance(validator);
136
+ // Sort by epoch descending to get most recent first, keep only epochs strictly before the current one, and get the first N
137
+ const pastEpochs = allPerformance.sort((a, b)=>Number(b.epoch - a.epoch)).filter((p)=>p.epoch < currentEpoch);
134
138
  // If we don't have enough historical data, don't slash
135
- if (allPerformance.length < requiredConsecutiveEpochs) {
139
+ if (pastEpochs.length < requiredConsecutiveEpochs) {
136
140
  this.logger.debug(`Not enough historical data for slashing ${validator} for inactivity (${allPerformance.length} epochs < ${requiredConsecutiveEpochs} required)`);
137
141
  return false;
138
142
  }
139
- // Sort by epoch descending to get most recent first, keep only epochs strictly before the current one, and get the first N
140
- return allPerformance.sort((a, b)=>Number(b.epoch - a.epoch)).filter((p)=>p.epoch < currentEpoch).slice(0, requiredConsecutiveEpochs).every((p)=>p.missed / p.total >= this.config.slashInactivityTargetPercentage);
143
+ // Check that we have at least requiredConsecutiveEpochs and that all of them are above the inactivity threshold
144
+ return pastEpochs.slice(0, requiredConsecutiveEpochs).every((p)=>p.missed / p.total >= this.config.slashInactivityTargetPercentage);
141
145
  }
142
146
  async handleProvenPerformance(epoch, performance) {
143
147
  if (this.config.slashInactivityPenalty === 0n) {
@@ -155,7 +159,7 @@ export class Sentinel extends EventEmitter {
155
159
  validator: EthAddress.fromString(address),
156
160
  amount: this.config.slashInactivityPenalty,
157
161
  offenseType: OffenseType.INACTIVITY,
158
- epochOrSlot: epoch
162
+ epochOrSlot: BigInt(epoch)
159
163
  }));
160
164
  if (criminals.length > 0) {
161
165
  this.logger.verbose(`Identified ${criminals.length} validators to slash due to inactivity in at least ${epochThreshold} consecutive epochs`, {
@@ -190,7 +194,11 @@ export class Sentinel extends EventEmitter {
190
194
  * We also don't move past the archiver last synced L2 slot, as we don't want to process data that is not yet available.
191
195
  * Last, we check the p2p is synced with the archiver, so it has pulled all attestations from it.
192
196
  */ async isReadyToProcess(currentSlot) {
193
- const targetSlot = currentSlot - 2n;
197
+ if (currentSlot < 2) {
198
+ this.logger.trace(`Current slot ${currentSlot} too early.`);
199
+ return false;
200
+ }
201
+ const targetSlot = SlotNumber(currentSlot - 2);
194
202
  if (this.lastProcessedSlot && this.lastProcessedSlot >= targetSlot) {
195
203
  this.logger.trace(`Already processed slot ${targetSlot}`, {
196
204
  lastProcessedSlot: this.lastProcessedSlot
@@ -206,7 +214,7 @@ export class Sentinel extends EventEmitter {
206
214
  return false;
207
215
  }
208
216
  const archiverSlot = await this.archiver.getL2SlotNumber();
209
- if (archiverSlot < targetSlot) {
217
+ if (archiverSlot === undefined || archiverSlot < targetSlot) {
210
218
  this.logger.debug(`Waiting for archiver to sync with L2 slot ${targetSlot}`, {
211
219
  archiverSlot,
212
220
  targetSlot
@@ -314,7 +322,7 @@ export class Sentinel extends EventEmitter {
314
322
  await this.store.getHistory(v)
315
323
  ]))) : await this.store.getHistories();
316
324
  const slotNow = this.epochCache.getEpochAndSlotNow().slot;
317
- fromSlot ??= (this.lastProcessedSlot ?? slotNow) - BigInt(this.store.getHistoryLength());
325
+ fromSlot ??= SlotNumber(Math.max((this.lastProcessedSlot ?? slotNow) - this.store.getHistoryLength(), 0));
318
326
  toSlot ??= this.lastProcessedSlot ?? slotNow;
319
327
  const stats = mapValues(histories, (history, address)=>this.computeStatsForValidator(address, history ?? [], fromSlot, toSlot));
320
328
  return {
@@ -330,25 +338,24 @@ export class Sentinel extends EventEmitter {
330
338
  return undefined;
331
339
  }
332
340
  const slotNow = this.epochCache.getEpochAndSlotNow().slot;
333
- const effectiveFromSlot = fromSlot ?? (this.lastProcessedSlot ?? slotNow) - BigInt(this.store.getHistoryLength());
341
+ const effectiveFromSlot = fromSlot ?? SlotNumber(Math.max((this.lastProcessedSlot ?? slotNow) - this.store.getHistoryLength(), 0));
334
342
  const effectiveToSlot = toSlot ?? this.lastProcessedSlot ?? slotNow;
335
343
  const historyLength = BigInt(this.store.getHistoryLength());
336
- if (effectiveToSlot - effectiveFromSlot > historyLength) {
337
- throw new Error(`Slot range (${effectiveToSlot - effectiveFromSlot}) exceeds history length (${historyLength}). ` + `Requested range: ${effectiveFromSlot} to ${effectiveToSlot}.`);
344
+ if (BigInt(effectiveToSlot) - BigInt(effectiveFromSlot) > historyLength) {
345
+ throw new Error(`Slot range (${BigInt(effectiveToSlot) - BigInt(effectiveFromSlot)}) exceeds history length (${historyLength}). ` + `Requested range: ${effectiveFromSlot} to ${effectiveToSlot}.`);
338
346
  }
339
347
  const validator = this.computeStatsForValidator(validatorAddress.toString(), history, effectiveFromSlot, effectiveToSlot);
340
- const allTimeProvenPerformance = await this.store.getProvenPerformance(validatorAddress);
341
348
  return {
342
349
  validator,
343
- allTimeProvenPerformance,
350
+ allTimeProvenPerformance: await this.store.getProvenPerformance(validatorAddress),
344
351
  lastProcessedSlot: this.lastProcessedSlot,
345
352
  initialSlot: this.initialSlot,
346
353
  slotWindow: this.store.getHistoryLength()
347
354
  };
348
355
  }
349
356
  computeStatsForValidator(address, allHistory, fromSlot, toSlot) {
350
- let history = fromSlot ? allHistory.filter((h)=>h.slot >= fromSlot) : allHistory;
351
- history = toSlot ? history.filter((h)=>h.slot <= toSlot) : history;
357
+ let history = fromSlot ? allHistory.filter((h)=>BigInt(h.slot) >= fromSlot) : allHistory;
358
+ history = toSlot ? history.filter((h)=>BigInt(h.slot) <= toSlot) : history;
352
359
  const lastProposal = history.filter((h)=>h.status === 'block-proposed' || h.status === 'block-mined').at(-1);
353
360
  const lastAttestation = history.filter((h)=>h.status === 'attestation-sent').at(-1);
354
361
  return {