@aztec/aztec-node 0.0.1-commit.d3ec352c → 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,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,12 @@ 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[]): Promise<TxScopedL2Log[][]> {
704
+ return this.logsSource.getPrivateLogsByTags(tags);
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(contractAddress: AztecAddress, tags: Tag[]): Promise<TxScopedL2Log[][]> {
708
+ return this.logsSource.getPublicLogsByTagsFromContract(contractAddress, tags);
670
709
  }
671
710
 
672
711
  /**
@@ -747,10 +786,19 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
747
786
  await tryStop(this.p2pClient);
748
787
  await tryStop(this.worldStateSynchronizer);
749
788
  await tryStop(this.blockSource);
789
+ await tryStop(this.blobClient);
750
790
  await tryStop(this.telemetry);
751
791
  this.log.info(`Stopped Aztec Node`);
752
792
  }
753
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
+
754
802
  /**
755
803
  * Method to retrieve pending txs.
756
804
  * @param limit - The number of items to returns
@@ -783,20 +831,12 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
783
831
  return compactArray(await Promise.all(txHashes.map(txHash => this.getTxByHash(txHash))));
784
832
  }
785
833
 
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
834
  public async findLeavesIndexes(
795
- blockNumber: BlockParameter,
835
+ block: BlockParameter,
796
836
  treeId: MerkleTreeId,
797
837
  leafValues: Fr[],
798
838
  ): Promise<(DataInBlock<bigint> | undefined)[]> {
799
- const committedDb = await this.#getWorldState(blockNumber);
839
+ const committedDb = await this.#getWorldState(block);
800
840
  const maybeIndices = await committedDb.findLeafIndices(
801
841
  treeId,
802
842
  leafValues.map(x => x.toBuffer()),
@@ -854,39 +894,27 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
854
894
  });
855
895
  }
856
896
 
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
897
  public async getNullifierSiblingPath(
864
- blockNumber: BlockParameter,
898
+ block: BlockParameter,
865
899
  leafIndex: bigint,
866
900
  ): Promise<SiblingPath<typeof NULLIFIER_TREE_HEIGHT>> {
867
- const committedDb = await this.#getWorldState(blockNumber);
901
+ const committedDb = await this.#getWorldState(block);
868
902
  return committedDb.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, leafIndex);
869
903
  }
870
904
 
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
905
  public async getNoteHashSiblingPath(
878
- blockNumber: BlockParameter,
906
+ block: BlockParameter,
879
907
  leafIndex: bigint,
880
908
  ): Promise<SiblingPath<typeof NOTE_HASH_TREE_HEIGHT>> {
881
- const committedDb = await this.#getWorldState(blockNumber);
909
+ const committedDb = await this.#getWorldState(block);
882
910
  return committedDb.getSiblingPath(MerkleTreeId.NOTE_HASH_TREE, leafIndex);
883
911
  }
884
912
 
885
913
  public async getArchiveMembershipWitness(
886
- blockNumber: BlockParameter,
914
+ block: BlockParameter,
887
915
  archive: Fr,
888
916
  ): Promise<MembershipWitness<typeof ARCHIVE_HEIGHT> | undefined> {
889
- const committedDb = await this.#getWorldState(blockNumber);
917
+ const committedDb = await this.#getWorldState(block);
890
918
  const [pathAndIndex] = await committedDb.findSiblingPaths<MerkleTreeId.ARCHIVE>(MerkleTreeId.ARCHIVE, [archive]);
891
919
  return pathAndIndex === undefined
892
920
  ? undefined
@@ -894,10 +922,10 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
894
922
  }
895
923
 
896
924
  public async getNoteHashMembershipWitness(
897
- blockNumber: BlockParameter,
925
+ block: BlockParameter,
898
926
  noteHash: Fr,
899
927
  ): Promise<MembershipWitness<typeof NOTE_HASH_TREE_HEIGHT> | undefined> {
900
- const committedDb = await this.#getWorldState(blockNumber);
928
+ const committedDb = await this.#getWorldState(block);
901
929
  const [pathAndIndex] = await committedDb.findSiblingPaths<MerkleTreeId.NOTE_HASH_TREE>(
902
930
  MerkleTreeId.NOTE_HASH_TREE,
903
931
  [noteHash],
@@ -907,17 +935,11 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
907
935
  : MembershipWitness.fromSiblingPath(pathAndIndex.index, pathAndIndex.path);
908
936
  }
909
937
 
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
938
  public async getL1ToL2MessageMembershipWitness(
917
- blockNumber: BlockParameter,
939
+ block: BlockParameter,
918
940
  l1ToL2Message: Fr,
919
941
  ): Promise<[bigint, SiblingPath<typeof L1_TO_L2_MSG_TREE_HEIGHT>] | undefined> {
920
- const db = await this.#getWorldState(blockNumber);
942
+ const db = await this.#getWorldState(block);
921
943
  const [witness] = await db.findSiblingPaths(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, [l1ToL2Message]);
922
944
  if (!witness) {
923
945
  return undefined;
@@ -929,7 +951,9 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
929
951
 
930
952
  public async getL1ToL2MessageBlock(l1ToL2Message: Fr): Promise<BlockNumber | undefined> {
931
953
  const messageIndex = await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message);
932
- return messageIndex ? BlockNumber(InboxLeaf.l2BlockFromIndex(messageIndex)) : undefined;
954
+ return messageIndex
955
+ ? BlockNumber.fromCheckpointNumber(InboxLeaf.checkpointNumberFromIndex(messageIndex))
956
+ : undefined;
933
957
  }
934
958
 
935
959
  /**
@@ -943,56 +967,51 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
943
967
  }
944
968
 
945
969
  /**
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).
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).
949
973
  */
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),
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)),
953
991
  );
