@aztec/validator-client 3.0.0-nightly.20250905 → 4.0.0-nightly.20250907
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/config.d.ts +3 -19
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +8 -2
- package/dest/validator.d.ts +4 -12
- package/dest/validator.d.ts.map +1 -1
- package/dest/validator.js +16 -11
- package/package.json +11 -11
- package/src/config.ts +18 -25
- package/src/validator.ts +18 -36
package/dest/config.d.ts
CHANGED
|
@@ -1,22 +1,6 @@
|
|
|
1
|
-
import { type ConfigMappingsType
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
* The Validator Configuration
|
|
5
|
-
*/
|
|
6
|
-
export interface ValidatorClientConfig {
|
|
7
|
-
/** The private keys of the validators participating in attestation duties */
|
|
8
|
-
validatorPrivateKeys?: SecretValue<`0x${string}`[]>;
|
|
9
|
-
/** The addresses of the validators to use with remote signers */
|
|
10
|
-
validatorAddresses?: EthAddress[];
|
|
11
|
-
/** Do not run the validator */
|
|
12
|
-
disableValidator: boolean;
|
|
13
|
-
/** Interval between polling for new attestations from peers */
|
|
14
|
-
attestationPollingIntervalMs: number;
|
|
15
|
-
/** Re-execute transactions before attesting */
|
|
16
|
-
validatorReexecute: boolean;
|
|
17
|
-
/** Will re-execute until this many milliseconds are left in the slot */
|
|
18
|
-
validatorReexecuteDeadlineMs: number;
|
|
19
|
-
}
|
|
1
|
+
import { type ConfigMappingsType } from '@aztec/foundation/config';
|
|
2
|
+
import type { ValidatorClientConfig } from '@aztec/stdlib/interfaces/server';
|
|
3
|
+
export type { ValidatorClientConfig };
|
|
20
4
|
export declare const validatorClientConfigMappings: ConfigMappingsType<ValidatorClientConfig>;
|
|
21
5
|
/**
|
|
22
6
|
* Returns the prover configuration from the environment variables.
|
package/dest/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EAKxB,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAE7E,YAAY,EAAE,qBAAqB,EAAE,CAAC;AAEtC,eAAO,MAAM,6BAA6B,EAAE,kBAAkB,CAAC,qBAAqB,CAgDnF,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,qBAAqB,CAExD"}
|
package/dest/config.js
CHANGED
|
@@ -12,12 +12,18 @@ export const validatorClientConfigMappings = {
|
|
|
12
12
|
validatorAddresses: {
|
|
13
13
|
env: 'VALIDATOR_ADDRESSES',
|
|
14
14
|
description: 'List of addresses of the validators to use with remote signers',
|
|
15
|
-
parseEnv: (val)=>val.split(',').map((address)=>EthAddress.fromString(address))
|
|
15
|
+
parseEnv: (val)=>val.split(',').filter((address)=>address && address.trim().length > 0).map((address)=>EthAddress.fromString(address.trim())),
|
|
16
|
+
defaultValue: []
|
|
16
17
|
},
|
|
17
18
|
disableValidator: {
|
|
18
19
|
env: 'VALIDATOR_DISABLED',
|
|
19
20
|
description: 'Do not run the validator',
|
|
20
|
-
...booleanConfigHelper()
|
|
21
|
+
...booleanConfigHelper(false)
|
|
22
|
+
},
|
|
23
|
+
disabledValidators: {
|
|
24
|
+
description: 'Temporarily disable these specific validator addresses',
|
|
25
|
+
parseEnv: (val)=>val.split(',').filter((address)=>address && address.trim().length > 0).map((address)=>EthAddress.fromString(address.trim())),
|
|
26
|
+
defaultValue: []
|
|
21
27
|
},
|
|
22
28
|
attestationPollingIntervalMs: {
|
|
23
29
|
env: 'VALIDATOR_ATTESTATIONS_POLLING_INTERVAL_MS',
|
package/dest/validator.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { TxProvider } from '@aztec/p2p';
|
|
|
8
8
|
import { type SlasherConfig, type Watcher, type WatcherEmitter } from '@aztec/slasher';
|
|
9
9
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
10
10
|
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
11
|
-
import type { IFullNodeBlockBuilder,
|
|
11
|
+
import type { IFullNodeBlockBuilder, Validator, ValidatorClientFullConfig } from '@aztec/stdlib/interfaces/server';
|
|
12
12
|
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
13
13
|
import type { BlockAttestation, BlockProposal, BlockProposalOptions } from '@aztec/stdlib/p2p';
|
|
14
14
|
import { type ProposedBlockHeader, type StateReference, type Tx } from '@aztec/stdlib/tx';
|
|
@@ -16,14 +16,6 @@ import { type TelemetryClient, type Tracer } from '@aztec/telemetry-client';
|
|
|
16
16
|
import type { TypedDataDefinition } from 'viem';
|
|
17
17
|
import type { ValidatorClientConfig } from './config.js';
|
|
18
18
|
import { NodeKeystoreAdapter } from './key_store/node_keystore_adapter.js';
|
|
19
|
-
export interface Validator {
|
|
20
|
-
start(): Promise<void>;
|
|
21
|
-
registerBlockProposalHandler(): void;
|
|
22
|
-
createBlockProposal(blockNumber: number, header: ProposedBlockHeader, archive: Fr, stateReference: StateReference, txs: Tx[], proposerAddress: EthAddress | undefined, options: BlockProposalOptions): Promise<BlockProposal | undefined>;
|
|
23
|
-
attestToProposal(proposal: BlockProposal, sender: PeerId): Promise<BlockAttestation[] | undefined>;
|
|
24
|
-
broadcastBlockProposal(proposal: BlockProposal): Promise<void>;
|
|
25
|
-
collectAttestations(proposal: BlockProposal, required: number, deadline: Date): Promise<BlockAttestation[]>;
|
|
26
|
-
}
|
|
27
19
|
declare const ValidatorClient_base: new () => WatcherEmitter;
|
|
28
20
|
/**
|
|
29
21
|
* Validator Client
|
|
@@ -43,12 +35,11 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
|
|
|
43
35
|
private validationService;
|
|
44
36
|
private metrics;
|
|
45
37
|
private previousProposal?;
|
|
46
|
-
private myAddresses;
|
|
47
38
|
private lastEpochForCommitteeUpdateLoop;
|
|
48
39
|
private epochCacheUpdateLoop;
|
|
49
40
|
private blockProposalValidator;
|
|
50
41
|
private proposersOfInvalidBlocks;
|
|
51
|
-
protected constructor(blockBuilder: IFullNodeBlockBuilder, keyStore: NodeKeystoreAdapter, epochCache: EpochCache, p2pClient: P2P, blockSource: L2BlockSource, l1ToL2MessageSource: L1ToL2MessageSource, txProvider: TxProvider, config:
|
|
42
|
+
protected constructor(blockBuilder: IFullNodeBlockBuilder, keyStore: NodeKeystoreAdapter, epochCache: EpochCache, p2pClient: P2P, blockSource: L2BlockSource, l1ToL2MessageSource: L1ToL2MessageSource, txProvider: TxProvider, config: ValidatorClientFullConfig, dateProvider?: DateProvider, telemetry?: TelemetryClient, log?: import("@aztec/foundation/log").Logger);
|
|
52
43
|
static validateKeyStoreConfiguration(keyStoreManager: KeystoreManager): void;
|
|
53
44
|
private handleEpochCommitteeUpdate;
|
|
54
45
|
static new(config: ValidatorClientConfig & Pick<SlasherConfig, 'slashBroadcastedInvalidBlockPenalty'>, blockBuilder: IFullNodeBlockBuilder, epochCache: EpochCache, p2pClient: P2P, blockSource: L2BlockSource, l1ToL2MessageSource: L1ToL2MessageSource, txProvider: TxProvider, keyStoreManager: KeystoreManager, dateProvider?: DateProvider, telemetry?: TelemetryClient): ValidatorClient;
|
|
@@ -56,7 +47,8 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
|
|
|
56
47
|
signWithAddress(addr: EthAddress, msg: TypedDataDefinition): Promise<import("@aztec/stdlib/block").Signature>;
|
|
57
48
|
getCoinbaseForAttestor(attestor: EthAddress): EthAddress;
|
|
58
49
|
getFeeRecipientForAttestor(attestor: EthAddress): AztecAddress;
|
|
59
|
-
|
|
50
|
+
getConfig(): ValidatorClientFullConfig;
|
|
51
|
+
updateConfig(config: Partial<ValidatorClientFullConfig>): void;
|
|
60
52
|
start(): Promise<void>;
|
|
61
53
|
stop(): Promise<void>;
|
|
62
54
|
registerBlockProposalHandler(): void;
|
package/dest/validator.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAK9C,OAAO,EAAE,YAAY,EAAS,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAiD,UAAU,EAAE,MAAM,YAAY,CAAC;AAGvF,OAAO,EAEL,KAAK,aAAa,EAElB,KAAK,OAAO,EACZ,KAAK,cAAc,EACpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,KAAK,EAAE,qBAAqB,EAAE,
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"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"}
|
package/dest/validator.js
CHANGED
|
@@ -38,7 +38,6 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
|
|
|
38
38
|
metrics;
|
|
39
39
|
// Used to check if we are sending the same proposal twice
|
|
40
40
|
previousProposal;
|
|
41
|
-
myAddresses;
|
|
42
41
|
lastEpochForCommitteeUpdateLoop;
|
|
43
42
|
epochCacheUpdateLoop;
|
|
44
43
|
blockProposalValidator;
|
|
@@ -50,9 +49,9 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
|
|
|
50
49
|
this.validationService = new ValidationService(keyStore);
|
|
51
50
|
this.blockProposalValidator = new BlockProposalValidator(epochCache);
|
|
52
51
|
// Refresh epoch cache every second to trigger alert if participation in committee changes
|
|
53
|
-
this.myAddresses = this.keyStore.getAddresses();
|
|
54
52
|
this.epochCacheUpdateLoop = new RunningPromise(this.handleEpochCommitteeUpdate.bind(this), log, 1000);
|
|
55
|
-
|
|
53
|
+
const myAddresses = this.getValidatorAddresses();
|
|
54
|
+
this.log.verbose(`Initialized validator with addresses: ${myAddresses.map((a)=>a.toString()).join(', ')}`);
|
|
56
55
|
}
|
|
57
56
|
static validateKeyStoreConfiguration(keyStoreManager) {
|
|
58
57
|
const validatorKeyStore = NodeKeystoreAdapter.fromKeyStoreManager(keyStoreManager);
|
|
@@ -80,7 +79,7 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
|
|
|
80
79
|
return;
|
|
81
80
|
}
|
|
82
81
|
if (epoch !== this.lastEpochForCommitteeUpdateLoop) {
|
|
83
|
-
const me = this.
|
|
82
|
+
const me = this.getValidatorAddresses();
|
|
84
83
|
const committeeSet = new Set(committee.map((v)=>v.toString()));
|
|
85
84
|
const inCommittee = me.filter((a)=>committeeSet.has(a.toString()));
|
|
86
85
|
if (inCommittee.length > 0) {
|
|
@@ -101,7 +100,7 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
|
|
|
101
100
|
return validator;
|
|
102
101
|
}
|
|
103
102
|
getValidatorAddresses() {
|
|
104
|
-
return this.keyStore.getAddresses();
|
|
103
|
+
return this.keyStore.getAddresses().filter((addr)=>!this.config.disabledValidators.some((disabled)=>disabled.equals(addr)));
|
|
105
104
|
}
|
|
106
105
|
signWithAddress(addr, msg) {
|
|
107
106
|
return this.keyStore.signTypedDataWithAddress(addr, msg);
|
|
@@ -112,13 +111,19 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
|
|
|
112
111
|
getFeeRecipientForAttestor(attestor) {
|
|
113
112
|
return this.keyStore.getFeeRecipient(attestor);
|
|
114
113
|
}
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
getConfig() {
|
|
115
|
+
return this.config;
|
|
116
|
+
}
|
|
117
|
+
updateConfig(config) {
|
|
118
|
+
this.config = {
|
|
119
|
+
...this.config,
|
|
120
|
+
...config
|
|
121
|
+
};
|
|
117
122
|
}
|
|
118
123
|
async start() {
|
|
119
124
|
// Sync the committee from the smart contract
|
|
120
125
|
// https://github.com/AztecProtocol/aztec-packages/issues/7962
|
|
121
|
-
const myAddresses = this.
|
|
126
|
+
const myAddresses = this.getValidatorAddresses();
|
|
122
127
|
const inCommittee = await this.epochCache.filterInCommittee('now', myAddresses);
|
|
123
128
|
if (inCommittee.length > 0) {
|
|
124
129
|
this.log.info(`Started validator with addresses in current validator committee: ${inCommittee.map((a)=>a.toString()).join(', ')}`);
|
|
@@ -142,7 +147,7 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
|
|
|
142
147
|
const blockNumber = proposal.blockNumber;
|
|
143
148
|
const proposer = proposal.getSender();
|
|
144
149
|
// Check that I have any address in current committee before attesting
|
|
145
|
-
const inCommittee = await this.epochCache.filterInCommittee(slotNumber, this.
|
|
150
|
+
const inCommittee = await this.epochCache.filterInCommittee(slotNumber, this.getValidatorAddresses());
|
|
146
151
|
const partOfCommittee = inCommittee.length > 0;
|
|
147
152
|
const proposalInfo = {
|
|
148
153
|
...proposal.toBlockInfo(),
|
|
@@ -337,7 +342,7 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
|
|
|
337
342
|
}
|
|
338
343
|
async collectOwnAttestations(proposal) {
|
|
339
344
|
const slot = proposal.payload.header.slotNumber.toBigInt();
|
|
340
|
-
const inCommittee = await this.epochCache.filterInCommittee(slot, this.
|
|
345
|
+
const inCommittee = await this.epochCache.filterInCommittee(slot, this.getValidatorAddresses());
|
|
341
346
|
this.log.debug(`Collecting ${inCommittee.length} self-attestations for slot ${slot}`, {
|
|
342
347
|
inCommittee
|
|
343
348
|
});
|
|
@@ -353,7 +358,7 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
|
|
|
353
358
|
}
|
|
354
359
|
await this.collectOwnAttestations(proposal);
|
|
355
360
|
const proposalId = proposal.archive.toString();
|
|
356
|
-
const myAddresses = this.
|
|
361
|
+
const myAddresses = this.getValidatorAddresses();
|
|
357
362
|
let attestations = [];
|
|
358
363
|
while(true){
|
|
359
364
|
const collectedAttestations = await this.p2pClient.getAttestationsForSlot(slot, proposalId);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/validator-client",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0-nightly.20250907",
|
|
4
4
|
"main": "dest/index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -64,16 +64,16 @@
|
|
|
64
64
|
]
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@aztec/constants": "
|
|
68
|
-
"@aztec/epoch-cache": "
|
|
69
|
-
"@aztec/ethereum": "
|
|
70
|
-
"@aztec/foundation": "
|
|
71
|
-
"@aztec/node-keystore": "
|
|
72
|
-
"@aztec/p2p": "
|
|
73
|
-
"@aztec/prover-client": "
|
|
74
|
-
"@aztec/slasher": "
|
|
75
|
-
"@aztec/stdlib": "
|
|
76
|
-
"@aztec/telemetry-client": "
|
|
67
|
+
"@aztec/constants": "4.0.0-nightly.20250907",
|
|
68
|
+
"@aztec/epoch-cache": "4.0.0-nightly.20250907",
|
|
69
|
+
"@aztec/ethereum": "4.0.0-nightly.20250907",
|
|
70
|
+
"@aztec/foundation": "4.0.0-nightly.20250907",
|
|
71
|
+
"@aztec/node-keystore": "4.0.0-nightly.20250907",
|
|
72
|
+
"@aztec/p2p": "4.0.0-nightly.20250907",
|
|
73
|
+
"@aztec/prover-client": "4.0.0-nightly.20250907",
|
|
74
|
+
"@aztec/slasher": "4.0.0-nightly.20250907",
|
|
75
|
+
"@aztec/stdlib": "4.0.0-nightly.20250907",
|
|
76
|
+
"@aztec/telemetry-client": "4.0.0-nightly.20250907",
|
|
77
77
|
"koa": "^2.16.1",
|
|
78
78
|
"koa-router": "^12.0.0",
|
|
79
79
|
"tslib": "^2.4.0",
|
package/src/config.ts
CHANGED
|
@@ -1,35 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type ConfigMappingsType,
|
|
3
|
-
type SecretValue,
|
|
4
3
|
booleanConfigHelper,
|
|
5
4
|
getConfigFromMappings,
|
|
6
5
|
numberConfigHelper,
|
|
7
6
|
secretValueConfigHelper,
|
|
8
7
|
} from '@aztec/foundation/config';
|
|
9
8
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
9
|
+
import type { ValidatorClientConfig } from '@aztec/stdlib/interfaces/server';
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
* The Validator Configuration
|
|
13
|
-
*/
|
|
14
|
-
export interface ValidatorClientConfig {
|
|
15
|
-
/** The private keys of the validators participating in attestation duties */
|
|
16
|
-
validatorPrivateKeys?: SecretValue<`0x${string}`[]>;
|
|
17
|
-
|
|
18
|
-
/** The addresses of the validators to use with remote signers */
|
|
19
|
-
validatorAddresses?: EthAddress[];
|
|
20
|
-
|
|
21
|
-
/** Do not run the validator */
|
|
22
|
-
disableValidator: boolean;
|
|
23
|
-
|
|
24
|
-
/** Interval between polling for new attestations from peers */
|
|
25
|
-
attestationPollingIntervalMs: number;
|
|
26
|
-
|
|
27
|
-
/** Re-execute transactions before attesting */
|
|
28
|
-
validatorReexecute: boolean;
|
|
29
|
-
|
|
30
|
-
/** Will re-execute until this many milliseconds are left in the slot */
|
|
31
|
-
validatorReexecuteDeadlineMs: number;
|
|
32
|
-
}
|
|
11
|
+
export type { ValidatorClientConfig };
|
|
33
12
|
|
|
34
13
|
export const validatorClientConfigMappings: ConfigMappingsType<ValidatorClientConfig> = {
|
|
35
14
|
validatorPrivateKeys: {
|
|
@@ -43,12 +22,26 @@ export const validatorClientConfigMappings: ConfigMappingsType<ValidatorClientCo
|
|
|
43
22
|
validatorAddresses: {
|
|
44
23
|
env: 'VALIDATOR_ADDRESSES',
|
|
45
24
|
description: 'List of addresses of the validators to use with remote signers',
|
|
46
|
-
parseEnv: (val: string) =>
|
|
25
|
+
parseEnv: (val: string) =>
|
|
26
|
+
val
|
|
27
|
+
.split(',')
|
|
28
|
+
.filter(address => address && address.trim().length > 0)
|
|
29
|
+
.map(address => EthAddress.fromString(address.trim())),
|
|
30
|
+
defaultValue: [],
|
|
47
31
|
},
|
|
48
32
|
disableValidator: {
|
|
49
33
|
env: 'VALIDATOR_DISABLED',
|
|
50
34
|
description: 'Do not run the validator',
|
|
51
|
-
...booleanConfigHelper(),
|
|
35
|
+
...booleanConfigHelper(false),
|
|
36
|
+
},
|
|
37
|
+
disabledValidators: {
|
|
38
|
+
description: 'Temporarily disable these specific validator addresses',
|
|
39
|
+
parseEnv: (val: string) =>
|
|
40
|
+
val
|
|
41
|
+
.split(',')
|
|
42
|
+
.filter(address => address && address.trim().length > 0)
|
|
43
|
+
.map(address => EthAddress.fromString(address.trim())),
|
|
44
|
+
defaultValue: [],
|
|
52
45
|
},
|
|
53
46
|
attestationPollingIntervalMs: {
|
|
54
47
|
env: 'VALIDATOR_ATTESTATIONS_POLLING_INTERVAL_MS',
|
package/src/validator.ts
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
23
23
|
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
24
24
|
import { getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
25
|
-
import type { IFullNodeBlockBuilder,
|
|
25
|
+
import type { IFullNodeBlockBuilder, Validator, ValidatorClientFullConfig } from '@aztec/stdlib/interfaces/server';
|
|
26
26
|
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
27
27
|
import type { BlockAttestation, BlockProposal, BlockProposalOptions } from '@aztec/stdlib/p2p';
|
|
28
28
|
import { GlobalVariables, type ProposedBlockHeader, type StateReference, type Tx } from '@aztec/stdlib/tx';
|
|
@@ -47,26 +47,6 @@ import { ValidatorMetrics } from './metrics.js';
|
|
|
47
47
|
// Just cap the set to avoid unbounded growth.
|
|
48
48
|
const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
|
|
49
49
|
|
|
50
|
-
export interface Validator {
|
|
51
|
-
start(): Promise<void>;
|
|
52
|
-
registerBlockProposalHandler(): void;
|
|
53
|
-
|
|
54
|
-
// Block validation responsibilities
|
|
55
|
-
createBlockProposal(
|
|
56
|
-
blockNumber: number,
|
|
57
|
-
header: ProposedBlockHeader,
|
|
58
|
-
archive: Fr,
|
|
59
|
-
stateReference: StateReference,
|
|
60
|
-
txs: Tx[],
|
|
61
|
-
proposerAddress: EthAddress | undefined,
|
|
62
|
-
options: BlockProposalOptions,
|
|
63
|
-
): Promise<BlockProposal | undefined>;
|
|
64
|
-
attestToProposal(proposal: BlockProposal, sender: PeerId): Promise<BlockAttestation[] | undefined>;
|
|
65
|
-
|
|
66
|
-
broadcastBlockProposal(proposal: BlockProposal): Promise<void>;
|
|
67
|
-
collectAttestations(proposal: BlockProposal, required: number, deadline: Date): Promise<BlockAttestation[]>;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
50
|
/**
|
|
71
51
|
* Validator Client
|
|
72
52
|
*/
|
|
@@ -78,7 +58,6 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
78
58
|
// Used to check if we are sending the same proposal twice
|
|
79
59
|
private previousProposal?: BlockProposal;
|
|
80
60
|
|
|
81
|
-
private myAddresses: EthAddress[];
|
|
82
61
|
private lastEpochForCommitteeUpdateLoop: bigint | undefined;
|
|
83
62
|
private epochCacheUpdateLoop: RunningPromise;
|
|
84
63
|
|
|
@@ -94,9 +73,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
94
73
|
private blockSource: L2BlockSource,
|
|
95
74
|
private l1ToL2MessageSource: L1ToL2MessageSource,
|
|
96
75
|
private txProvider: TxProvider,
|
|
97
|
-
private config:
|
|
98
|
-
Pick<SequencerConfig, 'txPublicSetupAllowList'> &
|
|
99
|
-
Pick<SlasherConfig, 'slashBroadcastedInvalidBlockPenalty'>,
|
|
76
|
+
private config: ValidatorClientFullConfig,
|
|
100
77
|
private dateProvider: DateProvider = new DateProvider(),
|
|
101
78
|
telemetry: TelemetryClient = getTelemetryClient(),
|
|
102
79
|
private log = createLogger('validator'),
|
|
@@ -110,10 +87,10 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
110
87
|
this.blockProposalValidator = new BlockProposalValidator(epochCache);
|
|
111
88
|
|
|
112
89
|
// Refresh epoch cache every second to trigger alert if participation in committee changes
|
|
113
|
-
this.myAddresses = this.keyStore.getAddresses();
|
|
114
90
|
this.epochCacheUpdateLoop = new RunningPromise(this.handleEpochCommitteeUpdate.bind(this), log, 1000);
|
|
115
91
|
|
|
116
|
-
|
|
92
|
+
const myAddresses = this.getValidatorAddresses();
|
|
93
|
+
this.log.verbose(`Initialized validator with addresses: ${myAddresses.map(a => a.toString()).join(', ')}`);
|
|
117
94
|
}
|
|
118
95
|
|
|
119
96
|
public static validateKeyStoreConfiguration(keyStoreManager: KeystoreManager) {
|
|
@@ -144,7 +121,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
144
121
|
return;
|
|
145
122
|
}
|
|
146
123
|
if (epoch !== this.lastEpochForCommitteeUpdateLoop) {
|
|
147
|
-
const me = this.
|
|
124
|
+
const me = this.getValidatorAddresses();
|
|
148
125
|
const committeeSet = new Set(committee.map(v => v.toString()));
|
|
149
126
|
const inCommittee = me.filter(a => committeeSet.has(a.toString()));
|
|
150
127
|
if (inCommittee.length > 0) {
|
|
@@ -194,7 +171,9 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
194
171
|
}
|
|
195
172
|
|
|
196
173
|
public getValidatorAddresses() {
|
|
197
|
-
return this.keyStore
|
|
174
|
+
return this.keyStore
|
|
175
|
+
.getAddresses()
|
|
176
|
+
.filter(addr => !this.config.disabledValidators.some(disabled => disabled.equals(addr)));
|
|
198
177
|
}
|
|
199
178
|
|
|
200
179
|
public signWithAddress(addr: EthAddress, msg: TypedDataDefinition) {
|
|
@@ -209,16 +188,19 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
209
188
|
return this.keyStore.getFeeRecipient(attestor);
|
|
210
189
|
}
|
|
211
190
|
|
|
212
|
-
public
|
|
213
|
-
this.config
|
|
214
|
-
|
|
191
|
+
public getConfig(): ValidatorClientFullConfig {
|
|
192
|
+
return this.config;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
public updateConfig(config: Partial<ValidatorClientFullConfig>) {
|
|
196
|
+
this.config = { ...this.config, ...config };
|
|
215
197
|
}
|
|
216
198
|
|
|
217
199
|
public async start() {
|
|
218
200
|
// Sync the committee from the smart contract
|
|
219
201
|
// https://github.com/AztecProtocol/aztec-packages/issues/7962
|
|
220
202
|
|
|
221
|
-
const myAddresses = this.
|
|
203
|
+
const myAddresses = this.getValidatorAddresses();
|
|
222
204
|
|
|
223
205
|
const inCommittee = await this.epochCache.filterInCommittee('now', myAddresses);
|
|
224
206
|
if (inCommittee.length > 0) {
|
|
@@ -254,7 +236,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
254
236
|
const proposer = proposal.getSender();
|
|
255
237
|
|
|
256
238
|
// Check that I have any address in current committee before attesting
|
|
257
|
-
const inCommittee = await this.epochCache.filterInCommittee(slotNumber, this.
|
|
239
|
+
const inCommittee = await this.epochCache.filterInCommittee(slotNumber, this.getValidatorAddresses());
|
|
258
240
|
const partOfCommittee = inCommittee.length > 0;
|
|
259
241
|
|
|
260
242
|
const proposalInfo = {
|
|
@@ -510,7 +492,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
510
492
|
|
|
511
493
|
async collectOwnAttestations(proposal: BlockProposal): Promise<BlockAttestation[]> {
|
|
512
494
|
const slot = proposal.payload.header.slotNumber.toBigInt();
|
|
513
|
-
const inCommittee = await this.epochCache.filterInCommittee(slot, this.
|
|
495
|
+
const inCommittee = await this.epochCache.filterInCommittee(slot, this.getValidatorAddresses());
|
|
514
496
|
this.log.debug(`Collecting ${inCommittee.length} self-attestations for slot ${slot}`, { inCommittee });
|
|
515
497
|
return this.doAttestToProposal(proposal, inCommittee);
|
|
516
498
|
}
|
|
@@ -530,7 +512,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
530
512
|
await this.collectOwnAttestations(proposal);
|
|
531
513
|
|
|
532
514
|
const proposalId = proposal.archive.toString();
|
|
533
|
-
const myAddresses = this.
|
|
515
|
+
const myAddresses = this.getValidatorAddresses();
|
|
534
516
|
|
|
535
517
|
let attestations: BlockAttestation[] = [];
|
|
536
518
|
while (true) {
|