@aztec/aztec-node 0.0.1-commit.c80b6263 → 0.0.1-commit.cd76b27
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 +7 -4
- package/dest/aztec-node/config.d.ts.map +1 -1
- package/dest/aztec-node/config.js +10 -2
- package/dest/aztec-node/server.d.ts +28 -18
- package/dest/aztec-node/server.d.ts.map +1 -1
- package/dest/aztec-node/server.js +172 -66
- package/dest/sentinel/sentinel.d.ts +2 -2
- package/dest/sentinel/sentinel.d.ts.map +1 -1
- package/dest/sentinel/sentinel.js +53 -27
- package/dest/sentinel/store.d.ts +2 -2
- package/dest/sentinel/store.d.ts.map +1 -1
- package/dest/sentinel/store.js +11 -7
- package/package.json +27 -25
- package/src/aztec-node/config.ts +24 -8
- package/src/aztec-node/server.ts +215 -99
- package/src/sentinel/sentinel.ts +56 -23
- package/src/sentinel/store.ts +12 -12
package/src/aztec-node/server.ts
CHANGED
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
import { Archiver, createArchiver } from '@aztec/archiver';
|
|
2
2
|
import { BBCircuitVerifier, QueuedIVCVerifier, TestCircuitVerifier } from '@aztec/bb-prover';
|
|
3
3
|
import { type BlobClientInterface, createBlobClientWithFileStores } from '@aztec/blob-client/client';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
type L1_TO_L2_MSG_TREE_HEIGHT,
|
|
7
|
-
type NOTE_HASH_TREE_HEIGHT,
|
|
8
|
-
type NULLIFIER_TREE_HEIGHT,
|
|
9
|
-
type PUBLIC_DATA_TREE_HEIGHT,
|
|
10
|
-
} from '@aztec/constants';
|
|
4
|
+
import { Blob } from '@aztec/blob-lib';
|
|
5
|
+
import { ARCHIVE_HEIGHT, type L1_TO_L2_MSG_TREE_HEIGHT, type NOTE_HASH_TREE_HEIGHT } from '@aztec/constants';
|
|
11
6
|
import { EpochCache, type EpochCacheInterface } from '@aztec/epoch-cache';
|
|
12
7
|
import { createEthereumChain } from '@aztec/ethereum/chain';
|
|
13
8
|
import { getPublicClient } from '@aztec/ethereum/client';
|
|
14
9
|
import { RegistryContract, RollupContract } from '@aztec/ethereum/contracts';
|
|
15
10
|
import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
|
|
16
11
|
import { BlockNumber, CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
17
|
-
import { compactArray, pick } from '@aztec/foundation/collection';
|
|
12
|
+
import { compactArray, pick, unique } from '@aztec/foundation/collection';
|
|
18
13
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
19
14
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
20
15
|
import { BadRequestError } from '@aztec/foundation/json-rpc';
|
|
@@ -22,14 +17,13 @@ import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
|
22
17
|
import { count } from '@aztec/foundation/string';
|
|
23
18
|
import { DateProvider, Timer } from '@aztec/foundation/timer';
|
|
24
19
|
import { MembershipWitness, SiblingPath } from '@aztec/foundation/trees';
|
|
25
|
-
import { KeystoreManager, loadKeystores, mergeKeystores } from '@aztec/node-keystore';
|
|
20
|
+
import { type KeyStore, KeystoreManager, loadKeystores, mergeKeystores } from '@aztec/node-keystore';
|
|
26
21
|
import { trySnapshotSync, uploadSnapshot } from '@aztec/node-lib/actions';
|
|
27
|
-
import {
|
|
28
|
-
createForwarderL1TxUtilsFromEthSigner,
|
|
29
|
-
createL1TxUtilsWithBlobsFromEthSigner,
|
|
30
|
-
} from '@aztec/node-lib/factories';
|
|
22
|
+
import { createForwarderL1TxUtilsFromSigners, createL1TxUtilsFromSigners } from '@aztec/node-lib/factories';
|
|
31
23
|
import { type P2P, type P2PClientDeps, createP2PClient, getDefaultAllowedSetupFunctions } from '@aztec/p2p';
|
|
32
24
|
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';
|
|
33
27
|
import { GlobalVariableBuilder, SequencerClient, type SequencerPublisher } from '@aztec/sequencer-client';
|
|
34
28
|
import { PublicProcessorFactory } from '@aztec/simulator/server';
|
|
35
29
|
import {
|
|
@@ -41,7 +35,14 @@ import {
|
|
|
41
35
|
} from '@aztec/slasher';
|
|
42
36
|
import { CollectionLimitsConfig, PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
|
43
37
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
44
|
-
import {
|
|
38
|
+
import {
|
|
39
|
+
type BlockData,
|
|
40
|
+
BlockHash,
|
|
41
|
+
type BlockParameter,
|
|
42
|
+
type DataInBlock,
|
|
43
|
+
L2Block,
|
|
44
|
+
type L2BlockSource,
|
|
45
|
+
} from '@aztec/stdlib/block';
|
|
45
46
|
import type { PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
46
47
|
import type {
|
|
47
48
|
ContractClassPublic,
|
|
@@ -135,6 +136,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
135
136
|
protected readonly l1ToL2MessageSource: L1ToL2MessageSource,
|
|
136
137
|
protected readonly worldStateSynchronizer: WorldStateSynchronizer,
|
|
137
138
|
protected readonly sequencer: SequencerClient | undefined,
|
|
139
|
+
protected readonly proverNode: ProverNode | undefined,
|
|
138
140
|
protected readonly slasherClient: SlasherClientInterface | undefined,
|
|
139
141
|
protected readonly validatorsSentinel: Sentinel | undefined,
|
|
140
142
|
protected readonly epochPruneWatcher: EpochPruneWatcher | undefined,
|
|
@@ -147,6 +149,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
147
149
|
private telemetry: TelemetryClient = getTelemetryClient(),
|
|
148
150
|
private log = createLogger('node'),
|
|
149
151
|
private blobClient?: BlobClientInterface,
|
|
152
|
+
private validatorClient?: ValidatorClient,
|
|
153
|
+
private keyStoreManager?: KeystoreManager,
|
|
150
154
|
) {
|
|
151
155
|
this.metrics = new NodeMetrics(telemetry, 'AztecNodeService');
|
|
152
156
|
this.tracer = telemetry.getTracer('AztecNodeService');
|
|
@@ -177,10 +181,12 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
177
181
|
publisher?: SequencerPublisher;
|
|
178
182
|
dateProvider?: DateProvider;
|
|
179
183
|
p2pClientDeps?: P2PClientDeps<P2PClientType.Full>;
|
|
184
|
+
proverNodeDeps?: Partial<ProverNodeDeps>;
|
|
180
185
|
} = {},
|
|
181
186
|
options: {
|
|
182
187
|
prefilledPublicData?: PublicDataTreeLeaf[];
|
|
183
188
|
dontStartSequencer?: boolean;
|
|
189
|
+
dontStartProverNode?: boolean;
|
|
184
190
|
} = {},
|
|
185
191
|
): Promise<AztecNodeService> {
|
|
186
192
|
const config = { ...inputConfig }; // Copy the config so we dont mutate the input object
|
|
@@ -190,16 +196,29 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
190
196
|
const dateProvider = deps.dateProvider ?? new DateProvider();
|
|
191
197
|
const ethereumChain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
|
|
192
198
|
|
|
193
|
-
// Build a key store from file if given or from environment otherwise
|
|
199
|
+
// Build a key store from file if given or from environment otherwise.
|
|
200
|
+
// We keep the raw KeyStore available so we can merge with prover keys if enableProverNode is set.
|
|
194
201
|
let keyStoreManager: KeystoreManager | undefined;
|
|
195
202
|
const keyStoreProvided = config.keyStoreDirectory !== undefined && config.keyStoreDirectory.length > 0;
|
|
196
203
|
if (keyStoreProvided) {
|
|
197
204
|
const keyStores = loadKeystores(config.keyStoreDirectory!);
|
|
198
205
|
keyStoreManager = new KeystoreManager(mergeKeystores(keyStores));
|
|
199
206
|
} else {
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
207
|
+
const rawKeyStores: KeyStore[] = [];
|
|
208
|
+
const validatorKeyStore = createKeyStoreForValidator(config);
|
|
209
|
+
if (validatorKeyStore) {
|
|
210
|
+
rawKeyStores.push(validatorKeyStore);
|
|
211
|
+
}
|
|
212
|
+
if (config.enableProverNode) {
|
|
213
|
+
const proverKeyStore = createKeyStoreForProver(config);
|
|
214
|
+
if (proverKeyStore) {
|
|
215
|
+
rawKeyStores.push(proverKeyStore);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (rawKeyStores.length > 0) {
|
|
219
|
+
keyStoreManager = new KeystoreManager(
|
|
220
|
+
rawKeyStores.length === 1 ? rawKeyStores[0] : mergeKeystores(rawKeyStores),
|
|
221
|
+
);
|
|
203
222
|
}
|
|
204
223
|
}
|
|
205
224
|
|
|
@@ -210,10 +229,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
210
229
|
if (keyStoreManager === undefined) {
|
|
211
230
|
throw new Error('Failed to create key store, a requirement for running a validator');
|
|
212
231
|
}
|
|
213
|
-
if (!keyStoreProvided) {
|
|
214
|
-
log.warn(
|
|
215
|
-
'KEY STORE CREATED FROM ENVIRONMENT, IT IS RECOMMENDED TO USE A FILE-BASED KEY STORE IN PRODUCTION ENVIRONMENTS',
|
|
216
|
-
);
|
|
232
|
+
if (!keyStoreProvided && process.env.NODE_ENV !== 'test') {
|
|
233
|
+
log.warn("Keystore created from env: it's recommended to use a file-based key store for production");
|
|
217
234
|
}
|
|
218
235
|
ValidatorClient.validateKeyStoreConfiguration(keyStoreManager, log);
|
|
219
236
|
}
|
|
@@ -255,7 +272,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
255
272
|
);
|
|
256
273
|
}
|
|
257
274
|
|
|
258
|
-
const blobClient = await createBlobClientWithFileStores(config,
|
|
275
|
+
const blobClient = await createBlobClientWithFileStores(config, log.createChild('blob-client'));
|
|
259
276
|
|
|
260
277
|
// attempt snapshot sync if possible
|
|
261
278
|
await trySnapshotSync(config, log);
|
|
@@ -418,19 +435,19 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
418
435
|
);
|
|
419
436
|
await slasherClient.start();
|
|
420
437
|
|
|
421
|
-
const l1TxUtils = config.
|
|
422
|
-
? await
|
|
438
|
+
const l1TxUtils = config.sequencerPublisherForwarderAddress
|
|
439
|
+
? await createForwarderL1TxUtilsFromSigners(
|
|
423
440
|
publicClient,
|
|
424
441
|
keyStoreManager!.createAllValidatorPublisherSigners(),
|
|
425
|
-
config.
|
|
442
|
+
config.sequencerPublisherForwarderAddress,
|
|
426
443
|
{ ...config, scope: 'sequencer' },
|
|
427
|
-
{ telemetry, logger: log.createChild('l1-tx-utils'), dateProvider },
|
|
444
|
+
{ telemetry, logger: log.createChild('l1-tx-utils'), dateProvider, kzg: Blob.getViemKzgInstance() },
|
|
428
445
|
)
|
|
429
|
-
: await
|
|
446
|
+
: await createL1TxUtilsFromSigners(
|
|
430
447
|
publicClient,
|
|
431
448
|
keyStoreManager!.createAllValidatorPublisherSigners(),
|
|
432
449
|
{ ...config, scope: 'sequencer' },
|
|
433
|
-
{ telemetry, logger: log.createChild('l1-tx-utils'), dateProvider },
|
|
450
|
+
{ telemetry, logger: log.createChild('l1-tx-utils'), dateProvider, kzg: Blob.getViemKzgInstance() },
|
|
434
451
|
);
|
|
435
452
|
|
|
436
453
|
// Create and start the sequencer client
|
|
@@ -467,6 +484,29 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
467
484
|
log.warn(`Sequencer created but not started`);
|
|
468
485
|
}
|
|
469
486
|
|
|
487
|
+
// Create prover node subsystem if enabled
|
|
488
|
+
let proverNode: ProverNode | undefined;
|
|
489
|
+
if (config.enableProverNode) {
|
|
490
|
+
proverNode = await createProverNode(config, {
|
|
491
|
+
...deps.proverNodeDeps,
|
|
492
|
+
telemetry,
|
|
493
|
+
dateProvider,
|
|
494
|
+
archiver,
|
|
495
|
+
worldStateSynchronizer,
|
|
496
|
+
p2pClient,
|
|
497
|
+
epochCache,
|
|
498
|
+
blobClient,
|
|
499
|
+
keyStoreManager,
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
if (!options.dontStartProverNode) {
|
|
503
|
+
await proverNode.start();
|
|
504
|
+
log.info(`Prover node subsystem started`);
|
|
505
|
+
} else {
|
|
506
|
+
log.info(`Prover node subsystem created but not started`);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
470
510
|
const globalVariableBuilder = new GlobalVariableBuilder({
|
|
471
511
|
...config,
|
|
472
512
|
rollupVersion: BigInt(config.rollupVersion),
|
|
@@ -474,7 +514,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
474
514
|
slotDuration: Number(slotDuration),
|
|
475
515
|
});
|
|
476
516
|
|
|
477
|
-
|
|
517
|
+
const node = new AztecNodeService(
|
|
478
518
|
config,
|
|
479
519
|
p2pClient,
|
|
480
520
|
archiver,
|
|
@@ -483,6 +523,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
483
523
|
archiver,
|
|
484
524
|
worldStateSynchronizer,
|
|
485
525
|
sequencer,
|
|
526
|
+
proverNode,
|
|
486
527
|
slasherClient,
|
|
487
528
|
validatorsSentinel,
|
|
488
529
|
epochPruneWatcher,
|
|
@@ -495,7 +536,11 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
495
536
|
telemetry,
|
|
496
537
|
log,
|
|
497
538
|
blobClient,
|
|
539
|
+
validatorClient,
|
|
540
|
+
keyStoreManager,
|
|
498
541
|
);
|
|
542
|
+
|
|
543
|
+
return node;
|
|
499
544
|
}
|
|
500
545
|
|
|
501
546
|
/**
|
|
@@ -506,6 +551,11 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
506
551
|
return this.sequencer;
|
|
507
552
|
}
|
|
508
553
|
|
|
554
|
+
/** Returns the prover node subsystem, if enabled. */
|
|
555
|
+
public getProverNode(): ProverNode | undefined {
|
|
556
|
+
return this.proverNode;
|
|
557
|
+
}
|
|
558
|
+
|
|
509
559
|
public getBlockSource(): L2BlockSource {
|
|
510
560
|
return this.blockSource;
|
|
511
561
|
}
|
|
@@ -559,6 +609,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
559
609
|
enr,
|
|
560
610
|
l1ContractAddresses: contractAddresses,
|
|
561
611
|
protocolContractAddresses: protocolContractAddresses,
|
|
612
|
+
realProofs: !!this.config.realProofs,
|
|
562
613
|
};
|
|
563
614
|
|
|
564
615
|
return nodeInfo;
|
|
@@ -570,8 +621,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
570
621
|
* @returns The requested block.
|
|
571
622
|
*/
|
|
572
623
|
public async getBlock(block: BlockParameter): Promise<L2Block | undefined> {
|
|
573
|
-
if (BlockHash.
|
|
574
|
-
return this.getBlockByHash(
|
|
624
|
+
if (BlockHash.isBlockHash(block)) {
|
|
625
|
+
return this.getBlockByHash(block);
|
|
575
626
|
}
|
|
576
627
|
const blockNumber = block === 'latest' ? await this.getBlockNumber() : (block as BlockNumber);
|
|
577
628
|
if (blockNumber === BlockNumber.ZERO) {
|
|
@@ -585,9 +636,9 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
585
636
|
* @param blockHash - The block hash being requested.
|
|
586
637
|
* @returns The requested block.
|
|
587
638
|
*/
|
|
588
|
-
public async getBlockByHash(blockHash:
|
|
639
|
+
public async getBlockByHash(blockHash: BlockHash): Promise<L2Block | undefined> {
|
|
589
640
|
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
590
|
-
if (blockHash.equals(
|
|
641
|
+
if (blockHash.equals(initialBlockHash)) {
|
|
591
642
|
return this.buildInitialBlock();
|
|
592
643
|
}
|
|
593
644
|
return await this.blockSource.getL2BlockByHash(blockHash);
|
|
@@ -697,8 +748,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
697
748
|
if (referenceBlock) {
|
|
698
749
|
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
699
750
|
if (!referenceBlock.equals(initialBlockHash)) {
|
|
700
|
-
const
|
|
701
|
-
const header = await this.blockSource.getBlockHeaderByHash(blockHashFr);
|
|
751
|
+
const header = await this.blockSource.getBlockHeaderByHash(referenceBlock);
|
|
702
752
|
if (!header) {
|
|
703
753
|
throw new Error(
|
|
704
754
|
`Block ${referenceBlock.toString()} not found in the node. This might indicate a reorg has occurred.`,
|
|
@@ -718,8 +768,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
718
768
|
if (referenceBlock) {
|
|
719
769
|
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
720
770
|
if (!referenceBlock.equals(initialBlockHash)) {
|
|
721
|
-
const
|
|
722
|
-
const header = await this.blockSource.getBlockHeaderByHash(blockHashFr);
|
|
771
|
+
const header = await this.blockSource.getBlockHeaderByHash(referenceBlock);
|
|
723
772
|
if (!header) {
|
|
724
773
|
throw new Error(
|
|
725
774
|
`Block ${referenceBlock.toString()} not found in the node. This might indicate a reorg has occurred.`,
|
|
@@ -810,6 +859,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
810
859
|
await tryStop(this.slasherClient);
|
|
811
860
|
await tryStop(this.proofVerifier);
|
|
812
861
|
await tryStop(this.sequencer);
|
|
862
|
+
await tryStop(this.proverNode);
|
|
813
863
|
await tryStop(this.p2pClient);
|
|
814
864
|
await tryStop(this.worldStateSynchronizer);
|
|
815
865
|
await tryStop(this.blockSource);
|
|
@@ -859,11 +909,11 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
859
909
|
}
|
|
860
910
|
|
|
861
911
|
public async findLeavesIndexes(
|
|
862
|
-
|
|
912
|
+
referenceBlock: BlockParameter,
|
|
863
913
|
treeId: MerkleTreeId,
|
|
864
914
|
leafValues: Fr[],
|
|
865
915
|
): Promise<(DataInBlock<bigint> | undefined)[]> {
|
|
866
|
-
const committedDb = await this.#getWorldState(
|
|
916
|
+
const committedDb = await this.#getWorldState(referenceBlock);
|
|
867
917
|
const maybeIndices = await committedDb.findLeafIndices(
|
|
868
918
|
treeId,
|
|
869
919
|
leafValues.map(x => x.toBuffer()),
|
|
@@ -915,44 +965,28 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
915
965
|
}
|
|
916
966
|
return {
|
|
917
967
|
l2BlockNumber: BlockNumber(Number(blockNumber)),
|
|
918
|
-
l2BlockHash: BlockHash
|
|
968
|
+
l2BlockHash: new BlockHash(blockHash),
|
|
919
969
|
data: index,
|
|
920
970
|
};
|
|
921
971
|
});
|
|
922
972
|
}
|
|
923
973
|
|
|
924
|
-
public async
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
): Promise<SiblingPath<typeof NULLIFIER_TREE_HEIGHT>> {
|
|
928
|
-
const committedDb = await this.#getWorldState(block);
|
|
929
|
-
return committedDb.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, leafIndex);
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
public async getNoteHashSiblingPath(
|
|
933
|
-
block: BlockParameter,
|
|
934
|
-
leafIndex: bigint,
|
|
935
|
-
): Promise<SiblingPath<typeof NOTE_HASH_TREE_HEIGHT>> {
|
|
936
|
-
const committedDb = await this.#getWorldState(block);
|
|
937
|
-
return committedDb.getSiblingPath(MerkleTreeId.NOTE_HASH_TREE, leafIndex);
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
public async getArchiveMembershipWitness(
|
|
941
|
-
block: BlockParameter,
|
|
942
|
-
archive: Fr,
|
|
974
|
+
public async getBlockHashMembershipWitness(
|
|
975
|
+
referenceBlock: BlockParameter,
|
|
976
|
+
blockHash: BlockHash,
|
|
943
977
|
): Promise<MembershipWitness<typeof ARCHIVE_HEIGHT> | undefined> {
|
|
944
|
-
const committedDb = await this.#getWorldState(
|
|
945
|
-
const [pathAndIndex] = await committedDb.findSiblingPaths<MerkleTreeId.ARCHIVE>(MerkleTreeId.ARCHIVE, [
|
|
978
|
+
const committedDb = await this.#getWorldState(referenceBlock);
|
|
979
|
+
const [pathAndIndex] = await committedDb.findSiblingPaths<MerkleTreeId.ARCHIVE>(MerkleTreeId.ARCHIVE, [blockHash]);
|
|
946
980
|
return pathAndIndex === undefined
|
|
947
981
|
? undefined
|
|
948
982
|
: MembershipWitness.fromSiblingPath(pathAndIndex.index, pathAndIndex.path);
|
|
949
983
|
}
|
|
950
984
|
|
|
951
985
|
public async getNoteHashMembershipWitness(
|
|
952
|
-
|
|
986
|
+
referenceBlock: BlockParameter,
|
|
953
987
|
noteHash: Fr,
|
|
954
988
|
): Promise<MembershipWitness<typeof NOTE_HASH_TREE_HEIGHT> | undefined> {
|
|
955
|
-
const committedDb = await this.#getWorldState(
|
|
989
|
+
const committedDb = await this.#getWorldState(referenceBlock);
|
|
956
990
|
const [pathAndIndex] = await committedDb.findSiblingPaths<MerkleTreeId.NOTE_HASH_TREE>(
|
|
957
991
|
MerkleTreeId.NOTE_HASH_TREE,
|
|
958
992
|
[noteHash],
|
|
@@ -963,10 +997,10 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
963
997
|
}
|
|
964
998
|
|
|
965
999
|
public async getL1ToL2MessageMembershipWitness(
|
|
966
|
-
|
|
1000
|
+
referenceBlock: BlockParameter,
|
|
967
1001
|
l1ToL2Message: Fr,
|
|
968
1002
|
): Promise<[bigint, SiblingPath<typeof L1_TO_L2_MSG_TREE_HEIGHT>] | undefined> {
|
|
969
|
-
const db = await this.#getWorldState(
|
|
1003
|
+
const db = await this.#getWorldState(referenceBlock);
|
|
970
1004
|
const [witness] = await db.findSiblingPaths(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, [l1ToL2Message]);
|
|
971
1005
|
if (!witness) {
|
|
972
1006
|
return undefined;
|
|
@@ -1019,27 +1053,11 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1019
1053
|
);
|
|
1020
1054
|
}
|
|
1021
1055
|
|
|
1022
|
-
public async getArchiveSiblingPath(
|
|
1023
|
-
block: BlockParameter,
|
|
1024
|
-
leafIndex: bigint,
|
|
1025
|
-
): Promise<SiblingPath<typeof ARCHIVE_HEIGHT>> {
|
|
1026
|
-
const committedDb = await this.#getWorldState(block);
|
|
1027
|
-
return committedDb.getSiblingPath(MerkleTreeId.ARCHIVE, leafIndex);
|
|
1028
|
-
}
|
|
1029
|
-
|
|
1030
|
-
public async getPublicDataSiblingPath(
|
|
1031
|
-
block: BlockParameter,
|
|
1032
|
-
leafIndex: bigint,
|
|
1033
|
-
): Promise<SiblingPath<typeof PUBLIC_DATA_TREE_HEIGHT>> {
|
|
1034
|
-
const committedDb = await this.#getWorldState(block);
|
|
1035
|
-
return committedDb.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, leafIndex);
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
1056
|
public async getNullifierMembershipWitness(
|
|
1039
|
-
|
|
1057
|
+
referenceBlock: BlockParameter,
|
|
1040
1058
|
nullifier: Fr,
|
|
1041
1059
|
): Promise<NullifierMembershipWitness | undefined> {
|
|
1042
|
-
const db = await this.#getWorldState(
|
|
1060
|
+
const db = await this.#getWorldState(referenceBlock);
|
|
1043
1061
|
const [witness] = await db.findSiblingPaths(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]);
|
|
1044
1062
|
if (!witness) {
|
|
1045
1063
|
return undefined;
|
|
@@ -1056,7 +1074,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1056
1074
|
|
|
1057
1075
|
/**
|
|
1058
1076
|
* Returns a low nullifier membership witness for a given nullifier at a given block.
|
|
1059
|
-
* @param
|
|
1077
|
+
* @param referenceBlock - The block parameter (block number, block hash, or 'latest') at which to get the data
|
|
1078
|
+
* (which contains the root of the nullifier tree in which we are searching for the nullifier).
|
|
1060
1079
|
* @param nullifier - Nullifier we try to find the low nullifier witness for.
|
|
1061
1080
|
* @returns The low nullifier membership witness (if found).
|
|
1062
1081
|
* @remarks Low nullifier witness can be used to perform a nullifier non-inclusion proof by leveraging the "linked
|
|
@@ -1069,10 +1088,10 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1069
1088
|
* TODO: This is a confusing behavior and we should eventually address that.
|
|
1070
1089
|
*/
|
|
1071
1090
|
public async getLowNullifierMembershipWitness(
|
|
1072
|
-
|
|
1091
|
+
referenceBlock: BlockParameter,
|
|
1073
1092
|
nullifier: Fr,
|
|
1074
1093
|
): Promise<NullifierMembershipWitness | undefined> {
|
|
1075
|
-
const committedDb = await this.#getWorldState(
|
|
1094
|
+
const committedDb = await this.#getWorldState(referenceBlock);
|
|
1076
1095
|
const findResult = await committedDb.getPreviousValueIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBigInt());
|
|
1077
1096
|
if (!findResult) {
|
|
1078
1097
|
return undefined;
|
|
@@ -1087,8 +1106,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1087
1106
|
return new NullifierMembershipWitness(BigInt(index), preimageData as NullifierLeafPreimage, siblingPath);
|
|
1088
1107
|
}
|
|
1089
1108
|
|
|
1090
|
-
async getPublicDataWitness(
|
|
1091
|
-
const committedDb = await this.#getWorldState(
|
|
1109
|
+
async getPublicDataWitness(referenceBlock: BlockParameter, leafSlot: Fr): Promise<PublicDataWitness | undefined> {
|
|
1110
|
+
const committedDb = await this.#getWorldState(referenceBlock);
|
|
1092
1111
|
const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
|
|
1093
1112
|
if (!lowLeafResult) {
|
|
1094
1113
|
return undefined;
|
|
@@ -1102,8 +1121,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1102
1121
|
}
|
|
1103
1122
|
}
|
|
1104
1123
|
|
|
1105
|
-
public async getPublicStorageAt(
|
|
1106
|
-
const committedDb = await this.#getWorldState(
|
|
1124
|
+
public async getPublicStorageAt(referenceBlock: BlockParameter, contract: AztecAddress, slot: Fr): Promise<Fr> {
|
|
1125
|
+
const committedDb = await this.#getWorldState(referenceBlock);
|
|
1107
1126
|
const leafSlot = await computePublicDataTreeLeafSlot(contract, slot);
|
|
1108
1127
|
|
|
1109
1128
|
const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
|
|
@@ -1118,14 +1137,13 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1118
1137
|
}
|
|
1119
1138
|
|
|
1120
1139
|
public async getBlockHeader(block: BlockParameter = 'latest'): Promise<BlockHeader | undefined> {
|
|
1121
|
-
if (BlockHash.
|
|
1140
|
+
if (BlockHash.isBlockHash(block)) {
|
|
1122
1141
|
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
1123
1142
|
if (block.equals(initialBlockHash)) {
|
|
1124
1143
|
// Block source doesn't handle initial header so we need to handle the case separately.
|
|
1125
1144
|
return this.worldStateSynchronizer.getCommitted().getInitialHeader();
|
|
1126
1145
|
}
|
|
1127
|
-
|
|
1128
|
-
return this.blockSource.getBlockHeaderByHash(blockHashFr);
|
|
1146
|
+
return this.blockSource.getBlockHeaderByHash(block);
|
|
1129
1147
|
} else {
|
|
1130
1148
|
// Block source doesn't handle initial header so we need to handle the case separately.
|
|
1131
1149
|
const blockNumber = block === 'latest' ? await this.getBlockNumber() : (block as BlockNumber);
|
|
@@ -1145,6 +1163,14 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1145
1163
|
return await this.blockSource.getBlockHeaderByArchive(archive);
|
|
1146
1164
|
}
|
|
1147
1165
|
|
|
1166
|
+
public getBlockData(number: BlockNumber): Promise<BlockData | undefined> {
|
|
1167
|
+
return this.blockSource.getBlockData(number);
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
public getBlockDataByArchive(archive: Fr): Promise<BlockData | undefined> {
|
|
1171
|
+
return this.blockSource.getBlockDataByArchive(archive);
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1148
1174
|
/**
|
|
1149
1175
|
* Simulates the public part of a transaction with the current state.
|
|
1150
1176
|
* @param tx - The transaction to simulate.
|
|
@@ -1168,7 +1194,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1168
1194
|
}
|
|
1169
1195
|
|
|
1170
1196
|
const txHash = tx.getTxHash();
|
|
1171
|
-
const
|
|
1197
|
+
const latestBlockNumber = await this.blockSource.getBlockNumber();
|
|
1198
|
+
const blockNumber = BlockNumber.add(latestBlockNumber, 1);
|
|
1172
1199
|
|
|
1173
1200
|
// If sequencer is not initialized, we just set these values to zero for simulation.
|
|
1174
1201
|
const coinbase = EthAddress.ZERO;
|
|
@@ -1192,6 +1219,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1192
1219
|
blockNumber,
|
|
1193
1220
|
});
|
|
1194
1221
|
|
|
1222
|
+
// Ensure world-state has caught up with the latest block we loaded from the archiver
|
|
1223
|
+
await this.worldStateSynchronizer.syncImmediate(latestBlockNumber);
|
|
1195
1224
|
const merkleTreeFork = await this.worldStateSynchronizer.fork();
|
|
1196
1225
|
try {
|
|
1197
1226
|
const config = PublicSimulatorConfig.from({
|
|
@@ -1234,7 +1263,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1234
1263
|
const db = this.worldStateSynchronizer.getCommitted();
|
|
1235
1264
|
const verifier = isSimulation ? undefined : this.proofVerifier;
|
|
1236
1265
|
|
|
1237
|
-
// We accept transactions if they are not expired by the next slot (checked based on the
|
|
1266
|
+
// We accept transactions if they are not expired by the next slot (checked based on the ExpirationTimestamp field)
|
|
1238
1267
|
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
1239
1268
|
const blockNumber = BlockNumber((await this.blockSource.getBlockNumber()) + 1);
|
|
1240
1269
|
const validator = createValidatorForAcceptingTxs(
|
|
@@ -1416,6 +1445,94 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1416
1445
|
}
|
|
1417
1446
|
}
|
|
1418
1447
|
|
|
1448
|
+
public async reloadKeystore(): Promise<void> {
|
|
1449
|
+
if (!this.config.keyStoreDirectory?.length) {
|
|
1450
|
+
throw new BadRequestError(
|
|
1451
|
+
'Cannot reload keystore: node is not using a file-based keystore. ' +
|
|
1452
|
+
'Set KEY_STORE_DIRECTORY to use file-based keystores.',
|
|
1453
|
+
);
|
|
1454
|
+
}
|
|
1455
|
+
if (!this.validatorClient) {
|
|
1456
|
+
throw new BadRequestError('Cannot reload keystore: validator is not enabled.');
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
this.log.info('Reloading keystore from disk');
|
|
1460
|
+
|
|
1461
|
+
// Re-read and validate keystore files
|
|
1462
|
+
const keyStores = loadKeystores(this.config.keyStoreDirectory);
|
|
1463
|
+
const newManager = new KeystoreManager(mergeKeystores(keyStores));
|
|
1464
|
+
await newManager.validateSigners();
|
|
1465
|
+
ValidatorClient.validateKeyStoreConfiguration(newManager, this.log);
|
|
1466
|
+
|
|
1467
|
+
// Validate that every validator's publisher keys overlap with the L1 signers
|
|
1468
|
+
// that were initialized at startup. Publishers cannot be hot-reloaded, so a
|
|
1469
|
+
// validator with a publisher key that doesn't match any existing L1 signer
|
|
1470
|
+
// would silently fail on every proposer slot.
|
|
1471
|
+
if (this.keyStoreManager && this.sequencer) {
|
|
1472
|
+
const oldAdapter = NodeKeystoreAdapter.fromKeyStoreManager(this.keyStoreManager);
|
|
1473
|
+
const availablePublishers = new Set(
|
|
1474
|
+
oldAdapter
|
|
1475
|
+
.getAttesterAddresses()
|
|
1476
|
+
.flatMap(a => oldAdapter.getPublisherAddresses(a).map(p => p.toString().toLowerCase())),
|
|
1477
|
+
);
|
|
1478
|
+
|
|
1479
|
+
const newAdapter = NodeKeystoreAdapter.fromKeyStoreManager(newManager);
|
|
1480
|
+
for (const attester of newAdapter.getAttesterAddresses()) {
|
|
1481
|
+
const pubs = newAdapter.getPublisherAddresses(attester);
|
|
1482
|
+
if (pubs.length > 0 && !pubs.some(p => availablePublishers.has(p.toString().toLowerCase()))) {
|
|
1483
|
+
throw new BadRequestError(
|
|
1484
|
+
`Cannot reload keystore: validator ${attester} has publisher keys ` +
|
|
1485
|
+
`[${pubs.map(p => p.toString()).join(', ')}] but none match the L1 signers initialized at startup ` +
|
|
1486
|
+
`[${[...availablePublishers].join(', ')}]. Publishers cannot be hot-reloaded — ` +
|
|
1487
|
+
`use an existing publisher key or restart the node.`,
|
|
1488
|
+
);
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
// Build adapters for old and new keystores to compute diff
|
|
1494
|
+
const newAdapter = NodeKeystoreAdapter.fromKeyStoreManager(newManager);
|
|
1495
|
+
const newAddresses = newAdapter.getAttesterAddresses();
|
|
1496
|
+
const oldAddresses = this.keyStoreManager
|
|
1497
|
+
? NodeKeystoreAdapter.fromKeyStoreManager(this.keyStoreManager).getAttesterAddresses()
|
|
1498
|
+
: [];
|
|
1499
|
+
|
|
1500
|
+
const oldSet = new Set(oldAddresses.map(a => a.toString()));
|
|
1501
|
+
const newSet = new Set(newAddresses.map(a => a.toString()));
|
|
1502
|
+
const added = newAddresses.filter(a => !oldSet.has(a.toString()));
|
|
1503
|
+
const removed = oldAddresses.filter(a => !newSet.has(a.toString()));
|
|
1504
|
+
|
|
1505
|
+
if (added.length > 0) {
|
|
1506
|
+
this.log.info(`Keystore reload: adding attester keys: ${added.map(a => a.toString()).join(', ')}`);
|
|
1507
|
+
}
|
|
1508
|
+
if (removed.length > 0) {
|
|
1509
|
+
this.log.info(`Keystore reload: removing attester keys: ${removed.map(a => a.toString()).join(', ')}`);
|
|
1510
|
+
}
|
|
1511
|
+
if (added.length === 0 && removed.length === 0) {
|
|
1512
|
+
this.log.info('Keystore reload: attester keys unchanged');
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
// Update the validator client (coinbase, feeRecipient, attester keys)
|
|
1516
|
+
this.validatorClient.reloadKeystore(newManager);
|
|
1517
|
+
|
|
1518
|
+
// Update the publisher factory's keystore so newly-added validators
|
|
1519
|
+
// can be matched to existing publisher keys when proposing blocks.
|
|
1520
|
+
if (this.sequencer) {
|
|
1521
|
+
this.sequencer.updatePublisherNodeKeyStore(newAdapter);
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
// Update slasher's "don't-slash-self" list with new validator addresses
|
|
1525
|
+
if (this.slasherClient && !this.config.slashSelfAllowed) {
|
|
1526
|
+
const slashValidatorsNever = unique(
|
|
1527
|
+
[...(this.config.slashValidatorsNever ?? []), ...newAddresses].map(a => a.toString()),
|
|
1528
|
+
).map(EthAddress.fromString);
|
|
1529
|
+
this.slasherClient.updateConfig({ slashValidatorsNever });
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
this.keyStoreManager = newManager;
|
|
1533
|
+
this.log.info('Keystore reloaded: coinbase, feeRecipient, and attester keys updated');
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1419
1536
|
#getInitialHeaderHash(): Promise<BlockHash> {
|
|
1420
1537
|
if (!this.initialHeaderHashPromise) {
|
|
1421
1538
|
this.initialHeaderHashPromise = this.worldStateSynchronizer.getCommitted().getInitialHeader().hash();
|
|
@@ -1442,15 +1559,14 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
|
|
|
1442
1559
|
return this.worldStateSynchronizer.getCommitted();
|
|
1443
1560
|
}
|
|
1444
1561
|
|
|
1445
|
-
if (BlockHash.
|
|
1562
|
+
if (BlockHash.isBlockHash(block)) {
|
|
1446
1563
|
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
1447
1564
|
if (block.equals(initialBlockHash)) {
|
|
1448
1565
|
// Block source doesn't handle initial header so we need to handle the case separately.
|
|
1449
1566
|
return this.worldStateSynchronizer.getSnapshot(BlockNumber.ZERO);
|
|
1450
1567
|
}
|
|
1451
1568
|
|
|
1452
|
-
const
|
|
1453
|
-
const header = await this.blockSource.getBlockHeaderByHash(blockHashFr);
|
|
1569
|
+
const header = await this.blockSource.getBlockHeaderByHash(block);
|
|
1454
1570
|
if (!header) {
|
|
1455
1571
|
throw new Error(
|
|
1456
1572
|
`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.`,
|