@aztec/aztec-node 0.0.1-commit.c7c42ec → 0.0.1-commit.f295ac2

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,14 +1,8 @@
1
1
  import { Archiver, createArchiver } from '@aztec/archiver';
2
2
  import { BBCircuitVerifier, QueuedIVCVerifier, TestCircuitVerifier } from '@aztec/bb-prover';
3
- import { type BlobClientInterface, createBlobClient } from '@aztec/blob-client/client';
4
- import {
5
- type BlobFileStoreMetadata,
6
- createReadOnlyFileStoreBlobClients,
7
- createWritableFileStoreBlobClient,
8
- } from '@aztec/blob-client/filestore';
3
+ import { type BlobClientInterface, createBlobClientWithFileStores } from '@aztec/blob-client/client';
9
4
  import {
10
5
  ARCHIVE_HEIGHT,
11
- INITIAL_L2_BLOCK_NUM,
12
6
  type L1_TO_L2_MSG_TREE_HEIGHT,
13
7
  type NOTE_HASH_TREE_HEIGHT,
14
8
  type NULLIFIER_TREE_HEIGHT,
@@ -19,7 +13,7 @@ import { createEthereumChain } from '@aztec/ethereum/chain';
19
13
  import { getPublicClient } from '@aztec/ethereum/client';
20
14
  import { RegistryContract, RollupContract } from '@aztec/ethereum/contracts';
21
15
  import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
22
- import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
16
+ import { BlockNumber, CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
23
17
  import { compactArray, pick } from '@aztec/foundation/collection';
24
18
  import { Fr } from '@aztec/foundation/curves/bn254';
25
19
  import { EthAddress } from '@aztec/foundation/eth-address';
@@ -36,14 +30,7 @@ import {
36
30
  } from '@aztec/node-lib/factories';
37
31
  import { type P2P, type P2PClientDeps, createP2PClient, getDefaultAllowedSetupFunctions } from '@aztec/p2p';
38
32
  import { ProtocolContractAddress } from '@aztec/protocol-contracts';
39
- import {
40
- BlockBuilder,
41
- GlobalVariableBuilder,
42
- SequencerClient,
43
- type SequencerPublisher,
44
- createValidatorForAcceptingTxs,
45
- } from '@aztec/sequencer-client';
46
- import { CheckpointsBuilder } from '@aztec/sequencer-client';
33
+ import { GlobalVariableBuilder, SequencerClient, type SequencerPublisher } from '@aztec/sequencer-client';
47
34
  import { PublicProcessorFactory } from '@aztec/simulator/server';
48
35
  import {
49
36
  AttestationsBlockWatcher,
@@ -56,12 +43,13 @@ import { CollectionLimitsConfig, PublicSimulatorConfig } from '@aztec/stdlib/avm
56
43
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
57
44
  import {
58
45
  type BlockParameter,
46
+ type CheckpointedL2Block,
59
47
  type DataInBlock,
60
- type L2Block,
61
48
  L2BlockHash,
49
+ L2BlockNew,
62
50
  type L2BlockSource,
63
- type PublishedL2Block,
64
51
  } from '@aztec/stdlib/block';
52
+ import type { PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
65
53
  import type {
66
54
  ContractClassPublic,
67
55
  ContractDataSource,
@@ -116,10 +104,13 @@ import {
116
104
  trackSpan,
117
105
  } from '@aztec/telemetry-client';
118
106
  import {
107
+ FullNodeCheckpointsBuilder as CheckpointsBuilder,
108
+ FullNodeCheckpointsBuilder,
119
109
  NodeKeystoreAdapter,
120
110
  ValidatorClient,
121
111
  createBlockProposalHandler,
122
112
  createValidatorClient,
113
+ createValidatorForAcceptingTxs,
123
114
  } from '@aztec/validator-client';
124
115
  import { createWorldStateSynchronizer } from '@aztec/world-state';
125
116
 
@@ -135,6 +126,7 @@ import { NodeMetrics } from './node_metrics.js';
135
126
  */
136
127
  export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
137
128
  private metrics: NodeMetrics;
129
+ private initialHeaderHashPromise: Promise<L2BlockHash> | undefined = undefined;
138
130
 
139
131
  // Prevent two snapshot operations to happen simultaneously
140
132
  private isUploadingSnapshot = false;
@@ -191,7 +183,6 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
191
183
  logger?: Logger;
192
184
  publisher?: SequencerPublisher;
193
185
  dateProvider?: DateProvider;
194
- blobClient?: BlobClientInterface;
195
186
  p2pClientDeps?: P2PClientDeps<P2PClientType.Full>;
196
187
  } = {},
197
188
  options: {
@@ -271,24 +262,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
271
262
  );
272
263
  }
273
264
 
274
- const blobFileStoreMetadata: BlobFileStoreMetadata = {
275
- l1ChainId: config.l1ChainId,
276
- rollupVersion: config.rollupVersion,
277
- rollupAddress: config.l1Contracts.rollupAddress.toString(),
278
- };
279
-
280
- const [fileStoreClients, fileStoreUploadClient] = await Promise.all([
281
- createReadOnlyFileStoreBlobClients(config.blobFileStoreUrls, blobFileStoreMetadata, log),
282
- createWritableFileStoreBlobClient(config.blobFileStoreUploadUrl, blobFileStoreMetadata, log),
283
- ]);
284
-
285
- const blobClient =
286
- deps.blobClient ??
287
- createBlobClient(config, {
288
- logger: createLogger('node:blob-client:client'),
289
- fileStoreClients,
290
- fileStoreUploadClient,
291
- });
265
+ const blobClient = await createBlobClientWithFileStores(config, createLogger('node:blob-client:client'));
292
266
 
293
267
  // attempt snapshot sync if possible
294
268
  await trySnapshotSync(config, log);
@@ -334,7 +308,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
334
308
  // We should really not be modifying the config object
335
309
  config.txPublicSetupAllowList = config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
336
310
 
337
- const blockBuilder = new BlockBuilder(
311
+ // Create FullNodeCheckpointsBuilder for validator and non-validator block proposal handling
312
+ const validatorCheckpointsBuilder = new FullNodeCheckpointsBuilder(
338
313
  { ...config, l1GenesisTime, slotDuration: Number(slotDuration) },
339
314
  worldStateSynchronizer,
340
315
  archiver,
@@ -346,16 +321,17 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
346
321
  const watchers: Watcher[] = [];
347
322
 
348
323
  // Create validator client if required
349
- const validatorClient = createValidatorClient(config, {
324
+ const validatorClient = await createValidatorClient(config, {
325
+ checkpointsBuilder: validatorCheckpointsBuilder,
326
+ worldState: worldStateSynchronizer,
350
327
  p2pClient,
351
328
  telemetry,
352
329
  dateProvider,
353
330
  epochCache,
354
- blockBuilder,
355
331
  blockSource: archiver,
356
332
  l1ToL2MessageSource: archiver,
357
333
  keyStoreManager,
358
- fileStoreBlobUploadClient: fileStoreUploadClient,
334
+ blobClient,
359
335
  });
360
336
 
361
337
  // If we have a validator client, register it as a source of offenses for the slasher,
@@ -373,7 +349,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
373
349
  if (!validatorClient && config.alwaysReexecuteBlockProposals) {
374
350
  log.info('Setting up block proposal reexecution for monitoring');
375
351
  createBlockProposalHandler(config, {
376
- blockBuilder,
352
+ checkpointsBuilder: validatorCheckpointsBuilder,
353
+ worldState: worldStateSynchronizer,
377
354
  epochCache,
378
355
  blockSource: archiver,
379
356
  l1ToL2MessageSource: archiver,
@@ -401,7 +378,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
401
378
  archiver,
402
379
  epochCache,
403
380
  p2pClient.getTxProvider(),
404
- blockBuilder,
381
+ validatorCheckpointsBuilder,
405
382
  config,
406
383
  );
407
384
  watchers.push(epochPruneWatcher);
@@ -466,6 +443,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
466
443
  // Create and start the sequencer client
467
444
  const checkpointsBuilder = new CheckpointsBuilder(
468
445
  { ...config, l1GenesisTime, slotDuration: Number(slotDuration) },
446
+ worldStateSynchronizer,
469
447
  archiver,
470
448
  dateProvider,
471
449
  telemetry,
@@ -594,13 +572,19 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
594
572
  }
595
573
 
596
574
  /**
597
- * Get a block specified by its number.
598
- * @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').
599
577
  * @returns The requested block.
600
578
  */
601
- public async getBlock(number: BlockParameter): Promise<L2Block | undefined> {
602
- const blockNumber = number === 'latest' ? await this.getBlockNumber() : (number as BlockNumber);
603
- 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);
604
588
  }
605
589
 
606
590
  /**
@@ -608,9 +592,17 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
608
592
  * @param blockHash - The block hash being requested.
609
593
  * @returns The requested block.
610
594
  */
611
- public async getBlockByHash(blockHash: Fr): Promise<L2Block | undefined> {
612
- const publishedBlock = await this.blockSource.getPublishedBlockByHash(blockHash);
613
- 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);
614
606
  }
615
607
 
616
608
  /**
@@ -618,9 +610,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
618
610
  * @param archive - The archive root being requested.
619
611
  * @returns The requested block.
620
612
  */
621
- public async getBlockByArchive(archive: Fr): Promise<L2Block | undefined> {
622
- const publishedBlock = await this.blockSource.getPublishedBlockByArchive(archive);
623
- return publishedBlock?.block;
613
+ public async getBlockByArchive(archive: Fr): Promise<L2BlockNew | undefined> {
614
+ return await this.blockSource.getL2BlockNewByArchive(archive);
624
615
  }
625
616
 
626
617
  /**
@@ -629,20 +620,32 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
629
620
  * @param limit - The maximum number of blocks to obtain.
630
621
  * @returns The blocks requested.
631
622
  */
632
- public async getBlocks(from: BlockNumber, limit: number): Promise<L2Block[]> {
633
- 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)) ?? [];
634
625
  }
635
626
 
636
- public async getPublishedBlocks(from: BlockNumber, limit: number): Promise<PublishedL2Block[]> {
627
+ public async getPublishedBlocks(from: BlockNumber, limit: number): Promise<CheckpointedL2Block[]> {
637
628
  return (await this.blockSource.getPublishedBlocks(from, limit)) ?? [];
638
629
  }
639
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
+
640
643
  /**
641
- * Method to fetch the current base fees.
642
- * @returns The current base fees.
644
+ * Method to fetch the current min L2 fees.
645
+ * @returns The current min L2 fees.
643
646
  */
644
- public async getCurrentBaseFees(): Promise<GasFees> {
645
- return await this.globalVariableBuilder.getCurrentBaseFees();
647
+ public async getCurrentMinFees(): Promise<GasFees> {
648
+ return await this.globalVariableBuilder.getCurrentMinFees();
646
649
  }
647
650
 
648
651
  public async getMaxPriorityFees(): Promise<GasFees> {
@@ -788,6 +791,14 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
788
791
  this.log.info(`Stopped Aztec Node`);
789
792
  }
790
793
 
794
+ /**
795
+ * Returns the blob client used by this node.
796
+ * @internal - Exposed for testing purposes only.
797
+ */
798
+ public getBlobClient(): BlobClientInterface | undefined {
799
+ return this.blobClient;
800
+ }
801
+
791
802
  /**
792
803
  * Method to retrieve pending txs.
793
804
  * @param limit - The number of items to returns
@@ -820,20 +831,12 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
820
831
  return compactArray(await Promise.all(txHashes.map(txHash => this.getTxByHash(txHash))));
821
832
  }
822
833
 
823
- /**
824
- * Find the indexes of the given leaves in the given tree along with a block metadata pointing to the block in which
825
- * the leaves were inserted.
826
- * @param blockNumber - The block number at which to get the data or 'latest' for latest data.
827
- * @param treeId - The tree to search in.
828
- * @param leafValues - The values to search for.
829
- * @returns The indices of leaves and the block metadata of a block in which the leaves were inserted.
830
- */
831
834
  public async findLeavesIndexes(
832
- blockNumber: BlockParameter,
835
+ block: BlockParameter,
833
836
  treeId: MerkleTreeId,
834
837
  leafValues: Fr[],
835
838
  ): Promise<(DataInBlock<bigint> | undefined)[]> {
836
- const committedDb = await this.#getWorldState(blockNumber);
839
+ const committedDb = await this.#getWorldState(block);
837
840
  const maybeIndices = await committedDb.findLeafIndices(
838
841
  treeId,
839
842
  leafValues.map(x => x.toBuffer()),
@@ -891,39 +894,27 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
891
894
  });
892
895
  }
893
896
 
894
- /**
895
- * Returns a sibling path for the given index in the nullifier tree.
896
- * @param blockNumber - The block number at which to get the data.
897
- * @param leafIndex - The index of the leaf for which the sibling path is required.
898
- * @returns The sibling path for the leaf index.
899
- */
900
897
  public async getNullifierSiblingPath(
901
- blockNumber: BlockParameter,
898
+ block: BlockParameter,
902
899
  leafIndex: bigint,
903
900
  ): Promise<SiblingPath<typeof NULLIFIER_TREE_HEIGHT>> {
904
- const committedDb = await this.#getWorldState(blockNumber);
901
+ const committedDb = await this.#getWorldState(block);
905
902
  return committedDb.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, leafIndex);
906
903
  }
907
904
 
908
- /**
909
- * Returns a sibling path for the given index in the data tree.
910
- * @param blockNumber - The block number at which to get the data.
911
- * @param leafIndex - The index of the leaf for which the sibling path is required.
912
- * @returns The sibling path for the leaf index.
913
- */
914
905
  public async getNoteHashSiblingPath(
915
- blockNumber: BlockParameter,
906
+ block: BlockParameter,
916
907
  leafIndex: bigint,
917
908
  ): Promise<SiblingPath<typeof NOTE_HASH_TREE_HEIGHT>> {
918
- const committedDb = await this.#getWorldState(blockNumber);
909
+ const committedDb = await this.#getWorldState(block);
919
910
  return committedDb.getSiblingPath(MerkleTreeId.NOTE_HASH_TREE, leafIndex);
920
911
  }
921
912
 
922
913
  public async getArchiveMembershipWitness(
923
- blockNumber: BlockParameter,
914
+ block: BlockParameter,
924
915
  archive: Fr,
925
916
  ): Promise<MembershipWitness<typeof ARCHIVE_HEIGHT> | undefined> {
926
- const committedDb = await this.#getWorldState(blockNumber);
917
+ const committedDb = await this.#getWorldState(block);
927
918
  const [pathAndIndex] = await committedDb.findSiblingPaths<MerkleTreeId.ARCHIVE>(MerkleTreeId.ARCHIVE, [archive]);
928
919
  return pathAndIndex === undefined
929
920
  ? undefined
@@ -931,10 +922,10 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
931
922
  }
932
923
 
933
924
  public async getNoteHashMembershipWitness(
934
- blockNumber: BlockParameter,
925
+ block: BlockParameter,
935
926
  noteHash: Fr,
936
927
  ): Promise<MembershipWitness<typeof NOTE_HASH_TREE_HEIGHT> | undefined> {
937
- const committedDb = await this.#getWorldState(blockNumber);
928
+ const committedDb = await this.#getWorldState(block);
938
929
  const [pathAndIndex] = await committedDb.findSiblingPaths<MerkleTreeId.NOTE_HASH_TREE>(
939
930
  MerkleTreeId.NOTE_HASH_TREE,
940
931
  [noteHash],
@@ -944,17 +935,11 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
944
935
  : MembershipWitness.fromSiblingPath(pathAndIndex.index, pathAndIndex.path);
945
936
  }
946
937
 
947
- /**
948
- * Returns the index and a sibling path for a leaf in the committed l1 to l2 data tree.
949
- * @param blockNumber - The block number at which to get the data.
950
- * @param l1ToL2Message - The l1ToL2Message to get the index / sibling path for.
951
- * @returns A tuple of the index and the sibling path of the L1ToL2Message (undefined if not found).
952
- */
953
938
  public async getL1ToL2MessageMembershipWitness(
954
- blockNumber: BlockParameter,
939
+ block: BlockParameter,
955
940
  l1ToL2Message: Fr,
956
941
  ): Promise<[bigint, SiblingPath<typeof L1_TO_L2_MSG_TREE_HEIGHT>] | undefined> {
957
- const db = await this.#getWorldState(blockNumber);
942
+ const db = await this.#getWorldState(block);
958
943
  const [witness] = await db.findSiblingPaths(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, [l1ToL2Message]);
959
944
  if (!witness) {
960
945
  return undefined;
@@ -982,56 +967,51 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
982
967
  }
983
968
 
984
969
  /**
985
- * Returns all the L2 to L1 messages in a block.
986
- * @param blockNumber - The block number at which to get the data.
987
- * @returns The L2 to L1 messages (undefined if the block number is not found).
970
+ * Returns all the L2 to L1 messages in an epoch.
971
+ * @param epoch - The epoch at which to get the data.
972
+ * @returns The L2 to L1 messages (empty array if the epoch is not found).
988
973
  */
989
- public async getL2ToL1Messages(blockNumber: BlockParameter): Promise<Fr[][] | undefined> {
990
- const block = await this.blockSource.getBlock(
991
- blockNumber === 'latest' ? await this.getBlockNumber() : (blockNumber as BlockNumber),
974
+ public async getL2ToL1Messages(epoch: EpochNumber): Promise<Fr[][][][]> {
975
+ // Assumes `getBlocksForEpoch` returns blocks in ascending order of block number.
976
+ const blocks = await this.blockSource.getBlocksForEpoch(epoch);
977
+ const blocksInCheckpoints: L2BlockNew[][] = [];
978
+ let previousSlotNumber = SlotNumber.ZERO;
979
+ let checkpointIndex = -1;
980
+ for (const block of blocks) {
981
+ const slotNumber = block.header.globalVariables.slotNumber;
982
+ if (slotNumber !== previousSlotNumber) {
983
+ checkpointIndex++;
984
+ blocksInCheckpoints.push([]);
985
+ previousSlotNumber = slotNumber;
986
+ }
987
+ blocksInCheckpoints[checkpointIndex].push(block);
988
+ }
989
+ return blocksInCheckpoints.map(blocks =>
990
+ blocks.map(block => block.body.txEffects.map(txEffect => txEffect.l2ToL1Msgs)),
992
991
  );
993
- return block?.body.txEffects.map(txEffect => txEffect.l2ToL1Msgs);
994
992
  }
995
993
 
996
- /**
997
- * Returns a sibling path for a leaf in the committed blocks tree.
998
- * @param blockNumber - The block number at which to get the data.
999
- * @param leafIndex - Index of the leaf in the tree.
1000
- * @returns The sibling path.
1001
- */
1002
994
  public async getArchiveSiblingPath(
1003
- blockNumber: BlockParameter,
995
+ block: BlockParameter,
1004
996
  leafIndex: bigint,
1005
997
  ): Promise<SiblingPath<typeof ARCHIVE_HEIGHT>> {
1006
- const committedDb = await this.#getWorldState(blockNumber);
998
+ const committedDb = await this.#getWorldState(block);
1007
999
  return committedDb.getSiblingPath(MerkleTreeId.ARCHIVE, leafIndex);
1008
1000
  }
1009
1001
 
1010
- /**
1011
- * Returns a sibling path for a leaf in the committed public data tree.
1012
- * @param blockNumber - The block number at which to get the data.
1013
- * @param leafIndex - Index of the leaf in the tree.
1014
- * @returns The sibling path.
1015
- */
1016
1002
  public async getPublicDataSiblingPath(
1017
- blockNumber: BlockParameter,
1003
+ block: BlockParameter,
1018
1004
  leafIndex: bigint,
1019
1005
  ): Promise<SiblingPath<typeof PUBLIC_DATA_TREE_HEIGHT>> {
1020
- const committedDb = await this.#getWorldState(blockNumber);
1006
+ const committedDb = await this.#getWorldState(block);
1021
1007
  return committedDb.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, leafIndex);
1022
1008
  }
1023
1009
 
1024
- /**
1025
- * Returns a nullifier membership witness for a given nullifier at a given block.
1026
- * @param blockNumber - The block number at which to get the index.
1027
- * @param nullifier - Nullifier we try to find witness for.
1028
- * @returns The nullifier membership witness (if found).
1029
- */
1030
1010
  public async getNullifierMembershipWitness(
1031
- blockNumber: BlockParameter,
1011
+ block: BlockParameter,
1032
1012
  nullifier: Fr,
1033
1013
  ): Promise<NullifierMembershipWitness | undefined> {
1034
- const db = await this.#getWorldState(blockNumber);
1014
+ const db = await this.#getWorldState(block);
1035
1015
  const [witness] = await db.findSiblingPaths(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]);
1036
1016
  if (!witness) {
1037
1017
  return undefined;
@@ -1048,7 +1028,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1048
1028
 
1049
1029
  /**
1050
1030
  * Returns a low nullifier membership witness for a given nullifier at a given block.
1051
- * @param blockNumber - The block number at which to get the index.
1031
+ * @param block - The block parameter (block number, block hash, or 'latest') at which to get the data.
1052
1032
  * @param nullifier - Nullifier we try to find the low nullifier witness for.
1053
1033
  * @returns The low nullifier membership witness (if found).
1054
1034
  * @remarks Low nullifier witness can be used to perform a nullifier non-inclusion proof by leveraging the "linked
@@ -1061,10 +1041,10 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1061
1041
  * TODO: This is a confusing behavior and we should eventually address that.
1062
1042
  */
1063
1043
  public async getLowNullifierMembershipWitness(
1064
- blockNumber: BlockParameter,
1044
+ block: BlockParameter,
1065
1045
  nullifier: Fr,
1066
1046
  ): Promise<NullifierMembershipWitness | undefined> {
1067
- const committedDb = await this.#getWorldState(blockNumber);
1047
+ const committedDb = await this.#getWorldState(block);
1068
1048
  const findResult = await committedDb.getPreviousValueIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBigInt());
1069
1049
  if (!findResult) {
1070
1050
  return undefined;
@@ -1079,8 +1059,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1079
1059
  return new NullifierMembershipWitness(BigInt(index), preimageData as NullifierLeafPreimage, siblingPath);
1080
1060
  }
1081
1061
 
1082
- async getPublicDataWitness(blockNumber: BlockParameter, leafSlot: Fr): Promise<PublicDataWitness | undefined> {
1083
- const committedDb = await this.#getWorldState(blockNumber);
1062
+ async getPublicDataWitness(block: BlockParameter, leafSlot: Fr): Promise<PublicDataWitness | undefined> {
1063
+ const committedDb = await this.#getWorldState(block);
1084
1064
  const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
1085
1065
  if (!lowLeafResult) {
1086
1066
  return undefined;
@@ -1094,19 +1074,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1094
1074
  }
1095
1075
  }
1096
1076
 
1097
- /**
1098
- * Gets the storage value at the given contract storage slot.
1099
- *
1100
- * @remarks The storage slot here refers to the slot as it is defined in Noir not the index in the merkle tree.
1101
- * Aztec's version of `eth_getStorageAt`.
1102
- *
1103
- * @param contract - Address of the contract to query.
1104
- * @param slot - Slot to query.
1105
- * @param blockNumber - The block number at which to get the data or 'latest'.
1106
- * @returns Storage value at the given contract slot.
1107
- */
1108
- public async getPublicStorageAt(blockNumber: BlockParameter, contract: AztecAddress, slot: Fr): Promise<Fr> {
1109
- const committedDb = await this.#getWorldState(blockNumber);
1077
+ public async getPublicStorageAt(block: BlockParameter, contract: AztecAddress, slot: Fr): Promise<Fr> {
1078
+ const committedDb = await this.#getWorldState(block);
1110
1079
  const leafSlot = await computePublicDataTreeLeafSlot(contract, slot);
1111
1080
 
1112
1081
  const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
@@ -1120,24 +1089,23 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1120
1089
  return preimage.leaf.value;
1121
1090
  }
1122
1091
 
1123
- /**
1124
- * Returns the currently committed block header, or the initial header if no blocks have been produced.
1125
- * @returns The current committed block header.
1126
- */
1127
- public async getBlockHeader(blockNumber: BlockParameter = 'latest'): Promise<BlockHeader | undefined> {
1128
- return blockNumber === BlockNumber.ZERO ||
1129
- (blockNumber === 'latest' && (await this.blockSource.getBlockNumber()) === BlockNumber.ZERO)
1130
- ? this.worldStateSynchronizer.getCommitted().getInitialHeader()
1131
- : this.blockSource.getBlockHeader(blockNumber === 'latest' ? blockNumber : (blockNumber as BlockNumber));
1132
- }
1133
-
1134
- /**
1135
- * Get a block header specified by its hash.
1136
- * @param blockHash - The block hash being requested.
1137
- * @returns The requested block header.
1138
- */
1139
- public async getBlockHeaderByHash(blockHash: Fr): Promise<BlockHeader | undefined> {
1140
- return await this.blockSource.getBlockHeaderByHash(blockHash);
1092
+ public async getBlockHeader(block: BlockParameter = 'latest'): Promise<BlockHeader | undefined> {
1093
+ if (L2BlockHash.isL2BlockHash(block)) {
1094
+ const initialBlockHash = await this.#getInitialHeaderHash();
1095
+ if (block.equals(initialBlockHash)) {
1096
+ // Block source doesn't handle initial header so we need to handle the case separately.
1097
+ return this.worldStateSynchronizer.getCommitted().getInitialHeader();
1098
+ }
1099
+ const blockHashFr = Fr.fromBuffer(block.toBuffer());
1100
+ return this.blockSource.getBlockHeaderByHash(blockHashFr);
1101
+ } else {
1102
+ // Block source doesn't handle initial header so we need to handle the case separately.
1103
+ const blockNumber = block === 'latest' ? await this.getBlockNumber() : (block as BlockNumber);
1104
+ if (blockNumber === BlockNumber.ZERO) {
1105
+ return this.worldStateSynchronizer.getCommitted().getInitialHeader();
1106
+ }
1107
+ return this.blockSource.getBlockHeader(block);
1108
+ }
1141
1109
  }
1142
1110
 
1143
1111
  /**
@@ -1246,7 +1214,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1246
1214
  l1ChainId: this.l1ChainId,
1247
1215
  rollupVersion: this.version,
1248
1216
  setupAllowList: this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions()),
1249
- gasFees: await this.getCurrentBaseFees(),
1217
+ gasFees: await this.getCurrentMinFees(),
1250
1218
  skipFeeEnforcement,
1251
1219
  txsPermitted: !this.config.disableTransactions,
1252
1220
  });
@@ -1318,7 +1286,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1318
1286
  }
1319
1287
 
1320
1288
  // And it has an L2 block hash
1321
- const l2BlockHash = await archiver.getL2Tips().then(tips => tips.latest.hash);
1289
+ const l2BlockHash = await archiver.getL2Tips().then(tips => tips.proposed.hash);
1322
1290
  if (!l2BlockHash) {
1323
1291
  this.metrics.recordSnapshotError();
1324
1292
  throw new Error(`Archiver has no latest L2 block hash downloaded. Cannot start snapshot.`);
@@ -1352,7 +1320,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1352
1320
  throw new Error('Archiver implementation does not support rollbacks.');
1353
1321
  }
1354
1322
 
1355
- const finalizedBlock = await archiver.getL2Tips().then(tips => tips.finalized.number);
1323
+ const finalizedBlock = await archiver.getL2Tips().then(tips => tips.finalized.block.number);
1356
1324
  if (targetBlock < finalizedBlock) {
1357
1325
  if (force) {
1358
1326
  this.log.warn(`Clearing world state database to allow rolling back behind finalized block ${finalizedBlock}`);
@@ -1413,16 +1381,23 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1413
1381
  }
1414
1382
  }
1415
1383
 
1384
+ #getInitialHeaderHash(): Promise<L2BlockHash> {
1385
+ if (!this.initialHeaderHashPromise) {
1386
+ this.initialHeaderHashPromise = this.worldStateSynchronizer
1387
+ .getCommitted()
1388
+ .getInitialHeader()
1389
+ .hash()
1390
+ .then(hash => L2BlockHash.fromField(hash));
1391
+ }
1392
+ return this.initialHeaderHashPromise;
1393
+ }
1394
+
1416
1395
  /**
1417
1396
  * Returns an instance of MerkleTreeOperations having first ensured the world state is fully synched
1418
- * @param blockNumber - The block number at which to get the data.
1397
+ * @param block - The block parameter (block number, block hash, or 'latest') at which to get the data.
1419
1398
  * @returns An instance of a committed MerkleTreeOperations
1420
1399
  */
1421
- async #getWorldState(blockNumber: BlockParameter) {
1422
- if (typeof blockNumber === 'number' && blockNumber < INITIAL_L2_BLOCK_NUM - 1) {
1423
- throw new Error('Invalid block number to get world state for: ' + blockNumber);
1424
- }
1425
-
1400
+ async #getWorldState(block: BlockParameter) {
1426
1401
  let blockSyncedTo: BlockNumber = BlockNumber.ZERO;
1427
1402
  try {
1428
1403
  // Attempt to sync the world state if necessary
@@ -1431,15 +1406,40 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1431
1406
  this.log.error(`Error getting world state: ${err}`);
1432
1407
  }
1433
1408
 
1434
- // using a snapshot could be less efficient than using the committed db
1435
- if (blockNumber === 'latest' /*|| blockNumber === blockSyncedTo*/) {
1436
- this.log.debug(`Using committed db for block ${blockNumber}, world state synced upto ${blockSyncedTo}`);
1409
+ if (block === 'latest') {
1410
+ this.log.debug(`Using committed db for block 'latest', world state synced upto ${blockSyncedTo}`);
1437
1411
  return this.worldStateSynchronizer.getCommitted();
1438
- } else if (blockNumber <= blockSyncedTo) {
1412
+ }
1413
+
1414
+ if (L2BlockHash.isL2BlockHash(block)) {
1415
+ const initialBlockHash = await this.#getInitialHeaderHash();
1416
+ if (block.equals(initialBlockHash)) {
1417
+ // Block source doesn't handle initial header so we need to handle the case separately.
1418
+ return this.worldStateSynchronizer.getSnapshot(BlockNumber.ZERO);
1419
+ }
1420
+
1421
+ const blockHashFr = Fr.fromBuffer(block.toBuffer());
1422
+ const header = await this.blockSource.getBlockHeaderByHash(blockHashFr);
1423
+ if (!header) {
1424
+ throw new Error(
1425
+ `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.`,
1426
+ );
1427
+ }
1428
+ const blockNumber = header.getBlockNumber();
1439
1429
  this.log.debug(`Using snapshot for block ${blockNumber}, world state synced upto ${blockSyncedTo}`);
1440
- return this.worldStateSynchronizer.getSnapshot(blockNumber as BlockNumber);
1441
- } else {
1442
- throw new Error(`Block ${blockNumber} not yet synced`);
1430
+ return this.worldStateSynchronizer.getSnapshot(blockNumber);
1431
+ }
1432
+
1433
+ // Block number provided
1434
+ {
1435
+ const blockNumber = block as BlockNumber;
1436
+
1437
+ if (blockNumber > blockSyncedTo) {
1438
+ throw new Error(`Queried block ${block} not yet synced by the node (node is synced upto ${blockSyncedTo}).`);
1439
+ }
1440
+
1441
+ this.log.debug(`Using snapshot for block ${blockNumber}, world state synced upto ${blockSyncedTo}`);
1442
+ return this.worldStateSynchronizer.getSnapshot(blockNumber);
1443
1443
  }
1444
1444
  }
1445
1445