@aztec/aztec-node 0.0.1-commit.d3ec352c → 0.0.1-commit.d431d1c

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.
@@ -1,26 +1,22 @@
1
1
  import { Archiver, createArchiver } from '@aztec/archiver';
2
2
  import { BBCircuitVerifier, QueuedIVCVerifier, TestCircuitVerifier } from '@aztec/bb-prover';
3
- import { type BlobSinkClientInterface, createBlobSinkClient } from '@aztec/blob-sink/client';
3
+ import { type BlobClientInterface, createBlobClientWithFileStores } from '@aztec/blob-client/client';
4
4
  import {
5
5
  ARCHIVE_HEIGHT,
6
- INITIAL_L2_BLOCK_NUM,
7
6
  type L1_TO_L2_MSG_TREE_HEIGHT,
8
7
  type NOTE_HASH_TREE_HEIGHT,
9
8
  type NULLIFIER_TREE_HEIGHT,
10
9
  type PUBLIC_DATA_TREE_HEIGHT,
11
10
  } from '@aztec/constants';
12
11
  import { EpochCache, type EpochCacheInterface } from '@aztec/epoch-cache';
13
- import {
14
- type L1ContractAddresses,
15
- RegistryContract,
16
- RollupContract,
17
- createEthereumChain,
18
- getPublicClient,
19
- } from '@aztec/ethereum';
20
- import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
12
+ import { createEthereumChain } from '@aztec/ethereum/chain';
13
+ import { getPublicClient } from '@aztec/ethereum/client';
14
+ import { RegistryContract, RollupContract } from '@aztec/ethereum/contracts';
15
+ import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
16
+ import { BlockNumber, CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
21
17
  import { compactArray, pick } from '@aztec/foundation/collection';
18
+ import { Fr } from '@aztec/foundation/curves/bn254';
22
19
  import { EthAddress } from '@aztec/foundation/eth-address';
23
- import { Fr } from '@aztec/foundation/fields';
24
20
  import { BadRequestError } from '@aztec/foundation/json-rpc';
25
21
  import { type Logger, createLogger } from '@aztec/foundation/log';
26
22
  import { count } from '@aztec/foundation/string';
@@ -28,16 +24,13 @@ import { DateProvider, Timer } from '@aztec/foundation/timer';
28
24
  import { MembershipWitness, SiblingPath } from '@aztec/foundation/trees';
29
25
  import { KeystoreManager, loadKeystores, mergeKeystores } from '@aztec/node-keystore';
30
26
  import { trySnapshotSync, uploadSnapshot } from '@aztec/node-lib/actions';
31
- import { createL1TxUtilsWithBlobsFromEthSigner } from '@aztec/node-lib/factories';
27
+ import {
28
+ createForwarderL1TxUtilsFromEthSigner,
29
+ createL1TxUtilsWithBlobsFromEthSigner,
30
+ } from '@aztec/node-lib/factories';
32
31
  import { type P2P, type P2PClientDeps, createP2PClient, getDefaultAllowedSetupFunctions } from '@aztec/p2p';
33
32
  import { ProtocolContractAddress } from '@aztec/protocol-contracts';
34
- import {
35
- BlockBuilder,
36
- GlobalVariableBuilder,
37
- SequencerClient,
38
- type SequencerPublisher,
39
- createValidatorForAcceptingTxs,
40
- } from '@aztec/sequencer-client';
33
+ import { GlobalVariableBuilder, SequencerClient, type SequencerPublisher } from '@aztec/sequencer-client';
41
34
  import { PublicProcessorFactory } from '@aztec/simulator/server';
42
35
  import {
43
36
  AttestationsBlockWatcher,
@@ -50,12 +43,13 @@ import { CollectionLimitsConfig, PublicSimulatorConfig } from '@aztec/stdlib/avm
50
43
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
51
44
  import {
52
45
  type BlockParameter,
46
+ type CheckpointedL2Block,
53
47
  type DataInBlock,
54
- type L2Block,
55
48
  L2BlockHash,
49
+ L2BlockNew,
56
50
  type L2BlockSource,
57
- type PublishedL2Block,
58
51
  } from '@aztec/stdlib/block';
52
+ import type { PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
59
53
  import type {
60
54
  ContractClassPublic,
61
55
  ContractDataSource,
@@ -82,7 +76,7 @@ import {
82
76
  type WorldStateSynchronizer,
83
77
  tryStop,
84
78
  } from '@aztec/stdlib/interfaces/server';
85
- import type { LogFilter, PrivateLog, TxScopedL2Log } from '@aztec/stdlib/logs';
79
+ import type { LogFilter, SiloedTag, Tag, TxScopedL2Log } from '@aztec/stdlib/logs';
86
80
  import { InboxLeaf, type L1ToL2MessageSource } from '@aztec/stdlib/messaging';
87
81
  import { P2PClientType } from '@aztec/stdlib/p2p';
88
82
  import type { Offense, SlashPayloadRound } from '@aztec/stdlib/slashing';
@@ -110,10 +104,13 @@ import {
110
104
  trackSpan,
111
105
  } from '@aztec/telemetry-client';
112
106
  import {
107
+ FullNodeCheckpointsBuilder as CheckpointsBuilder,
108
+ FullNodeCheckpointsBuilder,
113
109
  NodeKeystoreAdapter,
114
110
  ValidatorClient,
115
111
  createBlockProposalHandler,
116
112
  createValidatorClient,
113
+ createValidatorForAcceptingTxs,
117
114
  } from '@aztec/validator-client';
118
115
  import { createWorldStateSynchronizer } from '@aztec/world-state';
119
116
 
@@ -129,6 +126,7 @@ import { NodeMetrics } from './node_metrics.js';
129
126
  */
130
127
  export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
131
128
  private metrics: NodeMetrics;
129
+ private initialHeaderHashPromise: Promise<L2BlockHash> | undefined = undefined;
132
130
 
133
131
  // Prevent two snapshot operations to happen simultaneously
134
132
  private isUploadingSnapshot = false;
@@ -155,6 +153,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
155
153
  private proofVerifier: ClientProtocolCircuitVerifier,
156
154
  private telemetry: TelemetryClient = getTelemetryClient(),
157
155
  private log = createLogger('node'),
156
+ private blobClient?: BlobClientInterface,
158
157
  ) {
159
158
  this.metrics = new NodeMetrics(telemetry, 'AztecNodeService');
160
159
  this.tracer = telemetry.getTracer('AztecNodeService');
@@ -184,7 +183,6 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
184
183
  logger?: Logger;
185
184
  publisher?: SequencerPublisher;
186
185
  dateProvider?: DateProvider;
187
- blobSinkClient?: BlobSinkClientInterface;
188
186
  p2pClientDeps?: P2PClientDeps<P2PClientType.Full>;
189
187
  } = {},
190
188
  options: {
@@ -197,8 +195,6 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
197
195
  const packageVersion = getPackageVersion() ?? '';
198
196
  const telemetry = deps.telemetry ?? getTelemetryClient();
199
197
  const dateProvider = deps.dateProvider ?? new DateProvider();
200
- const blobSinkClient =
201
- deps.blobSinkClient ?? createBlobSinkClient(config, { logger: createLogger('node:blob-sink:client') });
202
198
  const ethereumChain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
203
199
 
204
200
  // Build a key store from file if given or from environment otherwise
@@ -238,7 +234,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
238
234
 
239
235
  const publicClient = createPublicClient({
240
236
  chain: ethereumChain.chainInfo,
241
- transport: fallback(config.l1RpcUrls.map((url: string) => http(url))),
237
+ transport: fallback(config.l1RpcUrls.map((url: string) => http(url, { batch: false }))),
242
238
  pollingInterval: config.viemPollingIntervalMS,
243
239
  });
244
240
 
@@ -266,6 +262,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
266
262
  );
267
263
  }
268
264
 
265
+ const blobClient = await createBlobClientWithFileStores(config, createLogger('node:blob-client:client'));
266
+
269
267
  // attempt snapshot sync if possible
270
268
  await trySnapshotSync(config, log);
271
269
 
@@ -273,7 +271,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
273
271
 
274
272
  const archiver = await createArchiver(
275
273
  config,
276
- { blobSinkClient, epochCache, telemetry, dateProvider },
274
+ { blobClient, epochCache, telemetry, dateProvider },
277
275
  { blockUntilSync: !config.skipArchiverInitialSync },
278
276
  );
279
277
 
@@ -284,9 +282,10 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
284
282
  options.prefilledPublicData,
285
283
  telemetry,
286
284
  );
287
- const circuitVerifier = config.realProofs
288
- ? await BBCircuitVerifier.new(config)
289
- : new TestCircuitVerifier(config.proverTestVerificationDelayMs);
285
+ const circuitVerifier =
286
+ config.realProofs || config.debugForceTxProofVerification
287
+ ? await BBCircuitVerifier.new(config)
288
+ : new TestCircuitVerifier(config.proverTestVerificationDelayMs);
290
289
  if (!config.realProofs) {
291
290
  log.warn(`Aztec node is accepting fake proofs`);
292
291
  }
@@ -309,7 +308,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
309
308
  // We should really not be modifying the config object
310
309
  config.txPublicSetupAllowList = config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
311
310
 
312
- const blockBuilder = new BlockBuilder(
311
+ // Create FullNodeCheckpointsBuilder for validator and non-validator block proposal handling
312
+ const validatorCheckpointsBuilder = new FullNodeCheckpointsBuilder(
313
313
  { ...config, l1GenesisTime, slotDuration: Number(slotDuration) },
314
314
  worldStateSynchronizer,
315
315
  archiver,
@@ -321,15 +321,17 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
321
321
  const watchers: Watcher[] = [];
322
322
 
323
323
  // Create validator client if required
324
- const validatorClient = createValidatorClient(config, {
324
+ const validatorClient = await createValidatorClient(config, {
325
+ checkpointsBuilder: validatorCheckpointsBuilder,
326
+ worldState: worldStateSynchronizer,
325
327
  p2pClient,
326
328
  telemetry,
327
329
  dateProvider,
328
330
  epochCache,
329
- blockBuilder,
330
331
  blockSource: archiver,
331
332
  l1ToL2MessageSource: archiver,
332
333
  keyStoreManager,
334
+ blobClient,
333
335
  });
334
336
 
335
337
  // If we have a validator client, register it as a source of offenses for the slasher,
@@ -347,7 +349,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
347
349
  if (!validatorClient && config.alwaysReexecuteBlockProposals) {
348
350
  log.info('Setting up block proposal reexecution for monitoring');
349
351
  createBlockProposalHandler(config, {
350
- blockBuilder,
352
+ checkpointsBuilder: validatorCheckpointsBuilder,
353
+ worldState: worldStateSynchronizer,
351
354
  epochCache,
352
355
  blockSource: archiver,
353
356
  l1ToL2MessageSource: archiver,
@@ -375,7 +378,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
375
378
  archiver,
376
379
  epochCache,
377
380
  p2pClient.getTxProvider(),
378
- blockBuilder,
381
+ validatorCheckpointsBuilder,
379
382
  config,
380
383
  );
381
384
  watchers.push(epochPruneWatcher);
@@ -403,7 +406,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
403
406
  // Validator enabled, create/start relevant service
404
407
  let sequencer: SequencerClient | undefined;
405
408
  let slasherClient: SlasherClientInterface | undefined;
406
- if (!config.disableValidator) {
409
+ if (!config.disableValidator && validatorClient) {
407
410
  // We create a slasher only if we have a sequencer, since all slashing actions go through the sequencer publisher
408
411
  // as they are executed when the node is selected as proposer.
409
412
  const validatorAddresses = keyStoreManager
@@ -422,14 +425,30 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
422
425
  );
423
426
  await slasherClient.start();
424
427
 
425
- const l1TxUtils = await createL1TxUtilsWithBlobsFromEthSigner(
426
- publicClient,
427
- keyStoreManager!.createAllValidatorPublisherSigners(),
428
- { ...config, scope: 'sequencer' },
429
- { telemetry, logger: log.createChild('l1-tx-utils'), dateProvider },
430
- );
428
+ const l1TxUtils = config.publisherForwarderAddress
429
+ ? await createForwarderL1TxUtilsFromEthSigner(
430
+ publicClient,
431
+ keyStoreManager!.createAllValidatorPublisherSigners(),
432
+ config.publisherForwarderAddress,
433
+ { ...config, scope: 'sequencer' },
434
+ { telemetry, logger: log.createChild('l1-tx-utils'), dateProvider },
435
+ )
436
+ : await createL1TxUtilsWithBlobsFromEthSigner(
437
+ publicClient,
438
+ keyStoreManager!.createAllValidatorPublisherSigners(),
439
+ { ...config, scope: 'sequencer' },
440
+ { telemetry, logger: log.createChild('l1-tx-utils'), dateProvider },
441
+ );
431
442
 
432
443
  // Create and start the sequencer client
444
+ const checkpointsBuilder = new CheckpointsBuilder(
445
+ { ...config, l1GenesisTime, slotDuration: Number(slotDuration) },
446
+ worldStateSynchronizer,
447
+ archiver,
448
+ dateProvider,
449
+ telemetry,
450
+ );
451
+
433
452
  sequencer = await SequencerClient.new(config, {
434
453
  ...deps,
435
454
  epochCache,
@@ -438,12 +457,12 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
438
457
  p2pClient,
439
458
  worldStateSynchronizer,
440
459
  slasherClient,
441
- blockBuilder,
460
+ checkpointsBuilder,
442
461
  l2BlockSource: archiver,
443
462
  l1ToL2MessageSource: archiver,
444
463
  telemetry,
445
464
  dateProvider,
446
- blobSinkClient,
465
+ blobClient,
447
466
  nodeKeyStore: keyStoreManager!,
448
467
  });
449
468
  }
@@ -455,6 +474,13 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
455
474
  log.warn(`Sequencer created but not started`);
456
475
  }
457
476
 
477
+ const globalVariableBuilder = new GlobalVariableBuilder({
478
+ ...config,
479
+ rollupVersion: BigInt(config.rollupVersion),
480
+ l1GenesisTime,
481
+ slotDuration: Number(slotDuration),
482
+ });
483
+
458
484
  return new AztecNodeService(
459
485
  config,
460
486
  p2pClient,
@@ -469,12 +495,13 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
469
495
  epochPruneWatcher,
470
496
  ethereumChain.chainInfo.id,
471
497
  config.rollupVersion,
472
- new GlobalVariableBuilder(config),
498
+ globalVariableBuilder,
473
499
  epochCache,
474
500
  packageVersion,
475
501
  proofVerifier,
476
502
  telemetry,
477
503
  log,
504
+ blobClient,
478
505
  );
479
506
  }
480
507
 
@@ -545,13 +572,19 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
545
572
  }
546
573
 
547
574
  /**
548
- * Get a block specified by its number.
549
- * @param number - The block number being requested.
575
+ * Get a block specified by its block number, block hash, or 'latest'.
576
+ * @param block - The block parameter (block number, block hash, or 'latest').
550
577
  * @returns The requested block.
551
578
  */
552
- public async getBlock(number: BlockParameter): Promise<L2Block | undefined> {
553
- const blockNumber = number === 'latest' ? await this.getBlockNumber() : (number as BlockNumber);
554
- return await this.blockSource.getBlock(blockNumber);
579
+ public async getBlock(block: BlockParameter): Promise<L2BlockNew | undefined> {
580
+ if (L2BlockHash.isL2BlockHash(block)) {
581
+ return this.getBlockByHash(Fr.fromBuffer(block.toBuffer()));
582
+ }
583
+ const blockNumber = block === 'latest' ? await this.getBlockNumber() : (block as BlockNumber);
584
+ if (blockNumber === BlockNumber.ZERO) {
585
+ return this.buildInitialBlock();
586
+ }
587
+ return await this.blockSource.getL2BlockNew(blockNumber);
555
588
  }
556
589
 
557
590
  /**
@@ -559,9 +592,17 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
559
592
  * @param blockHash - The block hash being requested.
560
593
  * @returns The requested block.
561
594
  */
562
- public async getBlockByHash(blockHash: Fr): Promise<L2Block | undefined> {
563
- const publishedBlock = await this.blockSource.getPublishedBlockByHash(blockHash);
564
- return publishedBlock?.block;
595
+ public async getBlockByHash(blockHash: Fr): Promise<L2BlockNew | undefined> {
596
+ const initialBlockHash = await this.#getInitialHeaderHash();
597
+ if (blockHash.equals(Fr.fromBuffer(initialBlockHash.toBuffer()))) {
598
+ return this.buildInitialBlock();
599
+ }
600
+ return await this.blockSource.getL2BlockNewByHash(blockHash);
601
+ }
602
+
603
+ private buildInitialBlock(): L2BlockNew {
604
+ const initialHeader = this.worldStateSynchronizer.getCommitted().getInitialHeader();
605
+ return L2BlockNew.empty(initialHeader);
565
606
  }
566
607
 
567
608
  /**
@@ -569,9 +610,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
569
610
  * @param archive - The archive root being requested.
570
611
  * @returns The requested block.
571
612
  */
572
- public async getBlockByArchive(archive: Fr): Promise<L2Block | undefined> {
573
- const publishedBlock = await this.blockSource.getPublishedBlockByArchive(archive);
574
- return publishedBlock?.block;
613
+ public async getBlockByArchive(archive: Fr): Promise<L2BlockNew | undefined> {
614
+ return await this.blockSource.getL2BlockNewByArchive(archive);
575
615
  }
576
616
 
577
617
  /**
@@ -580,20 +620,32 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
580
620
  * @param limit - The maximum number of blocks to obtain.
581
621
  * @returns The blocks requested.
582
622
  */
583
- public async getBlocks(from: BlockNumber, limit: number): Promise<L2Block[]> {
584
- return (await this.blockSource.getBlocks(from, limit)) ?? [];
623
+ public async getBlocks(from: BlockNumber, limit: number): Promise<L2BlockNew[]> {
624
+ return (await this.blockSource.getL2BlocksNew(from, limit)) ?? [];
585
625
  }
586
626
 
587
- public async getPublishedBlocks(from: BlockNumber, limit: number): Promise<PublishedL2Block[]> {
627
+ public async getPublishedBlocks(from: BlockNumber, limit: number): Promise<CheckpointedL2Block[]> {
588
628
  return (await this.blockSource.getPublishedBlocks(from, limit)) ?? [];
589
629
  }
590
630
 
631
+ public async getPublishedCheckpoints(from: CheckpointNumber, limit: number): Promise<PublishedCheckpoint[]> {
632
+ return (await this.blockSource.getPublishedCheckpoints(from, limit)) ?? [];
633
+ }
634
+
635
+ public async getL2BlocksNew(from: BlockNumber, limit: number): Promise<L2BlockNew[]> {
636
+ return (await this.blockSource.getL2BlocksNew(from, limit)) ?? [];
637
+ }
638
+
639
+ public async getCheckpointedBlocks(from: BlockNumber, limit: number, proven?: boolean) {
640
+ return (await this.blockSource.getCheckpointedBlocks(from, limit, proven)) ?? [];
641
+ }
642
+
591
643
  /**
592
- * Method to fetch the current base fees.
593
- * @returns The current base fees.
644
+ * Method to fetch the current min L2 fees.
645
+ * @returns The current min L2 fees.
594
646
  */
595
- public async getCurrentBaseFees(): Promise<GasFees> {
596
- return await this.globalVariableBuilder.getCurrentBaseFees();
647
+ public async getCurrentMinFees(): Promise<GasFees> {
648
+ return await this.globalVariableBuilder.getCurrentMinFees();
597
649
  }
598
650
 
599
651
  public async getMaxPriorityFees(): Promise<GasFees> {
@@ -648,25 +700,16 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
648
700
  return this.contractDataSource.getContract(address);
649
701
  }
650
702
 
651
- /**
652
- * Retrieves all private logs from up to `limit` blocks, starting from the block number `from`.
653
- * @param from - The block number from which to begin retrieving logs.
654
- * @param limit - The maximum number of blocks to retrieve logs from.
655
- * @returns An array of private logs from the specified range of blocks.
656
- */
657
- public getPrivateLogs(from: BlockNumber, limit: number): Promise<PrivateLog[]> {
658
- return this.logsSource.getPrivateLogs(from, limit);
703
+ public getPrivateLogsByTags(tags: SiloedTag[], page?: number): Promise<TxScopedL2Log[][]> {
704
+ return this.logsSource.getPrivateLogsByTags(tags, page);
659
705
  }
660
706
 
661
- /**
662
- * Gets all logs that match any of the received tags (i.e. logs with their first field equal to a tag).
663
- * @param tags - The tags to filter the logs by.
664
- * @param logsPerTag - The maximum number of logs to return for each tag. By default no limit is set
665
- * @returns For each received tag, an array of matching logs is returned. An empty array implies no logs match
666
- * that tag.
667
- */
668
- public getLogsByTags(tags: Fr[], logsPerTag?: number): Promise<TxScopedL2Log[][]> {
669
- return this.logsSource.getLogsByTags(tags, logsPerTag);
707
+ public getPublicLogsByTagsFromContract(
708
+ contractAddress: AztecAddress,
709
+ tags: Tag[],
710
+ page?: number,
711
+ ): Promise<TxScopedL2Log[][]> {
712
+ return this.logsSource.getPublicLogsByTagsFromContract(contractAddress, tags, page);
670
713
  }
671
714
 
672
715
  /**
@@ -747,10 +790,19 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
747
790
  await tryStop(this.p2pClient);
748
791
  await tryStop(this.worldStateSynchronizer);
749
792
  await tryStop(this.blockSource);
793
+ await tryStop(this.blobClient);
750
794
  await tryStop(this.telemetry);
751
795
  this.log.info(`Stopped Aztec Node`);
752
796
  }
753
797
 
798
+ /**
799
+ * Returns the blob client used by this node.
800
+ * @internal - Exposed for testing purposes only.
801
+ */
802
+ public getBlobClient(): BlobClientInterface | undefined {
803
+ return this.blobClient;
804
+ }
805
+
754
806
  /**
755
807
  * Method to retrieve pending txs.
756
808
  * @param limit - The number of items to returns
@@ -783,20 +835,12 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
783
835
  return compactArray(await Promise.all(txHashes.map(txHash => this.getTxByHash(txHash))));
784
836
  }
785
837
 
786
- /**
787
- * Find the indexes of the given leaves in the given tree along with a block metadata pointing to the block in which
788
- * the leaves were inserted.
789
- * @param blockNumber - The block number at which to get the data or 'latest' for latest data.
790
- * @param treeId - The tree to search in.
791
- * @param leafValues - The values to search for.
792
- * @returns The indices of leaves and the block metadata of a block in which the leaves were inserted.
793
- */
794
838
  public async findLeavesIndexes(
795
- blockNumber: BlockParameter,
839
+ block: BlockParameter,
796
840
  treeId: MerkleTreeId,
797
841
  leafValues: Fr[],
798
842
  ): Promise<(DataInBlock<bigint> | undefined)[]> {
799
- const committedDb = await this.#getWorldState(blockNumber);
843
+ const committedDb = await this.#getWorldState(block);
800
844
  const maybeIndices = await committedDb.findLeafIndices(
801
845
  treeId,
802
846
  leafValues.map(x => x.toBuffer()),
@@ -854,39 +898,27 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
854
898
  });
855
899
  }
856
900
 
857
- /**
858
- * Returns a sibling path for the given index in the nullifier tree.
859
- * @param blockNumber - The block number at which to get the data.
860
- * @param leafIndex - The index of the leaf for which the sibling path is required.
861
- * @returns The sibling path for the leaf index.
862
- */
863
901
  public async getNullifierSiblingPath(
864
- blockNumber: BlockParameter,
902
+ block: BlockParameter,
865
903
  leafIndex: bigint,
866
904
  ): Promise<SiblingPath<typeof NULLIFIER_TREE_HEIGHT>> {
867
- const committedDb = await this.#getWorldState(blockNumber);
905
+ const committedDb = await this.#getWorldState(block);
868
906
  return committedDb.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, leafIndex);
869
907
  }
870
908
 
871
- /**
872
- * Returns a sibling path for the given index in the data tree.
873
- * @param blockNumber - The block number at which to get the data.
874
- * @param leafIndex - The index of the leaf for which the sibling path is required.
875
- * @returns The sibling path for the leaf index.
876
- */
877
909
  public async getNoteHashSiblingPath(
878
- blockNumber: BlockParameter,
910
+ block: BlockParameter,
879
911
  leafIndex: bigint,
880
912
  ): Promise<SiblingPath<typeof NOTE_HASH_TREE_HEIGHT>> {
881
- const committedDb = await this.#getWorldState(blockNumber);
913
+ const committedDb = await this.#getWorldState(block);
882
914
  return committedDb.getSiblingPath(MerkleTreeId.NOTE_HASH_TREE, leafIndex);
883
915
  }
884
916
 
885
917
  public async getArchiveMembershipWitness(
886
- blockNumber: BlockParameter,
918
+ block: BlockParameter,
887
919
  archive: Fr,
888
920
  ): Promise<MembershipWitness<typeof ARCHIVE_HEIGHT> | undefined> {
889
- const committedDb = await this.#getWorldState(blockNumber);
921
+ const committedDb = await this.#getWorldState(block);
890
922
  const [pathAndIndex] = await committedDb.findSiblingPaths<MerkleTreeId.ARCHIVE>(MerkleTreeId.ARCHIVE, [archive]);
891
923
  return pathAndIndex === undefined
892
924
  ? undefined
@@ -894,10 +926,10 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
894
926
  }
895
927
 
896
928
  public async getNoteHashMembershipWitness(
897
- blockNumber: BlockParameter,
929
+ block: BlockParameter,
898
930
  noteHash: Fr,
899
931
  ): Promise<MembershipWitness<typeof NOTE_HASH_TREE_HEIGHT> | undefined> {
900
- const committedDb = await this.#getWorldState(blockNumber);
932
+ const committedDb = await this.#getWorldState(block);
901
933
  const [pathAndIndex] = await committedDb.findSiblingPaths<MerkleTreeId.NOTE_HASH_TREE>(
902
934
  MerkleTreeId.NOTE_HASH_TREE,
903
935
  [noteHash],
@@ -907,17 +939,11 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
907
939
  : MembershipWitness.fromSiblingPath(pathAndIndex.index, pathAndIndex.path);
908
940
  }
909
941
 
910
- /**
911
- * Returns the index and a sibling path for a leaf in the committed l1 to l2 data tree.
912
- * @param blockNumber - The block number at which to get the data.
913
- * @param l1ToL2Message - The l1ToL2Message to get the index / sibling path for.
914
- * @returns A tuple of the index and the sibling path of the L1ToL2Message (undefined if not found).
915
- */
916
942
  public async getL1ToL2MessageMembershipWitness(
917
- blockNumber: BlockParameter,
943
+ block: BlockParameter,
918
944
  l1ToL2Message: Fr,
919
945
  ): Promise<[bigint, SiblingPath<typeof L1_TO_L2_MSG_TREE_HEIGHT>] | undefined> {
920
- const db = await this.#getWorldState(blockNumber);
946
+ const db = await this.#getWorldState(block);
921
947
  const [witness] = await db.findSiblingPaths(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, [l1ToL2Message]);
922
948
  if (!witness) {
923
949
  return undefined;
@@ -929,7 +955,9 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
929
955
 
930
956
  public async getL1ToL2MessageBlock(l1ToL2Message: Fr): Promise<BlockNumber | undefined> {
931
957
  const messageIndex = await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message);
932
- return messageIndex ? BlockNumber(InboxLeaf.l2BlockFromIndex(messageIndex)) : undefined;
958
+ return messageIndex
959
+ ? BlockNumber.fromCheckpointNumber(InboxLeaf.checkpointNumberFromIndex(messageIndex))
960
+ : undefined;
933
961
  }
934
962
 
935
963
  /**
@@ -943,56 +971,51 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
943
971
  }
944
972
 
945
973
  /**
946
- * Returns all the L2 to L1 messages in a block.
947
- * @param blockNumber - The block number at which to get the data.
948
- * @returns The L2 to L1 messages (undefined if the block number is not found).
974
+ * Returns all the L2 to L1 messages in an epoch.
975
+ * @param epoch - The epoch at which to get the data.
976
+ * @returns The L2 to L1 messages (empty array if the epoch is not found).
949
977
  */
950
- public async getL2ToL1Messages(blockNumber: BlockParameter): Promise<Fr[][] | undefined> {
951
- const block = await this.blockSource.getBlock(
952
- blockNumber === 'latest' ? await this.getBlockNumber() : (blockNumber as BlockNumber),
978
+ public async getL2ToL1Messages(epoch: EpochNumber): Promise<Fr[][][][]> {
979
+ // Assumes `getBlocksForEpoch` returns blocks in ascending order of block number.
980
+ const blocks = await this.blockSource.getBlocksForEpoch(epoch);
981
+ const blocksInCheckpoints: L2BlockNew[][] = [];
982
+ let previousSlotNumber = SlotNumber.ZERO;
983
+ let checkpointIndex = -1;
984
+ for (const block of blocks) {
985
+ const slotNumber = block.header.globalVariables.slotNumber;
986
+ if (slotNumber !== previousSlotNumber) {
987
+ checkpointIndex++;
988
+ blocksInCheckpoints.push([]);
989
+ previousSlotNumber = slotNumber;
990
+ }
991
+ blocksInCheckpoints[checkpointIndex].push(block);
992
+ }
993
+ return blocksInCheckpoints.map(blocks =>
994
+ blocks.map(block => block.body.txEffects.map(txEffect => txEffect.l2ToL1Msgs)),
953
995
  );
954
- return block?.body.txEffects.map(txEffect => txEffect.l2ToL1Msgs);
955
996
  }
956
997
 
957
- /**
958
- * Returns a sibling path for a leaf in the committed blocks tree.
959
- * @param blockNumber - The block number at which to get the data.
960
- * @param leafIndex - Index of the leaf in the tree.
961
- * @returns The sibling path.
962
- */
963
998
  public async getArchiveSiblingPath(
964
- blockNumber: BlockParameter,
999
+ block: BlockParameter,
965
1000
  leafIndex: bigint,
966
1001
  ): Promise<SiblingPath<typeof ARCHIVE_HEIGHT>> {
967
- const committedDb = await this.#getWorldState(blockNumber);
1002
+ const committedDb = await this.#getWorldState(block);
968
1003
  return committedDb.getSiblingPath(MerkleTreeId.ARCHIVE, leafIndex);
969
1004
  }
970
1005
 
971
- /**
972
- * Returns a sibling path for a leaf in the committed public data tree.
973
- * @param blockNumber - The block number at which to get the data.
974
- * @param leafIndex - Index of the leaf in the tree.
975
- * @returns The sibling path.
976
- */
977
1006
  public async getPublicDataSiblingPath(
978
- blockNumber: BlockParameter,
1007
+ block: BlockParameter,
979
1008
  leafIndex: bigint,
980
1009
  ): Promise<SiblingPath<typeof PUBLIC_DATA_TREE_HEIGHT>> {
981
- const committedDb = await this.#getWorldState(blockNumber);
1010
+ const committedDb = await this.#getWorldState(block);
982
1011
  return committedDb.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, leafIndex);
983
1012
  }
984
1013
 
985
- /**
986
- * Returns a nullifier membership witness for a given nullifier at a given block.
987
- * @param blockNumber - The block number at which to get the index.
988
- * @param nullifier - Nullifier we try to find witness for.
989
- * @returns The nullifier membership witness (if found).
990
- */
991
1014
  public async getNullifierMembershipWitness(
992
- blockNumber: BlockParameter,
1015
+ block: BlockParameter,
993
1016
  nullifier: Fr,
994
1017
  ): Promise<NullifierMembershipWitness | undefined> {
995
- const db = await this.#getWorldState(blockNumber);
1018
+ const db = await this.#getWorldState(block);
996
1019
  const [witness] = await db.findSiblingPaths(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]);
997
1020
  if (!witness) {
998
1021
  return undefined;
@@ -1009,7 +1032,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1009
1032
 
1010
1033
  /**
1011
1034
  * Returns a low nullifier membership witness for a given nullifier at a given block.
1012
- * @param blockNumber - The block number at which to get the index.
1035
+ * @param block - The block parameter (block number, block hash, or 'latest') at which to get the data.
1013
1036
  * @param nullifier - Nullifier we try to find the low nullifier witness for.
1014
1037
  * @returns The low nullifier membership witness (if found).
1015
1038
  * @remarks Low nullifier witness can be used to perform a nullifier non-inclusion proof by leveraging the "linked
@@ -1022,10 +1045,10 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1022
1045
  * TODO: This is a confusing behavior and we should eventually address that.
1023
1046
  */
1024
1047
  public async getLowNullifierMembershipWitness(
1025
- blockNumber: BlockParameter,
1048
+ block: BlockParameter,
1026
1049
  nullifier: Fr,
1027
1050
  ): Promise<NullifierMembershipWitness | undefined> {
1028
- const committedDb = await this.#getWorldState(blockNumber);
1051
+ const committedDb = await this.#getWorldState(block);
1029
1052
  const findResult = await committedDb.getPreviousValueIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBigInt());
1030
1053
  if (!findResult) {
1031
1054
  return undefined;
@@ -1040,8 +1063,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1040
1063
  return new NullifierMembershipWitness(BigInt(index), preimageData as NullifierLeafPreimage, siblingPath);
1041
1064
  }
1042
1065
 
1043
- async getPublicDataWitness(blockNumber: BlockParameter, leafSlot: Fr): Promise<PublicDataWitness | undefined> {
1044
- const committedDb = await this.#getWorldState(blockNumber);
1066
+ async getPublicDataWitness(block: BlockParameter, leafSlot: Fr): Promise<PublicDataWitness | undefined> {
1067
+ const committedDb = await this.#getWorldState(block);
1045
1068
  const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
1046
1069
  if (!lowLeafResult) {
1047
1070
  return undefined;
@@ -1055,19 +1078,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1055
1078
  }
1056
1079
  }
1057
1080
 
1058
- /**
1059
- * Gets the storage value at the given contract storage slot.
1060
- *
1061
- * @remarks The storage slot here refers to the slot as it is defined in Noir not the index in the merkle tree.
1062
- * Aztec's version of `eth_getStorageAt`.
1063
- *
1064
- * @param contract - Address of the contract to query.
1065
- * @param slot - Slot to query.
1066
- * @param blockNumber - The block number at which to get the data or 'latest'.
1067
- * @returns Storage value at the given contract slot.
1068
- */
1069
- public async getPublicStorageAt(blockNumber: BlockParameter, contract: AztecAddress, slot: Fr): Promise<Fr> {
1070
- const committedDb = await this.#getWorldState(blockNumber);
1081
+ public async getPublicStorageAt(block: BlockParameter, contract: AztecAddress, slot: Fr): Promise<Fr> {
1082
+ const committedDb = await this.#getWorldState(block);
1071
1083
  const leafSlot = await computePublicDataTreeLeafSlot(contract, slot);
1072
1084
 
1073
1085
  const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
@@ -1081,24 +1093,23 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1081
1093
  return preimage.leaf.value;
1082
1094
  }
1083
1095
 
1084
- /**
1085
- * Returns the currently committed block header, or the initial header if no blocks have been produced.
1086
- * @returns The current committed block header.
1087
- */
1088
- public async getBlockHeader(blockNumber: BlockParameter = 'latest'): Promise<BlockHeader | undefined> {
1089
- return blockNumber === BlockNumber.ZERO ||
1090
- (blockNumber === 'latest' && (await this.blockSource.getBlockNumber()) === BlockNumber.ZERO)
1091
- ? this.worldStateSynchronizer.getCommitted().getInitialHeader()
1092
- : this.blockSource.getBlockHeader(blockNumber === 'latest' ? blockNumber : (blockNumber as BlockNumber));
1093
- }
1094
-
1095
- /**
1096
- * Get a block header specified by its hash.
1097
- * @param blockHash - The block hash being requested.
1098
- * @returns The requested block header.
1099
- */
1100
- public async getBlockHeaderByHash(blockHash: Fr): Promise<BlockHeader | undefined> {
1101
- return await this.blockSource.getBlockHeaderByHash(blockHash);
1096
+ public async getBlockHeader(block: BlockParameter = 'latest'): Promise<BlockHeader | undefined> {
1097
+ if (L2BlockHash.isL2BlockHash(block)) {
1098
+ const initialBlockHash = await this.#getInitialHeaderHash();
1099
+ if (block.equals(initialBlockHash)) {
1100
+ // Block source doesn't handle initial header so we need to handle the case separately.
1101
+ return this.worldStateSynchronizer.getCommitted().getInitialHeader();
1102
+ }
1103
+ const blockHashFr = Fr.fromBuffer(block.toBuffer());
1104
+ return this.blockSource.getBlockHeaderByHash(blockHashFr);
1105
+ } else {
1106
+ // Block source doesn't handle initial header so we need to handle the case separately.
1107
+ const blockNumber = block === 'latest' ? await this.getBlockNumber() : (block as BlockNumber);
1108
+ if (blockNumber === BlockNumber.ZERO) {
1109
+ return this.worldStateSynchronizer.getCommitted().getInitialHeader();
1110
+ }
1111
+ return this.blockSource.getBlockHeader(block);
1112
+ }
1102
1113
  }
1103
1114
 
1104
1115
  /**
@@ -1207,7 +1218,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1207
1218
  l1ChainId: this.l1ChainId,
1208
1219
  rollupVersion: this.version,
1209
1220
  setupAllowList: this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions()),
1210
- gasFees: await this.getCurrentBaseFees(),
1221
+ gasFees: await this.getCurrentMinFees(),
1211
1222
  skipFeeEnforcement,
1212
1223
  txsPermitted: !this.config.disableTransactions,
1213
1224
  });
@@ -1279,7 +1290,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1279
1290
  }
1280
1291
 
1281
1292
  // And it has an L2 block hash
1282
- const l2BlockHash = await archiver.getL2Tips().then(tips => tips.latest.hash);
1293
+ const l2BlockHash = await archiver.getL2Tips().then(tips => tips.proposed.hash);
1283
1294
  if (!l2BlockHash) {
1284
1295
  this.metrics.recordSnapshotError();
1285
1296
  throw new Error(`Archiver has no latest L2 block hash downloaded. Cannot start snapshot.`);
@@ -1313,7 +1324,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1313
1324
  throw new Error('Archiver implementation does not support rollbacks.');
1314
1325
  }
1315
1326
 
1316
- const finalizedBlock = await archiver.getL2Tips().then(tips => tips.finalized.number);
1327
+ const finalizedBlock = await archiver.getL2Tips().then(tips => tips.finalized.block.number);
1317
1328
  if (targetBlock < finalizedBlock) {
1318
1329
  if (force) {
1319
1330
  this.log.warn(`Clearing world state database to allow rolling back behind finalized block ${finalizedBlock}`);
@@ -1374,16 +1385,23 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1374
1385
  }
1375
1386
  }
1376
1387
 
1388
+ #getInitialHeaderHash(): Promise<L2BlockHash> {
1389
+ if (!this.initialHeaderHashPromise) {
1390
+ this.initialHeaderHashPromise = this.worldStateSynchronizer
1391
+ .getCommitted()
1392
+ .getInitialHeader()
1393
+ .hash()
1394
+ .then(hash => L2BlockHash.fromField(hash));
1395
+ }
1396
+ return this.initialHeaderHashPromise;
1397
+ }
1398
+
1377
1399
  /**
1378
1400
  * Returns an instance of MerkleTreeOperations having first ensured the world state is fully synched
1379
- * @param blockNumber - The block number at which to get the data.
1401
+ * @param block - The block parameter (block number, block hash, or 'latest') at which to get the data.
1380
1402
  * @returns An instance of a committed MerkleTreeOperations
1381
1403
  */
1382
- async #getWorldState(blockNumber: BlockParameter) {
1383
- if (typeof blockNumber === 'number' && blockNumber < INITIAL_L2_BLOCK_NUM - 1) {
1384
- throw new Error('Invalid block number to get world state for: ' + blockNumber);
1385
- }
1386
-
1404
+ async #getWorldState(block: BlockParameter) {
1387
1405
  let blockSyncedTo: BlockNumber = BlockNumber.ZERO;
1388
1406
  try {
1389
1407
  // Attempt to sync the world state if necessary
@@ -1392,15 +1410,40 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1392
1410
  this.log.error(`Error getting world state: ${err}`);
1393
1411
  }
1394
1412
 
1395
- // using a snapshot could be less efficient than using the committed db
1396
- if (blockNumber === 'latest' /*|| blockNumber === blockSyncedTo*/) {
1397
- this.log.debug(`Using committed db for block ${blockNumber}, world state synced upto ${blockSyncedTo}`);
1413
+ if (block === 'latest') {
1414
+ this.log.debug(`Using committed db for block 'latest', world state synced upto ${blockSyncedTo}`);
1398
1415
  return this.worldStateSynchronizer.getCommitted();
1399
- } else if (blockNumber <= blockSyncedTo) {
1416
+ }
1417
+
1418
+ if (L2BlockHash.isL2BlockHash(block)) {
1419
+ const initialBlockHash = await this.#getInitialHeaderHash();
1420
+ if (block.equals(initialBlockHash)) {
1421
+ // Block source doesn't handle initial header so we need to handle the case separately.
1422
+ return this.worldStateSynchronizer.getSnapshot(BlockNumber.ZERO);
1423
+ }
1424
+
1425
+ const blockHashFr = Fr.fromBuffer(block.toBuffer());
1426
+ const header = await this.blockSource.getBlockHeaderByHash(blockHashFr);
1427
+ if (!header) {
1428
+ throw new Error(
1429
+ `Block hash ${block.toString()} not found when querying world state. If the node API has been queried with anchor block hash possibly a reorg has occurred.`,
1430
+ );
1431
+ }
1432
+ const blockNumber = header.getBlockNumber();
1400
1433
  this.log.debug(`Using snapshot for block ${blockNumber}, world state synced upto ${blockSyncedTo}`);
1401
- return this.worldStateSynchronizer.getSnapshot(blockNumber as BlockNumber);
1402
- } else {
1403
- throw new Error(`Block ${blockNumber} not yet synced`);
1434
+ return this.worldStateSynchronizer.getSnapshot(blockNumber);
1435
+ }
1436
+
1437
+ // Block number provided
1438
+ {
1439
+ const blockNumber = block as BlockNumber;
1440
+
1441
+ if (blockNumber > blockSyncedTo) {
1442
+ throw new Error(`Queried block ${block} not yet synced by the node (node is synced upto ${blockSyncedTo}).`);
1443
+ }
1444
+
1445
+ this.log.debug(`Using snapshot for block ${blockNumber}, world state synced upto ${blockSyncedTo}`);
1446
+ return this.worldStateSynchronizer.getSnapshot(blockNumber);
1404
1447
  }
1405
1448
  }
1406
1449