@aztec/aztec-node 0.0.1-commit.cd76b27 → 0.0.1-commit.ce4f8c4f2
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.
- package/dest/aztec-node/config.d.ts +2 -2
- package/dest/aztec-node/config.d.ts.map +1 -1
- package/dest/aztec-node/config.js +1 -1
- package/dest/aztec-node/server.d.ts +22 -22
- package/dest/aztec-node/server.d.ts.map +1 -1
- package/dest/aztec-node/server.js +277 -163
- package/dest/sentinel/factory.d.ts +2 -2
- package/dest/sentinel/factory.d.ts.map +1 -1
- package/dest/sentinel/sentinel.js +8 -8
- package/package.json +26 -27
- package/src/aztec-node/config.ts +1 -1
- package/src/aztec-node/server.ts +303 -170
- package/src/sentinel/factory.ts +1 -1
- package/src/sentinel/sentinel.ts +8 -8
|
@@ -372,15 +372,16 @@ function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
|
|
|
372
372
|
}
|
|
373
373
|
var _dec, _initProto;
|
|
374
374
|
import { createArchiver } from '@aztec/archiver';
|
|
375
|
-
import { BBCircuitVerifier,
|
|
375
|
+
import { BBCircuitVerifier, BatchChonkVerifier, QueuedIVCVerifier } from '@aztec/bb-prover';
|
|
376
|
+
import { TestCircuitVerifier } from '@aztec/bb-prover/test';
|
|
376
377
|
import { createBlobClientWithFileStores } from '@aztec/blob-client/client';
|
|
377
378
|
import { Blob } from '@aztec/blob-lib';
|
|
378
379
|
import { EpochCache } from '@aztec/epoch-cache';
|
|
379
380
|
import { createEthereumChain } from '@aztec/ethereum/chain';
|
|
380
|
-
import { getPublicClient } from '@aztec/ethereum/client';
|
|
381
|
+
import { getPublicClient, makeL1HttpTransport } from '@aztec/ethereum/client';
|
|
381
382
|
import { RegistryContract, RollupContract } from '@aztec/ethereum/contracts';
|
|
382
|
-
import { BlockNumber
|
|
383
|
-
import { compactArray, pick, unique } from '@aztec/foundation/collection';
|
|
383
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
384
|
+
import { chunkBy, compactArray, pick, unique } from '@aztec/foundation/collection';
|
|
384
385
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
385
386
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
386
387
|
import { BadRequestError } from '@aztec/foundation/json-rpc';
|
|
@@ -391,7 +392,7 @@ import { MembershipWitness } from '@aztec/foundation/trees';
|
|
|
391
392
|
import { KeystoreManager, loadKeystores, mergeKeystores } from '@aztec/node-keystore';
|
|
392
393
|
import { trySnapshotSync, uploadSnapshot } from '@aztec/node-lib/actions';
|
|
393
394
|
import { createForwarderL1TxUtilsFromSigners, createL1TxUtilsFromSigners } from '@aztec/node-lib/factories';
|
|
394
|
-
import { createP2PClient, getDefaultAllowedSetupFunctions } from '@aztec/p2p';
|
|
395
|
+
import { createP2PClient, createTxValidatorForAcceptingTxsOverRPC, getDefaultAllowedSetupFunctions } from '@aztec/p2p';
|
|
395
396
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
396
397
|
import { createProverNode } from '@aztec/prover-node';
|
|
397
398
|
import { createKeyStoreForProver } from '@aztec/prover-node/config';
|
|
@@ -405,15 +406,15 @@ import { GasFees } from '@aztec/stdlib/gas';
|
|
|
405
406
|
import { computePublicDataTreeLeafSlot } from '@aztec/stdlib/hash';
|
|
406
407
|
import { AztecNodeAdminConfigSchema } from '@aztec/stdlib/interfaces/client';
|
|
407
408
|
import { tryStop } from '@aztec/stdlib/interfaces/server';
|
|
409
|
+
import { InMemoryDebugLogStore, NullDebugLogStore } from '@aztec/stdlib/logs';
|
|
408
410
|
import { InboxLeaf } from '@aztec/stdlib/messaging';
|
|
409
|
-
import { P2PClientType } from '@aztec/stdlib/p2p';
|
|
410
411
|
import { MerkleTreeId, NullifierMembershipWitness, PublicDataWitness } from '@aztec/stdlib/trees';
|
|
411
412
|
import { PublicSimulationOutput, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
412
413
|
import { getPackageVersion } from '@aztec/stdlib/update-checker';
|
|
413
414
|
import { Attributes, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
|
|
414
|
-
import { FullNodeCheckpointsBuilder as CheckpointsBuilder, FullNodeCheckpointsBuilder, NodeKeystoreAdapter, ValidatorClient, createBlockProposalHandler, createValidatorClient
|
|
415
|
+
import { FullNodeCheckpointsBuilder as CheckpointsBuilder, FullNodeCheckpointsBuilder, NodeKeystoreAdapter, ValidatorClient, createBlockProposalHandler, createValidatorClient } from '@aztec/validator-client';
|
|
415
416
|
import { createWorldStateSynchronizer } from '@aztec/world-state';
|
|
416
|
-
import { createPublicClient
|
|
417
|
+
import { createPublicClient } from 'viem';
|
|
417
418
|
import { createSentinel } from '../sentinel/factory.js';
|
|
418
419
|
import { createKeyStoreForValidator } from './config.js';
|
|
419
420
|
import { NodeMetrics } from './node_metrics.js';
|
|
@@ -440,12 +441,14 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
440
441
|
globalVariableBuilder;
|
|
441
442
|
epochCache;
|
|
442
443
|
packageVersion;
|
|
443
|
-
|
|
444
|
+
peerProofVerifier;
|
|
445
|
+
rpcProofVerifier;
|
|
444
446
|
telemetry;
|
|
445
447
|
log;
|
|
446
448
|
blobClient;
|
|
447
449
|
validatorClient;
|
|
448
450
|
keyStoreManager;
|
|
451
|
+
debugLogStore;
|
|
449
452
|
static{
|
|
450
453
|
({ e: [_initProto] } = _apply_decs_2203_r(this, [
|
|
451
454
|
[
|
|
@@ -460,7 +463,7 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
460
463
|
// Prevent two snapshot operations to happen simultaneously
|
|
461
464
|
isUploadingSnapshot;
|
|
462
465
|
tracer;
|
|
463
|
-
constructor(config, p2pClient, blockSource, logsSource, contractDataSource, l1ToL2MessageSource, worldStateSynchronizer, sequencer, proverNode, slasherClient, validatorsSentinel, epochPruneWatcher, l1ChainId, version, globalVariableBuilder, epochCache, packageVersion,
|
|
466
|
+
constructor(config, p2pClient, blockSource, logsSource, contractDataSource, l1ToL2MessageSource, worldStateSynchronizer, sequencer, proverNode, slasherClient, validatorsSentinel, epochPruneWatcher, l1ChainId, version, globalVariableBuilder, epochCache, packageVersion, peerProofVerifier, rpcProofVerifier, telemetry = getTelemetryClient(), log = createLogger('node'), blobClient, validatorClient, keyStoreManager, debugLogStore = new NullDebugLogStore()){
|
|
464
467
|
this.config = config;
|
|
465
468
|
this.p2pClient = p2pClient;
|
|
466
469
|
this.blockSource = blockSource;
|
|
@@ -478,18 +481,29 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
478
481
|
this.globalVariableBuilder = globalVariableBuilder;
|
|
479
482
|
this.epochCache = epochCache;
|
|
480
483
|
this.packageVersion = packageVersion;
|
|
481
|
-
this.
|
|
484
|
+
this.peerProofVerifier = peerProofVerifier;
|
|
485
|
+
this.rpcProofVerifier = rpcProofVerifier;
|
|
482
486
|
this.telemetry = telemetry;
|
|
483
487
|
this.log = log;
|
|
484
488
|
this.blobClient = blobClient;
|
|
485
489
|
this.validatorClient = validatorClient;
|
|
486
490
|
this.keyStoreManager = keyStoreManager;
|
|
491
|
+
this.debugLogStore = debugLogStore;
|
|
487
492
|
this.initialHeaderHashPromise = (_initProto(this), undefined);
|
|
488
493
|
this.isUploadingSnapshot = false;
|
|
489
494
|
this.metrics = new NodeMetrics(telemetry, 'AztecNodeService');
|
|
490
495
|
this.tracer = telemetry.getTracer('AztecNodeService');
|
|
491
496
|
this.log.info(`Aztec Node version: ${this.packageVersion}`);
|
|
492
497
|
this.log.info(`Aztec Node started on chain 0x${l1ChainId.toString(16)}`, config.l1Contracts);
|
|
498
|
+
// A defensive check that protects us against introducing a bug in the complex `createAndSync` function. We must
|
|
499
|
+
// never have debugLogStore enabled when not in test mode because then we would be accumulating debug logs in
|
|
500
|
+
// memory which could be a DoS vector on the sequencer (since no fees are paid for debug logs).
|
|
501
|
+
if (debugLogStore.isEnabled && config.realProofs) {
|
|
502
|
+
throw new Error('debugLogStore should never be enabled when realProofs are set');
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
/** @internal Exposed for testing — returns the RPC proof verifier. */ getProofVerifier() {
|
|
506
|
+
return this.rpcProofVerifier;
|
|
493
507
|
}
|
|
494
508
|
async getWorldStateSyncStatus() {
|
|
495
509
|
const status = await this.worldStateSynchronizer.status();
|
|
@@ -551,9 +565,9 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
551
565
|
}
|
|
552
566
|
const publicClient = createPublicClient({
|
|
553
567
|
chain: ethereumChain.chainInfo,
|
|
554
|
-
transport:
|
|
555
|
-
|
|
556
|
-
|
|
568
|
+
transport: makeL1HttpTransport(config.l1RpcUrls, {
|
|
569
|
+
timeout: config.l1HttpTimeoutMS
|
|
570
|
+
}),
|
|
557
571
|
pollingInterval: config.viemPollingIntervalMS
|
|
558
572
|
});
|
|
559
573
|
const l1ContractsAddresses = await RegistryContract.collectAddresses(publicClient, config.l1Contracts.registryAddress, config.rollupVersion ?? 'canonical');
|
|
@@ -563,10 +577,11 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
563
577
|
...l1ContractsAddresses
|
|
564
578
|
};
|
|
565
579
|
const rollupContract = new RollupContract(publicClient, config.l1Contracts.rollupAddress.toString());
|
|
566
|
-
const [l1GenesisTime, slotDuration, rollupVersionFromRollup] = await Promise.all([
|
|
580
|
+
const [l1GenesisTime, slotDuration, rollupVersionFromRollup, rollupManaLimit] = await Promise.all([
|
|
567
581
|
rollupContract.getL1GenesisTime(),
|
|
568
582
|
rollupContract.getSlotDuration(),
|
|
569
|
-
rollupContract.getVersion()
|
|
583
|
+
rollupContract.getVersion(),
|
|
584
|
+
rollupContract.getManaLimit().then(Number)
|
|
570
585
|
]);
|
|
571
586
|
config.rollupVersion ??= Number(rollupVersionFromRollup);
|
|
572
587
|
if (config.rollupVersion !== Number(rollupVersionFromRollup)) {
|
|
@@ -588,49 +603,74 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
588
603
|
});
|
|
589
604
|
// now create the merkle trees and the world state synchronizer
|
|
590
605
|
const worldStateSynchronizer = await createWorldStateSynchronizer(config, archiver, options.prefilledPublicData, telemetry);
|
|
591
|
-
const
|
|
606
|
+
const useRealVerifiers = config.realProofs || config.debugForceTxProofVerification;
|
|
607
|
+
let peerProofVerifier;
|
|
608
|
+
let rpcProofVerifier;
|
|
609
|
+
if (useRealVerifiers) {
|
|
610
|
+
peerProofVerifier = await BatchChonkVerifier.new(config, config.bbChonkVerifyMaxBatch, 'peer');
|
|
611
|
+
const rpcVerifier = await BBCircuitVerifier.new(config);
|
|
612
|
+
rpcProofVerifier = new QueuedIVCVerifier(rpcVerifier, config.numConcurrentIVCVerifiers);
|
|
613
|
+
} else {
|
|
614
|
+
peerProofVerifier = new TestCircuitVerifier(config.proverTestVerificationDelayMs);
|
|
615
|
+
rpcProofVerifier = new TestCircuitVerifier(config.proverTestVerificationDelayMs);
|
|
616
|
+
}
|
|
617
|
+
let debugLogStore;
|
|
592
618
|
if (!config.realProofs) {
|
|
593
619
|
log.warn(`Aztec node is accepting fake proofs`);
|
|
620
|
+
debugLogStore = new InMemoryDebugLogStore();
|
|
621
|
+
log.info('Aztec node started in test mode (realProofs set to false) hence debug logs from public functions will be collected and served');
|
|
622
|
+
} else {
|
|
623
|
+
debugLogStore = new NullDebugLogStore();
|
|
624
|
+
}
|
|
625
|
+
const proverOnly = config.enableProverNode && config.disableValidator;
|
|
626
|
+
if (proverOnly) {
|
|
627
|
+
log.info('Starting in prover-only mode: skipping validator, sequencer, sentinel, and slasher subsystems');
|
|
594
628
|
}
|
|
595
|
-
const proofVerifier = new QueuedIVCVerifier(config, circuitVerifier);
|
|
596
629
|
// create the tx pool and the p2p client, which will need the l2 block source
|
|
597
|
-
const p2pClient = await createP2PClient(
|
|
598
|
-
// We
|
|
599
|
-
|
|
600
|
-
// Create FullNodeCheckpointsBuilder for
|
|
630
|
+
const p2pClient = await createP2PClient(config, archiver, peerProofVerifier, worldStateSynchronizer, epochCache, packageVersion, dateProvider, telemetry, deps.p2pClientDeps);
|
|
631
|
+
// We'll accumulate sentinel watchers here
|
|
632
|
+
const watchers = [];
|
|
633
|
+
// Create FullNodeCheckpointsBuilder for block proposal handling and tx validation.
|
|
634
|
+
// Override maxTxsPerCheckpoint with the validator-specific limit if set.
|
|
601
635
|
const validatorCheckpointsBuilder = new FullNodeCheckpointsBuilder({
|
|
602
636
|
...config,
|
|
603
637
|
l1GenesisTime,
|
|
604
|
-
slotDuration: Number(slotDuration)
|
|
638
|
+
slotDuration: Number(slotDuration),
|
|
639
|
+
rollupManaLimit,
|
|
640
|
+
maxTxsPerCheckpoint: config.validateMaxTxsPerCheckpoint
|
|
605
641
|
}, worldStateSynchronizer, archiver, dateProvider, telemetry);
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
642
|
+
let validatorClient;
|
|
643
|
+
if (!proverOnly) {
|
|
644
|
+
// Create validator client if required
|
|
645
|
+
validatorClient = await createValidatorClient(config, {
|
|
646
|
+
checkpointsBuilder: validatorCheckpointsBuilder,
|
|
647
|
+
worldState: worldStateSynchronizer,
|
|
648
|
+
p2pClient,
|
|
649
|
+
telemetry,
|
|
650
|
+
dateProvider,
|
|
651
|
+
epochCache,
|
|
652
|
+
blockSource: archiver,
|
|
653
|
+
l1ToL2MessageSource: archiver,
|
|
654
|
+
keyStoreManager,
|
|
655
|
+
blobClient,
|
|
656
|
+
slashingProtectionDb: deps.slashingProtectionDb
|
|
657
|
+
});
|
|
658
|
+
// If we have a validator client, register it as a source of offenses for the slasher,
|
|
659
|
+
// and have it register callbacks on the p2p client *before* we start it, otherwise messages
|
|
660
|
+
// like attestations or auths will fail.
|
|
661
|
+
if (validatorClient) {
|
|
662
|
+
watchers.push(validatorClient);
|
|
663
|
+
if (!options.dontStartSequencer) {
|
|
664
|
+
await validatorClient.registerHandlers();
|
|
665
|
+
}
|
|
628
666
|
}
|
|
629
667
|
}
|
|
630
|
-
// If there's no validator client
|
|
631
|
-
//
|
|
632
|
-
|
|
633
|
-
|
|
668
|
+
// If there's no validator client, create a BlockProposalHandler to handle block proposals
|
|
669
|
+
// for monitoring or reexecution. Reexecution (default) allows us to follow the pending chain,
|
|
670
|
+
// while non-reexecution is used for validating the proposals and collecting their txs.
|
|
671
|
+
if (!validatorClient) {
|
|
672
|
+
const reexecute = !!config.alwaysReexecuteBlockProposals;
|
|
673
|
+
log.info(`Setting up block proposal handler` + (reexecute ? ' with reexecution of proposals' : ''));
|
|
634
674
|
createBlockProposalHandler(config, {
|
|
635
675
|
checkpointsBuilder: validatorCheckpointsBuilder,
|
|
636
676
|
worldState: worldStateSynchronizer,
|
|
@@ -640,26 +680,29 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
640
680
|
p2pClient,
|
|
641
681
|
dateProvider,
|
|
642
682
|
telemetry
|
|
643
|
-
}).
|
|
683
|
+
}).register(p2pClient, reexecute);
|
|
644
684
|
}
|
|
645
685
|
// Start world state and wait for it to sync to the archiver.
|
|
646
686
|
await worldStateSynchronizer.start();
|
|
647
687
|
// Start p2p. Note that it depends on world state to be running.
|
|
648
688
|
await p2pClient.start();
|
|
649
|
-
|
|
650
|
-
if (validatorsSentinel && config.slashInactivityPenalty > 0n) {
|
|
651
|
-
watchers.push(validatorsSentinel);
|
|
652
|
-
}
|
|
689
|
+
let validatorsSentinel;
|
|
653
690
|
let epochPruneWatcher;
|
|
654
|
-
if (config.slashPrunePenalty > 0n || config.slashDataWithholdingPenalty > 0n) {
|
|
655
|
-
epochPruneWatcher = new EpochPruneWatcher(archiver, archiver, epochCache, p2pClient.getTxProvider(), validatorCheckpointsBuilder, config);
|
|
656
|
-
watchers.push(epochPruneWatcher);
|
|
657
|
-
}
|
|
658
|
-
// We assume we want to slash for invalid attestations unless all max penalties are set to 0
|
|
659
691
|
let attestationsBlockWatcher;
|
|
660
|
-
if (
|
|
661
|
-
|
|
662
|
-
|
|
692
|
+
if (!proverOnly) {
|
|
693
|
+
validatorsSentinel = await createSentinel(epochCache, archiver, p2pClient, config);
|
|
694
|
+
if (validatorsSentinel && config.slashInactivityPenalty > 0n) {
|
|
695
|
+
watchers.push(validatorsSentinel);
|
|
696
|
+
}
|
|
697
|
+
if (config.slashPrunePenalty > 0n || config.slashDataWithholdingPenalty > 0n) {
|
|
698
|
+
epochPruneWatcher = new EpochPruneWatcher(archiver, archiver, epochCache, p2pClient.getTxProvider(), validatorCheckpointsBuilder, config);
|
|
699
|
+
watchers.push(epochPruneWatcher);
|
|
700
|
+
}
|
|
701
|
+
// We assume we want to slash for invalid attestations unless all max penalties are set to 0
|
|
702
|
+
if (config.slashProposeInvalidAttestationsPenalty > 0n || config.slashAttestDescendantOfInvalidPenalty > 0n) {
|
|
703
|
+
attestationsBlockWatcher = new AttestationsBlockWatcher(archiver, epochCache, config);
|
|
704
|
+
watchers.push(attestationsBlockWatcher);
|
|
705
|
+
}
|
|
663
706
|
}
|
|
664
707
|
// Start p2p-related services once the archiver has completed sync
|
|
665
708
|
void archiver.waitForInitialSync().then(async ()=>{
|
|
@@ -669,6 +712,13 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
669
712
|
await attestationsBlockWatcher?.start();
|
|
670
713
|
log.info(`All p2p services started`);
|
|
671
714
|
}).catch((err)=>log.error('Failed to start p2p services after archiver sync', err));
|
|
715
|
+
const globalVariableBuilder = new GlobalVariableBuilder(dateProvider, publicClient, {
|
|
716
|
+
l1Contracts: config.l1Contracts,
|
|
717
|
+
ethereumSlotDuration: config.ethereumSlotDuration,
|
|
718
|
+
rollupVersion: BigInt(config.rollupVersion),
|
|
719
|
+
l1GenesisTime,
|
|
720
|
+
slotDuration: Number(slotDuration)
|
|
721
|
+
});
|
|
672
722
|
// Validator enabled, create/start relevant service
|
|
673
723
|
let sequencer;
|
|
674
724
|
let slasherClient;
|
|
@@ -695,16 +745,34 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
695
745
|
dateProvider,
|
|
696
746
|
kzg: Blob.getViemKzgInstance()
|
|
697
747
|
});
|
|
748
|
+
// Create a funder L1TxUtils from the keystore funding account (if configured)
|
|
749
|
+
const fundingSigner = keyStoreManager?.createFundingSigner();
|
|
750
|
+
let funderL1TxUtils;
|
|
751
|
+
if (fundingSigner) {
|
|
752
|
+
const [funder] = await createL1TxUtilsFromSigners(publicClient, [
|
|
753
|
+
fundingSigner
|
|
754
|
+
], {
|
|
755
|
+
...config,
|
|
756
|
+
scope: 'sequencer'
|
|
757
|
+
}, {
|
|
758
|
+
telemetry,
|
|
759
|
+
logger: log.createChild('l1-tx-utils:funder'),
|
|
760
|
+
dateProvider
|
|
761
|
+
});
|
|
762
|
+
funderL1TxUtils = funder;
|
|
763
|
+
}
|
|
698
764
|
// Create and start the sequencer client
|
|
699
765
|
const checkpointsBuilder = new CheckpointsBuilder({
|
|
700
766
|
...config,
|
|
701
767
|
l1GenesisTime,
|
|
702
|
-
slotDuration: Number(slotDuration)
|
|
703
|
-
|
|
768
|
+
slotDuration: Number(slotDuration),
|
|
769
|
+
rollupManaLimit
|
|
770
|
+
}, worldStateSynchronizer, archiver, dateProvider, telemetry, debugLogStore);
|
|
704
771
|
sequencer = await SequencerClient.new(config, {
|
|
705
772
|
...deps,
|
|
706
773
|
epochCache,
|
|
707
774
|
l1TxUtils,
|
|
775
|
+
funderL1TxUtils,
|
|
708
776
|
validatorClient,
|
|
709
777
|
p2pClient,
|
|
710
778
|
worldStateSynchronizer,
|
|
@@ -715,7 +783,8 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
715
783
|
telemetry,
|
|
716
784
|
dateProvider,
|
|
717
785
|
blobClient,
|
|
718
|
-
nodeKeyStore: keyStoreManager
|
|
786
|
+
nodeKeyStore: keyStoreManager,
|
|
787
|
+
globalVariableBuilder
|
|
719
788
|
});
|
|
720
789
|
}
|
|
721
790
|
if (!options.dontStartSequencer && sequencer) {
|
|
@@ -745,13 +814,7 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
745
814
|
log.info(`Prover node subsystem created but not started`);
|
|
746
815
|
}
|
|
747
816
|
}
|
|
748
|
-
const
|
|
749
|
-
...config,
|
|
750
|
-
rollupVersion: BigInt(config.rollupVersion),
|
|
751
|
-
l1GenesisTime,
|
|
752
|
-
slotDuration: Number(slotDuration)
|
|
753
|
-
});
|
|
754
|
-
const node = new AztecNodeService(config, p2pClient, archiver, archiver, archiver, archiver, worldStateSynchronizer, sequencer, proverNode, slasherClient, validatorsSentinel, epochPruneWatcher, ethereumChain.chainInfo.id, config.rollupVersion, globalVariableBuilder, epochCache, packageVersion, proofVerifier, telemetry, log, blobClient, validatorClient, keyStoreManager);
|
|
817
|
+
const node = new AztecNodeService(config, p2pClient, archiver, archiver, archiver, archiver, worldStateSynchronizer, sequencer, proverNode, slasherClient, validatorsSentinel, epochPruneWatcher, ethereumChain.chainInfo.id, config.rollupVersion, globalVariableBuilder, epochCache, packageVersion, peerProofVerifier, rpcProofVerifier, telemetry, log, blobClient, validatorClient, keyStoreManager, debugLogStore);
|
|
755
818
|
return node;
|
|
756
819
|
}
|
|
757
820
|
/**
|
|
@@ -782,7 +845,10 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
782
845
|
return Promise.resolve(this.p2pClient.getEnr()?.encodeTxt());
|
|
783
846
|
}
|
|
784
847
|
async getAllowedPublicSetup() {
|
|
785
|
-
return
|
|
848
|
+
return [
|
|
849
|
+
...await getDefaultAllowedSetupFunctions(),
|
|
850
|
+
...this.config.txPublicSetupAllowListExtend ?? []
|
|
851
|
+
];
|
|
786
852
|
}
|
|
787
853
|
/**
|
|
788
854
|
* Method to determine if the node is ready to accept transactions.
|
|
@@ -860,6 +926,9 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
860
926
|
async getCheckpointedBlocks(from, limit) {
|
|
861
927
|
return await this.blockSource.getCheckpointedBlocks(from, limit) ?? [];
|
|
862
928
|
}
|
|
929
|
+
getCheckpointsDataForEpoch(epochNumber) {
|
|
930
|
+
return this.blockSource.getCheckpointsDataForEpoch(epochNumber);
|
|
931
|
+
}
|
|
863
932
|
/**
|
|
864
933
|
* Method to fetch the current min L2 fees.
|
|
865
934
|
* @returns The current min L2 fees.
|
|
@@ -887,6 +956,9 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
887
956
|
async getCheckpointedBlockNumber() {
|
|
888
957
|
return await this.blockSource.getCheckpointedL2BlockNumber();
|
|
889
958
|
}
|
|
959
|
+
getCheckpointNumber() {
|
|
960
|
+
return this.blockSource.getCheckpointNumber();
|
|
961
|
+
}
|
|
890
962
|
/**
|
|
891
963
|
* Method to fetch the version of the package.
|
|
892
964
|
* @returns The node package version
|
|
@@ -912,28 +984,36 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
912
984
|
return this.contractDataSource.getContract(address);
|
|
913
985
|
}
|
|
914
986
|
async getPrivateLogsByTags(tags, page, referenceBlock) {
|
|
987
|
+
let upToBlockNumber;
|
|
915
988
|
if (referenceBlock) {
|
|
916
989
|
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
917
|
-
if (
|
|
990
|
+
if (referenceBlock.equals(initialBlockHash)) {
|
|
991
|
+
upToBlockNumber = BlockNumber(0);
|
|
992
|
+
} else {
|
|
918
993
|
const header = await this.blockSource.getBlockHeaderByHash(referenceBlock);
|
|
919
994
|
if (!header) {
|
|
920
995
|
throw new Error(`Block ${referenceBlock.toString()} not found in the node. This might indicate a reorg has occurred.`);
|
|
921
996
|
}
|
|
997
|
+
upToBlockNumber = header.globalVariables.blockNumber;
|
|
922
998
|
}
|
|
923
999
|
}
|
|
924
|
-
return this.logsSource.getPrivateLogsByTags(tags, page);
|
|
1000
|
+
return this.logsSource.getPrivateLogsByTags(tags, page, upToBlockNumber);
|
|
925
1001
|
}
|
|
926
1002
|
async getPublicLogsByTagsFromContract(contractAddress, tags, page, referenceBlock) {
|
|
1003
|
+
let upToBlockNumber;
|
|
927
1004
|
if (referenceBlock) {
|
|
928
1005
|
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
929
|
-
if (
|
|
1006
|
+
if (referenceBlock.equals(initialBlockHash)) {
|
|
1007
|
+
upToBlockNumber = BlockNumber(0);
|
|
1008
|
+
} else {
|
|
930
1009
|
const header = await this.blockSource.getBlockHeaderByHash(referenceBlock);
|
|
931
1010
|
if (!header) {
|
|
932
1011
|
throw new Error(`Block ${referenceBlock.toString()} not found in the node. This might indicate a reorg has occurred.`);
|
|
933
1012
|
}
|
|
1013
|
+
upToBlockNumber = header.globalVariables.blockNumber;
|
|
934
1014
|
}
|
|
935
1015
|
}
|
|
936
|
-
return this.logsSource.getPublicLogsByTagsFromContract(contractAddress, tags, page);
|
|
1016
|
+
return this.logsSource.getPublicLogsByTagsFromContract(contractAddress, tags, page, upToBlockNumber);
|
|
937
1017
|
}
|
|
938
1018
|
/**
|
|
939
1019
|
* Gets public logs based on the provided filter.
|
|
@@ -968,8 +1048,9 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
968
1048
|
throw new Error(`Invalid tx: ${reason}`);
|
|
969
1049
|
}
|
|
970
1050
|
await this.p2pClient.sendTx(tx);
|
|
971
|
-
|
|
972
|
-
this.
|
|
1051
|
+
const duration = timer.ms();
|
|
1052
|
+
this.metrics.receivedTx(duration, true);
|
|
1053
|
+
this.log.info(`Received tx ${txHash} in ${duration}ms`, {
|
|
973
1054
|
txHash
|
|
974
1055
|
});
|
|
975
1056
|
}
|
|
@@ -980,18 +1061,20 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
980
1061
|
const isKnownToPool = txPoolStatus === 'pending' || txPoolStatus === 'mined';
|
|
981
1062
|
// Then get the actual tx from the archiver, which tracks every tx in a mined block.
|
|
982
1063
|
const settledTxReceipt = await this.blockSource.getSettledTxReceipt(txHash);
|
|
1064
|
+
let receipt;
|
|
983
1065
|
if (settledTxReceipt) {
|
|
984
|
-
|
|
985
|
-
return settledTxReceipt;
|
|
1066
|
+
receipt = settledTxReceipt;
|
|
986
1067
|
} else if (isKnownToPool) {
|
|
987
1068
|
// If the tx is in the pool but not in the archiver, it's pending.
|
|
988
1069
|
// This handles race conditions between archiver and p2p, where the archiver
|
|
989
1070
|
// has pruned the block in which a tx was mined, but p2p has not caught up yet.
|
|
990
|
-
|
|
1071
|
+
receipt = new TxReceipt(txHash, TxStatus.PENDING, undefined, undefined);
|
|
991
1072
|
} else {
|
|
992
1073
|
// Otherwise, if we don't know the tx, we consider it dropped.
|
|
993
|
-
|
|
1074
|
+
receipt = new TxReceipt(txHash, TxStatus.DROPPED, undefined, 'Tx dropped by P2P node');
|
|
994
1075
|
}
|
|
1076
|
+
this.debugLogStore.decorateReceiptWithLogs(txHash.toString(), receipt);
|
|
1077
|
+
return receipt;
|
|
995
1078
|
}
|
|
996
1079
|
getTxEffect(txHash) {
|
|
997
1080
|
return this.blockSource.getTxEffect(txHash);
|
|
@@ -1003,7 +1086,10 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
1003
1086
|
await tryStop(this.validatorsSentinel);
|
|
1004
1087
|
await tryStop(this.epochPruneWatcher);
|
|
1005
1088
|
await tryStop(this.slasherClient);
|
|
1006
|
-
await
|
|
1089
|
+
await Promise.all([
|
|
1090
|
+
tryStop(this.peerProofVerifier),
|
|
1091
|
+
tryStop(this.rpcProofVerifier)
|
|
1092
|
+
]);
|
|
1007
1093
|
await tryStop(this.sequencer);
|
|
1008
1094
|
await tryStop(this.proverNode);
|
|
1009
1095
|
await tryStop(this.p2pClient);
|
|
@@ -1045,70 +1131,82 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
1045
1131
|
return compactArray(await Promise.all(txHashes.map((txHash)=>this.getTxByHash(txHash))));
|
|
1046
1132
|
}
|
|
1047
1133
|
async findLeavesIndexes(referenceBlock, treeId, leafValues) {
|
|
1048
|
-
const committedDb = await this
|
|
1134
|
+
const committedDb = await this.getWorldState(referenceBlock);
|
|
1049
1135
|
const maybeIndices = await committedDb.findLeafIndices(treeId, leafValues.map((x)=>x.toBuffer()));
|
|
1050
|
-
//
|
|
1051
|
-
const
|
|
1052
|
-
// Now we find the block numbers for the indices
|
|
1053
|
-
const blockNumbers = await committedDb.getBlockNumbersForLeafIndices(treeId,
|
|
1054
|
-
//
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1136
|
+
// Filter out undefined values to query block numbers only for found leaves
|
|
1137
|
+
const definedIndices = maybeIndices.filter((x)=>x !== undefined);
|
|
1138
|
+
// Now we find the block numbers for the defined indices
|
|
1139
|
+
const blockNumbers = await committedDb.getBlockNumbersForLeafIndices(treeId, definedIndices);
|
|
1140
|
+
// Build a map from leaf index to block number
|
|
1141
|
+
const indexToBlockNumber = new Map();
|
|
1142
|
+
for(let i = 0; i < definedIndices.length; i++){
|
|
1143
|
+
const blockNumber = blockNumbers[i];
|
|
1144
|
+
if (blockNumber === undefined) {
|
|
1145
|
+
throw new Error(`Block number is undefined for leaf index ${definedIndices[i]} in tree ${MerkleTreeId[treeId]}`);
|
|
1058
1146
|
}
|
|
1147
|
+
indexToBlockNumber.set(definedIndices[i], blockNumber);
|
|
1059
1148
|
}
|
|
1060
1149
|
// Get unique block numbers in order to optimize num calls to getLeafValue function.
|
|
1061
1150
|
const uniqueBlockNumbers = [
|
|
1062
|
-
...new Set(
|
|
1151
|
+
...new Set(indexToBlockNumber.values())
|
|
1063
1152
|
];
|
|
1064
|
-
// Now we obtain the block hashes from the archive tree
|
|
1065
|
-
// (note that block number corresponds to the leaf index in the archive tree).
|
|
1153
|
+
// Now we obtain the block hashes from the archive tree (block number = leaf index in archive tree).
|
|
1066
1154
|
const blockHashes = await Promise.all(uniqueBlockNumbers.map((blockNumber)=>{
|
|
1067
1155
|
return committedDb.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(blockNumber));
|
|
1068
1156
|
}));
|
|
1069
|
-
//
|
|
1157
|
+
// Build a map from block number to block hash
|
|
1158
|
+
const blockNumberToHash = new Map();
|
|
1070
1159
|
for(let i = 0; i < uniqueBlockNumbers.length; i++){
|
|
1071
|
-
|
|
1160
|
+
const blockHash = blockHashes[i];
|
|
1161
|
+
if (blockHash === undefined) {
|
|
1072
1162
|
throw new Error(`Block hash is undefined for block number ${uniqueBlockNumbers[i]}`);
|
|
1073
1163
|
}
|
|
1164
|
+
blockNumberToHash.set(uniqueBlockNumbers[i], blockHash);
|
|
1074
1165
|
}
|
|
1075
1166
|
// Create DataInBlock objects by combining indices, blockNumbers and blockHashes and return them.
|
|
1076
|
-
return maybeIndices.map((index
|
|
1167
|
+
return maybeIndices.map((index)=>{
|
|
1077
1168
|
if (index === undefined) {
|
|
1078
1169
|
return undefined;
|
|
1079
1170
|
}
|
|
1080
|
-
const blockNumber =
|
|
1171
|
+
const blockNumber = indexToBlockNumber.get(index);
|
|
1081
1172
|
if (blockNumber === undefined) {
|
|
1082
|
-
|
|
1173
|
+
throw new Error(`Block number not found for leaf index ${index} in tree ${MerkleTreeId[treeId]}`);
|
|
1083
1174
|
}
|
|
1084
|
-
const
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
return undefined;
|
|
1175
|
+
const blockHash = blockNumberToHash.get(blockNumber);
|
|
1176
|
+
if (blockHash === undefined) {
|
|
1177
|
+
throw new Error(`Block hash not found for block number ${blockNumber}`);
|
|
1088
1178
|
}
|
|
1089
1179
|
return {
|
|
1090
|
-
l2BlockNumber:
|
|
1180
|
+
l2BlockNumber: blockNumber,
|
|
1091
1181
|
l2BlockHash: new BlockHash(blockHash),
|
|
1092
1182
|
data: index
|
|
1093
1183
|
};
|
|
1094
1184
|
});
|
|
1095
1185
|
}
|
|
1096
1186
|
async getBlockHashMembershipWitness(referenceBlock, blockHash) {
|
|
1097
|
-
|
|
1187
|
+
// The Noir circuit checks the archive membership proof against `anchor_block_header.last_archive.root`,
|
|
1188
|
+
// which is the archive tree root BEFORE the anchor block was added (i.e. the state after block N-1).
|
|
1189
|
+
// So we need the world state at block N-1, not block N, to produce a sibling path matching that root.
|
|
1190
|
+
const referenceBlockNumber = await this.resolveBlockNumber(referenceBlock);
|
|
1191
|
+
if (referenceBlockNumber === BlockNumber.ZERO) {
|
|
1192
|
+
// Block 0 (the initial block) has an empty archive, so no membership witness can exist.
|
|
1193
|
+
return undefined;
|
|
1194
|
+
}
|
|
1195
|
+
const committedDb = await this.getWorldState(BlockNumber(referenceBlockNumber - 1));
|
|
1098
1196
|
const [pathAndIndex] = await committedDb.findSiblingPaths(MerkleTreeId.ARCHIVE, [
|
|
1099
1197
|
blockHash
|
|
1100
1198
|
]);
|
|
1101
1199
|
return pathAndIndex === undefined ? undefined : MembershipWitness.fromSiblingPath(pathAndIndex.index, pathAndIndex.path);
|
|
1102
1200
|
}
|
|
1103
1201
|
async getNoteHashMembershipWitness(referenceBlock, noteHash) {
|
|
1104
|
-
const committedDb = await this
|
|
1202
|
+
const committedDb = await this.getWorldState(referenceBlock);
|
|
1105
1203
|
const [pathAndIndex] = await committedDb.findSiblingPaths(MerkleTreeId.NOTE_HASH_TREE, [
|
|
1106
1204
|
noteHash
|
|
1107
1205
|
]);
|
|
1108
1206
|
return pathAndIndex === undefined ? undefined : MembershipWitness.fromSiblingPath(pathAndIndex.index, pathAndIndex.path);
|
|
1109
1207
|
}
|
|
1110
1208
|
async getL1ToL2MessageMembershipWitness(referenceBlock, l1ToL2Message) {
|
|
1111
|
-
const db = await this
|
|
1209
|
+
const db = await this.getWorldState(referenceBlock);
|
|
1112
1210
|
const [witness] = await db.findSiblingPaths(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, [
|
|
1113
1211
|
l1ToL2Message
|
|
1114
1212
|
]);
|
|
@@ -1121,9 +1219,9 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
1121
1219
|
witness.path
|
|
1122
1220
|
];
|
|
1123
1221
|
}
|
|
1124
|
-
async
|
|
1222
|
+
async getL1ToL2MessageCheckpoint(l1ToL2Message) {
|
|
1125
1223
|
const messageIndex = await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message);
|
|
1126
|
-
return messageIndex ?
|
|
1224
|
+
return messageIndex ? InboxLeaf.checkpointNumberFromIndex(messageIndex) : undefined;
|
|
1127
1225
|
}
|
|
1128
1226
|
/**
|
|
1129
1227
|
* Returns whether an L1 to L2 message is synced by archiver and if it's ready to be included in a block.
|
|
@@ -1140,23 +1238,11 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
1140
1238
|
*/ async getL2ToL1Messages(epoch) {
|
|
1141
1239
|
// Assumes `getCheckpointedBlocksForEpoch` returns blocks in ascending order of block number.
|
|
1142
1240
|
const checkpointedBlocks = await this.blockSource.getCheckpointedBlocksForEpoch(epoch);
|
|
1143
|
-
const blocksInCheckpoints =
|
|
1144
|
-
let previousSlotNumber = SlotNumber.ZERO;
|
|
1145
|
-
let checkpointIndex = -1;
|
|
1146
|
-
for (const checkpointedBlock of checkpointedBlocks){
|
|
1147
|
-
const block = checkpointedBlock.block;
|
|
1148
|
-
const slotNumber = block.header.globalVariables.slotNumber;
|
|
1149
|
-
if (slotNumber !== previousSlotNumber) {
|
|
1150
|
-
checkpointIndex++;
|
|
1151
|
-
blocksInCheckpoints.push([]);
|
|
1152
|
-
previousSlotNumber = slotNumber;
|
|
1153
|
-
}
|
|
1154
|
-
blocksInCheckpoints[checkpointIndex].push(block);
|
|
1155
|
-
}
|
|
1241
|
+
const blocksInCheckpoints = chunkBy(checkpointedBlocks, (cb)=>cb.block.header.globalVariables.slotNumber).map((group)=>group.map((cb)=>cb.block));
|
|
1156
1242
|
return blocksInCheckpoints.map((blocks)=>blocks.map((block)=>block.body.txEffects.map((txEffect)=>txEffect.l2ToL1Msgs)));
|
|
1157
1243
|
}
|
|
1158
1244
|
async getNullifierMembershipWitness(referenceBlock, nullifier) {
|
|
1159
|
-
const db = await this
|
|
1245
|
+
const db = await this.getWorldState(referenceBlock);
|
|
1160
1246
|
const [witness] = await db.findSiblingPaths(MerkleTreeId.NULLIFIER_TREE, [
|
|
1161
1247
|
nullifier.toBuffer()
|
|
1162
1248
|
]);
|
|
@@ -1170,36 +1256,22 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
1170
1256
|
}
|
|
1171
1257
|
return new NullifierMembershipWitness(index, leafPreimage, path);
|
|
1172
1258
|
}
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
* @param referenceBlock - The block parameter (block number, block hash, or 'latest') at which to get the data
|
|
1176
|
-
* (which contains the root of the nullifier tree in which we are searching for the nullifier).
|
|
1177
|
-
* @param nullifier - Nullifier we try to find the low nullifier witness for.
|
|
1178
|
-
* @returns The low nullifier membership witness (if found).
|
|
1179
|
-
* @remarks Low nullifier witness can be used to perform a nullifier non-inclusion proof by leveraging the "linked
|
|
1180
|
-
* list structure" of leaves and proving that a lower nullifier is pointing to a bigger next value than the nullifier
|
|
1181
|
-
* we are trying to prove non-inclusion for.
|
|
1182
|
-
*
|
|
1183
|
-
* Note: This function returns the membership witness of the nullifier itself and not the low nullifier when
|
|
1184
|
-
* the nullifier already exists in the tree. This is because the `getPreviousValueIndex` function returns the
|
|
1185
|
-
* index of the nullifier itself when it already exists in the tree.
|
|
1186
|
-
* TODO: This is a confusing behavior and we should eventually address that.
|
|
1187
|
-
*/ async getLowNullifierMembershipWitness(referenceBlock, nullifier) {
|
|
1188
|
-
const committedDb = await this.#getWorldState(referenceBlock);
|
|
1259
|
+
async getLowNullifierMembershipWitness(referenceBlock, nullifier) {
|
|
1260
|
+
const committedDb = await this.getWorldState(referenceBlock);
|
|
1189
1261
|
const findResult = await committedDb.getPreviousValueIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBigInt());
|
|
1190
1262
|
if (!findResult) {
|
|
1191
1263
|
return undefined;
|
|
1192
1264
|
}
|
|
1193
1265
|
const { index, alreadyPresent } = findResult;
|
|
1194
1266
|
if (alreadyPresent) {
|
|
1195
|
-
|
|
1267
|
+
throw new Error(`Cannot prove nullifier non-inclusion: nullifier ${nullifier.toBigInt()} already exists in the tree`);
|
|
1196
1268
|
}
|
|
1197
1269
|
const preimageData = await committedDb.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index);
|
|
1198
1270
|
const siblingPath = await committedDb.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, BigInt(index));
|
|
1199
1271
|
return new NullifierMembershipWitness(BigInt(index), preimageData, siblingPath);
|
|
1200
1272
|
}
|
|
1201
1273
|
async getPublicDataWitness(referenceBlock, leafSlot) {
|
|
1202
|
-
const committedDb = await this
|
|
1274
|
+
const committedDb = await this.getWorldState(referenceBlock);
|
|
1203
1275
|
const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
|
|
1204
1276
|
if (!lowLeafResult) {
|
|
1205
1277
|
return undefined;
|
|
@@ -1210,7 +1282,7 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
1210
1282
|
}
|
|
1211
1283
|
}
|
|
1212
1284
|
async getPublicStorageAt(referenceBlock, contract, slot) {
|
|
1213
|
-
const committedDb = await this
|
|
1285
|
+
const committedDb = await this.getWorldState(referenceBlock);
|
|
1214
1286
|
const leafSlot = await computePublicDataTreeLeafSlot(contract, slot);
|
|
1215
1287
|
const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
|
|
1216
1288
|
if (!lowLeafResult || !lowLeafResult.alreadyPresent) {
|
|
@@ -1289,7 +1361,7 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
1289
1361
|
});
|
|
1290
1362
|
const processor = publicProcessorFactory.create(merkleTreeFork, newGlobalVariables, config);
|
|
1291
1363
|
// REFACTOR: Consider merging ProcessReturnValues into ProcessedTx
|
|
1292
|
-
const [processedTxs, failedTxs, _usedTxs, returns] = await processor.process([
|
|
1364
|
+
const [processedTxs, failedTxs, _usedTxs, returns, debugLogs] = await processor.process([
|
|
1293
1365
|
tx
|
|
1294
1366
|
]);
|
|
1295
1367
|
// REFACTOR: Consider returning the error rather than throwing
|
|
@@ -1300,26 +1372,33 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
1300
1372
|
throw failedTxs[0].error;
|
|
1301
1373
|
}
|
|
1302
1374
|
const [processedTx] = processedTxs;
|
|
1303
|
-
return new PublicSimulationOutput(processedTx.revertReason, processedTx.globalVariables, processedTx.txEffect, returns, processedTx.gasUsed);
|
|
1375
|
+
return new PublicSimulationOutput(processedTx.revertReason, processedTx.globalVariables, processedTx.txEffect, returns, processedTx.gasUsed, debugLogs);
|
|
1304
1376
|
} finally{
|
|
1305
1377
|
await merkleTreeFork.close();
|
|
1306
1378
|
}
|
|
1307
1379
|
}
|
|
1308
1380
|
async isValidTx(tx, { isSimulation, skipFeeEnforcement } = {}) {
|
|
1309
1381
|
const db = this.worldStateSynchronizer.getCommitted();
|
|
1310
|
-
const verifier = isSimulation ? undefined : this.
|
|
1382
|
+
const verifier = isSimulation ? undefined : this.rpcProofVerifier;
|
|
1311
1383
|
// We accept transactions if they are not expired by the next slot (checked based on the ExpirationTimestamp field)
|
|
1312
1384
|
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
1313
1385
|
const blockNumber = BlockNumber(await this.blockSource.getBlockNumber() + 1);
|
|
1314
|
-
const
|
|
1386
|
+
const l1Constants = await this.blockSource.getL1Constants();
|
|
1387
|
+
const validator = createTxValidatorForAcceptingTxsOverRPC(db, this.contractDataSource, verifier, {
|
|
1315
1388
|
timestamp: nextSlotTimestamp,
|
|
1316
1389
|
blockNumber,
|
|
1317
1390
|
l1ChainId: this.l1ChainId,
|
|
1318
1391
|
rollupVersion: this.version,
|
|
1319
|
-
setupAllowList:
|
|
1392
|
+
setupAllowList: [
|
|
1393
|
+
...await getDefaultAllowedSetupFunctions(),
|
|
1394
|
+
...this.config.txPublicSetupAllowListExtend ?? []
|
|
1395
|
+
],
|
|
1320
1396
|
gasFees: await this.getCurrentMinFees(),
|
|
1321
1397
|
skipFeeEnforcement,
|
|
1322
|
-
txsPermitted: !this.config.disableTransactions
|
|
1398
|
+
txsPermitted: !this.config.disableTransactions,
|
|
1399
|
+
rollupManaLimit: l1Constants.rollupManaLimit,
|
|
1400
|
+
maxBlockL2Gas: this.config.validateMaxL2BlockGas,
|
|
1401
|
+
maxBlockDAGas: this.config.validateMaxDABlockGas
|
|
1323
1402
|
}, this.log.getBindings());
|
|
1324
1403
|
return await validator.validateTx(tx);
|
|
1325
1404
|
}
|
|
@@ -1342,7 +1421,18 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
1342
1421
|
archiver.updateConfig(config);
|
|
1343
1422
|
}
|
|
1344
1423
|
if (newConfig.realProofs !== this.config.realProofs) {
|
|
1345
|
-
|
|
1424
|
+
await Promise.all([
|
|
1425
|
+
tryStop(this.peerProofVerifier),
|
|
1426
|
+
tryStop(this.rpcProofVerifier)
|
|
1427
|
+
]);
|
|
1428
|
+
if (newConfig.realProofs) {
|
|
1429
|
+
this.peerProofVerifier = await BatchChonkVerifier.new(newConfig, newConfig.bbChonkVerifyMaxBatch, 'peer');
|
|
1430
|
+
const rpcVerifier = await BBCircuitVerifier.new(newConfig);
|
|
1431
|
+
this.rpcProofVerifier = new QueuedIVCVerifier(rpcVerifier, newConfig.numConcurrentIVCVerifiers);
|
|
1432
|
+
} else {
|
|
1433
|
+
this.peerProofVerifier = new TestCircuitVerifier();
|
|
1434
|
+
this.rpcProofVerifier = new TestCircuitVerifier();
|
|
1435
|
+
}
|
|
1346
1436
|
}
|
|
1347
1437
|
this.config = newConfig;
|
|
1348
1438
|
}
|
|
@@ -1539,7 +1629,7 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
1539
1629
|
* Returns an instance of MerkleTreeOperations having first ensured the world state is fully synched
|
|
1540
1630
|
* @param block - The block parameter (block number, block hash, or 'latest') at which to get the data.
|
|
1541
1631
|
* @returns An instance of a committed MerkleTreeOperations
|
|
1542
|
-
*/ async
|
|
1632
|
+
*/ async getWorldState(block) {
|
|
1543
1633
|
let blockSyncedTo = BlockNumber.ZERO;
|
|
1544
1634
|
try {
|
|
1545
1635
|
// Attempt to sync the world state if necessary
|
|
@@ -1551,6 +1641,8 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
1551
1641
|
this.log.debug(`Using committed db for block 'latest', world state synced upto ${blockSyncedTo}`);
|
|
1552
1642
|
return this.worldStateSynchronizer.getCommitted();
|
|
1553
1643
|
}
|
|
1644
|
+
// Get the block number, either directly from the parameter or by quering the archiver with the block hash
|
|
1645
|
+
let blockNumber;
|
|
1554
1646
|
if (BlockHash.isBlockHash(block)) {
|
|
1555
1647
|
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
1556
1648
|
if (block.equals(initialBlockHash)) {
|
|
@@ -1561,19 +1653,41 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
1561
1653
|
if (!header) {
|
|
1562
1654
|
throw new Error(`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.`);
|
|
1563
1655
|
}
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
}
|
|
1568
|
-
//
|
|
1569
|
-
{
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1656
|
+
blockNumber = header.getBlockNumber();
|
|
1657
|
+
} else {
|
|
1658
|
+
blockNumber = block;
|
|
1659
|
+
}
|
|
1660
|
+
// Check it's within world state sync range
|
|
1661
|
+
if (blockNumber > blockSyncedTo) {
|
|
1662
|
+
throw new Error(`Queried block ${block} not yet synced by the node (node is synced upto ${blockSyncedTo}).`);
|
|
1663
|
+
}
|
|
1664
|
+
this.log.debug(`Using snapshot for block ${blockNumber}, world state synced upto ${blockSyncedTo}`);
|
|
1665
|
+
const snapshot = this.worldStateSynchronizer.getSnapshot(blockNumber);
|
|
1666
|
+
// Double-check world-state synced to the same block hash as was requested
|
|
1667
|
+
if (BlockHash.isBlockHash(block)) {
|
|
1668
|
+
const blockHash = await snapshot.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(blockNumber));
|
|
1669
|
+
if (!blockHash || !new BlockHash(blockHash).equals(block)) {
|
|
1670
|
+
throw new Error(`Block hash ${block.toString()} not found in world state at block number ${blockNumber}. If the node API has been queried with anchor block hash possibly a reorg has occurred.`);
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
return snapshot;
|
|
1674
|
+
}
|
|
1675
|
+
/** Resolves a block parameter to a block number. */ async resolveBlockNumber(block) {
|
|
1676
|
+
if (block === 'latest') {
|
|
1677
|
+
return BlockNumber(await this.blockSource.getBlockNumber());
|
|
1678
|
+
}
|
|
1679
|
+
if (BlockHash.isBlockHash(block)) {
|
|
1680
|
+
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
1681
|
+
if (block.equals(initialBlockHash)) {
|
|
1682
|
+
return BlockNumber.ZERO;
|
|
1683
|
+
}
|
|
1684
|
+
const header = await this.blockSource.getBlockHeaderByHash(block);
|
|
1685
|
+
if (!header) {
|
|
1686
|
+
throw new Error(`Block hash ${block.toString()} not found.`);
|
|
1573
1687
|
}
|
|
1574
|
-
|
|
1575
|
-
return this.worldStateSynchronizer.getSnapshot(blockNumber);
|
|
1688
|
+
return header.getBlockNumber();
|
|
1576
1689
|
}
|
|
1690
|
+
return block;
|
|
1577
1691
|
}
|
|
1578
1692
|
/**
|
|
1579
1693
|
* Ensure we fully sync the world state
|