@aztec/aztec-node 0.0.1-commit.d1da697d6 → 0.0.1-commit.d20b825a7
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/server.d.ts +13 -14
- package/dest/aztec-node/server.d.ts.map +1 -1
- package/dest/aztec-node/server.js +285 -239
- package/dest/sentinel/sentinel.js +1 -1
- package/package.json +26 -26
- package/src/aztec-node/server.ts +373 -317
- package/src/sentinel/sentinel.ts +1 -1
|
@@ -386,6 +386,7 @@ import { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
386
386
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
387
387
|
import { BadRequestError } from '@aztec/foundation/json-rpc';
|
|
388
388
|
import { createLogger } from '@aztec/foundation/log';
|
|
389
|
+
import { retryUntil } from '@aztec/foundation/retry';
|
|
389
390
|
import { count } from '@aztec/foundation/string';
|
|
390
391
|
import { DateProvider, Timer } from '@aztec/foundation/timer';
|
|
391
392
|
import { MembershipWitness } from '@aztec/foundation/trees';
|
|
@@ -396,7 +397,7 @@ import { createP2PClient, createTxValidatorForAcceptingTxsOverRPC, getDefaultAll
|
|
|
396
397
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
397
398
|
import { createProverNode } from '@aztec/prover-node';
|
|
398
399
|
import { createKeyStoreForProver } from '@aztec/prover-node/config';
|
|
399
|
-
import { GlobalVariableBuilder, SequencerClient } from '@aztec/sequencer-client';
|
|
400
|
+
import { FeeProviderImpl, GlobalVariableBuilder, SequencerClient } from '@aztec/sequencer-client';
|
|
400
401
|
import { PublicProcessorFactory } from '@aztec/simulator/server';
|
|
401
402
|
import { AttestationsBlockWatcher, EpochPruneWatcher, createSlasher } from '@aztec/slasher';
|
|
402
403
|
import { CollectionLimitsConfig, PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
|
@@ -439,6 +440,7 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
439
440
|
l1ChainId;
|
|
440
441
|
version;
|
|
441
442
|
globalVariableBuilder;
|
|
443
|
+
feeProvider;
|
|
442
444
|
epochCache;
|
|
443
445
|
packageVersion;
|
|
444
446
|
peerProofVerifier;
|
|
@@ -463,7 +465,7 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
463
465
|
// Prevent two snapshot operations to happen simultaneously
|
|
464
466
|
isUploadingSnapshot;
|
|
465
467
|
tracer;
|
|
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()){
|
|
468
|
+
constructor(config, p2pClient, blockSource, logsSource, contractDataSource, l1ToL2MessageSource, worldStateSynchronizer, sequencer, proverNode, slasherClient, validatorsSentinel, epochPruneWatcher, l1ChainId, version, globalVariableBuilder, feeProvider, epochCache, packageVersion, peerProofVerifier, rpcProofVerifier, telemetry = getTelemetryClient(), log = createLogger('node'), blobClient, validatorClient, keyStoreManager, debugLogStore = new NullDebugLogStore()){
|
|
467
469
|
this.config = config;
|
|
468
470
|
this.p2pClient = p2pClient;
|
|
469
471
|
this.blockSource = blockSource;
|
|
@@ -479,6 +481,7 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
479
481
|
this.l1ChainId = l1ChainId;
|
|
480
482
|
this.version = version;
|
|
481
483
|
this.globalVariableBuilder = globalVariableBuilder;
|
|
484
|
+
this.feeProvider = feeProvider;
|
|
482
485
|
this.epochCache = epochCache;
|
|
483
486
|
this.packageVersion = packageVersion;
|
|
484
487
|
this.peerProofVerifier = peerProofVerifier;
|
|
@@ -593,234 +596,252 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
593
596
|
const epochCache = await EpochCache.create(config.l1Contracts.rollupAddress, config, {
|
|
594
597
|
dateProvider
|
|
595
598
|
});
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
dateProvider
|
|
601
|
-
}, {
|
|
602
|
-
blockUntilSync: !config.skipArchiverInitialSync
|
|
603
|
-
});
|
|
604
|
-
// now create the merkle trees and the world state synchronizer
|
|
605
|
-
const worldStateSynchronizer = await createWorldStateSynchronizer(config, archiver, options.prefilledPublicData, telemetry);
|
|
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;
|
|
618
|
-
if (!config.realProofs) {
|
|
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');
|
|
628
|
-
}
|
|
629
|
-
// create the tx pool and the p2p client, which will need the l2 block source
|
|
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.
|
|
635
|
-
const validatorCheckpointsBuilder = new FullNodeCheckpointsBuilder({
|
|
636
|
-
...config,
|
|
637
|
-
l1GenesisTime,
|
|
638
|
-
slotDuration: Number(slotDuration),
|
|
639
|
-
rollupManaLimit,
|
|
640
|
-
maxTxsPerCheckpoint: config.validateMaxTxsPerCheckpoint
|
|
641
|
-
}, worldStateSynchronizer, archiver, dateProvider, telemetry);
|
|
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,
|
|
599
|
+
// Track started resources so we can clean up on partial failure during node creation.
|
|
600
|
+
const started = [];
|
|
601
|
+
try {
|
|
602
|
+
const archiver = await createArchiver(config, {
|
|
655
603
|
blobClient,
|
|
656
|
-
|
|
604
|
+
epochCache,
|
|
605
|
+
telemetry,
|
|
606
|
+
dateProvider
|
|
607
|
+
}, {
|
|
608
|
+
blockUntilSync: !config.skipArchiverInitialSync
|
|
657
609
|
});
|
|
658
|
-
|
|
659
|
-
//
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
610
|
+
started.push(archiver);
|
|
611
|
+
// now create the merkle trees and the world state synchronizer
|
|
612
|
+
const worldStateSynchronizer = await createWorldStateSynchronizer(config, archiver, options.genesis, telemetry);
|
|
613
|
+
started.push(worldStateSynchronizer);
|
|
614
|
+
const useRealVerifiers = config.realProofs || config.debugForceTxProofVerification;
|
|
615
|
+
let peerProofVerifier;
|
|
616
|
+
let rpcProofVerifier;
|
|
617
|
+
if (useRealVerifiers) {
|
|
618
|
+
peerProofVerifier = await BatchChonkVerifier.new(config, config.bbChonkVerifyMaxBatch, 'peer');
|
|
619
|
+
const rpcVerifier = await BBCircuitVerifier.new(config);
|
|
620
|
+
rpcProofVerifier = new QueuedIVCVerifier(rpcVerifier, config.numConcurrentIVCVerifiers);
|
|
621
|
+
} else {
|
|
622
|
+
peerProofVerifier = new TestCircuitVerifier(config.proverTestVerificationDelayMs);
|
|
623
|
+
rpcProofVerifier = new TestCircuitVerifier(config.proverTestVerificationDelayMs);
|
|
669
624
|
}
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
createProposalHandler(config, {
|
|
679
|
-
checkpointsBuilder: validatorCheckpointsBuilder,
|
|
680
|
-
worldState: worldStateSynchronizer,
|
|
681
|
-
epochCache,
|
|
682
|
-
blockSource: archiver,
|
|
683
|
-
l1ToL2MessageSource: archiver,
|
|
684
|
-
p2pClient,
|
|
685
|
-
blobClient,
|
|
686
|
-
dateProvider,
|
|
687
|
-
telemetry
|
|
688
|
-
}).register(p2pClient, reexecute, archiver);
|
|
689
|
-
}
|
|
690
|
-
// Start world state and wait for it to sync to the archiver.
|
|
691
|
-
await worldStateSynchronizer.start();
|
|
692
|
-
// Start p2p. Note that it depends on world state to be running.
|
|
693
|
-
await p2pClient.start();
|
|
694
|
-
let validatorsSentinel;
|
|
695
|
-
let epochPruneWatcher;
|
|
696
|
-
let attestationsBlockWatcher;
|
|
697
|
-
if (!proverOnly) {
|
|
698
|
-
validatorsSentinel = await createSentinel(epochCache, archiver, p2pClient, config);
|
|
699
|
-
if (validatorsSentinel && config.slashInactivityPenalty > 0n) {
|
|
700
|
-
watchers.push(validatorsSentinel);
|
|
625
|
+
started.push(peerProofVerifier, rpcProofVerifier);
|
|
626
|
+
let debugLogStore;
|
|
627
|
+
if (!config.realProofs) {
|
|
628
|
+
log.warn(`Aztec node is accepting fake proofs`);
|
|
629
|
+
debugLogStore = new InMemoryDebugLogStore();
|
|
630
|
+
log.info('Aztec node started in test mode (realProofs set to false) hence debug logs from public functions will be collected and served');
|
|
631
|
+
} else {
|
|
632
|
+
debugLogStore = new NullDebugLogStore();
|
|
701
633
|
}
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
634
|
+
const globalVariableBuilderConfig = {
|
|
635
|
+
l1Contracts: config.l1Contracts,
|
|
636
|
+
ethereumSlotDuration: config.ethereumSlotDuration,
|
|
637
|
+
rollupVersion: BigInt(config.rollupVersion),
|
|
638
|
+
l1GenesisTime,
|
|
639
|
+
slotDuration: Number(slotDuration)
|
|
640
|
+
};
|
|
641
|
+
const globalVariableBuilder = new GlobalVariableBuilder(dateProvider, publicClient, globalVariableBuilderConfig);
|
|
642
|
+
const feeProvider = new FeeProviderImpl(dateProvider, publicClient, globalVariableBuilderConfig);
|
|
643
|
+
const proverOnly = config.enableProverNode && config.disableValidator;
|
|
644
|
+
if (proverOnly) {
|
|
645
|
+
log.info('Starting in prover-only mode: skipping validator, sequencer, sentinel, and slasher subsystems');
|
|
705
646
|
}
|
|
706
|
-
//
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
647
|
+
// create the tx pool and the p2p client, which will need the l2 block source
|
|
648
|
+
const p2pClient = await createP2PClient(config, archiver, peerProofVerifier, worldStateSynchronizer, epochCache, feeProvider, packageVersion, dateProvider, telemetry, deps.p2pClientDeps);
|
|
649
|
+
started.push(p2pClient);
|
|
650
|
+
// We'll accumulate sentinel watchers here
|
|
651
|
+
const watchers = [];
|
|
652
|
+
// Create FullNodeCheckpointsBuilder for block proposal handling and tx validation.
|
|
653
|
+
// Override maxTxsPerCheckpoint with the validator-specific limit if set.
|
|
654
|
+
const validatorCheckpointsBuilder = new FullNodeCheckpointsBuilder({
|
|
655
|
+
...config,
|
|
656
|
+
l1GenesisTime,
|
|
657
|
+
slotDuration: Number(slotDuration),
|
|
658
|
+
rollupManaLimit,
|
|
659
|
+
maxTxsPerCheckpoint: config.validateMaxTxsPerCheckpoint
|
|
660
|
+
}, worldStateSynchronizer, archiver, dateProvider, telemetry);
|
|
661
|
+
let validatorClient;
|
|
662
|
+
if (!proverOnly) {
|
|
663
|
+
// Create validator client if required
|
|
664
|
+
validatorClient = await createValidatorClient(config, {
|
|
665
|
+
checkpointsBuilder: validatorCheckpointsBuilder,
|
|
666
|
+
worldState: worldStateSynchronizer,
|
|
667
|
+
p2pClient,
|
|
668
|
+
telemetry,
|
|
669
|
+
dateProvider,
|
|
670
|
+
epochCache,
|
|
671
|
+
blockSource: archiver,
|
|
672
|
+
l1ToL2MessageSource: archiver,
|
|
673
|
+
keyStoreManager,
|
|
674
|
+
blobClient,
|
|
675
|
+
slashingProtectionDb: deps.slashingProtectionDb
|
|
676
|
+
});
|
|
677
|
+
// If we have a validator client, register it as a source of offenses for the slasher,
|
|
678
|
+
// and have it register callbacks on the p2p client *before* we start it, otherwise messages
|
|
679
|
+
// like attestations or auths will fail.
|
|
680
|
+
if (validatorClient) {
|
|
681
|
+
watchers.push(validatorClient);
|
|
682
|
+
const vc = validatorClient;
|
|
683
|
+
const getValidatorAddresses = ()=>vc.getValidatorAddresses().map((a)=>a.toString());
|
|
684
|
+
validatorClient.getProposalHandler().register(p2pClient, true, archiver, getValidatorAddresses);
|
|
685
|
+
if (!options.dontStartSequencer) {
|
|
686
|
+
await validatorClient.registerHandlers();
|
|
687
|
+
}
|
|
688
|
+
}
|
|
710
689
|
}
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
690
|
+
// If there's no validator client, create a ProposalHandler to handle block and checkpoint proposals
|
|
691
|
+
// for monitoring or reexecution. Reexecution (default) allows us to follow the pending chain,
|
|
692
|
+
// while non-reexecution is used for validating the proposals and collecting their txs.
|
|
693
|
+
// Checkpoint proposals rebuild blobs if the blob client can upload blobs.
|
|
694
|
+
if (!validatorClient) {
|
|
695
|
+
const reexecute = !!config.alwaysReexecuteBlockProposals;
|
|
696
|
+
log.info(`Setting up proposal handler` + (reexecute ? ' with reexecution of proposals' : ''));
|
|
697
|
+
createProposalHandler(config, {
|
|
698
|
+
checkpointsBuilder: validatorCheckpointsBuilder,
|
|
699
|
+
worldState: worldStateSynchronizer,
|
|
700
|
+
epochCache,
|
|
701
|
+
blockSource: archiver,
|
|
702
|
+
l1ToL2MessageSource: archiver,
|
|
703
|
+
p2pClient,
|
|
704
|
+
blobClient,
|
|
705
|
+
dateProvider,
|
|
706
|
+
telemetry
|
|
707
|
+
}).register(p2pClient, reexecute, archiver);
|
|
708
|
+
}
|
|
709
|
+
// Start world state and wait for it to sync to the archiver.
|
|
710
|
+
await worldStateSynchronizer.start();
|
|
711
|
+
// Start p2p. Note that it depends on world state to be running.
|
|
714
712
|
await p2pClient.start();
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
},
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
kzg: Blob.getViemKzgInstance()
|
|
752
|
-
});
|
|
753
|
-
// Create a funder L1TxUtils from the keystore funding account (if configured)
|
|
754
|
-
const fundingSigner = keyStoreManager?.createFundingSigner();
|
|
755
|
-
let funderL1TxUtils;
|
|
756
|
-
if (fundingSigner) {
|
|
757
|
-
const [funder] = await createL1TxUtilsFromSigners(publicClient, [
|
|
758
|
-
fundingSigner
|
|
759
|
-
], {
|
|
713
|
+
let validatorsSentinel;
|
|
714
|
+
let epochPruneWatcher;
|
|
715
|
+
let attestationsBlockWatcher;
|
|
716
|
+
if (!proverOnly) {
|
|
717
|
+
validatorsSentinel = await createSentinel(epochCache, archiver, p2pClient, config);
|
|
718
|
+
if (validatorsSentinel && config.slashInactivityPenalty > 0n) {
|
|
719
|
+
watchers.push(validatorsSentinel);
|
|
720
|
+
}
|
|
721
|
+
if (config.slashPrunePenalty > 0n || config.slashDataWithholdingPenalty > 0n) {
|
|
722
|
+
epochPruneWatcher = new EpochPruneWatcher(archiver, archiver, epochCache, p2pClient.getTxProvider(), validatorCheckpointsBuilder, config);
|
|
723
|
+
watchers.push(epochPruneWatcher);
|
|
724
|
+
}
|
|
725
|
+
// We assume we want to slash for invalid attestations unless all max penalties are set to 0
|
|
726
|
+
if (config.slashProposeInvalidAttestationsPenalty > 0n || config.slashAttestDescendantOfInvalidPenalty > 0n) {
|
|
727
|
+
attestationsBlockWatcher = new AttestationsBlockWatcher(archiver, epochCache, config);
|
|
728
|
+
watchers.push(attestationsBlockWatcher);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
// Start p2p-related services once the archiver has completed sync
|
|
732
|
+
void archiver.waitForInitialSync().then(async ()=>{
|
|
733
|
+
await validatorsSentinel?.start();
|
|
734
|
+
await epochPruneWatcher?.start();
|
|
735
|
+
await attestationsBlockWatcher?.start();
|
|
736
|
+
log.info(`All p2p services started`);
|
|
737
|
+
}).catch((err)=>log.error('Failed to start p2p services after archiver sync', err));
|
|
738
|
+
// Validator enabled, create/start relevant service
|
|
739
|
+
let sequencer;
|
|
740
|
+
let slasherClient;
|
|
741
|
+
if (!config.disableValidator && validatorClient) {
|
|
742
|
+
// We create a slasher only if we have a sequencer, since all slashing actions go through the sequencer publisher
|
|
743
|
+
// as they are executed when the node is selected as proposer.
|
|
744
|
+
const validatorAddresses = keyStoreManager ? NodeKeystoreAdapter.fromKeyStoreManager(keyStoreManager).getAddresses() : [];
|
|
745
|
+
slasherClient = await createSlasher(config, config.l1Contracts, getPublicClient(config), watchers, dateProvider, epochCache, validatorAddresses, undefined);
|
|
746
|
+
await slasherClient.start();
|
|
747
|
+
started.push(slasherClient);
|
|
748
|
+
const l1TxUtils = config.sequencerPublisherForwarderAddress ? await createForwarderL1TxUtilsFromSigners(publicClient, keyStoreManager.createAllValidatorPublisherSigners(), config.sequencerPublisherForwarderAddress, {
|
|
760
749
|
...config,
|
|
761
750
|
scope: 'sequencer'
|
|
762
751
|
}, {
|
|
763
752
|
telemetry,
|
|
764
|
-
logger: log.createChild('l1-tx-utils
|
|
765
|
-
dateProvider
|
|
753
|
+
logger: log.createChild('l1-tx-utils'),
|
|
754
|
+
dateProvider,
|
|
755
|
+
kzg: Blob.getViemKzgInstance()
|
|
756
|
+
}) : await createL1TxUtilsFromSigners(publicClient, keyStoreManager.createAllValidatorPublisherSigners(), {
|
|
757
|
+
...config,
|
|
758
|
+
scope: 'sequencer'
|
|
759
|
+
}, {
|
|
760
|
+
telemetry,
|
|
761
|
+
logger: log.createChild('l1-tx-utils'),
|
|
762
|
+
dateProvider,
|
|
763
|
+
kzg: Blob.getViemKzgInstance()
|
|
764
|
+
});
|
|
765
|
+
// Create a funder L1TxUtils from the keystore funding account (if configured)
|
|
766
|
+
const fundingSigner = keyStoreManager?.createFundingSigner();
|
|
767
|
+
let funderL1TxUtils;
|
|
768
|
+
if (fundingSigner) {
|
|
769
|
+
const [funder] = await createL1TxUtilsFromSigners(publicClient, [
|
|
770
|
+
fundingSigner
|
|
771
|
+
], {
|
|
772
|
+
...config,
|
|
773
|
+
scope: 'sequencer'
|
|
774
|
+
}, {
|
|
775
|
+
telemetry,
|
|
776
|
+
logger: log.createChild('l1-tx-utils:funder'),
|
|
777
|
+
dateProvider
|
|
778
|
+
});
|
|
779
|
+
funderL1TxUtils = funder;
|
|
780
|
+
}
|
|
781
|
+
// Create and start the sequencer client
|
|
782
|
+
const checkpointsBuilder = new CheckpointsBuilder({
|
|
783
|
+
...config,
|
|
784
|
+
l1GenesisTime,
|
|
785
|
+
slotDuration: Number(slotDuration),
|
|
786
|
+
rollupManaLimit
|
|
787
|
+
}, worldStateSynchronizer, archiver, dateProvider, telemetry, debugLogStore);
|
|
788
|
+
sequencer = await SequencerClient.new(config, {
|
|
789
|
+
...deps,
|
|
790
|
+
epochCache,
|
|
791
|
+
l1TxUtils,
|
|
792
|
+
funderL1TxUtils,
|
|
793
|
+
validatorClient,
|
|
794
|
+
p2pClient,
|
|
795
|
+
worldStateSynchronizer,
|
|
796
|
+
slasherClient,
|
|
797
|
+
checkpointsBuilder,
|
|
798
|
+
l2BlockSource: archiver,
|
|
799
|
+
l1ToL2MessageSource: archiver,
|
|
800
|
+
telemetry,
|
|
801
|
+
dateProvider,
|
|
802
|
+
blobClient,
|
|
803
|
+
nodeKeyStore: keyStoreManager,
|
|
804
|
+
globalVariableBuilder
|
|
766
805
|
});
|
|
767
|
-
funderL1TxUtils = funder;
|
|
768
806
|
}
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
}, worldStateSynchronizer, archiver, dateProvider, telemetry, debugLogStore);
|
|
776
|
-
sequencer = await SequencerClient.new(config, {
|
|
777
|
-
...deps,
|
|
778
|
-
epochCache,
|
|
779
|
-
l1TxUtils,
|
|
780
|
-
funderL1TxUtils,
|
|
781
|
-
validatorClient,
|
|
782
|
-
p2pClient,
|
|
783
|
-
worldStateSynchronizer,
|
|
784
|
-
slasherClient,
|
|
785
|
-
checkpointsBuilder,
|
|
786
|
-
l2BlockSource: archiver,
|
|
787
|
-
l1ToL2MessageSource: archiver,
|
|
788
|
-
telemetry,
|
|
789
|
-
dateProvider,
|
|
790
|
-
blobClient,
|
|
791
|
-
nodeKeyStore: keyStoreManager,
|
|
792
|
-
globalVariableBuilder
|
|
793
|
-
});
|
|
794
|
-
}
|
|
795
|
-
if (!options.dontStartSequencer && sequencer) {
|
|
796
|
-
await sequencer.start();
|
|
797
|
-
log.verbose(`Sequencer started`);
|
|
798
|
-
} else if (sequencer) {
|
|
799
|
-
log.warn(`Sequencer created but not started`);
|
|
800
|
-
}
|
|
801
|
-
// Create prover node subsystem if enabled
|
|
802
|
-
let proverNode;
|
|
803
|
-
if (config.enableProverNode) {
|
|
804
|
-
proverNode = await createProverNode(config, {
|
|
805
|
-
...deps.proverNodeDeps,
|
|
806
|
-
telemetry,
|
|
807
|
-
dateProvider,
|
|
808
|
-
archiver,
|
|
809
|
-
worldStateSynchronizer,
|
|
810
|
-
p2pClient,
|
|
811
|
-
epochCache,
|
|
812
|
-
blobClient,
|
|
813
|
-
keyStoreManager
|
|
814
|
-
});
|
|
815
|
-
if (!options.dontStartProverNode) {
|
|
816
|
-
await proverNode.start();
|
|
817
|
-
log.info(`Prover node subsystem started`);
|
|
818
|
-
} else {
|
|
819
|
-
log.info(`Prover node subsystem created but not started`);
|
|
807
|
+
if (!options.dontStartSequencer && sequencer) {
|
|
808
|
+
await sequencer.start();
|
|
809
|
+
started.push(sequencer);
|
|
810
|
+
log.verbose(`Sequencer started`);
|
|
811
|
+
} else if (sequencer) {
|
|
812
|
+
log.warn(`Sequencer created but not started`);
|
|
820
813
|
}
|
|
814
|
+
// Create prover node subsystem if enabled
|
|
815
|
+
let proverNode;
|
|
816
|
+
if (config.enableProverNode) {
|
|
817
|
+
proverNode = await createProverNode(config, {
|
|
818
|
+
...deps.proverNodeDeps,
|
|
819
|
+
telemetry,
|
|
820
|
+
dateProvider,
|
|
821
|
+
archiver,
|
|
822
|
+
worldStateSynchronizer,
|
|
823
|
+
p2pClient,
|
|
824
|
+
epochCache,
|
|
825
|
+
blobClient,
|
|
826
|
+
keyStoreManager
|
|
827
|
+
});
|
|
828
|
+
if (!options.dontStartProverNode) {
|
|
829
|
+
await proverNode.start();
|
|
830
|
+
started.push(proverNode);
|
|
831
|
+
log.info(`Prover node subsystem started`);
|
|
832
|
+
} else {
|
|
833
|
+
log.info(`Prover node subsystem created but not started`);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
const node = new AztecNodeService(config, p2pClient, archiver, archiver, archiver, archiver, worldStateSynchronizer, sequencer, proverNode, slasherClient, validatorsSentinel, epochPruneWatcher, ethereumChain.chainInfo.id, config.rollupVersion, globalVariableBuilder, feeProvider, epochCache, packageVersion, peerProofVerifier, rpcProofVerifier, telemetry, log, blobClient, validatorClient, keyStoreManager, debugLogStore);
|
|
837
|
+
return node;
|
|
838
|
+
} catch (err) {
|
|
839
|
+
log.error('Failed during node creation, stopping started resources', err);
|
|
840
|
+
for (const resource of started.reverse()){
|
|
841
|
+
await tryStop(resource);
|
|
842
|
+
}
|
|
843
|
+
throw err;
|
|
821
844
|
}
|
|
822
|
-
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);
|
|
823
|
-
return node;
|
|
824
845
|
}
|
|
825
846
|
/**
|
|
826
847
|
* Returns the sequencer client instance.
|
|
@@ -934,11 +955,11 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
934
955
|
getCheckpointsDataForEpoch(epochNumber) {
|
|
935
956
|
return this.blockSource.getCheckpointsDataForEpoch(epochNumber);
|
|
936
957
|
}
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
return await this.
|
|
958
|
+
async getCurrentMinFees() {
|
|
959
|
+
return await this.feeProvider.getCurrentMinFees();
|
|
960
|
+
}
|
|
961
|
+
/** Returns predicted min fees for the current slot and next N slots. */ async getPredictedMinFees(manaUsage) {
|
|
962
|
+
return await this.feeProvider.getPredictedMinFees(manaUsage);
|
|
942
963
|
}
|
|
943
964
|
async getMaxPriorityFees() {
|
|
944
965
|
for await (const tx of this.p2pClient.iteratePendingTxs()){
|
|
@@ -1177,13 +1198,13 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
1177
1198
|
if (blockNumber === undefined) {
|
|
1178
1199
|
throw new Error(`Block number not found for leaf index ${index} in tree ${MerkleTreeId[treeId]}`);
|
|
1179
1200
|
}
|
|
1180
|
-
const
|
|
1181
|
-
if (
|
|
1201
|
+
const l2BlockHash = blockNumberToHash.get(blockNumber);
|
|
1202
|
+
if (l2BlockHash === undefined) {
|
|
1182
1203
|
throw new Error(`Block hash not found for block number ${blockNumber}`);
|
|
1183
1204
|
}
|
|
1184
1205
|
return {
|
|
1185
1206
|
l2BlockNumber: blockNumber,
|
|
1186
|
-
l2BlockHash
|
|
1207
|
+
l2BlockHash,
|
|
1187
1208
|
data: index
|
|
1188
1209
|
};
|
|
1189
1210
|
});
|
|
@@ -1545,18 +1566,12 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
1545
1566
|
this.blockSource.resume();
|
|
1546
1567
|
return Promise.resolve();
|
|
1547
1568
|
}
|
|
1548
|
-
getSlashPayloads() {
|
|
1549
|
-
if (!this.slasherClient) {
|
|
1550
|
-
throw new Error(`Slasher client not enabled`);
|
|
1551
|
-
}
|
|
1552
|
-
return this.slasherClient.getSlashPayloads();
|
|
1553
|
-
}
|
|
1554
1569
|
getSlashOffenses(round) {
|
|
1555
1570
|
if (!this.slasherClient) {
|
|
1556
1571
|
throw new Error(`Slasher client not enabled`);
|
|
1557
1572
|
}
|
|
1558
1573
|
if (round === 'all') {
|
|
1559
|
-
return this.slasherClient.
|
|
1574
|
+
return this.slasherClient.getOffenses();
|
|
1560
1575
|
} else {
|
|
1561
1576
|
return this.slasherClient.gatherOffensesForRound(round === 'current' ? undefined : BigInt(round));
|
|
1562
1577
|
}
|
|
@@ -1628,6 +1643,33 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
1628
1643
|
this.keyStoreManager = newManager;
|
|
1629
1644
|
this.log.info('Keystore reloaded: coinbase, feeRecipient, and attester keys updated');
|
|
1630
1645
|
}
|
|
1646
|
+
async mineBlock() {
|
|
1647
|
+
if (!this.sequencer) {
|
|
1648
|
+
throw new BadRequestError('Cannot mine block: no sequencer is running');
|
|
1649
|
+
}
|
|
1650
|
+
const currentBlockNumber = await this.getBlockNumber();
|
|
1651
|
+
// Use slot duration + 50% buffer as the timeout so this works on running networks too
|
|
1652
|
+
const { slotDuration } = await this.blockSource.getL1Constants();
|
|
1653
|
+
const timeoutSeconds = Math.ceil(slotDuration * 1.5);
|
|
1654
|
+
// Temporarily set minTxsPerBlock to 0 so the sequencer produces a block even with no txs
|
|
1655
|
+
const originalMinTxsPerBlock = this.sequencer.getSequencer().getConfig().minTxsPerBlock;
|
|
1656
|
+
this.sequencer.updateConfig({
|
|
1657
|
+
minTxsPerBlock: 0
|
|
1658
|
+
});
|
|
1659
|
+
try {
|
|
1660
|
+
// Trigger the sequencer to produce a block immediately
|
|
1661
|
+
void this.sequencer.trigger();
|
|
1662
|
+
// Wait for the new L2 block to appear
|
|
1663
|
+
await retryUntil(async ()=>{
|
|
1664
|
+
const newBlockNumber = await this.getBlockNumber();
|
|
1665
|
+
return newBlockNumber > currentBlockNumber ? true : undefined;
|
|
1666
|
+
}, 'mineBlock', timeoutSeconds, 0.1);
|
|
1667
|
+
} finally{
|
|
1668
|
+
this.sequencer.updateConfig({
|
|
1669
|
+
minTxsPerBlock: originalMinTxsPerBlock
|
|
1670
|
+
});
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1631
1673
|
#getInitialHeaderHash() {
|
|
1632
1674
|
if (!this.initialHeaderHashPromise) {
|
|
1633
1675
|
this.initialHeaderHashPromise = this.worldStateSynchronizer.getCommitted().getInitialHeader().hash();
|
|
@@ -1655,14 +1697,17 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
1655
1697
|
if (BlockHash.isBlockHash(block)) {
|
|
1656
1698
|
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
1657
1699
|
if (block.equals(initialBlockHash)) {
|
|
1658
|
-
// Block
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1700
|
+
// Block 0 is a first-class historical block: its state lives in the trees' persisted
|
|
1701
|
+
// block-0 payload. Resolving the genesis hash to block number 0 lets the snapshot path
|
|
1702
|
+
// pin reads to genesis state even after the node has advanced past it.
|
|
1703
|
+
blockNumber = BlockNumber.ZERO;
|
|
1704
|
+
} else {
|
|
1705
|
+
const header = await this.blockSource.getBlockHeaderByHash(block);
|
|
1706
|
+
if (!header) {
|
|
1707
|
+
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.`);
|
|
1708
|
+
}
|
|
1709
|
+
blockNumber = header.getBlockNumber();
|
|
1664
1710
|
}
|
|
1665
|
-
blockNumber = header.getBlockNumber();
|
|
1666
1711
|
} else {
|
|
1667
1712
|
blockNumber = block;
|
|
1668
1713
|
}
|
|
@@ -1675,8 +1720,9 @@ _dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
|
1675
1720
|
// Double-check world-state synced to the same block hash as was requested
|
|
1676
1721
|
if (BlockHash.isBlockHash(block)) {
|
|
1677
1722
|
const blockHash = await snapshot.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(blockNumber));
|
|
1678
|
-
if (!blockHash || !
|
|
1679
|
-
|
|
1723
|
+
if (!blockHash || !block.equals(blockHash)) {
|
|
1724
|
+
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
1725
|
+
throw new Error(`Block hash ${block.toString()} not found in world state at block number ${blockNumber} (world state has ${blockHash?.toString() ?? 'no hash'} at that index, genesis header hash is ${initialBlockHash.toString()}). If the node API has been queried with anchor block hash possibly a reorg has occurred.`);
|
|
1680
1726
|
}
|
|
1681
1727
|
}
|
|
1682
1728
|
return snapshot;
|
|
@@ -163,7 +163,7 @@ export class Sentinel extends EventEmitter {
|
|
|
163
163
|
if (this.config.slashInactivityPenalty === 0n) {
|
|
164
164
|
return;
|
|
165
165
|
}
|
|
166
|
-
const inactiveValidators = getEntries(performance).filter(([_, { missed, total }])=>missed / total >= this.config.slashInactivityTargetPercentage).map(([address])=>address);
|
|
166
|
+
const inactiveValidators = getEntries(performance).filter(([_, { missed, total }])=>total > 0 && missed / total >= this.config.slashInactivityTargetPercentage).map(([address])=>address);
|
|
167
167
|
this.logger.debug(`Found ${inactiveValidators.length} inactive validators in epoch ${epoch}`, {
|
|
168
168
|
inactiveValidators,
|
|
169
169
|
epoch,
|