Skip to content

Commit 80a54b5

Browse files
committed
refactor: make prover-node a subsystem of aztec-node
Changes the prover-node so, instead of a separate entrypoint, it acts as a subsystem of the aztec-node. This should help eliminate differences between the two. - Turns the prover-node from a standalone process into an optional subsystem of the aztec-node, controlled by an `enableProverNode` config flag - When enabled, `AztecNodeService.createAndSync` calls the prover-node factory passing shared subsystems (archiver, world-state, p2p, epoch cache, blob client, telemetry), so they are created once instead of duplicated - The prover-node factory creates only prover-specific sub-subsystems (broker, prover client, publisher factory, epoch monitor, L1 metrics, rollup contract) and returns a self-contained `ProverNode` - Adds owned-resources tracking to `ProverNode` so it doesn't stop shared resources on shutdown when running as a subsystem - Updates all e2e tests to create prover nodes as aztec-node subsystems instead of standalone instances - Breaks `TxSenderConfig` and `PublisherConfig` into distinct Sequencer and Prover configs, so they don't overlap with each other. Future work: - Remove the p2p client "prover" flavor - Rename prover-node to prover-client (following the naming of sequencer-client) and rename the current prover-client - Lift node-lib to aztec-node - Simplify config (eventually) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
1 parent ba40940 commit 80a54b5

48 files changed

Lines changed: 542 additions & 604 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

yarn-project/aztec-node/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
"@aztec/p2p": "workspace:^",
8383
"@aztec/protocol-contracts": "workspace:^",
8484
"@aztec/prover-client": "workspace:^",
85+
"@aztec/prover-node": "workspace:^",
8586
"@aztec/sequencer-client": "workspace:^",
8687
"@aztec/simulator": "workspace:^",
8788
"@aztec/slasher": "workspace:^",

yarn-project/aztec-node/src/aztec-node/config.test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { EthAddress } from '@aztec/foundation/eth-address';
22
import type { EthPrivateKey } from '@aztec/node-keystore';
33
import type { SharedNodeConfig } from '@aztec/node-lib/config';
4-
import type { SequencerClientConfig, TxSenderConfig } from '@aztec/sequencer-client/config';
4+
import type { SequencerClientConfig, SequencerTxSenderConfig } from '@aztec/sequencer-client/config';
55
import { AztecAddress } from '@aztec/stdlib/aztec-address';
66
import type { ValidatorClientConfig } from '@aztec/validator-client/config';
77

