@lodestar/validator 1.43.0-dev.a140dd987e → 1.43.0-dev.a45ba75824
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/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/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 +2 -0
- package/lib/services/validatorStore.d.ts.map +1 -1
- package/lib/services/validatorStore.js +30 -1
- package/lib/services/validatorStore.js.map +1 -1
- package/lib/util/externalSignerClient.d.ts +5 -1
- package/lib/util/externalSignerClient.d.ts.map +1 -1
- package/lib/util/externalSignerClient.js +4 -0
- package/lib/util/externalSignerClient.js.map +1 -1
- package/lib/validator.d.ts +4 -1
- package/lib/validator.d.ts.map +1 -1
- package/lib/validator.js +8 -2
- package/lib/validator.js.map +1 -1
- package/package.json +12 -12
- package/src/metrics.ts +46 -0
- package/src/services/chainHeaderTracker.ts +31 -7
- package/src/services/emitter.ts +31 -0
- package/src/services/ptc.ts +131 -0
- package/src/services/ptcDuties.ts +246 -0
- package/src/services/validatorStore.ts +42 -0
- package/src/util/externalSignerClient.ts +7 -1
- package/src/validator.ts +20 -1
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import {ApiClient, routes} from "@lodestar/api";
|
|
2
|
+
import {ChainForkConfig} from "@lodestar/config";
|
|
3
|
+
import {SLOTS_PER_EPOCH, isForkPostGloas} from "@lodestar/params";
|
|
4
|
+
import {computeEpochAtSlot, isStartSlotOfEpoch} from "@lodestar/state-transition";
|
|
5
|
+
import {Epoch, RootHex, Slot, ValidatorIndex} from "@lodestar/types";
|
|
6
|
+
import {toPubkeyHex} from "@lodestar/utils";
|
|
7
|
+
import {Metrics} from "../metrics.js";
|
|
8
|
+
import {PubkeyHex} from "../types.js";
|
|
9
|
+
import {IClock, LoggerVc} from "../util/index.js";
|
|
10
|
+
import {ChainHeaderTracker, HeadEventData} from "./chainHeaderTracker.js";
|
|
11
|
+
import {SyncingStatusTracker} from "./syncingStatusTracker.js";
|
|
12
|
+
import {ValidatorStore} from "./validatorStore.js";
|
|
13
|
+
|
|
14
|
+
/** Only retain `HISTORICAL_DUTIES_EPOCHS` duties prior to the current epoch. */
|
|
15
|
+
const HISTORICAL_DUTIES_EPOCHS = 2;
|
|
16
|
+
|
|
17
|
+
type PtcDutiesAtEpoch = {dependentRoot: RootHex; dutiesByIndex: Map<ValidatorIndex, routes.validator.PtcDuty>};
|
|
18
|
+
|
|
19
|
+
export class PtcDutiesService {
|
|
20
|
+
/** Maps a validator index to its PTC duty for each epoch. */
|
|
21
|
+
private readonly dutiesByIndexByEpoch = new Map<Epoch, PtcDutiesAtEpoch>();
|
|
22
|
+
|
|
23
|
+
constructor(
|
|
24
|
+
private readonly config: ChainForkConfig,
|
|
25
|
+
private readonly logger: LoggerVc,
|
|
26
|
+
private readonly api: ApiClient,
|
|
27
|
+
private readonly clock: IClock,
|
|
28
|
+
private readonly validatorStore: ValidatorStore,
|
|
29
|
+
chainHeadTracker: ChainHeaderTracker,
|
|
30
|
+
syncingStatusTracker: SyncingStatusTracker,
|
|
31
|
+
private readonly metrics: Metrics | null
|
|
32
|
+
) {
|
|
33
|
+
clock.runEveryEpoch(this.runDutiesTasks);
|
|
34
|
+
chainHeadTracker.runOnNewHead(this.onNewHead);
|
|
35
|
+
syncingStatusTracker.runOnResynced(async (slot) => {
|
|
36
|
+
// Skip on first slot of epoch since tasks are already scheduled.
|
|
37
|
+
if (!isStartSlotOfEpoch(slot)) {
|
|
38
|
+
return this.runDutiesTasks(computeEpochAtSlot(slot));
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (metrics) {
|
|
43
|
+
metrics.ptcDutiesCount.addCollect(() => {
|
|
44
|
+
const currentSlot = this.clock.getCurrentSlot();
|
|
45
|
+
let duties = 0;
|
|
46
|
+
let nextDutySlot = null;
|
|
47
|
+
for (const [epoch, ptcDutiesAtEpoch] of this.dutiesByIndexByEpoch) {
|
|
48
|
+
duties += ptcDutiesAtEpoch.dutiesByIndex.size;
|
|
49
|
+
|
|
50
|
+
// Epochs are sorted, stop searching once a next duty slot is found.
|
|
51
|
+
if (epoch < this.clock.currentEpoch || nextDutySlot !== null) continue;
|
|
52
|
+
|
|
53
|
+
for (const duty of ptcDutiesAtEpoch.dutiesByIndex.values()) {
|
|
54
|
+
if (duty.slot > currentSlot && (nextDutySlot === null || duty.slot < nextDutySlot)) {
|
|
55
|
+
nextDutySlot = duty.slot;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
metrics.ptcDutiesCount.set(duties);
|
|
60
|
+
metrics.ptcDutiesEpochCount.set(this.dutiesByIndexByEpoch.size);
|
|
61
|
+
if (nextDutySlot !== null) metrics.ptcDutiesNextSlot.set(nextDutySlot);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
removeDutiesForKey(pubkey: PubkeyHex): void {
|
|
67
|
+
for (const [epoch, ptcDutiesAtEpoch] of this.dutiesByIndexByEpoch) {
|
|
68
|
+
for (const [validatorIndex, duty] of ptcDutiesAtEpoch.dutiesByIndex) {
|
|
69
|
+
if (toPubkeyHex(duty.pubkey) === pubkey) {
|
|
70
|
+
ptcDutiesAtEpoch.dutiesByIndex.delete(validatorIndex);
|
|
71
|
+
if (ptcDutiesAtEpoch.dutiesByIndex.size === 0) {
|
|
72
|
+
this.dutiesByIndexByEpoch.delete(epoch);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Returns all PTC duties for the given slot. */
|
|
80
|
+
getDutiesAtSlot(slot: Slot): routes.validator.PtcDuty[] {
|
|
81
|
+
const epoch = computeEpochAtSlot(slot);
|
|
82
|
+
const duties: routes.validator.PtcDuty[] = [];
|
|
83
|
+
const epochDuties = this.dutiesByIndexByEpoch.get(epoch);
|
|
84
|
+
if (epochDuties === undefined) {
|
|
85
|
+
return duties;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
for (const duty of epochDuties.dutiesByIndex.values()) {
|
|
89
|
+
if (duty.slot === slot) {
|
|
90
|
+
duties.push(duty);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return duties;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private runDutiesTasks = async (epoch: Epoch): Promise<void> => {
|
|
98
|
+
const nextEpoch = epoch + 1;
|
|
99
|
+
if (!isForkPostGloas(this.config.getForkName(nextEpoch * SLOTS_PER_EPOCH))) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
await Promise.all([
|
|
104
|
+
this.pollPtcDuties(epoch, this.validatorStore.getAllLocalIndices()).catch((e: Error) => {
|
|
105
|
+
this.logger.error("Error on poll PTC duties", {epoch}, e);
|
|
106
|
+
}),
|
|
107
|
+
|
|
108
|
+
this.validatorStore
|
|
109
|
+
.pollValidatorIndices()
|
|
110
|
+
.then((newIndices) => this.pollPtcDuties(epoch, newIndices))
|
|
111
|
+
.catch((e: Error) => {
|
|
112
|
+
this.logger.error("Error on poll indices and PTC duties", {epoch}, e);
|
|
113
|
+
}),
|
|
114
|
+
]);
|
|
115
|
+
|
|
116
|
+
this.pruneOldDuties(epoch);
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
private async pollPtcDuties(currentEpoch: Epoch, indexArr: ValidatorIndex[]): Promise<void> {
|
|
120
|
+
const nextEpoch = currentEpoch + 1;
|
|
121
|
+
|
|
122
|
+
if (indexArr.length === 0) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
for (const epoch of [currentEpoch, nextEpoch]) {
|
|
127
|
+
await this.pollPtcDutiesForEpoch(epoch, indexArr).catch((e: Error) => {
|
|
128
|
+
this.logger.error("Failed to download PTC duties", {epoch}, e);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private async pollPtcDutiesForEpoch(epoch: Epoch, indexArr: ValidatorIndex[]): Promise<void> {
|
|
134
|
+
if (epoch < 0) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (!isForkPostGloas(this.config.getForkName(epoch * SLOTS_PER_EPOCH))) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const res = await this.api.validator.getPtcDuties({epoch, indices: indexArr});
|
|
143
|
+
const ptcDuties = res.value();
|
|
144
|
+
const {dependentRoot} = res.meta();
|
|
145
|
+
const relevantDuties = ptcDuties.filter((duty) => {
|
|
146
|
+
const pubkeyHex = toPubkeyHex(duty.pubkey);
|
|
147
|
+
return this.validatorStore.hasVotingPubkey(pubkeyHex) && this.validatorStore.isDoppelgangerSafe(pubkeyHex);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
this.logger.debug("Downloaded PTC duties", {epoch, dependentRoot, count: relevantDuties.length});
|
|
151
|
+
|
|
152
|
+
const dutiesAtEpoch = this.dutiesByIndexByEpoch.get(epoch);
|
|
153
|
+
const priorDependentRoot = dutiesAtEpoch?.dependentRoot;
|
|
154
|
+
const dependentRootChanged = priorDependentRoot !== undefined && priorDependentRoot !== dependentRoot;
|
|
155
|
+
|
|
156
|
+
if (!priorDependentRoot || dependentRootChanged) {
|
|
157
|
+
const dutiesByIndex = new Map<ValidatorIndex, routes.validator.PtcDuty>();
|
|
158
|
+
for (const duty of relevantDuties) {
|
|
159
|
+
dutiesByIndex.set(duty.validatorIndex, duty);
|
|
160
|
+
}
|
|
161
|
+
this.dutiesByIndexByEpoch.set(epoch, {dependentRoot, dutiesByIndex});
|
|
162
|
+
|
|
163
|
+
if (priorDependentRoot && dependentRootChanged) {
|
|
164
|
+
this.metrics?.ptcDutiesReorg.inc();
|
|
165
|
+
this.logger.warn("PTC duties re-org. This may happen from time to time", {
|
|
166
|
+
priorDependentRoot,
|
|
167
|
+
dependentRoot,
|
|
168
|
+
epoch,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
} else {
|
|
172
|
+
const existingDuties = dutiesAtEpoch.dutiesByIndex;
|
|
173
|
+
const existingDutiesCount = existingDuties.size;
|
|
174
|
+
const discoveredNewDuties = relevantDuties.length > existingDutiesCount;
|
|
175
|
+
|
|
176
|
+
if (discoveredNewDuties) {
|
|
177
|
+
for (const duty of relevantDuties) {
|
|
178
|
+
if (!existingDuties.has(duty.validatorIndex)) {
|
|
179
|
+
existingDuties.set(duty.validatorIndex, duty);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
this.logger.debug("Discovered new PTC duties", {
|
|
184
|
+
epoch,
|
|
185
|
+
dependentRoot,
|
|
186
|
+
count: relevantDuties.length - existingDutiesCount,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
private onNewHead = async ({
|
|
193
|
+
slot,
|
|
194
|
+
previousDutyDependentRoot,
|
|
195
|
+
currentDutyDependentRoot,
|
|
196
|
+
}: HeadEventData): Promise<void> => {
|
|
197
|
+
const currentEpoch = computeEpochAtSlot(slot);
|
|
198
|
+
const nextEpoch = currentEpoch + 1;
|
|
199
|
+
|
|
200
|
+
const nextEpochDependentRoot = this.dutiesByIndexByEpoch.get(nextEpoch)?.dependentRoot;
|
|
201
|
+
if (nextEpochDependentRoot && currentDutyDependentRoot !== nextEpochDependentRoot) {
|
|
202
|
+
this.logger.warn("Potential next epoch PTC duties reorg", {
|
|
203
|
+
slot,
|
|
204
|
+
dutyEpoch: nextEpoch,
|
|
205
|
+
priorDependentRoot: nextEpochDependentRoot,
|
|
206
|
+
newDependentRoot: currentDutyDependentRoot,
|
|
207
|
+
});
|
|
208
|
+
await this.handlePtcDutiesReorg(nextEpoch, slot, nextEpochDependentRoot, currentDutyDependentRoot);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const currentEpochDependentRoot = this.dutiesByIndexByEpoch.get(currentEpoch)?.dependentRoot;
|
|
212
|
+
if (currentEpochDependentRoot && currentEpochDependentRoot !== previousDutyDependentRoot) {
|
|
213
|
+
this.logger.warn("Potential current epoch PTC duties reorg", {
|
|
214
|
+
slot,
|
|
215
|
+
dutyEpoch: currentEpoch,
|
|
216
|
+
priorDependentRoot: currentEpochDependentRoot,
|
|
217
|
+
newDependentRoot: previousDutyDependentRoot,
|
|
218
|
+
});
|
|
219
|
+
await this.handlePtcDutiesReorg(currentEpoch, slot, currentEpochDependentRoot, previousDutyDependentRoot);
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
private async handlePtcDutiesReorg(
|
|
224
|
+
dutyEpoch: Epoch,
|
|
225
|
+
slot: Slot,
|
|
226
|
+
oldDependentRoot: RootHex,
|
|
227
|
+
newDependentRoot: RootHex
|
|
228
|
+
): Promise<void> {
|
|
229
|
+
this.metrics?.ptcDutiesReorg.inc();
|
|
230
|
+
const logContext = {dutyEpoch, slot, oldDependentRoot, newDependentRoot};
|
|
231
|
+
this.logger.debug("Redownload PTC duties", logContext);
|
|
232
|
+
|
|
233
|
+
await this.pollPtcDutiesForEpoch(dutyEpoch, this.validatorStore.getAllLocalIndices()).catch((e: Error) => {
|
|
234
|
+
this.logger.error("Failed to redownload PTC duties when reorg happens", logContext, e);
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** Run once per epoch to prune duties map. */
|
|
239
|
+
private pruneOldDuties(currentEpoch: Epoch): void {
|
|
240
|
+
for (const epoch of this.dutiesByIndexByEpoch.keys()) {
|
|
241
|
+
if (epoch + HISTORICAL_DUTIES_EPOCHS < currentEpoch) {
|
|
242
|
+
this.dutiesByIndexByEpoch.delete(epoch);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
DOMAIN_BEACON_BUILDER,
|
|
10
10
|
DOMAIN_BEACON_PROPOSER,
|
|
11
11
|
DOMAIN_CONTRIBUTION_AND_PROOF,
|
|
12
|
+
DOMAIN_PTC_ATTESTER,
|
|
12
13
|
DOMAIN_RANDAO,
|
|
13
14
|
DOMAIN_SELECTION_PROOF,
|
|
14
15
|
DOMAIN_SYNC_COMMITTEE,
|
|
@@ -668,6 +669,41 @@ export class ValidatorStore {
|
|
|
668
669
|
};
|
|
669
670
|
}
|
|
670
671
|
|
|
672
|
+
async signPayloadAttestation(
|
|
673
|
+
duty: routes.validator.PtcDuty,
|
|
674
|
+
data: gloas.PayloadAttestationData,
|
|
675
|
+
currentSlot: Slot,
|
|
676
|
+
logger?: LoggerVc
|
|
677
|
+
): Promise<gloas.PayloadAttestationMessage> {
|
|
678
|
+
if (data.slot > currentSlot) {
|
|
679
|
+
throw Error(`Not signing payload attestation with slot ${data.slot} greater than current slot ${currentSlot}`);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
this.assertDoppelgangerSafe(duty.pubkey);
|
|
683
|
+
this.validatePtcDuty(duty, data);
|
|
684
|
+
|
|
685
|
+
const signingSlot = data.slot;
|
|
686
|
+
const domain = this.config.getDomain(signingSlot, DOMAIN_PTC_ATTESTER);
|
|
687
|
+
const signingRoot = computeSigningRoot(ssz.gloas.PayloadAttestationData, data, domain);
|
|
688
|
+
|
|
689
|
+
logger?.debug("Signing payload attestation message", {
|
|
690
|
+
slot: signingSlot,
|
|
691
|
+
beaconBlockRoot: toRootHex(data.beaconBlockRoot),
|
|
692
|
+
signingRoot: toRootHex(signingRoot),
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
const signableMessage: SignableMessage = {
|
|
696
|
+
type: SignableMessageType.PAYLOAD_ATTESTATION,
|
|
697
|
+
data,
|
|
698
|
+
};
|
|
699
|
+
|
|
700
|
+
return {
|
|
701
|
+
validatorIndex: duty.validatorIndex,
|
|
702
|
+
data,
|
|
703
|
+
signature: await this.getSignature(duty.pubkey, signingRoot, signingSlot, signableMessage),
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
|
|
671
707
|
async signAttestationSelectionProof(pubkey: BLSPubkeyMaybeHex, slot: Slot): Promise<BLSSignature> {
|
|
672
708
|
const signingSlot = slot;
|
|
673
709
|
const domain = this.config.getDomain(slot, DOMAIN_SELECTION_PROOF);
|
|
@@ -852,6 +888,12 @@ export class ValidatorStore {
|
|
|
852
888
|
}
|
|
853
889
|
}
|
|
854
890
|
|
|
891
|
+
private validatePtcDuty(duty: routes.validator.PtcDuty, data: gloas.PayloadAttestationData): void {
|
|
892
|
+
if (duty.slot !== data.slot) {
|
|
893
|
+
throw Error(`Inconsistent PTC duties during signing: duty.slot ${duty.slot} != data.slot ${data.slot}`);
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
|
|
855
897
|
private assertDoppelgangerSafe(pubKey: PubkeyHex | BLSPubkey): void {
|
|
856
898
|
const pubkeyHex = typeof pubKey === "string" ? pubKey : toPubkeyHex(pubKey);
|
|
857
899
|
if (!this.isDoppelgangerSafe(pubkeyHex)) {
|
|
@@ -34,6 +34,7 @@ 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",
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
const AggregationSlotType = new ContainerType({
|
|
@@ -83,7 +84,8 @@ export type SignableMessage =
|
|
|
83
84
|
| {type: SignableMessageType.SYNC_COMMITTEE_SELECTION_PROOF; data: ValueOf<typeof SyncAggregatorSelectionDataType>}
|
|
84
85
|
| {type: SignableMessageType.SYNC_COMMITTEE_CONTRIBUTION_AND_PROOF; data: altair.ContributionAndProof}
|
|
85
86
|
| {type: SignableMessageType.VALIDATOR_REGISTRATION; data: ValidatorRegistrationV1}
|
|
86
|
-
| {type: SignableMessageType.EXECUTION_PAYLOAD_ENVELOPE; data: gloas.ExecutionPayloadEnvelope}
|
|
87
|
+
| {type: SignableMessageType.EXECUTION_PAYLOAD_ENVELOPE; data: gloas.ExecutionPayloadEnvelope}
|
|
88
|
+
| {type: SignableMessageType.PAYLOAD_ATTESTATION; data: gloas.PayloadAttestationData};
|
|
87
89
|
|
|
88
90
|
const requiresForkInfo: Record<SignableMessageType, boolean> = {
|
|
89
91
|
[SignableMessageType.AGGREGATION_SLOT]: true,
|
|
@@ -99,6 +101,7 @@ const requiresForkInfo: Record<SignableMessageType, boolean> = {
|
|
|
99
101
|
[SignableMessageType.SYNC_COMMITTEE_CONTRIBUTION_AND_PROOF]: true,
|
|
100
102
|
[SignableMessageType.VALIDATOR_REGISTRATION]: false,
|
|
101
103
|
[SignableMessageType.EXECUTION_PAYLOAD_ENVELOPE]: true,
|
|
104
|
+
[SignableMessageType.PAYLOAD_ATTESTATION]: true,
|
|
102
105
|
};
|
|
103
106
|
|
|
104
107
|
type Web3SignerSerializedRequest = {
|
|
@@ -273,6 +276,9 @@ function serializerSignableMessagePayload(config: BeaconConfig, payload: Signabl
|
|
|
273
276
|
|
|
274
277
|
case SignableMessageType.EXECUTION_PAYLOAD_ENVELOPE:
|
|
275
278
|
return {execution_payload_envelope: ssz.gloas.ExecutionPayloadEnvelope.toJson(payload.data)};
|
|
279
|
+
|
|
280
|
+
case SignableMessageType.PAYLOAD_ATTESTATION:
|
|
281
|
+
return {payload_attestation: ssz.gloas.PayloadAttestationData.toJson(payload.data)};
|
|
276
282
|
}
|
|
277
283
|
}
|
|
278
284
|
|
package/src/validator.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {ValidatorEventEmitter} from "./services/emitter.js";
|
|
|
15
15
|
import {ExternalSignerOptions, pollExternalSignerPubkeys} from "./services/externalSignerSync.js";
|
|
16
16
|
import {IndicesService} from "./services/indices.js";
|
|
17
17
|
import {pollBuilderValidatorRegistration, pollPrepareBeaconProposer} from "./services/prepareBeaconProposer.js";
|
|
18
|
+
import {PtcService} from "./services/ptc.js";
|
|
18
19
|
import {SyncCommitteeService} from "./services/syncCommittee.js";
|
|
19
20
|
import {SyncingStatusTracker} from "./services/syncingStatusTracker.js";
|
|
20
21
|
import {Signer, ValidatorProposerConfig, ValidatorStore, defaultOptions} from "./services/validatorStore.js";
|
|
@@ -30,6 +31,7 @@ export type ValidatorModules = {
|
|
|
30
31
|
slashingProtection: ISlashingProtection;
|
|
31
32
|
blockProposingService: BlockProposingService;
|
|
32
33
|
attestationService: AttestationService;
|
|
34
|
+
ptcService: PtcService;
|
|
33
35
|
syncCommitteeService: SyncCommitteeService;
|
|
34
36
|
config: BeaconConfig;
|
|
35
37
|
api: ApiClient;
|
|
@@ -84,6 +86,7 @@ export class Validator {
|
|
|
84
86
|
private readonly slashingProtection: ISlashingProtection;
|
|
85
87
|
private readonly blockProposingService: BlockProposingService;
|
|
86
88
|
private readonly attestationService: AttestationService;
|
|
89
|
+
private readonly ptcService: PtcService;
|
|
87
90
|
private readonly syncCommitteeService: SyncCommitteeService;
|
|
88
91
|
private readonly config: BeaconConfig;
|
|
89
92
|
private readonly api: ApiClient;
|
|
@@ -102,6 +105,7 @@ export class Validator {
|
|
|
102
105
|
slashingProtection,
|
|
103
106
|
blockProposingService,
|
|
104
107
|
attestationService,
|
|
108
|
+
ptcService,
|
|
105
109
|
syncCommitteeService,
|
|
106
110
|
config,
|
|
107
111
|
api,
|
|
@@ -118,6 +122,7 @@ export class Validator {
|
|
|
118
122
|
this.slashingProtection = slashingProtection;
|
|
119
123
|
this.blockProposingService = blockProposingService;
|
|
120
124
|
this.attestationService = attestationService;
|
|
125
|
+
this.ptcService = ptcService;
|
|
121
126
|
this.syncCommitteeService = syncCommitteeService;
|
|
122
127
|
this.config = config;
|
|
123
128
|
this.api = api;
|
|
@@ -225,7 +230,7 @@ export class Validator {
|
|
|
225
230
|
// We set infinity to prevent MaxListenersExceededWarning which get logged when listeners > 10
|
|
226
231
|
emitter.setMaxListeners(Infinity);
|
|
227
232
|
|
|
228
|
-
const chainHeaderTracker = new ChainHeaderTracker(logger, api, emitter);
|
|
233
|
+
const chainHeaderTracker = new ChainHeaderTracker(config, logger, api, emitter);
|
|
229
234
|
const syncingStatusTracker = new SyncingStatusTracker(logger, api, clock, metrics);
|
|
230
235
|
|
|
231
236
|
const blockProposingService = new BlockProposingService(config, loggerVc, api, clock, validatorStore, metrics, {
|
|
@@ -249,6 +254,18 @@ export class Validator {
|
|
|
249
254
|
}
|
|
250
255
|
);
|
|
251
256
|
|
|
257
|
+
const ptcService = new PtcService(
|
|
258
|
+
config,
|
|
259
|
+
loggerVc,
|
|
260
|
+
api,
|
|
261
|
+
clock,
|
|
262
|
+
validatorStore,
|
|
263
|
+
emitter,
|
|
264
|
+
chainHeaderTracker,
|
|
265
|
+
syncingStatusTracker,
|
|
266
|
+
metrics
|
|
267
|
+
);
|
|
268
|
+
|
|
252
269
|
const syncCommitteeService = new SyncCommitteeService(
|
|
253
270
|
config,
|
|
254
271
|
loggerVc,
|
|
@@ -272,6 +289,7 @@ export class Validator {
|
|
|
272
289
|
slashingProtection,
|
|
273
290
|
blockProposingService,
|
|
274
291
|
attestationService,
|
|
292
|
+
ptcService,
|
|
275
293
|
syncCommitteeService,
|
|
276
294
|
config,
|
|
277
295
|
api,
|
|
@@ -338,6 +356,7 @@ export class Validator {
|
|
|
338
356
|
removeDutiesForKey(pubkey: PubkeyHex): void {
|
|
339
357
|
this.blockProposingService.removeDutiesForKey(pubkey);
|
|
340
358
|
this.attestationService.removeDutiesForKey(pubkey);
|
|
359
|
+
this.ptcService.removeDutiesForKey(pubkey);
|
|
341
360
|
this.syncCommitteeService.removeDutiesForKey(pubkey);
|
|
342
361
|
}
|
|
343
362
|
|