@lodestar/validator 1.43.0-dev.bc569affb9 → 1.43.0-dev.c5efeb6c90
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 +85 -7
- package/lib/services/blockDuties.d.ts.map +1 -1
- package/lib/services/blockDuties.js +186 -74
- 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 +212 -79
- 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 +47 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proposerPreferences.d.ts","sourceRoot":"","sources":["../../src/services/proposerPreferences.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,eAAe,CAAC;AACxC,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAKjD,OAAO,EAAC,OAAO,EAAC,MAAM,eAAe,CAAC;AACtC,OAAO,EAAC,MAAM,EAAE,QAAQ,EAAC,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAC,kBAAkB,EAAC,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAC,cAAc,EAAC,MAAM,qBAAqB,CAAC;AAgBnD;;;;;;;GAOG;AACH,qBAAa,0BAA0B;IAInC,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAEpB,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IARrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsC;IAEhE,YACmB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,QAAQ,EAChB,GAAG,EAAE,SAAS,EAC/B,KAAK,EAAE,MAAM,EACI,cAAc,EAAE,cAAc,EAC9B,kBAAkB,EAAE,kBAAkB,EACvD,QAAQ,EAAE,OAAO,GAAG,IAAI,EAGzB;IAED,OAAO,CAAC,0BAA0B,CA0EhC;CACH"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { SLOTS_PER_EPOCH, isForkPostGloas } from "@lodestar/params";
|
|
2
|
+
import { computeEpochAtSlot } from "@lodestar/state-transition";
|
|
3
|
+
import { fromHex, toPubkeyHex } from "@lodestar/utils";
|
|
4
|
+
/**
|
|
5
|
+
* Submit a proposer's `SignedProposerPreferences` this many slots before the proposal slot.
|
|
6
|
+
*
|
|
7
|
+
* Earlier submission means more reorg-triggered resubmits (and gossip flood); later
|
|
8
|
+
* submission risks missing the bid-auction window for this proposal slot. The bid for
|
|
9
|
+
* slot S typically arrives at slot S-1, so we want preferences propagated to the network
|
|
10
|
+
* and consumed by builders before then. SLOTS_PER_EPOCH / 4 (8 slots @ 32 SPE, ~96s @ 12s
|
|
11
|
+
* slots) gives ample margin while bounding redundant resubmits.
|
|
12
|
+
*/
|
|
13
|
+
const SUBMIT_BEFORE_PROPOSAL_SLOTS = Math.floor(SLOTS_PER_EPOCH / 4);
|
|
14
|
+
/**
|
|
15
|
+
* Signs and submits `SignedProposerPreferences` for any local validator that will propose
|
|
16
|
+
* within the next `SUBMIT_BEFORE_PROPOSAL_SLOTS`. Re-submits automatically when the proposer
|
|
17
|
+
* dependent root for an epoch shifts (e.g. after a reorg) — detected by comparing the cached
|
|
18
|
+
* `dependentRoot` reported by `BlockDutiesService` against the one we last submitted under.
|
|
19
|
+
*
|
|
20
|
+
* No-op pre-gloas.
|
|
21
|
+
*/
|
|
22
|
+
export class ProposerPreferencesService {
|
|
23
|
+
config;
|
|
24
|
+
logger;
|
|
25
|
+
api;
|
|
26
|
+
validatorStore;
|
|
27
|
+
blockDutiesService;
|
|
28
|
+
submitted = new Map();
|
|
29
|
+
constructor(config, logger, api, clock, validatorStore, blockDutiesService, _metrics) {
|
|
30
|
+
this.config = config;
|
|
31
|
+
this.logger = logger;
|
|
32
|
+
this.api = api;
|
|
33
|
+
this.validatorStore = validatorStore;
|
|
34
|
+
this.blockDutiesService = blockDutiesService;
|
|
35
|
+
clock.runEverySlot(this.runProposerPreferencesTask);
|
|
36
|
+
}
|
|
37
|
+
runProposerPreferencesTask = async (slot) => {
|
|
38
|
+
if (!isForkPostGloas(this.config.getForkName(slot))) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const currentEpoch = computeEpochAtSlot(slot);
|
|
42
|
+
const batch = [];
|
|
43
|
+
// Track which `(submission, slot)` pairs are pending an API submission so we can mark
|
|
44
|
+
// them only after the network call succeeds. Marking before would silently drop a
|
|
45
|
+
// preference on transient API failure (no retry until dependent_root shifts).
|
|
46
|
+
const pending = [];
|
|
47
|
+
for (const epoch of [currentEpoch, currentEpoch + 1]) {
|
|
48
|
+
const dutiesAtEpoch = this.blockDutiesService.getProposersAtEpoch(epoch);
|
|
49
|
+
if (!dutiesAtEpoch)
|
|
50
|
+
continue;
|
|
51
|
+
// Reset submission tracking if the dependent root for this epoch has shifted
|
|
52
|
+
// (e.g. due to a reorg). Any previously-submitted preferences are now stale.
|
|
53
|
+
let submission = this.submitted.get(epoch);
|
|
54
|
+
if (submission === undefined || submission.dependentRoot !== dutiesAtEpoch.dependentRoot) {
|
|
55
|
+
if (submission !== undefined) {
|
|
56
|
+
this.logger.info("Proposer-shuffling dependent root shifted; resubmitting preferences", {
|
|
57
|
+
epoch,
|
|
58
|
+
priorDependentRoot: submission.dependentRoot,
|
|
59
|
+
dependentRoot: dutiesAtEpoch.dependentRoot,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
submission = { dependentRoot: dutiesAtEpoch.dependentRoot, slots: new Set() };
|
|
63
|
+
this.submitted.set(epoch, submission);
|
|
64
|
+
}
|
|
65
|
+
const dependentRootBytes = fromHex(dutiesAtEpoch.dependentRoot);
|
|
66
|
+
for (const duty of dutiesAtEpoch.data) {
|
|
67
|
+
if (duty.slot <= slot)
|
|
68
|
+
continue;
|
|
69
|
+
if (duty.slot > slot + SUBMIT_BEFORE_PROPOSAL_SLOTS)
|
|
70
|
+
continue;
|
|
71
|
+
if (submission.slots.has(duty.slot))
|
|
72
|
+
continue;
|
|
73
|
+
try {
|
|
74
|
+
const pubkeyHex = toPubkeyHex(duty.pubkey);
|
|
75
|
+
const signed = await this.validatorStore.signProposerPreferences(duty, dependentRootBytes, this.validatorStore.getFeeRecipient(pubkeyHex), this.validatorStore.getGasLimit(pubkeyHex), slot);
|
|
76
|
+
batch.push(signed);
|
|
77
|
+
pending.push({ submission, slot: duty.slot });
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
this.logger.error("Error signing proposer preferences", { slot: duty.slot, validatorIndex: duty.validatorIndex }, e);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (batch.length === 0) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
await this.api.beacon.submitSignedProposerPreferences({ signedProposerPreferences: batch });
|
|
89
|
+
// Only mark as submitted after the API call succeeds; a thrown error leaves the
|
|
90
|
+
// slot eligible for retry on the next tick.
|
|
91
|
+
for (const { submission, slot: submittedSlot } of pending) {
|
|
92
|
+
submission.slots.add(submittedSlot);
|
|
93
|
+
}
|
|
94
|
+
this.logger.debug("Submitted signed proposer preferences", { count: batch.length });
|
|
95
|
+
}
|
|
96
|
+
catch (e) {
|
|
97
|
+
this.logger.error("Error submitting signed proposer preferences", { count: batch.length }, e);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=proposerPreferences.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proposerPreferences.js","sourceRoot":"","sources":["../../src/services/proposerPreferences.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ApiClient } from "@lodestar/api";
|
|
2
|
+
import { ChainForkConfig } from "@lodestar/config";
|
|
3
|
+
import { Metrics } from "../metrics.js";
|
|
4
|
+
import { PubkeyHex } from "../types.js";
|
|
5
|
+
import { IClock, LoggerVc } from "../util/index.js";
|
|
6
|
+
import { ChainHeaderTracker } from "./chainHeaderTracker.js";
|
|
7
|
+
import { ValidatorEventEmitter } from "./emitter.js";
|
|
8
|
+
import { SyncingStatusTracker } from "./syncingStatusTracker.js";
|
|
9
|
+
import { ValidatorStore } from "./validatorStore.js";
|
|
10
|
+
/**
|
|
11
|
+
* Service that sets up and handles validator Payload Timeliness Committee duties.
|
|
12
|
+
*/
|
|
13
|
+
export declare class PtcService {
|
|
14
|
+
private readonly config;
|
|
15
|
+
private readonly logger;
|
|
16
|
+
private readonly api;
|
|
17
|
+
private readonly clock;
|
|
18
|
+
private readonly validatorStore;
|
|
19
|
+
private readonly emitter;
|
|
20
|
+
private readonly metrics;
|
|
21
|
+
private readonly dutiesService;
|
|
22
|
+
constructor(config: ChainForkConfig, logger: LoggerVc, api: ApiClient, clock: IClock, validatorStore: ValidatorStore, emitter: ValidatorEventEmitter, chainHeadTracker: ChainHeaderTracker, syncingStatusTracker: SyncingStatusTracker, metrics: Metrics | null);
|
|
23
|
+
removeDutiesForKey(pubkey: PubkeyHex): void;
|
|
24
|
+
private runPtcTasks;
|
|
25
|
+
private producePayloadAttestationData;
|
|
26
|
+
private signAndPublishPayloadAttestations;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=ptc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ptc.d.ts","sourceRoot":"","sources":["../../src/services/ptc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAS,MAAM,eAAe,CAAC;AAChD,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAIjD,OAAO,EAAC,OAAO,EAAC,MAAM,eAAe,CAAC;AACtC,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AACtC,OAAO,EAAC,MAAM,EAAE,QAAQ,EAAC,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAC,kBAAkB,EAAC,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAC,qBAAqB,EAAC,MAAM,cAAc,CAAC;AAEnD,OAAO,EAAC,oBAAoB,EAAC,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAC,cAAc,EAAC,MAAM,qBAAqB,CAAC;AAEnD;;GAEG;AACH,qBAAa,UAAU;IAInB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAGxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAX1B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAmB;IAEjD,YACmB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,QAAQ,EAChB,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,cAAc,EAC9B,OAAO,EAAE,qBAAqB,EAC/C,gBAAgB,EAAE,kBAAkB,EACpC,oBAAoB,EAAE,oBAAoB,EACzB,OAAO,EAAE,OAAO,GAAG,IAAI,EAczC;IAED,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAE1C;IAED,OAAO,CAAC,WAAW,CA2BjB;YAEY,6BAA6B;YAI7B,iCAAiC;CAgDhD"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { isForkPostGloas } from "@lodestar/params";
|
|
2
|
+
import { prettyBytes, sleep, toRootHex } from "@lodestar/utils";
|
|
3
|
+
import { PtcDutiesService } from "./ptcDuties.js";
|
|
4
|
+
/**
|
|
5
|
+
* Service that sets up and handles validator Payload Timeliness Committee duties.
|
|
6
|
+
*/
|
|
7
|
+
export class PtcService {
|
|
8
|
+
config;
|
|
9
|
+
logger;
|
|
10
|
+
api;
|
|
11
|
+
clock;
|
|
12
|
+
validatorStore;
|
|
13
|
+
emitter;
|
|
14
|
+
metrics;
|
|
15
|
+
dutiesService;
|
|
16
|
+
constructor(config, logger, api, clock, validatorStore, emitter, chainHeadTracker, syncingStatusTracker, metrics) {
|
|
17
|
+
this.config = config;
|
|
18
|
+
this.logger = logger;
|
|
19
|
+
this.api = api;
|
|
20
|
+
this.clock = clock;
|
|
21
|
+
this.validatorStore = validatorStore;
|
|
22
|
+
this.emitter = emitter;
|
|
23
|
+
this.metrics = metrics;
|
|
24
|
+
this.dutiesService = new PtcDutiesService(config, logger, api, clock, validatorStore, chainHeadTracker, syncingStatusTracker, metrics);
|
|
25
|
+
clock.runEverySlot(this.runPtcTasks);
|
|
26
|
+
}
|
|
27
|
+
removeDutiesForKey(pubkey) {
|
|
28
|
+
this.dutiesService.removeDutiesForKey(pubkey);
|
|
29
|
+
}
|
|
30
|
+
runPtcTasks = async (slot, signal) => {
|
|
31
|
+
const fork = this.config.getForkName(slot);
|
|
32
|
+
if (!isForkPostGloas(fork)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const duties = this.dutiesService.getDutiesAtSlot(slot);
|
|
36
|
+
if (duties.length === 0) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const payloadAttestationDueMs = this.config.getSlotComponentDurationMs(this.config.PAYLOAD_ATTESTATION_DUE_BPS);
|
|
40
|
+
await Promise.race([
|
|
41
|
+
sleep(payloadAttestationDueMs - this.clock.msFromSlot(slot), signal),
|
|
42
|
+
this.emitter.waitForExecutionPayloadAvailableSlot(slot),
|
|
43
|
+
]);
|
|
44
|
+
this.metrics?.ptcStepCallProducePayloadAttestation.observe(this.clock.secFromSlot(slot) - payloadAttestationDueMs / 1000);
|
|
45
|
+
try {
|
|
46
|
+
const payloadAttestationData = await this.producePayloadAttestationData(slot);
|
|
47
|
+
await this.signAndPublishPayloadAttestations(slot, payloadAttestationData, duties);
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
this.logger.error("Error on PTC routine", { slot }, e);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
async producePayloadAttestationData(slot) {
|
|
54
|
+
return (await this.api.validator.producePayloadAttestationData({ slot })).value();
|
|
55
|
+
}
|
|
56
|
+
async signAndPublishPayloadAttestations(slot, payloadAttestationData, duties) {
|
|
57
|
+
const payloadAttestationMessages = [];
|
|
58
|
+
const beaconBlockRootHex = toRootHex(payloadAttestationData.beaconBlockRoot);
|
|
59
|
+
await Promise.all(duties.map(async (duty) => {
|
|
60
|
+
const logCtxValidator = { slot, validatorIndex: duty.validatorIndex, beaconBlockRoot: beaconBlockRootHex };
|
|
61
|
+
try {
|
|
62
|
+
payloadAttestationMessages.push(await this.validatorStore.signPayloadAttestation(duty, payloadAttestationData, this.clock.getCurrentSlot(), this.logger));
|
|
63
|
+
this.logger.debug("Signed payload attestation message", logCtxValidator);
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
this.metrics?.ptcError.inc({ error: "sign" });
|
|
67
|
+
this.logger.error("Error signing payload attestation message", logCtxValidator, e);
|
|
68
|
+
}
|
|
69
|
+
}));
|
|
70
|
+
this.metrics?.ptcStepCallPublishPayloadAttestation.observe(this.clock.secFromSlot(slot) -
|
|
71
|
+
this.config.getSlotComponentDurationMs(this.config.PAYLOAD_ATTESTATION_DUE_BPS) / 1000);
|
|
72
|
+
if (payloadAttestationMessages.length > 0) {
|
|
73
|
+
try {
|
|
74
|
+
(await this.api.beacon.submitPayloadAttestationMessages({ payloadAttestationMessages })).assertOk();
|
|
75
|
+
this.logger.info("Published payload attestation messages", {
|
|
76
|
+
slot,
|
|
77
|
+
beaconBlockRoot: prettyBytes(beaconBlockRootHex),
|
|
78
|
+
count: payloadAttestationMessages.length,
|
|
79
|
+
});
|
|
80
|
+
this.metrics?.publishedPayloadAttestations.inc(payloadAttestationMessages.length);
|
|
81
|
+
}
|
|
82
|
+
catch (e) {
|
|
83
|
+
this.metrics?.ptcError.inc({ error: "publish" });
|
|
84
|
+
this.logger.error("Error publishing payload attestation messages", { slot }, e);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=ptc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ptc.js","sourceRoot":"","sources":["../../src/services/ptc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ApiClient, routes } from "@lodestar/api";
|
|
2
|
+
import { ChainForkConfig } from "@lodestar/config";
|
|
3
|
+
import { Slot } from "@lodestar/types";
|
|
4
|
+
import { Metrics } from "../metrics.js";
|
|
5
|
+
import { PubkeyHex } from "../types.js";
|
|
6
|
+
import { IClock, LoggerVc } from "../util/index.js";
|
|
7
|
+
import { ChainHeaderTracker } from "./chainHeaderTracker.js";
|
|
8
|
+
import { SyncingStatusTracker } from "./syncingStatusTracker.js";
|
|
9
|
+
import { ValidatorStore } from "./validatorStore.js";
|
|
10
|
+
export declare class PtcDutiesService {
|
|
11
|
+
private readonly config;
|
|
12
|
+
private readonly logger;
|
|
13
|
+
private readonly api;
|
|
14
|
+
private readonly clock;
|
|
15
|
+
private readonly validatorStore;
|
|
16
|
+
private readonly metrics;
|
|
17
|
+
/** Maps a validator index to its PTC duty for each epoch. */
|
|
18
|
+
private readonly dutiesByIndexByEpoch;
|
|
19
|
+
constructor(config: ChainForkConfig, logger: LoggerVc, api: ApiClient, clock: IClock, validatorStore: ValidatorStore, chainHeadTracker: ChainHeaderTracker, syncingStatusTracker: SyncingStatusTracker, metrics: Metrics | null);
|
|
20
|
+
removeDutiesForKey(pubkey: PubkeyHex): void;
|
|
21
|
+
/** Returns all PTC duties for the given slot. */
|
|
22
|
+
getDutiesAtSlot(slot: Slot): routes.validator.PtcDuty[];
|
|
23
|
+
private runDutiesTasks;
|
|
24
|
+
private pollPtcDuties;
|
|
25
|
+
private pollPtcDutiesForEpoch;
|
|
26
|
+
private onNewHead;
|
|
27
|
+
private handlePtcDutiesReorg;
|
|
28
|
+
/** Run once per epoch to prune duties map. */
|
|
29
|
+
private pruneOldDuties;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=ptcDuties.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ptcDuties.d.ts","sourceRoot":"","sources":["../../src/services/ptcDuties.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAE,MAAM,EAAC,MAAM,eAAe,CAAC;AAChD,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAAiB,IAAI,EAAiB,MAAM,iBAAiB,CAAC;AAErE,OAAO,EAAC,OAAO,EAAC,MAAM,eAAe,CAAC;AACtC,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AACtC,OAAO,EAAC,MAAM,EAAE,QAAQ,EAAC,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAC,kBAAkB,EAAgB,MAAM,yBAAyB,CAAC;AAC1E,OAAO,EAAC,oBAAoB,EAAC,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAC,cAAc,EAAC,MAAM,qBAAqB,CAAC;AAOnD,qBAAa,gBAAgB;IAKzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,cAAc;IAG/B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAX1B,6DAA6D;IAC7D,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAsC;IAE3E,YACmB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,QAAQ,EAChB,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,cAAc,EAC/C,gBAAgB,EAAE,kBAAkB,EACpC,oBAAoB,EAAE,oBAAoB,EACzB,OAAO,EAAE,OAAO,GAAG,IAAI,EAiCzC;IAED,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAW1C;IAED,iDAAiD;IACjD,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,CAetD;IAED,OAAO,CAAC,cAAc,CAoBpB;YAEY,aAAa;YAcb,qBAAqB;IA2DnC,OAAO,CAAC,SAAS,CA6Bf;YAEY,oBAAoB;IAelC,8CAA8C;IAC9C,OAAO,CAAC,cAAc;CAOvB"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { SLOTS_PER_EPOCH, isForkPostGloas } from "@lodestar/params";
|
|
2
|
+
import { computeEpochAtSlot, isStartSlotOfEpoch } from "@lodestar/state-transition";
|
|
3
|
+
import { toPubkeyHex } from "@lodestar/utils";
|
|
4
|
+
/** Only retain `HISTORICAL_DUTIES_EPOCHS` duties prior to the current epoch. */
|
|
5
|
+
const HISTORICAL_DUTIES_EPOCHS = 2;
|
|
6
|
+
export class PtcDutiesService {
|
|
7
|
+
config;
|
|
8
|
+
logger;
|
|
9
|
+
api;
|
|
10
|
+
clock;
|
|
11
|
+
validatorStore;
|
|
12
|
+
metrics;
|
|
13
|
+
/** Maps a validator index to its PTC duty for each epoch. */
|
|
14
|
+
dutiesByIndexByEpoch = new Map();
|
|
15
|
+
constructor(config, logger, api, clock, validatorStore, chainHeadTracker, syncingStatusTracker, metrics) {
|
|
16
|
+
this.config = config;
|
|
17
|
+
this.logger = logger;
|
|
18
|
+
this.api = api;
|
|
19
|
+
this.clock = clock;
|
|
20
|
+
this.validatorStore = validatorStore;
|
|
21
|
+
this.metrics = metrics;
|
|
22
|
+
clock.runEveryEpoch(this.runDutiesTasks);
|
|
23
|
+
chainHeadTracker.runOnNewHead(this.onNewHead);
|
|
24
|
+
syncingStatusTracker.runOnResynced(async (slot) => {
|
|
25
|
+
// Skip on first slot of epoch since tasks are already scheduled.
|
|
26
|
+
if (!isStartSlotOfEpoch(slot)) {
|
|
27
|
+
return this.runDutiesTasks(computeEpochAtSlot(slot));
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
if (metrics) {
|
|
31
|
+
metrics.ptcDutiesCount.addCollect(() => {
|
|
32
|
+
const currentSlot = this.clock.getCurrentSlot();
|
|
33
|
+
let duties = 0;
|
|
34
|
+
let nextDutySlot = null;
|
|
35
|
+
for (const [epoch, ptcDutiesAtEpoch] of this.dutiesByIndexByEpoch) {
|
|
36
|
+
duties += ptcDutiesAtEpoch.dutiesByIndex.size;
|
|
37
|
+
// Epochs are sorted, stop searching once a next duty slot is found.
|
|
38
|
+
if (epoch < this.clock.currentEpoch || nextDutySlot !== null)
|
|
39
|
+
continue;
|
|
40
|
+
for (const duty of ptcDutiesAtEpoch.dutiesByIndex.values()) {
|
|
41
|
+
if (duty.slot > currentSlot && (nextDutySlot === null || duty.slot < nextDutySlot)) {
|
|
42
|
+
nextDutySlot = duty.slot;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
metrics.ptcDutiesCount.set(duties);
|
|
47
|
+
metrics.ptcDutiesEpochCount.set(this.dutiesByIndexByEpoch.size);
|
|
48
|
+
if (nextDutySlot !== null)
|
|
49
|
+
metrics.ptcDutiesNextSlot.set(nextDutySlot);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
removeDutiesForKey(pubkey) {
|
|
54
|
+
for (const [epoch, ptcDutiesAtEpoch] of this.dutiesByIndexByEpoch) {
|
|
55
|
+
for (const [validatorIndex, duty] of ptcDutiesAtEpoch.dutiesByIndex) {
|
|
56
|
+
if (toPubkeyHex(duty.pubkey) === pubkey) {
|
|
57
|
+
ptcDutiesAtEpoch.dutiesByIndex.delete(validatorIndex);
|
|
58
|
+
if (ptcDutiesAtEpoch.dutiesByIndex.size === 0) {
|
|
59
|
+
this.dutiesByIndexByEpoch.delete(epoch);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** Returns all PTC duties for the given slot. */
|
|
66
|
+
getDutiesAtSlot(slot) {
|
|
67
|
+
const epoch = computeEpochAtSlot(slot);
|
|
68
|
+
const duties = [];
|
|
69
|
+
const epochDuties = this.dutiesByIndexByEpoch.get(epoch);
|
|
70
|
+
if (epochDuties === undefined) {
|
|
71
|
+
return duties;
|
|
72
|
+
}
|
|
73
|
+
for (const duty of epochDuties.dutiesByIndex.values()) {
|
|
74
|
+
if (duty.slot === slot) {
|
|
75
|
+
duties.push(duty);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return duties;
|
|
79
|
+
}
|
|
80
|
+
runDutiesTasks = async (epoch) => {
|
|
81
|
+
const nextEpoch = epoch + 1;
|
|
82
|
+
if (!isForkPostGloas(this.config.getForkName(nextEpoch * SLOTS_PER_EPOCH))) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
await Promise.all([
|
|
86
|
+
this.pollPtcDuties(epoch, this.validatorStore.getAllLocalIndices()).catch((e) => {
|
|
87
|
+
this.logger.error("Error on poll PTC duties", { epoch }, e);
|
|
88
|
+
}),
|
|
89
|
+
this.validatorStore
|
|
90
|
+
.pollValidatorIndices()
|
|
91
|
+
.then((newIndices) => this.pollPtcDuties(epoch, newIndices))
|
|
92
|
+
.catch((e) => {
|
|
93
|
+
this.logger.error("Error on poll indices and PTC duties", { epoch }, e);
|
|
94
|
+
}),
|
|
95
|
+
]);
|
|
96
|
+
this.pruneOldDuties(epoch);
|
|
97
|
+
};
|
|
98
|
+
async pollPtcDuties(currentEpoch, indexArr) {
|
|
99
|
+
const nextEpoch = currentEpoch + 1;
|
|
100
|
+
if (indexArr.length === 0) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
for (const epoch of [currentEpoch, nextEpoch]) {
|
|
104
|
+
await this.pollPtcDutiesForEpoch(epoch, indexArr).catch((e) => {
|
|
105
|
+
this.logger.error("Failed to download PTC duties", { epoch }, e);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async pollPtcDutiesForEpoch(epoch, indexArr) {
|
|
110
|
+
if (epoch < 0) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (!isForkPostGloas(this.config.getForkName(epoch * SLOTS_PER_EPOCH))) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const res = await this.api.validator.getPtcDuties({ epoch, indices: indexArr });
|
|
117
|
+
const ptcDuties = res.value();
|
|
118
|
+
const { dependentRoot } = res.meta();
|
|
119
|
+
const relevantDuties = ptcDuties.filter((duty) => {
|
|
120
|
+
const pubkeyHex = toPubkeyHex(duty.pubkey);
|
|
121
|
+
return this.validatorStore.hasVotingPubkey(pubkeyHex) && this.validatorStore.isDoppelgangerSafe(pubkeyHex);
|
|
122
|
+
});
|
|
123
|
+
this.logger.debug("Downloaded PTC duties", { epoch, dependentRoot, count: relevantDuties.length });
|
|
124
|
+
const dutiesAtEpoch = this.dutiesByIndexByEpoch.get(epoch);
|
|
125
|
+
const priorDependentRoot = dutiesAtEpoch?.dependentRoot;
|
|
126
|
+
const dependentRootChanged = priorDependentRoot !== undefined && priorDependentRoot !== dependentRoot;
|
|
127
|
+
if (!priorDependentRoot || dependentRootChanged) {
|
|
128
|
+
const dutiesByIndex = new Map();
|
|
129
|
+
for (const duty of relevantDuties) {
|
|
130
|
+
dutiesByIndex.set(duty.validatorIndex, duty);
|
|
131
|
+
}
|
|
132
|
+
this.dutiesByIndexByEpoch.set(epoch, { dependentRoot, dutiesByIndex });
|
|
133
|
+
if (priorDependentRoot && dependentRootChanged) {
|
|
134
|
+
this.metrics?.ptcDutiesReorg.inc();
|
|
135
|
+
this.logger.warn("PTC duties re-org. This may happen from time to time", {
|
|
136
|
+
priorDependentRoot,
|
|
137
|
+
dependentRoot,
|
|
138
|
+
epoch,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
const existingDuties = dutiesAtEpoch.dutiesByIndex;
|
|
144
|
+
const existingDutiesCount = existingDuties.size;
|
|
145
|
+
const discoveredNewDuties = relevantDuties.length > existingDutiesCount;
|
|
146
|
+
if (discoveredNewDuties) {
|
|
147
|
+
for (const duty of relevantDuties) {
|
|
148
|
+
if (!existingDuties.has(duty.validatorIndex)) {
|
|
149
|
+
existingDuties.set(duty.validatorIndex, duty);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
this.logger.debug("Discovered new PTC duties", {
|
|
153
|
+
epoch,
|
|
154
|
+
dependentRoot,
|
|
155
|
+
count: relevantDuties.length - existingDutiesCount,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
onNewHead = async ({ slot, previousDutyDependentRoot, currentDutyDependentRoot, }) => {
|
|
161
|
+
const currentEpoch = computeEpochAtSlot(slot);
|
|
162
|
+
const nextEpoch = currentEpoch + 1;
|
|
163
|
+
const nextEpochDependentRoot = this.dutiesByIndexByEpoch.get(nextEpoch)?.dependentRoot;
|
|
164
|
+
if (nextEpochDependentRoot && currentDutyDependentRoot !== nextEpochDependentRoot) {
|
|
165
|
+
this.logger.warn("Potential next epoch PTC duties reorg", {
|
|
166
|
+
slot,
|
|
167
|
+
dutyEpoch: nextEpoch,
|
|
168
|
+
priorDependentRoot: nextEpochDependentRoot,
|
|
169
|
+
newDependentRoot: currentDutyDependentRoot,
|
|
170
|
+
});
|
|
171
|
+
await this.handlePtcDutiesReorg(nextEpoch, slot, nextEpochDependentRoot, currentDutyDependentRoot);
|
|
172
|
+
}
|
|
173
|
+
const currentEpochDependentRoot = this.dutiesByIndexByEpoch.get(currentEpoch)?.dependentRoot;
|
|
174
|
+
if (currentEpochDependentRoot && currentEpochDependentRoot !== previousDutyDependentRoot) {
|
|
175
|
+
this.logger.warn("Potential current epoch PTC duties reorg", {
|
|
176
|
+
slot,
|
|
177
|
+
dutyEpoch: currentEpoch,
|
|
178
|
+
priorDependentRoot: currentEpochDependentRoot,
|
|
179
|
+
newDependentRoot: previousDutyDependentRoot,
|
|
180
|
+
});
|
|
181
|
+
await this.handlePtcDutiesReorg(currentEpoch, slot, currentEpochDependentRoot, previousDutyDependentRoot);
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
async handlePtcDutiesReorg(dutyEpoch, slot, oldDependentRoot, newDependentRoot) {
|
|
185
|
+
this.metrics?.ptcDutiesReorg.inc();
|
|
186
|
+
const logContext = { dutyEpoch, slot, oldDependentRoot, newDependentRoot };
|
|
187
|
+
this.logger.debug("Redownload PTC duties", logContext);
|
|
188
|
+
await this.pollPtcDutiesForEpoch(dutyEpoch, this.validatorStore.getAllLocalIndices()).catch((e) => {
|
|
189
|
+
this.logger.error("Failed to redownload PTC duties when reorg happens", logContext, e);
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
/** Run once per epoch to prune duties map. */
|
|
193
|
+
pruneOldDuties(currentEpoch) {
|
|
194
|
+
for (const epoch of this.dutiesByIndexByEpoch.keys()) {
|
|
195
|
+
if (epoch + HISTORICAL_DUTIES_EPOCHS < currentEpoch) {
|
|
196
|
+
this.dutiesByIndexByEpoch.delete(epoch);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=ptcDuties.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ptcDuties.js","sourceRoot":"","sources":["../../src/services/ptcDuties.ts"],"names":[],"mappings":"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"}
|
|
@@ -123,6 +123,8 @@ export declare class ValidatorStore {
|
|
|
123
123
|
pubkey: BLSPubkeyMaybeHex;
|
|
124
124
|
validatorIndex: number;
|
|
125
125
|
}, selectionProof: BLSSignature, contribution: altair.SyncCommitteeContribution): Promise<altair.SignedContributionAndProof>;
|
|
126
|
+
signPayloadAttestation(duty: routes.validator.PtcDuty, data: gloas.PayloadAttestationData, currentSlot: Slot, logger?: LoggerVc): Promise<gloas.PayloadAttestationMessage>;
|
|
127
|
+
signProposerPreferences(duty: routes.validator.ProposerDuty, dependentRoot: Uint8Array, feeRecipient: ExecutionAddress, gasLimit: number, currentSlot: Slot): Promise<gloas.SignedProposerPreferences>;
|
|
126
128
|
signAttestationSelectionProof(pubkey: BLSPubkeyMaybeHex, slot: Slot): Promise<BLSSignature>;
|
|
127
129
|
signSyncCommitteeSelectionProof(pubkey: BLSPubkeyMaybeHex, slot: Slot, subcommitteeIndex: number): Promise<BLSSignature>;
|
|
128
130
|
signVoluntaryExit(pubkey: BLSPubkeyMaybeHex, validatorIndex: number, exitEpoch: Epoch): Promise<phase0.SignedVoluntaryExit>;
|
|
@@ -138,6 +140,7 @@ export declare class ValidatorStore {
|
|
|
138
140
|
private getSignature;
|
|
139
141
|
/** Prevent signing bad data sent by the Beacon node */
|
|
140
142
|
private validateAttestationDuty;
|
|
143
|
+
private validatePtcDuty;
|
|
141
144
|
private assertDoppelgangerSafe;
|
|
142
145
|
}
|
|
143
146
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validatorStore.d.ts","sourceRoot":"","sources":["../../src/services/validatorStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAE1C,OAAO,EAAC,MAAM,EAAC,MAAM,eAAe,CAAC;AACrC,OAAO,EAAC,YAAY,EAAC,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"validatorStore.d.ts","sourceRoot":"","sources":["../../src/services/validatorStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BitArray } from "@chainsafe/ssz";
|
|
2
2
|
import { routes } from "@lodestar/api";
|
|
3
|
-
import { DOMAIN_AGGREGATE_AND_PROOF, DOMAIN_APPLICATION_BUILDER, DOMAIN_BEACON_ATTESTER, DOMAIN_BEACON_BUILDER, DOMAIN_BEACON_PROPOSER, DOMAIN_CONTRIBUTION_AND_PROOF, DOMAIN_RANDAO, DOMAIN_SELECTION_PROOF, DOMAIN_SYNC_COMMITTEE, DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF, ForkSeq, } from "@lodestar/params";
|
|
3
|
+
import { DOMAIN_AGGREGATE_AND_PROOF, DOMAIN_APPLICATION_BUILDER, DOMAIN_BEACON_ATTESTER, DOMAIN_BEACON_BUILDER, DOMAIN_BEACON_PROPOSER, DOMAIN_CONTRIBUTION_AND_PROOF, DOMAIN_PROPOSER_PREFERENCES, DOMAIN_PTC_ATTESTER, DOMAIN_RANDAO, DOMAIN_SELECTION_PROOF, DOMAIN_SYNC_COMMITTEE, DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF, ForkSeq, } from "@lodestar/params";
|
|
4
4
|
import { ZERO_HASH, blindedOrFullBlockHashTreeRoot, computeDomain, computeEpochAtSlot, computeSigningRoot, computeStartSlotAtEpoch, } from "@lodestar/state-transition";
|
|
5
5
|
import { ssz, } from "@lodestar/types";
|
|
6
6
|
import { fromHex, toPubkeyHex, toRootHex } from "@lodestar/utils";
|
|
@@ -429,6 +429,54 @@ export class ValidatorStore {
|
|
|
429
429
|
signature: await this.getSignature(duty.pubkey, signingRoot, signingSlot, signableMessage),
|
|
430
430
|
};
|
|
431
431
|
}
|
|
432
|
+
async signPayloadAttestation(duty, data, currentSlot, logger) {
|
|
433
|
+
if (data.slot > currentSlot) {
|
|
434
|
+
throw Error(`Not signing payload attestation with slot ${data.slot} greater than current slot ${currentSlot}`);
|
|
435
|
+
}
|
|
436
|
+
this.assertDoppelgangerSafe(duty.pubkey);
|
|
437
|
+
this.validatePtcDuty(duty, data);
|
|
438
|
+
const signingSlot = data.slot;
|
|
439
|
+
const domain = this.config.getDomain(signingSlot, DOMAIN_PTC_ATTESTER);
|
|
440
|
+
const signingRoot = computeSigningRoot(ssz.gloas.PayloadAttestationData, data, domain);
|
|
441
|
+
logger?.debug("Signing payload attestation message", {
|
|
442
|
+
slot: signingSlot,
|
|
443
|
+
beaconBlockRoot: toRootHex(data.beaconBlockRoot),
|
|
444
|
+
signingRoot: toRootHex(signingRoot),
|
|
445
|
+
});
|
|
446
|
+
const signableMessage = {
|
|
447
|
+
type: SignableMessageType.PAYLOAD_ATTESTATION,
|
|
448
|
+
data,
|
|
449
|
+
};
|
|
450
|
+
return {
|
|
451
|
+
validatorIndex: duty.validatorIndex,
|
|
452
|
+
data,
|
|
453
|
+
signature: await this.getSignature(duty.pubkey, signingRoot, signingSlot, signableMessage),
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
async signProposerPreferences(duty, dependentRoot, feeRecipient, gasLimit, currentSlot) {
|
|
457
|
+
if (duty.slot <= currentSlot) {
|
|
458
|
+
throw Error(`Not signing proposer preferences for past slot ${duty.slot} (current ${currentSlot})`);
|
|
459
|
+
}
|
|
460
|
+
this.assertDoppelgangerSafe(duty.pubkey);
|
|
461
|
+
const message = {
|
|
462
|
+
dependentRoot,
|
|
463
|
+
proposalSlot: duty.slot,
|
|
464
|
+
validatorIndex: duty.validatorIndex,
|
|
465
|
+
feeRecipient: fromHex(feeRecipient),
|
|
466
|
+
gasLimit,
|
|
467
|
+
};
|
|
468
|
+
const signingSlot = duty.slot;
|
|
469
|
+
const domain = this.config.getDomain(signingSlot, DOMAIN_PROPOSER_PREFERENCES);
|
|
470
|
+
const signingRoot = computeSigningRoot(ssz.gloas.ProposerPreferences, message, domain);
|
|
471
|
+
const signableMessage = {
|
|
472
|
+
type: SignableMessageType.PROPOSER_PREFERENCES,
|
|
473
|
+
data: message,
|
|
474
|
+
};
|
|
475
|
+
return {
|
|
476
|
+
message,
|
|
477
|
+
signature: await this.getSignature(duty.pubkey, signingRoot, signingSlot, signableMessage),
|
|
478
|
+
};
|
|
479
|
+
}
|
|
432
480
|
async signAttestationSelectionProof(pubkey, slot) {
|
|
433
481
|
const signingSlot = slot;
|
|
434
482
|
const domain = this.config.getDomain(slot, DOMAIN_SELECTION_PROOF);
|
|
@@ -561,6 +609,11 @@ export class ValidatorStore {
|
|
|
561
609
|
throw Error(`Non-zero committee index post-electra during signing: att.committeeIndex ${data.index}`);
|
|
562
610
|
}
|
|
563
611
|
}
|
|
612
|
+
validatePtcDuty(duty, data) {
|
|
613
|
+
if (duty.slot !== data.slot) {
|
|
614
|
+
throw Error(`Inconsistent PTC duties during signing: duty.slot ${duty.slot} != data.slot ${data.slot}`);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
564
617
|
assertDoppelgangerSafe(pubKey) {
|
|
565
618
|
const pubkeyHex = typeof pubKey === "string" ? pubKey : toPubkeyHex(pubKey);
|
|
566
619
|
if (!this.isDoppelgangerSafe(pubkeyHex)) {
|