@@ -33,7 +33,7 @@ describe('createKeyStoreForValidator', () => {
3333
web3SignerUrl?: string,
3434
validatorAddresses: EthAddress[] = [],
3535
publisherAddresses: EthAddress[] = [],
36-
): TxSenderConfig & ValidatorClientConfig & SequencerClientConfig & SharedNodeConfig => {
36+
): SequencerTxSenderConfig & ValidatorClientConfig & SequencerClientConfig & SharedNodeConfig => {
3737
const mockValidatorPrivateKeys =
3838
validatorKeys.length > 0
3939
? {
@@ -46,14 +46,14 @@ describe('createKeyStoreForValidator', () => {
4646

4747
return {
4848
validatorPrivateKeys: mockValidatorPrivateKeys,
49-
publisherPrivateKeys: mockPublisherPrivateKeys,
49+
sequencerPublisherPrivateKeys: mockPublisherPrivateKeys,
5050
coinbase: coinbase,
5151
feeRecipient: feeRecipient,
5252
web3SignerUrl,
5353
validatorAddresses: validatorAddresses.map(addr => addr),
54-
publisherAddresses: publisherAddresses.map(addr => addr),
54+
sequencerPublisherAddresses: publisherAddresses.map(addr => addr),
5555
l1Contracts: { rollupAddress: EthAddress.random() },
56-
} as TxSenderConfig & ValidatorClientConfig & SequencerClientConfig & SharedNodeConfig;
56+
} as SequencerTxSenderConfig & ValidatorClientConfig & SequencerClientConfig & SharedNodeConfig;
5757
};
5858

5959
beforeAll(async () => {
@@ -69,11 +69,11 @@ describe('createKeyStoreForValidator', () => {
6969
it('should return undefined when validatorPrivateKeys is undefined', () => {
7070
const config = {
7171
validatorPrivateKeys: undefined,
72-
publisherPrivateKeys: undefined,
72+
sequencerPublisherPrivateKeys: undefined,
7373
coinbase: undefined,
7474
feeRecipient: undefined,
7575
l1Contracts: { rollupAddress: EthAddress.random() },
76-
} as unknown as TxSenderConfig & ValidatorClientConfig & SequencerClientConfig & SharedNodeConfig;
76+
} as unknown as SequencerTxSenderConfig & ValidatorClientConfig & SequencerClientConfig & SharedNodeConfig;
7777
const result = createKeyStoreForValidator(config);
7878
expect(result).toBeUndefined();
7979
});

yarn-project/aztec-node/src/aztec-node/config.ts

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,14 @@ import {
1313
import { type SharedNodeConfig, sharedNodeConfigMappings } from '@aztec/node-lib/config';
1414
import { type P2PConfig, p2pConfigMappings } from '@aztec/p2p/config';
1515
import { type ProverClientUserConfig, proverClientConfigMappings } from '@aztec/prover-client/config';
16+
import {
17+
type ProverNodeConfig,
18+
proverNodeConfigMappings,
19+
specificProverNodeConfigMappings,
20+
} from '@aztec/prover-node/config';
1621
import {
1722
type SequencerClientConfig,
18-
type TxSenderConfig,
23+
type SequencerTxSenderConfig,
1924
sequencerClientConfigMappings,
2025
} from '@aztec/sequencer-client/config';
2126
import { slasherConfigMappings } from '@aztec/slasher';
@@ -46,23 +51,26 @@ export type AztecNodeConfig = ArchiverConfig &
4651
SharedNodeConfig &
4752
GenesisStateConfig &
4853
NodeRPCConfig &
49-
SlasherConfig & {
54+
SlasherConfig &
55+
ProverNodeConfig & {
5056
/** L1 contracts addresses */
5157
l1Contracts: L1ContractAddresses;
5258
/** Whether the validator is disabled for this node */
5359
disableValidator: boolean;
5460
/** Whether to skip waiting for the archiver to be fully synced before starting other services */
5561
skipArchiverInitialSync: boolean;
56-
5762
/** A flag to force verification of tx Chonk proofs. Only used for testnet */
5863
debugForceTxProofVerification: boolean;
64+
/** Whether to enable the prover node as a subsystem. */
65+
enableProverNode: boolean;
5966
};
6067

6168
export const aztecNodeConfigMappings: ConfigMappingsType<AztecNodeConfig> = {
6269
...dataConfigMappings,
6370
...keyStoreConfigMappings,
6471
...archiverConfigMappings,
6572
...sequencerClientConfigMappings,
73+
...proverNodeConfigMappings,
6674
...validatorClientConfigMappings,
6775
...proverClientConfigMappings,
6876
...worldStateConfigMappings,
@@ -72,6 +80,7 @@ export const aztecNodeConfigMappings: ConfigMappingsType<AztecNodeConfig> = {
7280
...genesisStateConfigMappings,
7381
...nodeRpcConfigMappings,
7482
...slasherConfigMappings,
83+
...specificProverNodeConfigMappings,
7584
l1Contracts: {
7685
description: 'The deployed L1 contract addresses',
7786
nested: l1ContractAddressesMapping,
@@ -91,6 +100,11 @@ export const aztecNodeConfigMappings: ConfigMappingsType<AztecNodeConfig> = {
91100
description: 'Whether to skip waiting for the archiver to be fully synced before starting other services.',
92101
...booleanConfigHelper(false),
93102
},
103+
enableProverNode: {
104+
env: 'ENABLE_PROVER_NODE',
105+
description: 'Whether to enable the prover node as a subsystem.',
106+
...booleanConfigHelper(false),
107+
},
94108
};
95109

96110
/**
@@ -101,7 +115,7 @@ export function getConfigEnvVars(): AztecNodeConfig {
101115
return getConfigFromMappings<AztecNodeConfig>(aztecNodeConfigMappings);
102116
}
103117

104-
type ConfigRequiredToBuildKeyStore = TxSenderConfig & SequencerClientConfig & SharedNodeConfig & ValidatorClientConfig;
118+
type ConfigRequiredToBuildKeyStore = SequencerClientConfig & SharedNodeConfig & ValidatorClientConfig;
105119

106120
function createKeyStoreFromWeb3Signer(config: ConfigRequiredToBuildKeyStore): KeyStore | undefined {
107121
const validatorKeyStores: ValidatorKeyStore[] = [];
@@ -120,7 +134,7 @@ function createKeyStoreFromWeb3Signer(config: ConfigRequiredToBuildKeyStore): Ke
120134
feeRecipient: config.feeRecipient ?? AztecAddress.ZERO,
121135
coinbase: config.coinbase ?? config.validatorAddresses[0],
122136
remoteSigner: config.web3SignerUrl,
123-
publisher: config.publisherAddresses ?? [],
137+
publisher: config.sequencerPublisherAddresses ?? [],
124138
});
125139

126140
const keyStore: KeyStore = {
@@ -145,8 +159,10 @@ function createKeyStoreFromPrivateKeys(config: ConfigRequiredToBuildKeyStore): K
145159
const coinbase = config.coinbase ?? EthAddress.fromString(privateKeyToAddress(ethPrivateKeys[0]));
146160
const feeRecipient = config.feeRecipient ?? AztecAddress.ZERO;
147161

148-
const publisherKeys = config.publisherPrivateKeys
149-
? config.publisherPrivateKeys.map((k: { getValue: () => string }) => ethPrivateKeySchema.parse(k.getValue()))
162+
const publisherKeys = config.sequencerPublisherPrivateKeys
163+
? config.sequencerPublisherPrivateKeys.map((k: { getValue: () => string }) =>
164+
ethPrivateKeySchema.parse(k.getValue()),
165+
)
150166
: [];
151167

152168
validatorKeyStores.push({
@@ -168,7 +184,7 @@ function createKeyStoreFromPrivateKeys(config: ConfigRequiredToBuildKeyStore): K
168184
}
169185

170186
export function createKeyStoreForValidator(
171-
config: TxSenderConfig & SequencerClientConfig & SharedNodeConfig,
187+
config: SequencerTxSenderConfig & SequencerClientConfig & SharedNodeConfig,
172188
): KeyStore | undefined {
173189
if (config.web3SignerUrl !== undefined && config.web3SignerUrl.length > 0) {
174190
return createKeyStoreFromWeb3Signer(config);

yarn-project/aztec-node/src/aztec-node/server.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ describe('aztec node', () => {
173173
undefined,
174174
undefined,
175175
undefined,
176+
undefined,
176177
12345,
177178
rollupVersion.toNumber(),
178179
globalVariablesBuilder,

yarn-project/aztec-node/src/aztec-node/server.ts

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ import { type Logger, createLogger } from '@aztec/foundation/log';
1717
import { count } from '@aztec/foundation/string';
1818
import { DateProvider, Timer } from '@aztec/foundation/timer';
1919
import { MembershipWitness, SiblingPath } from '@aztec/foundation/trees';
20-
import { KeystoreManager, loadKeystores, mergeKeystores } from '@aztec/node-keystore';
20+
import { type KeyStore, KeystoreManager, loadKeystores, mergeKeystores } from '@aztec/node-keystore';
2121
import { trySnapshotSync, uploadSnapshot } from '@aztec/node-lib/actions';
2222
import { createForwarderL1TxUtilsFromSigners, createL1TxUtilsFromSigners } from '@aztec/node-lib/factories';
2323
import { type P2P, type P2PClientDeps, createP2PClient, getDefaultAllowedSetupFunctions } from '@aztec/p2p';
2424
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
25+
import { type ProverNode, type ProverNodeDeps, createProverNode } from '@aztec/prover-node';
26+
import { createKeyStoreForProver } from '@aztec/prover-node/config';
2527
import { GlobalVariableBuilder, SequencerClient, type SequencerPublisher } from '@aztec/sequencer-client';
2628
import { PublicProcessorFactory } from '@aztec/simulator/server';
2729
import {
@@ -134,6 +136,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
134136
protected readonly l1ToL2MessageSource: L1ToL2MessageSource,
135137
protected readonly worldStateSynchronizer: WorldStateSynchronizer,
136138
protected readonly sequencer: SequencerClient | undefined,
139+
protected readonly proverNode: ProverNode | undefined,
137140
protected readonly slasherClient: SlasherClientInterface | undefined,
138141
protected readonly validatorsSentinel: Sentinel | undefined,
139142
protected readonly epochPruneWatcher: EpochPruneWatcher | undefined,
@@ -176,10 +179,12 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
176179
publisher?: SequencerPublisher;
177180
dateProvider?: DateProvider;
178181
p2pClientDeps?: P2PClientDeps<P2PClientType.Full>;
182+
proverNodeDeps?: Partial<ProverNodeDeps>;
179183
} = {},
180184
options: {
181185
prefilledPublicData?: PublicDataTreeLeaf[];
182186
dontStartSequencer?: boolean;
187+
dontStartProverNode?: boolean;
183188
} = {},
184189
): Promise<AztecNodeService> {
185190
const config = { ...inputConfig }; // Copy the config so we dont mutate the input object
@@ -189,16 +194,29 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
189194
const dateProvider = deps.dateProvider ?? new DateProvider();
190195
const ethereumChain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
191196

192-
// Build a key store from file if given or from environment otherwise
197+
// Build a key store from file if given or from environment otherwise.
198+
// We keep the raw KeyStore available so we can merge with prover keys if enableProverNode is set.
193199
let keyStoreManager: KeystoreManager | undefined;
194200
const keyStoreProvided = config.keyStoreDirectory !== undefined && config.keyStoreDirectory.length > 0;
195201
if (keyStoreProvided) {
196202
const keyStores = loadKeystores(config.keyStoreDirectory!);
197203
keyStoreManager = new KeystoreManager(mergeKeystores(keyStores));
198204
} else {
199-
const keyStore = createKeyStoreForValidator(config);
200-
if (keyStore) {
201-
keyStoreManager = new KeystoreManager(keyStore);
205+
const rawKeyStores: KeyStore[] = [];
206+
const validatorKeyStore = createKeyStoreForValidator(config);
207+
if (validatorKeyStore) {
208+
rawKeyStores.push(validatorKeyStore);
209+
}
210+
if (config.enableProverNode) {
211+
const proverKeyStore = createKeyStoreForProver(config);
212+
if (proverKeyStore) {
213+
rawKeyStores.push(proverKeyStore);
214+
}
215+
}
216+
if (rawKeyStores.length > 0) {
217+
keyStoreManager = new KeystoreManager(
218+
rawKeyStores.length === 1 ? rawKeyStores[0] : mergeKeystores(rawKeyStores),
219+
);
202220
}
203221
}
204222

@@ -209,10 +227,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
209227
if (keyStoreManager === undefined) {
210228
throw new Error('Failed to create key store, a requirement for running a validator');
211229
}
212-
if (!keyStoreProvided) {
213-
log.warn(
214-
'KEY STORE CREATED FROM ENVIRONMENT, IT IS RECOMMENDED TO USE A FILE-BASED KEY STORE IN PRODUCTION ENVIRONMENTS',
215-
);
230+
if (!keyStoreProvided && process.env.NODE_ENV !== 'test') {
231+
log.warn("Keystore created from env: it's recommended to use a file-based key store for production");
216232
}
217233
ValidatorClient.validateKeyStoreConfiguration(keyStoreManager, log);
218234
}
@@ -254,7 +270,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
254270
);
255271
}
256272

257-
const blobClient = await createBlobClientWithFileStores(config, createLogger('node:blob-client:client'));
273+
const blobClient = await createBlobClientWithFileStores(config, log.createChild('blob-client'));
258274

259275
// attempt snapshot sync if possible
260276
await trySnapshotSync(config, log);
@@ -417,11 +433,11 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
417433
);
418434
await slasherClient.start();
419435

420-
const l1TxUtils = config.publisherForwarderAddress
436+
const l1TxUtils = config.sequencerPublisherForwarderAddress
421437
? await createForwarderL1TxUtilsFromSigners(
422438
publicClient,
423439
keyStoreManager!.createAllValidatorPublisherSigners(),
424-
config.publisherForwarderAddress,
440+
config.sequencerPublisherForwarderAddress,
425441
{ ...config, scope: 'sequencer' },
426442
{ telemetry, logger: log.createChild('l1-tx-utils'), dateProvider, kzg: Blob.getViemKzgInstance() },
427443
)
@@ -466,6 +482,29 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
466482
log.warn(`Sequencer created but not started`);
467483
}
468484

485+
// Create prover node subsystem if enabled
486+
let proverNode: ProverNode | undefined;
487+
if (config.enableProverNode) {
488+
proverNode = await createProverNode(config, {
489+
...deps.proverNodeDeps,
490+
telemetry,
491+
dateProvider,
492+
archiver,
493+
worldStateSynchronizer,
494+
p2pClient,
495+
epochCache,
496+
blobClient,
497+
keyStoreManager,
498+
});
499+
500+
if (!options.dontStartProverNode) {
501+
await proverNode.start();
502+
log.info(`Prover node subsystem started`);
503+
} else {
504+
log.info(`Prover node subsystem created but not started`);
505+
}
506+
}
507+
469508
const globalVariableBuilder = new GlobalVariableBuilder({
470509
...config,
471510
rollupVersion: BigInt(config.rollupVersion),
@@ -482,6 +521,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
482521
archiver,
483522
worldStateSynchronizer,
484523
sequencer,
524+
proverNode,
485525
slasherClient,
486526
validatorsSentinel,
487527
epochPruneWatcher,
@@ -507,6 +547,11 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
507547
return this.sequencer;
508548
}
509549

550+
/** Returns the prover node subsystem, if enabled. */
551+
public getProverNode(): ProverNode | undefined {
552+
return this.proverNode;
553+
}
554+
510555
public getBlockSource(): L2BlockSource {
511556
return this.blockSource;
512557
}
@@ -810,6 +855,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
810855
await tryStop(this.slasherClient);
811856
await tryStop(this.proofVerifier);
812857
await tryStop(this.sequencer);
858+
await tryStop(this.proverNode);
813859
await tryStop(this.p2pClient);
814860
await tryStop(this.worldStateSynchronizer);
815861
await tryStop(this.blockSource);

yarn-project/aztec-node/tsconfig.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@
5757
{
5858
"path": "../prover-client"
5959
},
60+
{
61+
"path": "../prover-node"
62+
},
6063
{
6164
"path": "../sequencer-client"
6265
},

yarn-project/aztec/src/cli/aztec_start_action.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,17 @@ export async function aztecStart(options: any, userLog: LogFn, debugLogger: Logg
4848
signalHandlers.push(stop);
4949
services.node = [node, AztecNodeApiSchema];
5050
} else {
51+
// Route --prover-node through startNode
52+
if (options.proverNode && !options.node) {
53+
options.node = true;
54+
}
55+
5156
if (options.node) {
5257
const { startNode } = await import('./cmds/start_node.js');
5358
({ config } = await startNode(options, signalHandlers, services, adminServices, userLog));
5459
} else if (options.bot) {
5560
const { startBot } = await import('./cmds/start_bot.js');
5661
await startBot(options, signalHandlers, services, userLog);
57-
} else if (options.proverNode) {
58-
const { startProverNode } = await import('./cmds/start_prover_node.js');
59-
({ config } = await startProverNode(options, signalHandlers, services, userLog));
6062
} else if (options.archiver) {
6163
const { startArchiver } = await import('./cmds/start_archiver.js');
6264
({ config } = await startArchiver(options, signalHandlers, services));

yarn-project/aztec/src/cli/aztec_start_options.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -222,12 +222,8 @@ export const aztecStartOptions: { [key: string]: AztecStartOption[] } = {
222222
'proverNode',
223223
omitConfigMappings(proverNodeConfigMappings, [
224224
// filter out options passed separately
225-
...getKeys(archiverConfigMappings),
226225
...getKeys(proverBrokerConfigMappings),
227226
...getKeys(proverAgentConfigMappings),
228-
...getKeys(p2pConfigMappings),
229-
...getKeys(worldStateConfigMappings),
230-
...getKeys(sharedNodeConfigMappings),
231227
]),
232228
),
233229
],

0 commit comments

Comments
 (0)