@lodestar/validator 1.50.0 → 1.51.0-dev.15ecdb3b27

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.
Files changed (72) hide show
  1. package/lib/services/attestation.d.ts.map +1 -1
  2. package/lib/services/attestation.js +1 -2
  3. package/lib/services/attestation.js.map +1 -1
  4. package/lib/services/attestationDuties.d.ts.map +1 -1
  5. package/lib/services/attestationDuties.js +12 -4
  6. package/lib/services/attestationDuties.js.map +1 -1
  7. package/lib/services/block.d.ts.map +1 -1
  8. package/lib/services/block.js +1 -1
  9. package/lib/services/block.js.map +1 -1
  10. package/lib/services/blockDuties.d.ts.map +1 -1
  11. package/lib/services/blockDuties.js +3 -1
  12. package/lib/services/blockDuties.js.map +1 -1
  13. package/lib/services/chainHeaderTracker.d.ts.map +1 -1
  14. package/lib/services/chainHeaderTracker.js +6 -1
  15. package/lib/services/chainHeaderTracker.js.map +1 -1
  16. package/lib/services/emitter.d.ts +10 -1
  17. package/lib/services/emitter.d.ts.map +1 -1
  18. package/lib/services/emitter.js +4 -0
  19. package/lib/services/emitter.js.map +1 -1
  20. package/lib/services/inclusionList.d.ts +25 -0
  21. package/lib/services/inclusionList.d.ts.map +1 -0
  22. package/lib/services/inclusionList.js +101 -0
  23. package/lib/services/inclusionList.js.map +1 -0
  24. package/lib/services/inclusionListDuties.d.ts +59 -0
  25. package/lib/services/inclusionListDuties.d.ts.map +1 -0
  26. package/lib/services/inclusionListDuties.js +252 -0
  27. package/lib/services/inclusionListDuties.js.map +1 -0
  28. package/lib/services/ptc.d.ts.map +1 -1
  29. package/lib/services/ptc.js +3 -2
  30. package/lib/services/ptc.js.map +1 -1
  31. package/lib/services/syncCommittee.js +1 -1
  32. package/lib/services/syncCommittee.js.map +1 -1
  33. package/lib/services/syncCommitteeDuties.d.ts.map +1 -1
  34. package/lib/services/syncCommitteeDuties.js +10 -5
  35. package/lib/services/syncCommitteeDuties.js.map +1 -1
  36. package/lib/services/validatorStore.d.ts +7 -1
  37. package/lib/services/validatorStore.d.ts.map +1 -1
  38. package/lib/services/validatorStore.js +29 -3
  39. package/lib/services/validatorStore.js.map +1 -1
  40. package/lib/slashingProtection/attestation/index.d.ts +1 -0
  41. package/lib/slashingProtection/attestation/index.d.ts.map +1 -1
  42. package/lib/slashingProtection/attestation/index.js +77 -44
  43. package/lib/slashingProtection/attestation/index.js.map +1 -1
  44. package/lib/slashingProtection/index.d.ts +2 -0
  45. package/lib/slashingProtection/index.d.ts.map +1 -1
  46. package/lib/slashingProtection/index.js +48 -5
  47. package/lib/slashingProtection/index.js.map +1 -1
  48. package/lib/util/externalSignerClient.d.ts +7 -4
  49. package/lib/util/externalSignerClient.d.ts.map +1 -1
  50. package/lib/util/externalSignerClient.js +4 -0
  51. package/lib/util/externalSignerClient.js.map +1 -1
  52. package/lib/validator.d.ts +4 -1
  53. package/lib/validator.d.ts.map +1 -1
  54. package/lib/validator.js +11 -4
  55. package/lib/validator.js.map +1 -1
  56. package/package.json +12 -12
  57. package/src/services/attestation.ts +1 -2
  58. package/src/services/attestationDuties.ts +18 -4
  59. package/src/services/block.ts +6 -3
  60. package/src/services/blockDuties.ts +3 -1
  61. package/src/services/chainHeaderTracker.ts +8 -1
  62. package/src/services/emitter.ts +10 -0
  63. package/src/services/inclusionList.ts +140 -0
  64. package/src/services/inclusionListDuties.ts +306 -0
  65. package/src/services/ptc.ts +6 -2
  66. package/src/services/syncCommittee.ts +1 -1
  67. package/src/services/syncCommitteeDuties.ts +13 -5
  68. package/src/services/validatorStore.ts +43 -3
  69. package/src/slashingProtection/attestation/index.ts +81 -46
  70. package/src/slashingProtection/index.ts +50 -6
  71. package/src/util/externalSignerClient.ts +10 -3
  72. package/src/validator.ts +31 -3
@@ -1,8 +1,8 @@
1
1
  import {GENESIS_EPOCH} from "@lodestar/params";
