@lodestar/validator 1.43.0-dev.bc569affb9 → 1.43.0-dev.c98da75ec7
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/lib/metrics.d.ts +10 -0
- package/lib/metrics.d.ts.map +1 -1
- package/lib/metrics.js +37 -0
- package/lib/metrics.js.map +1 -1
- package/lib/services/block.d.ts +2 -1
- package/lib/services/block.d.ts.map +1 -1
- package/lib/services/block.js +4 -3
- package/lib/services/block.js.map +1 -1
- package/lib/services/blockDuties.d.ts +20 -4
- package/lib/services/blockDuties.d.ts.map +1 -1
- package/lib/services/blockDuties.js +18 -3
- package/lib/services/blockDuties.js.map +1 -1
- package/lib/services/chainHeaderTracker.d.ts +8 -2
- package/lib/services/chainHeaderTracker.d.ts.map +1 -1
- package/lib/services/chainHeaderTracker.js +23 -8
- package/lib/services/chainHeaderTracker.js.map +1 -1
- package/lib/services/emitter.d.ts +14 -1
- package/lib/services/emitter.d.ts.map +1 -1
- package/lib/services/emitter.js +22 -0
- package/lib/services/emitter.js.map +1 -1
- package/lib/services/proposerPreferences.d.ts +25 -0
- package/lib/services/proposerPreferences.d.ts.map +1 -0
- package/lib/services/proposerPreferences.js +101 -0
- package/lib/services/proposerPreferences.js.map +1 -0
- package/lib/services/ptc.d.ts +28 -0
- package/lib/services/ptc.d.ts.map +1 -0
- package/lib/services/ptc.js +89 -0
- package/lib/services/ptc.js.map +1 -0
- package/lib/services/ptcDuties.d.ts +31 -0
- package/lib/services/ptcDuties.d.ts.map +1 -0
- package/lib/services/ptcDuties.js +201 -0
- package/lib/services/ptcDuties.js.map +1 -0
- package/lib/services/validatorStore.d.ts +3 -0
- package/lib/services/validatorStore.d.ts.map +1 -1
- package/lib/services/validatorStore.js +54 -1
- package/lib/services/validatorStore.js.map +1 -1
- package/lib/util/externalSignerClient.d.ts +9 -1
- package/lib/util/externalSignerClient.d.ts.map +1 -1
- package/lib/util/externalSignerClient.js +8 -0
- package/lib/util/externalSignerClient.js.map +1 -1
- package/lib/util/params.js +3 -0
- package/lib/util/params.js.map +1 -1
- package/lib/validator.d.ts +4 -1
- package/lib/validator.d.ts.map +1 -1
- package/lib/validator.js +13 -3
- package/lib/validator.js.map +1 -1
- package/package.json +12 -12
- package/src/metrics.ts +46 -0
- package/src/services/block.ts +3 -9
- package/src/services/blockDuties.ts +21 -6
- package/src/services/chainHeaderTracker.ts +31 -7
- package/src/services/emitter.ts +31 -0
- package/src/services/proposerPreferences.ts +124 -0
- package/src/services/ptc.ts +131 -0
- package/src/services/ptcDuties.ts +246 -0
- package/src/services/validatorStore.ts +79 -0
- package/src/util/externalSignerClient.ts +13 -1
- package/src/util/params.ts +3 -0
- package/src/validator.ts +39 -5
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
DOMAIN_BEACON_BUILDER,
|
|
10
10
|
DOMAIN_BEACON_PROPOSER,
|
|
11
11
|
DOMAIN_CONTRIBUTION_AND_PROOF,
|
|
12
|
+
DOMAIN_PROPOSER_PREFERENCES,
|
|
13
|
+
DOMAIN_PTC_ATTESTER,
|
|
12
14
|
DOMAIN_RANDAO,
|
|
13
15
|
DOMAIN_SELECTION_PROOF,
|
|
14
16
|
DOMAIN_SYNC_COMMITTEE,
|
|
@@ -668,6 +670,77 @@ export class ValidatorStore {
|
|
|
668
670
|
};
|
|
669
671
|
}
|
|
670
672
|
|
|
673
|
+
async signPayloadAttestation(
|
|
674
|
+
duty: routes.validator.PtcDuty,
|
|
675
|
+
data: gloas.PayloadAttestationData,
|
|
676
|
+
currentSlot: Slot,
|
|
677
|
+
logger?: LoggerVc
|
|
678
|
+
): Promise<gloas.PayloadAttestationMessage> {
|
|
679
|
+
if (data.slot > currentSlot) {
|
|
680
|
+
throw Error(`Not signing payload attestation with slot ${data.slot} greater than current slot ${currentSlot}`);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
this.assertDoppelgangerSafe(duty.pubkey);
|
|
684
|
+
this.validatePtcDuty(duty, data);
|
|
685
|
+
|
|
686
|
+
const signingSlot = data.slot;
|
|
687
|
+
const domain = this.config.getDomain(signingSlot, DOMAIN_PTC_ATTESTER);
|
|
688
|
+
const signingRoot = computeSigningRoot(ssz.gloas.PayloadAttestationData, data, domain);
|
|
689
|
+
|
|
690
|
+
logger?.debug("Signing payload attestation message", {
|
|
691
|
+
slot: signingSlot,
|
|
692
|
+
beaconBlockRoot: toRootHex(data.beaconBlockRoot),
|
|
693
|
+
signingRoot: toRootHex(signingRoot),
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
const signableMessage: SignableMessage = {
|
|
697
|
+
type: SignableMessageType.PAYLOAD_ATTESTATION,
|
|
698
|
+
data,
|
|
699
|
+
};
|
|
700
|
+
|
|
701
|
+
return {
|
|
702
|
+
validatorIndex: duty.validatorIndex,
|
|
703
|
+
data,
|
|
704
|
+
signature: await this.getSignature(duty.pubkey, signingRoot, signingSlot, signableMessage),
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
async signProposerPreferences(
|
|
709
|
+
duty: routes.validator.ProposerDuty,
|
|
710
|
+
dependentRoot: Uint8Array,
|
|
711
|
+
feeRecipient: ExecutionAddress,
|
|
712
|
+
gasLimit: number,
|
|
713
|
+
currentSlot: Slot
|
|
714
|
+
): Promise<gloas.SignedProposerPreferences> {
|
|
715
|
+
if (duty.slot <= currentSlot) {
|
|
716
|
+
throw Error(`Not signing proposer preferences for past slot ${duty.slot} (current ${currentSlot})`);
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
this.assertDoppelgangerSafe(duty.pubkey);
|
|
720
|
+
|
|
721
|
+
const message: gloas.ProposerPreferences = {
|
|
722
|
+
dependentRoot,
|
|
723
|
+
proposalSlot: duty.slot,
|
|
724
|
+
validatorIndex: duty.validatorIndex,
|
|
725
|
+
feeRecipient: fromHex(feeRecipient),
|
|
726
|
+
gasLimit,
|
|
727
|
+
};
|
|
728
|
+
|
|
729
|
+
const signingSlot = duty.slot;
|
|
730
|
+
const domain = this.config.getDomain(signingSlot, DOMAIN_PROPOSER_PREFERENCES);
|
|
731
|
+
const signingRoot = computeSigningRoot(ssz.gloas.ProposerPreferences, message, domain);
|
|
732
|
+
|
|
733
|
+
const signableMessage: SignableMessage = {
|
|
734
|
+
type: SignableMessageType.PROPOSER_PREFERENCES,
|
|
735
|
+
data: message,
|
|
736
|
+
};
|
|
737
|
+
|
|
738
|
+
return {
|
|
739
|
+
message,
|
|
740
|
+
signature: await this.getSignature(duty.pubkey, signingRoot, signingSlot, signableMessage),
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
|
|
671
744
|
async signAttestationSelectionProof(pubkey: BLSPubkeyMaybeHex, slot: Slot): Promise<BLSSignature> {
|
|
672
745
|
const signingSlot = slot;
|
|
673
746
|
const domain = this.config.getDomain(slot, DOMAIN_SELECTION_PROOF);
|
|
@@ -852,6 +925,12 @@ export class ValidatorStore {
|
|
|
852
925
|
}
|
|
853
926
|
}
|
|
854
927
|
|
|
928
|
+
private validatePtcDuty(duty: routes.validator.PtcDuty, data: gloas.PayloadAttestationData): void {
|
|
929
|
+
if (duty.slot !== data.slot) {
|
|
930
|
+
throw Error(`Inconsistent PTC duties during signing: duty.slot ${duty.slot} != data.slot ${data.slot}`);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
|
|
855
934
|
private assertDoppelgangerSafe(pubKey: PubkeyHex | BLSPubkey): void {
|
|
856
935
|
const pubkeyHex = typeof pubKey === "string" ? pubKey : toPubkeyHex(pubKey);
|
|
857
936
|
if (!this.isDoppelgangerSafe(pubkeyHex)) {
|
|
@@ -34,6 +34,8 @@ export enum SignableMessageType {
|
|
|
34
34
|
SYNC_COMMITTEE_CONTRIBUTION_AND_PROOF = "SYNC_COMMITTEE_CONTRIBUTION_AND_PROOF",
|
|
35
35
|
VALIDATOR_REGISTRATION = "VALIDATOR_REGISTRATION",
|
|
36
36
|
EXECUTION_PAYLOAD_ENVELOPE = "EXECUTION_PAYLOAD_ENVELOPE",
|
|
37
|
+
PAYLOAD_ATTESTATION = "PAYLOAD_ATTESTATION",
|
|
38
|
+
PROPOSER_PREFERENCES = "PROPOSER_PREFERENCES",
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
const AggregationSlotType = new ContainerType({
|
|
@@ -83,7 +85,9 @@ export type SignableMessage =
|
|
|
83
85
|
| {type: SignableMessageType.SYNC_COMMITTEE_SELECTION_PROOF; data: ValueOf<typeof SyncAggregatorSelectionDataType>}
|
|
84
86
|
| {type: SignableMessageType.SYNC_COMMITTEE_CONTRIBUTION_AND_PROOF; data: altair.ContributionAndProof}
|
|
85
87
|
| {type: SignableMessageType.VALIDATOR_REGISTRATION; data: ValidatorRegistrationV1}
|
|
86
|
-
| {type: SignableMessageType.EXECUTION_PAYLOAD_ENVELOPE; data: gloas.ExecutionPayloadEnvelope}
|
|
88
|
+
| {type: SignableMessageType.EXECUTION_PAYLOAD_ENVELOPE; data: gloas.ExecutionPayloadEnvelope}
|
|
89
|
+
| {type: SignableMessageType.PAYLOAD_ATTESTATION; data: gloas.PayloadAttestationData}
|
|
90
|
+
| {type: SignableMessageType.PROPOSER_PREFERENCES; data: gloas.ProposerPreferences};
|
|
87
91
|
|
|
88
92
|
const requiresForkInfo: Record<SignableMessageType, boolean> = {
|
|
89
93
|
[SignableMessageType.AGGREGATION_SLOT]: true,
|
|
@@ -99,6 +103,8 @@ const requiresForkInfo: Record<SignableMessageType, boolean> = {
|
|
|
99
103
|
[SignableMessageType.SYNC_COMMITTEE_CONTRIBUTION_AND_PROOF]: true,
|
|
100
104
|
[SignableMessageType.VALIDATOR_REGISTRATION]: false,
|
|
101
105
|
[SignableMessageType.EXECUTION_PAYLOAD_ENVELOPE]: true,
|
|
106
|
+
[SignableMessageType.PAYLOAD_ATTESTATION]: true,
|
|
107
|
+
[SignableMessageType.PROPOSER_PREFERENCES]: true,
|
|
102
108
|
};
|
|
103
109
|
|
|
104
110
|
type Web3SignerSerializedRequest = {
|
|
@@ -273,6 +279,12 @@ function serializerSignableMessagePayload(config: BeaconConfig, payload: Signabl
|
|
|
273
279
|
|
|
274
280
|
case SignableMessageType.EXECUTION_PAYLOAD_ENVELOPE:
|
|
275
281
|
return {execution_payload_envelope: ssz.gloas.ExecutionPayloadEnvelope.toJson(payload.data)};
|
|
282
|
+
|
|
283
|
+
case SignableMessageType.PAYLOAD_ATTESTATION:
|
|
284
|
+
return {payload_attestation: ssz.gloas.PayloadAttestationData.toJson(payload.data)};
|
|
285
|
+
|
|
286
|
+
case SignableMessageType.PROPOSER_PREFERENCES:
|
|
287
|
+
return {proposer_preferences: ssz.gloas.ProposerPreferences.toJson(payload.data)};
|
|
276
288
|
}
|
|
277
289
|
}
|
|
278
290
|
|
package/src/util/params.ts
CHANGED
|
@@ -327,5 +327,8 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record<keyof ConfigWit
|
|
|
327
327
|
BUILDER_PENDING_WITHDRAWALS_LIMIT: gloasForkRelevant,
|
|
328
328
|
MAX_BUILDERS_PER_WITHDRAWALS_SWEEP: gloasForkRelevant,
|
|
329
329
|
MIN_BUILDER_WITHDRAWABILITY_DELAY: gloasForkRelevant,
|
|
330
|
+
CHURN_LIMIT_QUOTIENT_GLOAS: gloasForkRelevant,
|
|
331
|
+
CONSOLIDATION_CHURN_LIMIT_QUOTIENT: gloasForkRelevant,
|
|
332
|
+
MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT_GLOAS: gloasForkRelevant,
|
|
330
333
|
};
|
|
331
334
|
}
|
package/src/validator.ts
CHANGED
|
@@ -9,12 +9,15 @@ import {Metrics} from "./metrics.js";
|
|
|
9
9
|
import {MetaDataRepository} from "./repositories/metaDataRepository.js";
|
|
10
10
|
import {AttestationService} from "./services/attestation.js";
|
|
11
11
|
import {BlockProposingService} from "./services/block.js";
|
|
12
|
+
import {BlockDutiesService} from "./services/blockDuties.js";
|
|
12
13
|
import {ChainHeaderTracker} from "./services/chainHeaderTracker.js";
|
|
13
14
|
import {DoppelgangerService} from "./services/doppelgangerService.js";
|
|
14
15
|
import {ValidatorEventEmitter} from "./services/emitter.js";
|
|
15
16
|
import {ExternalSignerOptions, pollExternalSignerPubkeys} from "./services/externalSignerSync.js";
|
|
16
17
|
import {IndicesService} from "./services/indices.js";
|
|
17
18
|
import {pollBuilderValidatorRegistration, pollPrepareBeaconProposer} from "./services/prepareBeaconProposer.js";
|
|
19
|
+
import {ProposerPreferencesService} from "./services/proposerPreferences.js";
|
|
20
|
+
import {PtcService} from "./services/ptc.js";
|
|
18
21
|
import {SyncCommitteeService} from "./services/syncCommittee.js";
|
|
19
22
|
import {SyncingStatusTracker} from "./services/syncingStatusTracker.js";
|
|
20
23
|
import {Signer, ValidatorProposerConfig, ValidatorStore, defaultOptions} from "./services/validatorStore.js";
|
|
@@ -30,6 +33,7 @@ export type ValidatorModules = {
|
|
|
30
33
|
slashingProtection: ISlashingProtection;
|
|
31
34
|
blockProposingService: BlockProposingService;
|
|
32
35
|
attestationService: AttestationService;
|
|
36
|
+
ptcService: PtcService;
|
|
33
37
|
syncCommitteeService: SyncCommitteeService;
|
|
34
38
|
config: BeaconConfig;
|
|
35
39
|
api: ApiClient;
|
|
@@ -84,6 +88,7 @@ export class Validator {
|
|
|
84
88
|
private readonly slashingProtection: ISlashingProtection;
|
|
85
89
|
private readonly blockProposingService: BlockProposingService;
|
|
86
90
|
private readonly attestationService: AttestationService;
|
|
91
|
+
private readonly ptcService: PtcService;
|
|
87
92
|
private readonly syncCommitteeService: SyncCommitteeService;
|
|
88
93
|
private readonly config: BeaconConfig;
|
|
89
94
|
private readonly api: ApiClient;
|
|
@@ -102,6 +107,7 @@ export class Validator {
|
|
|
102
107
|
slashingProtection,
|
|
103
108
|
blockProposingService,
|
|
104
109
|
attestationService,
|
|
110
|
+
ptcService,
|
|
105
111
|
syncCommitteeService,
|
|
106
112
|
config,
|
|
107
113
|
api,
|
|
@@ -118,6 +124,7 @@ export class Validator {
|
|
|
118
124
|
this.slashingProtection = slashingProtection;
|
|
119
125
|
this.blockProposingService = blockProposingService;
|
|
120
126
|
this.attestationService = attestationService;
|
|
127
|
+
this.ptcService = ptcService;
|
|
121
128
|
this.syncCommitteeService = syncCommitteeService;
|
|
122
129
|
this.config = config;
|
|
123
130
|
this.api = api;
|
|
@@ -225,13 +232,24 @@ export class Validator {
|
|
|
225
232
|
// We set infinity to prevent MaxListenersExceededWarning which get logged when listeners > 10
|
|
226
233
|
emitter.setMaxListeners(Infinity);
|
|
227
234
|
|
|
228
|
-
const chainHeaderTracker = new ChainHeaderTracker(logger, api, emitter);
|
|
235
|
+
const chainHeaderTracker = new ChainHeaderTracker(config, logger, api, emitter);
|
|
229
236
|
const syncingStatusTracker = new SyncingStatusTracker(logger, api, clock, metrics);
|
|
230
237
|
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
238
|
+
const blockDutiesService = new BlockDutiesService(config, loggerVc, api, clock, validatorStore, metrics);
|
|
239
|
+
|
|
240
|
+
const blockProposingService = new BlockProposingService(
|
|
241
|
+
config,
|
|
242
|
+
loggerVc,
|
|
243
|
+
api,
|
|
244
|
+
clock,
|
|
245
|
+
validatorStore,
|
|
246
|
+
blockDutiesService,
|
|
247
|
+
metrics,
|
|
248
|
+
{
|
|
249
|
+
broadcastValidation: opts.broadcastValidation ?? defaultOptions.broadcastValidation,
|
|
250
|
+
blindedLocal: opts.blindedLocal ?? defaultOptions.blindedLocal,
|
|
251
|
+
}
|
|
252
|
+
);
|
|
235
253
|
|
|
236
254
|
const attestationService = new AttestationService(
|
|
237
255
|
loggerVc,
|
|
@@ -249,6 +267,18 @@ export class Validator {
|
|
|
249
267
|
}
|
|
250
268
|
);
|
|
251
269
|
|
|
270
|
+
const ptcService = new PtcService(
|
|
271
|
+
config,
|
|
272
|
+
loggerVc,
|
|
273
|
+
api,
|
|
274
|
+
clock,
|
|
275
|
+
validatorStore,
|
|
276
|
+
emitter,
|
|
277
|
+
chainHeaderTracker,
|
|
278
|
+
syncingStatusTracker,
|
|
279
|
+
metrics
|
|
280
|
+
);
|
|
281
|
+
|
|
252
282
|
const syncCommitteeService = new SyncCommitteeService(
|
|
253
283
|
config,
|
|
254
284
|
loggerVc,
|
|
@@ -265,6 +295,8 @@ export class Validator {
|
|
|
265
295
|
}
|
|
266
296
|
);
|
|
267
297
|
|
|
298
|
+
new ProposerPreferencesService(config, loggerVc, api, clock, validatorStore, blockDutiesService, metrics);
|
|
299
|
+
|
|
268
300
|
return new Validator({
|
|
269
301
|
opts,
|
|
270
302
|
genesis,
|
|
@@ -272,6 +304,7 @@ export class Validator {
|
|
|
272
304
|
slashingProtection,
|
|
273
305
|
blockProposingService,
|
|
274
306
|
attestationService,
|
|
307
|
+
ptcService,
|
|
275
308
|
syncCommitteeService,
|
|
276
309
|
config,
|
|
277
310
|
api,
|
|
@@ -338,6 +371,7 @@ export class Validator {
|
|
|
338
371
|
removeDutiesForKey(pubkey: PubkeyHex): void {
|
|
339
372
|
this.blockProposingService.removeDutiesForKey(pubkey);
|
|
340
373
|
this.attestationService.removeDutiesForKey(pubkey);
|
|
374
|
+
this.ptcService.removeDutiesForKey(pubkey);
|
|
341
375
|
this.syncCommitteeService.removeDutiesForKey(pubkey);
|
|
342
376
|
}
|
|
343
377
|
|