@aztec/aztec-node 3.0.0-canary.a9708bd → 3.0.0-devnet.2-patch.1

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.
@@ -10,26 +10,25 @@ import {
10
10
  type PUBLIC_DATA_TREE_HEIGHT,
11
11
  } from '@aztec/constants';
12
12
  import { EpochCache, type EpochCacheInterface } from '@aztec/epoch-cache';
13
- import {
14
- type EthSigner,
15
- type L1ContractAddresses,
16
- RegistryContract,
17
- RollupContract,
18
- createEthereumChain,
19
- getPublicClient,
20
- } from '@aztec/ethereum';
21
- import { createL1TxUtilsWithBlobsFromEthSigner } from '@aztec/ethereum/l1-tx-utils-with-blobs';
13
+ import { createEthereumChain } from '@aztec/ethereum/chain';
14
+ import { getPublicClient } from '@aztec/ethereum/client';
15
+ import { RegistryContract, RollupContract } from '@aztec/ethereum/contracts';
16
+ import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
17
+ import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
22
18
  import { compactArray, pick } from '@aztec/foundation/collection';
19
+ import { Fr } from '@aztec/foundation/curves/bn254';
23
20
  import { EthAddress } from '@aztec/foundation/eth-address';
24
- import { Fr } from '@aztec/foundation/fields';
25
21
  import { BadRequestError } from '@aztec/foundation/json-rpc';
26
22
  import { type Logger, createLogger } from '@aztec/foundation/log';
27
- import { SerialQueue } from '@aztec/foundation/queue';
28
23
  import { count } from '@aztec/foundation/string';
29
24
  import { DateProvider, Timer } from '@aztec/foundation/timer';
30
25
  import { MembershipWitness, SiblingPath } from '@aztec/foundation/trees';
31
26
  import { KeystoreManager, loadKeystores, mergeKeystores } from '@aztec/node-keystore';
32
27
  import { trySnapshotSync, uploadSnapshot } from '@aztec/node-lib/actions';
28
+ import {
29
+ createForwarderL1TxUtilsFromEthSigner,
30
+ createL1TxUtilsWithBlobsFromEthSigner,
31
+ } from '@aztec/node-lib/factories';
33
32
  import { type P2P, type P2PClientDeps, createP2PClient, getDefaultAllowedSetupFunctions } from '@aztec/p2p';
34
33
  import { ProtocolContractAddress } from '@aztec/protocol-contracts';
35
34
  import {
@@ -47,12 +46,13 @@ import {
47
46
  type Watcher,
48
47
  createSlasher,
49
48
  } from '@aztec/slasher';
49
+ import { CollectionLimitsConfig, PublicSimulatorConfig } from '@aztec/stdlib/avm';
50
50
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
51
51
  import {
52
- type InBlock,
52
+ type BlockParameter,
53
+ type DataInBlock,
53
54
  type L2Block,
54
55
  L2BlockHash,
55
- type L2BlockNumber,
56
56
  type L2BlockSource,
57
57
  type PublishedL2Block,
58
58
  } from '@aztec/stdlib/block';
@@ -63,7 +63,7 @@ import type {
63
63
  NodeInfo,
64
64
  ProtocolContractAddresses,
65
65
  } from '@aztec/stdlib/contract';
66
- import type { GasFees } from '@aztec/stdlib/gas';
66
+ import { GasFees } from '@aztec/stdlib/gas';
67
67
  import { computePublicDataTreeLeafSlot } from '@aztec/stdlib/hash';
68
68
  import {
69
69
  type AztecNode,
@@ -74,6 +74,7 @@ import {
74
74
  type GetPublicLogsResponse,
75
75
  } from '@aztec/stdlib/interfaces/client';
76
76
  import {
77
+ type AllowedElement,
77
78
  type ClientProtocolCircuitVerifier,
78
79
  type L2LogsSource,
79
80
  type Service,
@@ -81,8 +82,8 @@ import {
81
82
  type WorldStateSynchronizer,
82
83
  tryStop,
83
84
  } from '@aztec/stdlib/interfaces/server';
84
- import type { LogFilter, PrivateLog, TxScopedL2Log } from '@aztec/stdlib/logs';
85
- import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
85
+ import type { LogFilter, TxScopedL2Log } from '@aztec/stdlib/logs';
86
+ import { InboxLeaf, type L1ToL2MessageSource } from '@aztec/stdlib/messaging';
86
87
  import { P2PClientType } from '@aztec/stdlib/p2p';
87
88
  import type { Offense, SlashPayloadRound } from '@aztec/stdlib/slashing';
88
89
  import type { NullifierLeafPreimage, PublicDataTreeLeaf, PublicDataTreeLeafPreimage } from '@aztec/stdlib/trees';
@@ -108,7 +109,12 @@ import {
108
109
  getTelemetryClient,
109
110
  trackSpan,
110
111
  } from '@aztec/telemetry-client';
111
- import { NodeKeystoreAdapter, ValidatorClient, createValidatorClient } from '@aztec/validator-client';
112
+ import {
113
+ NodeKeystoreAdapter,
114
+ ValidatorClient,
115
+ createBlockProposalHandler,
116
+ createValidatorClient,
117
+ } from '@aztec/validator-client';
112
118
  import { createWorldStateSynchronizer } from '@aztec/world-state';
113
119
 
114
120
  import { createPublicClient, fallback, http } from 'viem';
@@ -127,9 +133,6 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
127
133
  // Prevent two snapshot operations to happen simultaneously
128
134
  private isUploadingSnapshot = false;
129
135
 
130
- // Serial queue to ensure that we only send one tx at a time
131
- private txQueue: SerialQueue = new SerialQueue();
132
-
133
136
  public readonly tracer: Tracer;
134
137
 
135
138
  constructor(
@@ -155,7 +158,6 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
155
158
  ) {
156
159
  this.metrics = new NodeMetrics(telemetry, 'AztecNodeService');
157
160
  this.tracer = telemetry.getTracer('AztecNodeService');
158
- this.txQueue.start();
159
161
 
160
162
  this.log.info(`Aztec Node version: ${this.packageVersion}`);
161
163
  this.log.info(`Aztec Node started on chain 0x${l1ChainId.toString(16)}`, config.l1Contracts);
@@ -212,6 +214,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
212
214
  }
213
215
  }
214
216
 
217
+ await keyStoreManager?.validateSigners();
218
+
215
219
  // If we are a validator, verify our configuration before doing too much more.
216
220
  if (!config.disableValidator) {
217
221
  if (keyStoreManager === undefined) {
@@ -222,7 +226,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
222
226
  'KEY STORE CREATED FROM ENVIRONMENT, IT IS RECOMMENDED TO USE A FILE-BASED KEY STORE IN PRODUCTION ENVIRONMENTS',
223
227
  );
224
228
  }
225
- ValidatorClient.validateKeyStoreConfiguration(keyStoreManager);
229
+ ValidatorClient.validateKeyStoreConfiguration(keyStoreManager, log);
226
230
  }
227
231
 
228
232
  // validate that the actual chain id matches that specified in configuration
@@ -270,7 +274,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
270
274
  const archiver = await createArchiver(
271
275
  config,
272
276
  { blobSinkClient, epochCache, telemetry, dateProvider },
273
- { blockUntilSync: true },
277
+ { blockUntilSync: !config.skipArchiverInitialSync },
274
278
  );
275
279
 
276
280
  // now create the merkle trees and the world state synchronizer
@@ -280,7 +284,10 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
280
284
  options.prefilledPublicData,
281
285
  telemetry,
282
286
  );