2
2
  import {BLSPubkey, Epoch, Root} from "@lodestar/types";
3
- import {Logger, toPubkeyHex} from "@lodestar/utils";
3
+ import {Logger, defer, toPubkeyHex} from "@lodestar/utils";
4
4
  import {uniqueVectorArr} from "../slashingProtection/utils.js";
5
- import {LodestarValidatorDatabaseController} from "../types.js";
5
+ import {LodestarValidatorDatabaseController, PubkeyHex} from "../types.js";
6
6
  import {
7
7
  AttestationByTargetRepository,
8
8
  AttestationLowerBoundRepository,
@@ -34,6 +34,8 @@ export type {ISlashingProtection, InterchangeFormatVersion, SlashingProtectionBl
34
34
  export class SlashingProtection implements ISlashingProtection {
35
35
  private blockService: SlashingProtectionBlockService;
36
36
  private attestationService: SlashingProtectionAttestationService;
37
+ private readonly importing = new Map<PubkeyHex, Promise<void>>();
38
+ private lastImport: Promise<void> | null = null;
37
39
 
38
40
  constructor(protected db: LodestarValidatorDatabaseController) {
39
41
  const blockBySlotRepository = new BlockBySlotRepository(db);
@@ -51,10 +53,26 @@ export class SlashingProtection implements ISlashingProtection {
51
53
  }
52
54
 
53
55
  async checkAndInsertBlockProposal(pubKey: BLSPubkey, block: SlashingProtectionBlock): Promise<void> {
56
+ if (this.importing.size !== 0) {
57
+ const pubkeyHex = toPubkeyHex(pubKey);
58
+ let importing = this.importing.get(pubkeyHex);
59
+ while (importing !== undefined) {
60
+ await importing;
61
+ importing = this.importing.get(pubkeyHex);
62
+ }
63
+ }
54
64
  await this.blockService.checkAndInsertBlockProposal(pubKey, block);
55
65
  }
56
66
 
57
67
  async checkAndInsertAttestation(pubKey: BLSPubkey, attestation: SlashingProtectionAttestation): Promise<void> {
68
+ if (this.importing.size !== 0) {
69
+ const pubkeyHex = toPubkeyHex(pubKey);
70
+ let importing = this.importing.get(pubkeyHex);
71
+ while (importing !== undefined) {
72
+ await importing;
73
+ importing = this.importing.get(pubkeyHex);
74
+ }
75
+ }
58
76
  await this.attestationService.checkAndInsertAttestation(pubKey, attestation);
59
77
  }
60
78
 
@@ -84,10 +102,36 @@ export class SlashingProtection implements ISlashingProtection {
84
102
  }
85
103
  }
86
104
  }
87
- for (const validator of data) {
88
- logger?.info("Importing slashing protection", {pubkey: toPubkeyHex(validator.pubkey)});
89
- await this.blockService.importBlocks(validator.pubkey, validator.signedBlocks);
90
- await this.attestationService.importAttestations(validator.pubkey, validator.signedAttestations);
105
+
106
+ // Checks for keys in the file wait for the whole import, a key that is already signing must not sign against
107
+ // a history the import is still extending. Imports run one after another so a later one cannot release a key early.
108
+ const pubkeyHexes = data.map((validator) => toPubkeyHex(validator.pubkey));
109
+ const previous = this.lastImport;
110
+ const {promise, resolve} = defer<void>();
111
+ this.lastImport = promise;
112
+ for (const pubkeyHex of pubkeyHexes) {
113
+ this.importing.set(pubkeyHex, promise);
114
+ }
115
+
116
+ try {
117
+ if (previous !== null) {
118
+ await previous;
119
+ }
120
+ for (const validator of data) {
121
+ logger?.info("Importing slashing protection", {pubkey: toPubkeyHex(validator.pubkey)});
122
+ await this.blockService.importBlocks(validator.pubkey, validator.signedBlocks);
123
+ await this.attestationService.importAttestations(validator.pubkey, validator.signedAttestations);
124
+ }
125
+ } finally {
126
+ resolve();
127
+ if (this.lastImport === promise) {
128
+ this.lastImport = null;
129
+ }
130
+ for (const pubkeyHex of pubkeyHexes) {
131
+ if (this.importing.get(pubkeyHex) === promise) {
132
+ this.importing.delete(pubkeyHex);
133
+ }
134
+ }
91
135
  }
92
136
  }
93
137
 
@@ -1,6 +1,6 @@
1
1
  import {ContainerType, ValueOf} from "@chainsafe/ssz";
2
2
  import {BeaconConfig} from "@lodestar/config";
3
- import {ForkName, ForkPostGloas, ForkPreBellatrix, ForkSeq, isForkPostDeneb} from "@lodestar/params";
3
+ import {ForkName, ForkPostGloas, ForkSeq, isForkPostDeneb} from "@lodestar/params";
4
4
  import {blindedOrFullBlockToHeader, computeEpochAtSlot} from "@lodestar/state-transition";
5
5
  import {
6
6
  AggregateAndProof,
@@ -12,6 +12,7 @@ import {
12
12
  Slot,
13
13
  altair,
14
14
  gloas,
15
+ heze,
15
16
  phase0,
16
17
  ssz,
17
18
  sszTypesFor,
@@ -37,6 +38,7 @@ export enum SignableMessageType {
37
38
  PAYLOAD_ATTESTATION_MESSAGE = "PAYLOAD_ATTESTATION_MESSAGE",
38
39
  PROPOSER_PREFERENCES = "PROPOSER_PREFERENCES",
39
40
  BUILDER_REQUEST_AUTH = "BUILDER_REQUEST_AUTH",
41
+ INCLUSION_LIST = "INCLUSION_LIST",
40
42
  }
41
43
 
42
44
  const AggregationSlotType = new ContainerType({
@@ -78,7 +80,7 @@ export type SignableMessage =
78
80
  | {type: SignableMessageType.AGGREGATE_AND_PROOF; data: phase0.AggregateAndProof}
79
81
  | {type: SignableMessageType.AGGREGATE_AND_PROOF_V2; data: AggregateAndProof}
80
82
  | {type: SignableMessageType.ATTESTATION; data: phase0.AttestationData}
81
- | {type: SignableMessageType.BLOCK_V2; data: BeaconBlock<ForkPreBellatrix> | BlindedBeaconBlock}
83
+ | {type: SignableMessageType.BLOCK_V2; data: BeaconBlock | BlindedBeaconBlock}
82
84
  | {type: SignableMessageType.DEPOSIT; data: ValueOf<typeof DepositType>}
83
85
  | {type: SignableMessageType.RANDAO_REVEAL; data: {epoch: Epoch}}
84
86
  | {type: SignableMessageType.VOLUNTARY_EXIT; data: phase0.VoluntaryExit}
@@ -89,7 +91,8 @@ export type SignableMessage =
89
91
  | {type: SignableMessageType.EXECUTION_PAYLOAD_ENVELOPE; data: gloas.ExecutionPayloadEnvelope}
90
92
  | {type: SignableMessageType.PAYLOAD_ATTESTATION_MESSAGE; data: gloas.PayloadAttestationData}
91
93
  | {type: SignableMessageType.PROPOSER_PREFERENCES; data: gloas.ProposerPreferences}
92
- | {type: SignableMessageType.BUILDER_REQUEST_AUTH; data: gloas.BuilderRequestAuth};
94
+ | {type: SignableMessageType.BUILDER_REQUEST_AUTH; data: gloas.BuilderRequestAuth}
95
+ | {type: SignableMessageType.INCLUSION_LIST; data: heze.InclusionList};
93
96
 
94
97
  const requiresForkInfo: Record<SignableMessageType, boolean> = {
95
98
  [SignableMessageType.AGGREGATION_SLOT]: true,
@@ -108,6 +111,7 @@ const requiresForkInfo: Record<SignableMessageType, boolean> = {
108
111
  [SignableMessageType.PAYLOAD_ATTESTATION_MESSAGE]: true,
109
112
  [SignableMessageType.PROPOSER_PREFERENCES]: true,
110
113
  [SignableMessageType.BUILDER_REQUEST_AUTH]: false,
114
+ [SignableMessageType.INCLUSION_LIST]: true,
111
115
  };
112
116
 
113
117
  type Web3SignerSerializedRequest = {
@@ -319,6 +323,9 @@ function serializerSignableMessagePayload(config: BeaconConfig, payload: Signabl
319
323
  },
320
324
  };
321
325
  }
326
+
327
+ case SignableMessageType.INCLUSION_LIST:
328
+ return {inclusion_list: ssz.heze.InclusionList.toJson(payload.data)};
322
329
  }
323
330
  }
324
331
 
package/src/validator.ts CHANGED
@@ -6,7 +6,14 @@ import {
6
6
  assertEqualParams,
7
7
  createBeaconConfig,
8
8
  } from "@lodestar/config";
9
- import {Clock, ClockOptions, IClock, computeEpochAtSlot, getCurrentSlot} from "@lodestar/state-transition";
9
+ import {
10
+ Clock,
11
+ ClockOptions,
12
+ IClock,
13
+ computeEpochAtSlot,
14
+ getCurrentSlot,
15
+ getSlotDurations,
16
+ } from "@lodestar/state-transition";
10
17
  import {BLSPubkey, phase0, ssz} from "@lodestar/types";
11
18
  import {Genesis} from "@lodestar/types/phase0";
12
19
  import {Logger, prettyGweiToEth, toPrintableUrl, toRootHex} from "@lodestar/utils";
@@ -20,6 +27,7 @@ import {ChainHeaderTracker} from "./services/chainHeaderTracker.js";
20
27
  import {DoppelgangerService} from "./services/doppelgangerService.js";
21
28
  import {ValidatorEventEmitter} from "./services/emitter.js";
22
29
  import {ExternalSignerOptions, pollExternalSignerPubkeys} from "./services/externalSignerSync.js";
30
+ import {InclusionListService} from "./services/inclusionList.js";
23
31
  import {IndicesService} from "./services/indices.js";
24
32
  import {pollBuilderValidatorRegistration, pollPrepareBeaconProposer} from "./services/prepareBeaconProposer.js";
25
33
  import {ProposalPreferencesService} from "./services/proposalPreferences.js";
@@ -46,6 +54,7 @@ export type ValidatorModules = {
46
54
  blockProposingService: BlockProposingService;
47
55
  attestationService: AttestationService;
48
56
  ptcService: PtcService;
57
+ inclusionListService: InclusionListService;
49
58
  syncCommitteeService: SyncCommitteeService;
50
59
  config: BeaconConfig;
51
60
  api: ApiClient;
@@ -102,6 +111,7 @@ export class Validator {
102
111
  private readonly blockProposingService: BlockProposingService;
103
112
  private readonly attestationService: AttestationService;
104
113
  private readonly ptcService: PtcService;
114
+ private readonly inclusionListService: InclusionListService;
105
115
  private readonly syncCommitteeService: SyncCommitteeService;
106
116
  private readonly config: BeaconConfig;
107
117
  private readonly api: ApiClient;
@@ -121,6 +131,7 @@ export class Validator {
121
131
  blockProposingService,
122
132
  attestationService,
123
133
  ptcService,
134
+ inclusionListService,
124
135
  syncCommitteeService,
125
136
  config,
126
137
  api,
@@ -138,6 +149,7 @@ export class Validator {
138
149
  this.blockProposingService = blockProposingService;
139
150
  this.attestationService = attestationService;
140
151
  this.ptcService = ptcService;
152
+ this.inclusionListService = inclusionListService;
141
153
  this.syncCommitteeService = syncCommitteeService;
142
154
  this.config = config;
143
155
  this.api = api;
@@ -202,7 +214,9 @@ export class Validator {
202
214
  globalInit: {
203
215
  signal: controller.signal,
204
216
  ...globalInit,
205
- timeoutMs: globalInit?.timeoutMs ?? config.SLOT_DURATION_MS,
217
+ timeoutMs:
218
+ globalInit?.timeoutMs ??
219
+ Math.min(...getSlotDurations(config).map(([, slotDurationMs]) => slotDurationMs)),
206
220
  },
207
221
  },
208
222
  {config, logger, metrics: metrics?.restApiClient}
@@ -303,6 +317,17 @@ export class Validator {
303
317
  metrics
304
318
  );
305
319
 
320
+ const inclusionListService = new InclusionListService(
321
+ config,
322
+ loggerVc,
323
+ api,
324
+ clock,
325
+ validatorStore,
326
+ chainHeaderTracker,
327
+ syncingStatusTracker,
328
+ emitter
329
+ );
330
+
306
331
  const syncCommitteeService = new SyncCommitteeService(
307
332
  config,
308
333
  loggerVc,
@@ -338,6 +363,7 @@ export class Validator {
338
363
  blockProposingService,
339
364
  attestationService,
340
365
  ptcService,
366
+ inclusionListService,
341
367
  syncCommitteeService,
342
368
  config,
343
369
  api,
@@ -366,7 +392,8 @@ export class Validator {
366
392
  urls: urls.map(toPrintableUrl).toString(),
367
393
  requestWireFormat: globalInit?.requestWireFormat ?? defaultInit.requestWireFormat,
368
394
  responseWireFormat: globalInit?.responseWireFormat ?? defaultInit.responseWireFormat,
369
- requestTimeoutMs: globalInit?.timeoutMs ?? config.SLOT_DURATION_MS,
395
+ requestTimeoutMs:
396
+ globalInit?.timeoutMs ?? Math.min(...getSlotDurations(config).map(([, slotDurationMs]) => slotDurationMs)),
370
397
  });
371
398
  } else {
372
399
  api = clientOrUrls;
@@ -423,6 +450,7 @@ export class Validator {
423
450
  this.blockProposingService.removeDutiesForKey(pubkey);
424
451
  this.attestationService.removeDutiesForKey(pubkey);
425
452
  this.ptcService.removeDutiesForKey(pubkey);
453
+ this.inclusionListService.removeDutiesForKey(pubkey);
426
454
  this.syncCommitteeService.removeDutiesForKey(pubkey);
427
455
  }
428
456