954
- return block?.body.txEffects.map(txEffect => txEffect.l2ToL1Msgs);
955
992
  }
956
993
 
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
994
  public async getArchiveSiblingPath(
964
- blockNumber: BlockParameter,
995
+ block: BlockParameter,
965
996
  leafIndex: bigint,
966
997
  ): Promise<SiblingPath<typeof ARCHIVE_HEIGHT>> {
967
- const committedDb = await this.#getWorldState(blockNumber);
998
+ const committedDb = await this.#getWorldState(block);
968
999
  return committedDb.getSiblingPath(MerkleTreeId.ARCHIVE, leafIndex);
969
1000
  }
970
1001
 
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
1002
  public async getPublicDataSiblingPath(
978
- blockNumber: BlockParameter,
1003
+ block: BlockParameter,
979
1004
  leafIndex: bigint,
980
1005
  ): Promise<SiblingPath<typeof PUBLIC_DATA_TREE_HEIGHT>> {
981
- const committedDb = await this.#getWorldState(blockNumber);
1006
+ const committedDb = await this.#getWorldState(block);
982
1007
  return committedDb.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, leafIndex);
983
1008
  }
984
1009
 
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
1010
  public async getNullifierMembershipWitness(
992
- blockNumber: BlockParameter,
1011
+ block: BlockParameter,
993
1012
  nullifier: Fr,
994
1013
  ): Promise<NullifierMembershipWitness | undefined> {
995
- const db = await this.#getWorldState(blockNumber);
1014
+ const db = await this.#getWorldState(block);
996
1015
  const [witness] = await db.findSiblingPaths(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]);