283
- const circuitVerifier = config.realProofs ? await BBCircuitVerifier.new(config) : new TestCircuitVerifier();
287
+ const circuitVerifier =
288
+ config.realProofs || config.debugForceTxProofVerification
289
+ ? await BBCircuitVerifier.new(config)
290
+ : new TestCircuitVerifier(config.proverTestVerificationDelayMs);
284
291
  if (!config.realProofs) {
285
292
  log.warn(`Aztec node is accepting fake proofs`);
286
293
  }
@@ -300,12 +307,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
300
307
  deps.p2pClientDeps,
301
308
  );
302
309
 
303
- // Start world state and wait for it to sync to the archiver.
304
- await worldStateSynchronizer.start();
305
-
306
- // Start p2p. Note that it depends on world state to be running.
307
- await p2pClient.start();
308
-
310
+ // We should really not be modifying the config object
309
311
  config.txPublicSetupAllowList = config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
310
312
 
311
313
  const blockBuilder = new BlockBuilder(
@@ -316,17 +318,57 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
316
318
  telemetry,
317
319
  );
318
320
 
321
+ // We'll accumulate sentinel watchers here
319
322
  const watchers: Watcher[] = [];
320
323
 
321
- const validatorsSentinel = await createSentinel(epochCache, archiver, p2pClient, config);
322
- if (validatorsSentinel) {
323
- // we can run a sentinel without trying to slash.
324
- await validatorsSentinel.start();
325
- if (config.slashInactivityPenalty > 0n) {
326
- watchers.push(validatorsSentinel);
324
+ // Create validator client if required
325
+ const validatorClient = createValidatorClient(config, {
326
+ p2pClient,
327
+ telemetry,
328
+ dateProvider,
329
+ epochCache,
330
+ blockBuilder,
331
+ blockSource: archiver,
332
+ l1ToL2MessageSource: archiver,
333
+ keyStoreManager,
334
+ });
335
+
336
+ // If we have a validator client, register it as a source of offenses for the slasher,
337
+ // and have it register callbacks on the p2p client *before* we start it, otherwise messages
338
+ // like attestations or auths will fail.
339
+ if (validatorClient) {
340
+ watchers.push(validatorClient);
341
+ if (!options.dontStartSequencer) {
342
+ await validatorClient.registerHandlers();
327
343
  }
328
344
  }
329
345
 
346
+ // If there's no validator client but alwaysReexecuteBlockProposals is enabled,
347
+ // create a BlockProposalHandler to reexecute block proposals for monitoring
348
+ if (!validatorClient && config.alwaysReexecuteBlockProposals) {
349
+ log.info('Setting up block proposal reexecution for monitoring');
350
+ createBlockProposalHandler(config, {
351
+ blockBuilder,
352
+ epochCache,
353
+ blockSource: archiver,
354
+ l1ToL2MessageSource: archiver,
355
+ p2pClient,
356
+ dateProvider,
357
+ telemetry,
358
+ }).registerForReexecution(p2pClient);
359
+ }
360
+
361
+ // Start world state and wait for it to sync to the archiver.
362
+ await worldStateSynchronizer.start();
363
+
364
+ // Start p2p. Note that it depends on world state to be running.
365
+ await p2pClient.start();
366
+
367
+ const validatorsSentinel = await createSentinel(epochCache, archiver, p2pClient, config);
368
+ if (validatorsSentinel && config.slashInactivityPenalty > 0n) {
369
+ watchers.push(validatorsSentinel);
370
+ }
371
+
330
372
  let epochPruneWatcher: EpochPruneWatcher | undefined;
331
373
  if (config.slashPrunePenalty > 0n || config.slashDataWithholdingPenalty > 0n) {
332
374
  epochPruneWatcher = new EpochPruneWatcher(
@@ -337,7 +379,6 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
337
379
  blockBuilder,
338
380
  config,
339
381
  );
340
- await epochPruneWatcher.start();
341
382
  watchers.push(epochPruneWatcher);
342
383
  }
343
384
 
@@ -345,31 +386,24 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
345
386
  let attestationsBlockWatcher: AttestationsBlockWatcher | undefined;
346
387
  if (config.slashProposeInvalidAttestationsPenalty > 0n || config.slashAttestDescendantOfInvalidPenalty > 0n) {
347
388
  attestationsBlockWatcher = new AttestationsBlockWatcher(archiver, epochCache, config);
348
- await attestationsBlockWatcher.start();
349
389
  watchers.push(attestationsBlockWatcher);
350
390
  }
351
391
 
352
- const validatorClient = createValidatorClient(config, {
353
- p2pClient,
354
- telemetry,
355
- dateProvider,
356
- epochCache,
357
- blockBuilder,
358
- blockSource: archiver,
359
- l1ToL2MessageSource: archiver,
360
- keyStoreManager,
361
- });
362
-
363
- if (validatorClient) {
364
- watchers.push(validatorClient);
365
- }
366
-
367
- log.verbose(`All Aztec Node subsystems synced`);
392
+ // Start p2p-related services once the archiver has completed sync
393
+ void archiver
394
+ .waitForInitialSync()
395
+ .then(async () => {
396
+ await p2pClient.start();
397
+ await validatorsSentinel?.start();
398
+ await epochPruneWatcher?.start();
399
+ await attestationsBlockWatcher?.start();
400
+ log.info(`All p2p services started`);
401
+ })
402
+ .catch(err => log.error('Failed to start p2p services after archiver sync', err));
368
403
 
369
404
  // Validator enabled, create/start relevant service
370
405
  let sequencer: SequencerClient | undefined;
371
406
  let slasherClient: SlasherClientInterface | undefined;
372
-
373
407
  if (!config.disableValidator) {
374
408
  // We create a slasher only if we have a sequencer, since all slashing actions go through the sequencer publisher
375
409
  // as they are executed when the node is selected as proposer.
@@ -389,13 +423,23 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
389
423
  );
390
424
  await slasherClient.start();
391
425
 
392
- const l1TxUtils = keyStoreManager!.createAllValidatorPublisherSigners().map((signer: EthSigner) => {
393
- return createL1TxUtilsWithBlobsFromEthSigner(publicClient, signer, log, dateProvider, config);
394
- });
395
-
426
+ const l1TxUtils = config.publisherForwarderAddress
427
+ ? await createForwarderL1TxUtilsFromEthSigner(
428
+ publicClient,
429
+ keyStoreManager!.createAllValidatorPublisherSigners(),
430
+ config.publisherForwarderAddress,
431
+ { ...config, scope: 'sequencer' },
432
+ { telemetry, logger: log.createChild('l1-tx-utils'), dateProvider },
433
+ )
434
+ : await createL1TxUtilsWithBlobsFromEthSigner(
435
+ publicClient,
436
+ keyStoreManager!.createAllValidatorPublisherSigners(),
437
+ { ...config, scope: 'sequencer' },
438
+ { telemetry, logger: log.createChild('l1-tx-utils'), dateProvider },
439
+ );
440
+
441
+ // Create and start the sequencer client
396
442
  sequencer = await SequencerClient.new(config, {
397
- // if deps were provided, they should override the defaults,
398
- // or things that we created in this function
399
443
  ...deps,
400
444
  epochCache,
401
445
  l1TxUtils,
@@ -416,6 +460,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
416
460
  if (!options.dontStartSequencer && sequencer) {
417
461
  await sequencer.start();
418
462
  log.verbose(`Sequencer started`);
463
+ } else if (sequencer) {
464
+ log.warn(`Sequencer created but not started`);
419
465
  }
420
466
 
421
467
  return new AztecNodeService(
@@ -473,6 +519,10 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
473
519
  return Promise.resolve(this.p2pClient.getEnr()?.encodeTxt());
474
520
  }
475
521
 
522
+ public async getAllowedPublicSetup(): Promise<AllowedElement[]> {
523
+ return this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
524
+ }
525
+
476
526
  /**
477
527
  * Method to determine if the node is ready to accept transactions.
478
528
  * @returns - Flag indicating the readiness for tx submission.
@@ -508,8 +558,29 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
508
558
  * @param number - The block number being requested.
509
559
  * @returns The requested block.
510
560
  */
511
- public async getBlock(number: number): Promise<L2Block | undefined> {
512
- return await this.blockSource.getBlock(number);
561
+ public async getBlock(number: BlockParameter): Promise<L2Block | undefined> {
562
+ const blockNumber = number === 'latest' ? await this.getBlockNumber() : (number as BlockNumber);
563
+ return await this.blockSource.getBlock(blockNumber);
564
+ }
565
+
566
+ /**
567
+ * Get a block specified by its hash.
568
+ * @param blockHash - The block hash being requested.
569
+ * @returns The requested block.
570
+ */
571
+ public async getBlockByHash(blockHash: Fr): Promise<L2Block | undefined> {
572
+ const publishedBlock = await this.blockSource.getPublishedBlockByHash(blockHash);
573
+ return publishedBlock?.block;
574
+ }
575
+
576
+ /**
577
+ * Get a block specified by its archive root.
578
+ * @param archive - The archive root being requested.
579
+ * @returns The requested block.
580
+ */
581
+ public async getBlockByArchive(archive: Fr): Promise<L2Block | undefined> {
582
+ const publishedBlock = await this.blockSource.getPublishedBlockByArchive(archive);
583
+ return publishedBlock?.block;
513
584
  }
514
585
 
515
586
  /**
@@ -518,11 +589,11 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
518
589
  * @param limit - The maximum number of blocks to obtain.
519
590
  * @returns The blocks requested.
520
591
  */
521
- public async getBlocks(from: number, limit: number): Promise<L2Block[]> {
592
+ public async getBlocks(from: BlockNumber, limit: number): Promise<L2Block[]> {
522
593
  return (await this.blockSource.getBlocks(from, limit)) ?? [];
523
594
  }
524
595
 
525
- public async getPublishedBlocks(from: number, limit: number): Promise<PublishedL2Block[]> {
596
+ public async getPublishedBlocks(from: BlockNumber, limit: number): Promise<PublishedL2Block[]> {
526
597
  return (await this.blockSource.getPublishedBlocks(from, limit)) ?? [];
527
598
  }
528
599
 
@@ -534,15 +605,23 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
534
605
  return await this.globalVariableBuilder.getCurrentBaseFees();
535
606
  }
536
607
 
608
+ public async getMaxPriorityFees(): Promise<GasFees> {
609
+ for await (const tx of this.p2pClient.iteratePendingTxs()) {
610
+ return tx.getGasSettings().maxPriorityFeesPerGas;
611
+ }
612
+
613
+ return GasFees.from({ feePerDaGas: 0n, feePerL2Gas: 0n });
614
+ }
615
+
537
616
  /**
538
617
  * Method to fetch the latest block number synchronized by the node.
539
618
  * @returns The block number.
540
619
  */
541
- public async getBlockNumber(): Promise<number> {
620
+ public async getBlockNumber(): Promise<BlockNumber> {
542
621
  return await this.blockSource.getBlockNumber();
543
622
  }
544
623
 
545
- public async getProvenBlockNumber(): Promise<number> {
624
+ public async getProvenBlockNumber(): Promise<BlockNumber> {
546
625
  return await this.blockSource.getProvenBlockNumber();
547
626
  }
548
627
 
@@ -578,16 +657,6 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
578
657
  return this.contractDataSource.getContract(address);
579
658
  }
580
659
 
581
- /**
582
- * Retrieves all private logs from up to `limit` blocks, starting from the block number `from`.
583
- * @param from - The block number from which to begin retrieving logs.
584
- * @param limit - The maximum number of blocks to retrieve logs from.
585
- * @returns An array of private logs from the specified range of blocks.
586
- */
587
- public getPrivateLogs(from: number, limit: number): Promise<PrivateLog[]> {
588
- return this.logsSource.getPrivateLogs(from, limit);
589
- }
590
-
591
660
  /**
592
661
  * Gets all logs that match any of the received tags (i.e. logs with their first field equal to a tag).
593
662
  * @param tags - The tags to filter the logs by.
@@ -622,7 +691,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
622
691
  * @param tx - The transaction to be submitted.
623
692
  */
624
693
  public async sendTx(tx: Tx) {
625
- await this.txQueue.put(() => this.#sendTx(tx));
694
+ await this.#sendTx(tx);
626
695
  }
627
696
 
628
697
  async #sendTx(tx: Tx) {
@@ -669,7 +738,6 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
669
738
  */
670
739
  public async stop() {
671
740
  this.log.info(`Stopping Aztec Node`);
672
- await this.txQueue.end();
673
741
  await tryStop(this.validatorsSentinel);
674
742
  await tryStop(this.epochPruneWatcher);
675
743
  await tryStop(this.slasherClient);
@@ -723,10 +791,10 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
723
791
  * @returns The indices of leaves and the block metadata of a block in which the leaves were inserted.
724
792
  */
725
793
  public async findLeavesIndexes(
726
- blockNumber: L2BlockNumber,
794
+ blockNumber: BlockParameter,
727
795
  treeId: MerkleTreeId,
728
796
  leafValues: Fr[],
729
- ): Promise<(InBlock<bigint> | undefined)[]> {
797
+ ): Promise<(DataInBlock<bigint> | undefined)[]> {
730
798
  const committedDb = await this.#getWorldState(blockNumber);
731
799
  const maybeIndices = await committedDb.findLeafIndices(
732
800
  treeId,
@@ -752,7 +820,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
752
820
  // (note that block number corresponds to the leaf index in the archive tree).
753
821
  const blockHashes = await Promise.all(
754
822
  uniqueBlockNumbers.map(blockNumber => {
755
- return committedDb.getLeafValue(MerkleTreeId.ARCHIVE, blockNumber!);
823
+ return committedDb.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(blockNumber));
756
824
  }),
757
825
  );
758
826
 
@@ -763,7 +831,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
763
831
  }
764
832
  }
765
833
 
766
- // Create InBlock objects by combining indices, blockNumbers and blockHashes and return them.
834
+ // Create DataInBlock objects by combining indices, blockNumbers and blockHashes and return them.
767
835
  return maybeIndices.map((index, i) => {
768
836
  if (index === undefined) {
769
837
  return undefined;
@@ -778,7 +846,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
778
846
  return undefined;
779
847
  }
780
848
  return {
781
- l2BlockNumber: Number(blockNumber),
849
+ l2BlockNumber: BlockNumber(Number(blockNumber)),
782
850
  l2BlockHash: L2BlockHash.fromField(blockHash),
783
851
  data: index,
784
852
  };
@@ -792,7 +860,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
792
860
  * @returns The sibling path for the leaf index.
793
861
  */
794
862
  public async getNullifierSiblingPath(
795
- blockNumber: L2BlockNumber,
863
+ blockNumber: BlockParameter,
796
864
  leafIndex: bigint,
797
865
  ): Promise<SiblingPath<typeof NULLIFIER_TREE_HEIGHT>> {
798
866
  const committedDb = await this.#getWorldState(blockNumber);
@@ -806,7 +874,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
806
874
  * @returns The sibling path for the leaf index.
807
875
  */
808
876
  public async getNoteHashSiblingPath(
809
- blockNumber: L2BlockNumber,
877
+ blockNumber: BlockParameter,
810
878
  leafIndex: bigint,
811
879
  ): Promise<SiblingPath<typeof NOTE_HASH_TREE_HEIGHT>> {
812
880
  const committedDb = await this.#getWorldState(blockNumber);
@@ -814,7 +882,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
814
882
  }
815
883
 
816
884
  public async getArchiveMembershipWitness(
817
- blockNumber: L2BlockNumber,
885
+ blockNumber: BlockParameter,
818
886
  archive: Fr,
819
887
  ): Promise<MembershipWitness<typeof ARCHIVE_HEIGHT> | undefined> {
820
888
  const committedDb = await this.#getWorldState(blockNumber);
@@ -825,7 +893,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
825
893
  }
826
894
 
827
895
  public async getNoteHashMembershipWitness(
828
- blockNumber: L2BlockNumber,
896
+ blockNumber: BlockParameter,
829
897
  noteHash: Fr,
830
898
  ): Promise<MembershipWitness<typeof NOTE_HASH_TREE_HEIGHT> | undefined> {
831
899
  const committedDb = await this.#getWorldState(blockNumber);
@@ -845,7 +913,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
845
913
  * @returns A tuple of the index and the sibling path of the L1ToL2Message (undefined if not found).
846
914
  */
847
915
  public async getL1ToL2MessageMembershipWitness(
848
- blockNumber: L2BlockNumber,
916
+ blockNumber: BlockParameter,
849
917
  l1ToL2Message: Fr,
850
918
  ): Promise<[bigint, SiblingPath<typeof L1_TO_L2_MSG_TREE_HEIGHT>] | undefined> {
851
919
  const db = await this.#getWorldState(blockNumber);
@@ -858,13 +926,21 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
858
926
  return [witness.index, witness.path];
859
927
  }
860
928
 
929
+ public async getL1ToL2MessageBlock(l1ToL2Message: Fr): Promise<BlockNumber | undefined> {
930
+ const messageIndex = await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message);
931
+ return messageIndex
932
+ ? BlockNumber.fromCheckpointNumber(InboxLeaf.checkpointNumberFromIndex(messageIndex))
933
+ : undefined;
934
+ }
935
+
861
936
  /**
862
937
  * Returns whether an L1 to L2 message is synced by archiver and if it's ready to be included in a block.
863
938
  * @param l1ToL2Message - The L1 to L2 message to check.
864
939
  * @returns Whether the message is synced and ready to be included in a block.
865
940
  */
866
941
  public async isL1ToL2MessageSynced(l1ToL2Message: Fr): Promise<boolean> {
867
- return (await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message)) !== undefined;
942
+ const messageIndex = await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message);
943
+ return messageIndex !== undefined;
868
944
  }
869
945
 
870
946
  /**
@@ -872,8 +948,10 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
872
948
  * @param blockNumber - The block number at which to get the data.
873
949
  * @returns The L2 to L1 messages (undefined if the block number is not found).
874
950
  */
875
- public async getL2ToL1Messages(blockNumber: L2BlockNumber): Promise<Fr[][] | undefined> {
876
- const block = await this.blockSource.getBlock(blockNumber === 'latest' ? await this.getBlockNumber() : blockNumber);
951
+ public async getL2ToL1Messages(blockNumber: BlockParameter): Promise<Fr[][] | undefined> {
952
+ const block = await this.blockSource.getBlock(
953
+ blockNumber === 'latest' ? await this.getBlockNumber() : (blockNumber as BlockNumber),
954
+ );
877
955
  return block?.body.txEffects.map(txEffect => txEffect.l2ToL1Msgs);
878
956
  }
879
957
 
@@ -884,7 +962,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
884
962
  * @returns The sibling path.
885
963
  */
886
964
  public async getArchiveSiblingPath(
887
- blockNumber: L2BlockNumber,
965
+ blockNumber: BlockParameter,
888
966
  leafIndex: bigint,
889
967
  ): Promise<SiblingPath<typeof ARCHIVE_HEIGHT>> {
890
968
  const committedDb = await this.#getWorldState(blockNumber);
@@ -898,7 +976,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
898
976
  * @returns The sibling path.
899
977
  */
900
978
  public async getPublicDataSiblingPath(
901
- blockNumber: L2BlockNumber,
979
+ blockNumber: BlockParameter,
902
980
  leafIndex: bigint,
903
981
  ): Promise<SiblingPath<typeof PUBLIC_DATA_TREE_HEIGHT>> {
904
982
  const committedDb = await this.#getWorldState(blockNumber);
@@ -912,7 +990,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
912
990
  * @returns The nullifier membership witness (if found).
913
991
  */
914
992
  public async getNullifierMembershipWitness(
915
- blockNumber: L2BlockNumber,
993
+ blockNumber: BlockParameter,
916
994
  nullifier: Fr,
917
995
  ): Promise<NullifierMembershipWitness | undefined> {
918
996
  const db = await this.#getWorldState(blockNumber);
@@ -945,7 +1023,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
945
1023
  * TODO: This is a confusing behavior and we should eventually address that.
946
1024
  */
947
1025
  public async getLowNullifierMembershipWitness(
948
- blockNumber: L2BlockNumber,
1026
+ blockNumber: BlockParameter,
949
1027
  nullifier: Fr,
950
1028
  ): Promise<NullifierMembershipWitness | undefined> {
951
1029
  const committedDb = await this.#getWorldState(blockNumber);
@@ -963,7 +1041,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
963
1041
  return new NullifierMembershipWitness(BigInt(index), preimageData as NullifierLeafPreimage, siblingPath);
964
1042
  }
965
1043
 
966
- async getPublicDataWitness(blockNumber: L2BlockNumber, leafSlot: Fr): Promise<PublicDataWitness | undefined> {
1044
+ async getPublicDataWitness(blockNumber: BlockParameter, leafSlot: Fr): Promise<PublicDataWitness | undefined> {
967
1045
  const committedDb = await this.#getWorldState(blockNumber);
968
1046
  const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
969
1047
  if (!lowLeafResult) {
@@ -989,7 +1067,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
989
1067
  * @param blockNumber - The block number at which to get the data or 'latest'.
990
1068
  * @returns Storage value at the given contract slot.
991
1069
  */
992
- public async getPublicStorageAt(blockNumber: L2BlockNumber, contract: AztecAddress, slot: Fr): Promise<Fr> {
1070
+ public async getPublicStorageAt(blockNumber: BlockParameter, contract: AztecAddress, slot: Fr): Promise<Fr> {
993
1071
  const committedDb = await this.#getWorldState(blockNumber);
994
1072
  const leafSlot = await computePublicDataTreeLeafSlot(contract, slot);
995
1073
 
@@ -1008,10 +1086,29 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1008
1086
  * Returns the currently committed block header, or the initial header if no blocks have been produced.
1009
1087
  * @returns The current committed block header.
1010
1088
  */
1011
- public async getBlockHeader(blockNumber: L2BlockNumber = 'latest'): Promise<BlockHeader | undefined> {
1012
- return blockNumber === 0 || (blockNumber === 'latest' && (await this.blockSource.getBlockNumber()) === 0)
1089
+ public async getBlockHeader(blockNumber: BlockParameter = 'latest'): Promise<BlockHeader | undefined> {
1090
+ return blockNumber === BlockNumber.ZERO ||
1091
+ (blockNumber === 'latest' && (await this.blockSource.getBlockNumber()) === BlockNumber.ZERO)
1013
1092
  ? this.worldStateSynchronizer.getCommitted().getInitialHeader()
1014
- : this.blockSource.getBlockHeader(blockNumber);
1093
+ : this.blockSource.getBlockHeader(blockNumber === 'latest' ? blockNumber : (blockNumber as BlockNumber));
1094
+ }
1095
+
1096
+ /**
1097
+ * Get a block header specified by its hash.
1098
+ * @param blockHash - The block hash being requested.
1099
+ * @returns The requested block header.
1100
+ */
1101
+ public async getBlockHeaderByHash(blockHash: Fr): Promise<BlockHeader | undefined> {
1102
+ return await this.blockSource.getBlockHeaderByHash(blockHash);
1103
+ }
1104
+
1105
+ /**
1106
+ * Get a block header specified by its archive root.
1107
+ * @param archive - The archive root being requested.
1108
+ * @returns The requested block header.
1109
+ */
1110
+ public async getBlockHeaderByArchive(archive: Fr): Promise<BlockHeader | undefined> {
1111
+ return await this.blockSource.getBlockHeaderByArchive(archive);
1015
1112
  }
1016
1113
 
1017
1114
  /**
@@ -1037,7 +1134,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1037
1134
  }
1038
1135
 
1039
1136
  const txHash = tx.getTxHash();
1040
- const blockNumber = (await this.blockSource.getBlockNumber()) + 1;
1137
+ const blockNumber = BlockNumber((await this.blockSource.getBlockNumber()) + 1);
1041
1138
 
1042
1139
  // If sequencer is not initialized, we just set these values to zero for simulation.
1043
1140
  const coinbase = EthAddress.ZERO;
@@ -1062,12 +1159,17 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1062
1159
 
1063
1160
  const merkleTreeFork = await this.worldStateSynchronizer.fork();
1064
1161
  try {
1065
- const processor = publicProcessorFactory.create(
1066
- merkleTreeFork,
1067
- newGlobalVariables,
1162
+ const config = PublicSimulatorConfig.from({
1068
1163
  skipFeeEnforcement,
1069
- /*clientInitiatedSimulation*/ true,
1070
- );
1164
+ collectDebugLogs: true,
1165
+ collectHints: false,
1166
+ collectCallMetadata: true,
1167
+ collectStatistics: false,
1168
+ collectionLimits: CollectionLimitsConfig.from({
1169
+ maxDebugLogMemoryReads: this.config.rpcSimulatePublicMaxDebugLogMemoryReads,
1170
+ }),
1171
+ });
1172
+ const processor = publicProcessorFactory.create(merkleTreeFork, newGlobalVariables, config);
1071
1173
 
1072
1174
  // REFACTOR: Consider merging ProcessReturnValues into ProcessedTx
1073
1175
  const [processedTxs, failedTxs, _usedTxs, returns] = await processor.process([tx]);
@@ -1099,7 +1201,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1099
1201
 
1100
1202
  // We accept transactions if they are not expired by the next slot (checked based on the IncludeByTimestamp field)
1101
1203
  const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
1102
- const blockNumber = (await this.blockSource.getBlockNumber()) + 1;
1204
+ const blockNumber = BlockNumber((await this.blockSource.getBlockNumber()) + 1);
1103
1205
  const validator = createValidatorForAcceptingTxs(db, this.contractDataSource, verifier, {
1104
1206
  timestamp: nextSlotTimestamp,
1105
1207
  blockNumber,
@@ -1122,12 +1224,14 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1122
1224
 
1123
1225
  public async setConfig(config: Partial<AztecNodeAdminConfig>): Promise<void> {
1124
1226
  const newConfig = { ...this.config, ...config };
1125
- this.sequencer?.updateSequencerConfig(config);
1227
+ this.sequencer?.updateConfig(config);
1126
1228
  this.slasherClient?.updateConfig(config);
1127
1229
  this.validatorsSentinel?.updateConfig(config);
1128
- // this.blockBuilder.updateConfig(config); // TODO: Spyros has a PR to add the builder to `this`, so we can do this
1129
1230
  await this.p2pClient.updateP2PConfig(config);
1130
-
1231
+ const archiver = this.blockSource as Archiver;
1232
+ if ('updateConfig' in archiver) {
1233
+ archiver.updateConfig(config);
1234
+ }
1131
1235
  if (newConfig.realProofs !== this.config.realProofs) {
1132
1236
  this.proofVerifier = config.realProofs ? await BBCircuitVerifier.new(newConfig) : new TestCircuitVerifier();
1133
1237
  }
@@ -1154,8 +1258,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1154
1258
 
1155
1259
  public getValidatorStats(
1156
1260
  validatorAddress: EthAddress,
1157
- fromSlot?: bigint,
1158
- toSlot?: bigint,
1261
+ fromSlot?: SlotNumber,
1262
+ toSlot?: SlotNumber,
1159
1263
  ): Promise<SingleValidatorStats | undefined> {
1160
1264
  return this.validatorsSentinel?.getValidatorStats(validatorAddress, fromSlot, toSlot) ?? Promise.resolve(undefined);
1161
1265
  }
@@ -1165,39 +1269,46 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1165
1269
  // We break support for archiver running remotely to the node
1166
1270
  const archiver = this.blockSource as Archiver;
1167
1271
  if (!('backupTo' in archiver)) {
1272
+ this.metrics.recordSnapshotError();
1168
1273
  throw new Error('Archiver implementation does not support backups. Cannot generate snapshot.');
1169
1274
  }
1170
1275
 
1171
1276
  // Test that the archiver has done an initial sync.
1172
1277
  if (!archiver.isInitialSyncComplete()) {
1278
+ this.metrics.recordSnapshotError();
1173
1279
  throw new Error(`Archiver initial sync not complete. Cannot start snapshot.`);
1174
1280
  }
1175
1281
 
1176
1282
  // And it has an L2 block hash
1177
1283
  const l2BlockHash = await archiver.getL2Tips().then(tips => tips.latest.hash);
1178
1284
  if (!l2BlockHash) {
1285
+ this.metrics.recordSnapshotError();
1179
1286
  throw new Error(`Archiver has no latest L2 block hash downloaded. Cannot start snapshot.`);
1180
1287
  }
1181
1288
 
1182
1289
  if (this.isUploadingSnapshot) {
1290
+ this.metrics.recordSnapshotError();
1183
1291
  throw new Error(`Snapshot upload already in progress. Cannot start another one until complete.`);
1184
1292
  }
1185
1293
 
1186
1294
  // Do not wait for the upload to be complete to return to the caller, but flag that an operation is in progress
1187
1295
  this.isUploadingSnapshot = true;
1296
+ const timer = new Timer();
1188
1297
  void uploadSnapshot(location, this.blockSource as Archiver, this.worldStateSynchronizer, this.config, this.log)
1189
1298
  .then(() => {
1190
1299
  this.isUploadingSnapshot = false;
1300
+ this.metrics.recordSnapshot(timer.ms());
1191
1301
  })
1192
1302
  .catch(err => {
1193
1303
  this.isUploadingSnapshot = false;
1304
+ this.metrics.recordSnapshotError();
1194
1305
  this.log.error(`Error uploading snapshot: ${err}`);
1195
1306
  });
1196
1307
 
1197
1308
  return Promise.resolve();
1198
1309
  }
1199
1310
 
1200
- public async rollbackTo(targetBlock: number, force?: boolean): Promise<void> {
1311
+ public async rollbackTo(targetBlock: BlockNumber, force?: boolean): Promise<void> {
1201
1312
  const archiver = this.blockSource as Archiver;
1202
1313
  if (!('rollbackTo' in archiver)) {
1203
1314
  throw new Error('Archiver implementation does not support rollbacks.');
@@ -1269,12 +1380,12 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1269
1380
  * @param blockNumber - The block number at which to get the data.
1270
1381
  * @returns An instance of a committed MerkleTreeOperations
1271
1382
  */
1272
- async #getWorldState(blockNumber: L2BlockNumber) {
1383
+ async #getWorldState(blockNumber: BlockParameter) {
1273
1384
  if (typeof blockNumber === 'number' && blockNumber < INITIAL_L2_BLOCK_NUM - 1) {
1274
1385
  throw new Error('Invalid block number to get world state for: ' + blockNumber);
1275
1386
  }
1276
1387
 
1277
- let blockSyncedTo: number = 0;
1388
+ let blockSyncedTo: BlockNumber = BlockNumber.ZERO;
1278
1389
  try {
1279
1390
  // Attempt to sync the world state if necessary
1280
1391
  blockSyncedTo = await this.#syncWorldState();
@@ -1288,7 +1399,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1288
1399
  return this.worldStateSynchronizer.getCommitted();
1289
1400
  } else if (blockNumber <= blockSyncedTo) {
1290
1401
  this.log.debug(`Using snapshot for block ${blockNumber}, world state synced upto ${blockSyncedTo}`);
1291
- return this.worldStateSynchronizer.getSnapshot(blockNumber);
1402
+ return this.worldStateSynchronizer.getSnapshot(blockNumber as BlockNumber);
1292
1403
  } else {
1293
1404
  throw new Error(`Block ${blockNumber} not yet synced`);
1294
1405
  }
@@ -1298,8 +1409,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1298
1409
  * Ensure we fully sync the world state
1299
1410
  * @returns A promise that fulfils once the world state is synced
1300
1411
  */
1301
- async #syncWorldState(): Promise<number> {
1412
+ async #syncWorldState(): Promise<BlockNumber> {
1302
1413
  const blockSourceHeight = await this.blockSource.getBlockNumber();
1303
- return this.worldStateSynchronizer.syncImmediate(blockSourceHeight);
1414
+ return await this.worldStateSynchronizer.syncImmediate(blockSourceHeight);
1304
1415
  }
1305
1416
  }