997
1016
  if (!witness) {
998
1017
  return undefined;
@@ -1009,7 +1028,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1009
1028
 
1010
1029
  /**
1011
1030
  * 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.
1031
+ * @param block - The block parameter (block number, block hash, or 'latest') at which to get the data.
1013
1032
  * @param nullifier - Nullifier we try to find the low nullifier witness for.
1014
1033
  * @returns The low nullifier membership witness (if found).
1015
1034
  * @remarks Low nullifier witness can be used to perform a nullifier non-inclusion proof by leveraging the "linked
@@ -1022,10 +1041,10 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1022
1041
  * TODO: This is a confusing behavior and we should eventually address that.
1023
1042
  */
1024
1043
  public async getLowNullifierMembershipWitness(
1025
- blockNumber: BlockParameter,
1044
+ block: BlockParameter,
1026
1045
  nullifier: Fr,
1027
1046
  ): Promise<NullifierMembershipWitness | undefined> {
1028
- const committedDb = await this.#getWorldState(blockNumber);
1047
+ const committedDb = await this.#getWorldState(block);
1029
1048
  const findResult = await committedDb.getPreviousValueIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBigInt());
1030
1049
  if (!findResult) {
1031
1050
  return undefined;
@@ -1040,8 +1059,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1040
1059
  return new NullifierMembershipWitness(BigInt(index), preimageData as NullifierLeafPreimage, siblingPath);
1041
1060
  }
1042
1061
 
1043
- async getPublicDataWitness(blockNumber: BlockParameter, leafSlot: Fr): Promise<PublicDataWitness | undefined> {
1044
- const committedDb = await this.#getWorldState(blockNumber);
1062
+ async getPublicDataWitness(block: BlockParameter, leafSlot: Fr): Promise<PublicDataWitness | undefined> {
1063
+ const committedDb = await this.#getWorldState(block);
1045
1064
  const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
1046
1065
  if (!lowLeafResult) {
1047
1066
  return undefined;
@@ -1055,19 +1074,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1055
1074
  }
1056
1075
  }
1057
1076
 
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);
1077
+ public async getPublicStorageAt(block: BlockParameter, contract: AztecAddress, slot: Fr): Promise<Fr> {
1078
+ const committedDb = await this.#getWorldState(block);
1071
1079
  const leafSlot = await computePublicDataTreeLeafSlot(contract, slot);
1072
1080
 
1073
1081
  const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
@@ -1081,24 +1089,23 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1081
1089
  return preimage.leaf.value;
1082
1090
  }
1083
1091
 
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);
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
+ }
1102
1109
  }
1103
1110
 
1104
1111
  /**
@@ -1207,7 +1214,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1207
1214
  l1ChainId: this.l1ChainId,
1208
1215
  rollupVersion: this.version,
1209
1216
  setupAllowList: this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions()),
1210
- gasFees: await this.getCurrentBaseFees(),
1217
+ gasFees: await this.getCurrentMinFees(),
1211
1218
  skipFeeEnforcement,
1212
1219
  txsPermitted: !this.config.disableTransactions,
1213
1220
  });
@@ -1279,7 +1286,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1279
1286
  }
1280
1287
 
1281
1288
  // And it has an L2 block hash
1282
- const l2BlockHash = await archiver.getL2Tips().then(tips => tips.latest.hash);
1289
+ const l2BlockHash = await archiver.getL2Tips().then(tips => tips.proposed.hash);
1283
1290
  if (!l2BlockHash) {
1284
1291
  this.metrics.recordSnapshotError();
1285
1292
  throw new Error(`Archiver has no latest L2 block hash downloaded. Cannot start snapshot.`);
@@ -1313,7 +1320,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1313
1320
  throw new Error('Archiver implementation does not support rollbacks.');
1314
1321
  }
1315
1322
 
1316
- const finalizedBlock = await archiver.getL2Tips().then(tips => tips.finalized.number);
1323
+ const finalizedBlock = await archiver.getL2Tips().then(tips => tips.finalized.block.number);
1317
1324
  if (targetBlock < finalizedBlock) {
1318
1325
  if (force) {
1319
1326
  this.log.warn(`Clearing world state database to allow rolling back behind finalized block ${finalizedBlock}`);
@@ -1374,16 +1381,23 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1374
1381
  }
1375
1382
  }
1376
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
+
1377
1395
  /**
1378
1396
  * 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.
1397
+ * @param block - The block parameter (block number, block hash, or 'latest') at which to get the data.
1380
1398
  * @returns An instance of a committed MerkleTreeOperations
1381
1399
  */
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
-
1400
+ async #getWorldState(block: BlockParameter) {
1387
1401
  let blockSyncedTo: BlockNumber = BlockNumber.ZERO;
1388
1402
  try {
1389
1403
  // Attempt to sync the world state if necessary
@@ -1392,15 +1406,40 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
1392
1406
  this.log.error(`Error getting world state: ${err}`);
1393
1407
  }
1394
1408
 
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}`);
1409
+ if (block === 'latest') {
1410
+ this.log.debug(`Using committed db for block 'latest', world state synced upto ${blockSyncedTo}`);
1398
1411
  return this.worldStateSynchronizer.getCommitted();
1399
- } 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();
1400
1429
  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`);
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);
1404
1443
  }
1405
1444
  }
1406
1445