@lodestar/validator 1.45.0 → 1.46.0-dev.20101a8cc1
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/genesis.d.ts.map +1 -1
- package/lib/genesis.js +7 -3
- package/lib/genesis.js.map +1 -1
- package/lib/metrics.d.ts +3 -0
- package/lib/metrics.d.ts.map +1 -1
- package/lib/metrics.js +5 -0
- package/lib/metrics.js.map +1 -1
- package/lib/services/attestation.d.ts +2 -1
- package/lib/services/attestation.d.ts.map +1 -1
- package/lib/services/attestation.js.map +1 -1
- package/lib/services/attestationDuties.d.ts +2 -1
- package/lib/services/attestationDuties.d.ts.map +1 -1
- package/lib/services/attestationDuties.js +1 -1
- package/lib/services/attestationDuties.js.map +1 -1
- package/lib/services/block.d.ts +3 -1
- package/lib/services/block.d.ts.map +1 -1
- package/lib/services/block.js +86 -40
- package/lib/services/block.js.map +1 -1
- package/lib/services/blockDuties.d.ts +2 -1
- package/lib/services/blockDuties.d.ts.map +1 -1
- package/lib/services/blockDuties.js.map +1 -1
- package/lib/services/doppelgangerService.d.ts +1 -1
- package/lib/services/doppelgangerService.d.ts.map +1 -1
- package/lib/services/doppelgangerService.js.map +1 -1
- package/lib/services/prepareBeaconProposer.d.ts +2 -1
- package/lib/services/prepareBeaconProposer.d.ts.map +1 -1
- package/lib/services/prepareBeaconProposer.js.map +1 -1
- package/lib/services/proposerPreferences.d.ts +2 -1
- package/lib/services/proposerPreferences.d.ts.map +1 -1
- package/lib/services/proposerPreferences.js.map +1 -1
- package/lib/services/ptc.d.ts +2 -1
- package/lib/services/ptc.d.ts.map +1 -1
- package/lib/services/ptc.js.map +1 -1
- package/lib/services/ptcDuties.d.ts +2 -1
- package/lib/services/ptcDuties.d.ts.map +1 -1
- package/lib/services/ptcDuties.js.map +1 -1
- package/lib/services/syncCommittee.d.ts +2 -1
- package/lib/services/syncCommittee.d.ts.map +1 -1
- package/lib/services/syncCommittee.js.map +1 -1
- package/lib/services/syncCommitteeDuties.d.ts +2 -1
- package/lib/services/syncCommitteeDuties.d.ts.map +1 -1
- package/lib/services/syncCommitteeDuties.js.map +1 -1
- package/lib/services/syncingStatusTracker.d.ts +1 -1
- package/lib/services/syncingStatusTracker.d.ts.map +1 -1
- package/lib/services/syncingStatusTracker.js.map +1 -1
- package/lib/services/validatorStore.d.ts +1 -1
- package/lib/services/validatorStore.d.ts.map +1 -1
- package/lib/services/validatorStore.js +12 -6
- package/lib/services/validatorStore.js.map +1 -1
- package/lib/util/index.d.ts +0 -2
- package/lib/util/index.d.ts.map +1 -1
- package/lib/util/index.js +0 -2
- package/lib/util/index.js.map +1 -1
- package/lib/util/logger.d.ts +1 -1
- package/lib/util/logger.d.ts.map +1 -1
- package/lib/util/logger.js.map +1 -1
- package/lib/validator.d.ts +2 -1
- package/lib/validator.d.ts.map +1 -1
- package/lib/validator.js +7 -5
- package/lib/validator.js.map +1 -1
- package/package.json +15 -15
- package/src/genesis.ts +6 -4
- package/src/metrics.ts +6 -0
- package/src/services/attestation.ts +2 -2
- package/src/services/attestationDuties.ts +7 -2
- package/src/services/block.ts +113 -52
- package/src/services/blockDuties.ts +2 -2
- package/src/services/doppelgangerService.ts +1 -2
- package/src/services/prepareBeaconProposer.ts +2 -1
- package/src/services/proposerPreferences.ts +2 -2
- package/src/services/ptc.ts +2 -1
- package/src/services/ptcDuties.ts +2 -2
- package/src/services/syncCommittee.ts +2 -1
- package/src/services/syncCommitteeDuties.ts +2 -1
- package/src/services/syncingStatusTracker.ts +1 -1
- package/src/services/validatorStore.ts +22 -7
- package/src/util/index.ts +0 -2
- package/src/util/logger.ts +1 -1
- package/src/validator.ts +14 -5
- package/lib/util/clock.d.ts +0 -55
- package/lib/util/clock.d.ts.map +0 -1
- package/lib/util/clock.js +0 -141
- package/lib/util/clock.js.map +0 -1
- package/lib/util/params.d.ts +0 -20
- package/lib/util/params.d.ts.map +0 -1
- package/lib/util/params.js +0 -295
- package/lib/util/params.js.map +0 -1
- package/src/util/clock.ts +0 -182
- package/src/util/params.ts +0 -341
package/src/services/block.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {ApiClient, routes} from "@lodestar/api";
|
|
2
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
3
|
-
import {BUILDER_INDEX_SELF_BUILD, isForkPostGloas} from "@lodestar/params";
|
|
3
|
+
import {BUILDER_INDEX_SELF_BUILD, ForkPostGloas, isForkPostGloas} from "@lodestar/params";
|
|
4
|
+
import {IClock} from "@lodestar/state-transition";
|
|
4
5
|
import {
|
|
5
6
|
BLSPubkey,
|
|
6
7
|
BLSSignature,
|
|
@@ -16,7 +17,7 @@ import {
|
|
|
16
17
|
import {extendError, prettyBytes, prettyWeiToEth, toPubkeyHex, toRootHex} from "@lodestar/utils";
|
|
17
18
|
import {Metrics} from "../metrics.js";
|
|
18
19
|
import {PubkeyHex} from "../types.js";
|
|
19
|
-
import {
|
|
20
|
+
import {LoggerVc} from "../util/index.js";
|
|
20
21
|
import {BlockDutiesService, GENESIS_SLOT} from "./blockDuties.js";
|
|
21
22
|
import {ValidatorStore} from "./validatorStore.js";
|
|
22
23
|
|
|
@@ -39,6 +40,7 @@ type DebugLogCtx = {debugLogCtx: Record<string, string | boolean | undefined>};
|
|
|
39
40
|
type BlockProposalOpts = {
|
|
40
41
|
broadcastValidation: routes.beacon.BroadcastValidation;
|
|
41
42
|
blindedLocal: boolean;
|
|
43
|
+
payloadLocal: boolean;
|
|
42
44
|
};
|
|
43
45
|
/**
|
|
44
46
|
* Service that sets up and handles validator block proposal duties.
|
|
@@ -166,11 +168,19 @@ export class BlockProposingService {
|
|
|
166
168
|
}
|
|
167
169
|
|
|
168
170
|
/**
|
|
169
|
-
* Gloas
|
|
170
|
-
* 1. Produce beacon block
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
171
|
+
* Gloas block production flow:
|
|
172
|
+
* 1. Produce the beacon block, which commits to an execution payload bid. When self-building with
|
|
173
|
+
* the stateless flow (`payloadLocal=false`), the response also includes the full block contents
|
|
174
|
+
* (execution payload envelope, KZG proofs and blobs).
|
|
175
|
+
* 2. Sign and publish the beacon block.
|
|
176
|
+
* 3. Reveal the execution payload envelope:
|
|
177
|
+
* - Self-build: the proposer signs and publishes the envelope
|
|
178
|
+
* - Stateless (`payloadLocal=false`): envelope and blobs are already available from step 1,
|
|
179
|
+
* publish `SignedExecutionPayloadEnvelopeContents` which can be sent via any beacon node
|
|
180
|
+
* - Stateful (`payloadLocal=true`): fetch the envelope from the beacon node that produced the
|
|
181
|
+
* block, then publish the bare `SignedExecutionPayloadEnvelope` back to it; that node
|
|
182
|
+
* attaches the cached blobs and KZG proofs
|
|
183
|
+
* - Builder bid: the builder reveals the envelope, so the proposer does nothing further
|
|
174
184
|
*/
|
|
175
185
|
private async createAndPublishBlockGloas(pubkey: BLSPubkey, slot: Slot): Promise<void> {
|
|
176
186
|
const pubkeyHex = toPubkeyHex(pubkey);
|
|
@@ -180,8 +190,11 @@ export class BlockProposingService {
|
|
|
180
190
|
const randaoReveal = await this.validatorStore.signRandao(pubkey, slot);
|
|
181
191
|
const graffiti = this.validatorStore.getGraffiti(pubkeyHex);
|
|
182
192
|
const feeRecipient = this.validatorStore.getFeeRecipient(pubkeyHex);
|
|
193
|
+
const {broadcastValidation, payloadLocal} = this.opts;
|
|
194
|
+
const {selection: builderSelection, boostFactor: builderBoostFactor} =
|
|
195
|
+
this.validatorStore.getBuilderSelectionParams(pubkeyHex, slot);
|
|
183
196
|
|
|
184
|
-
this.logger.debug("Producing block", {...debugLogCtx, feeRecipient});
|
|
197
|
+
this.logger.debug("Producing block", {...debugLogCtx, feeRecipient, payloadLocal, builderSelection});
|
|
185
198
|
this.metrics?.proposerStepCallProduceBlock.observe(this.clock.secFromSlot(slot));
|
|
186
199
|
|
|
187
200
|
// Step 1: Produce beacon block with execution payload bid
|
|
@@ -191,19 +204,29 @@ export class BlockProposingService {
|
|
|
191
204
|
randaoReveal,
|
|
192
205
|
graffiti,
|
|
193
206
|
feeRecipient,
|
|
207
|
+
includePayload: !payloadLocal,
|
|
208
|
+
builderSelection,
|
|
209
|
+
builderBoostFactor,
|
|
194
210
|
})
|
|
195
211
|
.catch((e: Error) => {
|
|
196
212
|
this.metrics?.blockProposingErrors.inc({error: "produce"});
|
|
197
213
|
throw extendError(e, "Failed to produce block");
|
|
198
214
|
});
|
|
199
|
-
const
|
|
215
|
+
const blockOrContents = blockRes.value();
|
|
200
216
|
const blockMeta = blockRes.meta();
|
|
217
|
+
const {executionPayloadIncluded} = blockMeta;
|
|
218
|
+
const block = executionPayloadIncluded
|
|
219
|
+
? (blockOrContents as BlockContents<ForkPostGloas>).block
|
|
220
|
+
: (blockOrContents as BeaconBlock<ForkPostGloas>);
|
|
201
221
|
const beaconBlockRoot = this.config.getForkTypes(slot).BeaconBlock.hashTreeRoot(block);
|
|
202
222
|
const blockRootHex = toRootHex(beaconBlockRoot);
|
|
203
223
|
|
|
204
224
|
this.logger.debug("Produced block", {
|
|
205
225
|
...debugLogCtx,
|
|
226
|
+
executionPayloadValue: prettyWeiToEth(blockMeta.executionPayloadValue),
|
|
206
227
|
consensusBlockValue: prettyWeiToEth(blockMeta.consensusBlockValue),
|
|
228
|
+
totalBlockValue: prettyWeiToEth(blockMeta.executionPayloadValue + blockMeta.consensusBlockValue),
|
|
229
|
+
executionPayloadIncluded,
|
|
207
230
|
blockRoot: blockRootHex,
|
|
208
231
|
});
|
|
209
232
|
this.metrics?.blocksProduced.inc();
|
|
@@ -211,8 +234,6 @@ export class BlockProposingService {
|
|
|
211
234
|
// Step 2: Sign and publish the beacon block
|
|
212
235
|
const signedBlock = await this.validatorStore.signBlock(pubkey, block, slot, this.logger);
|
|
213
236
|
|
|
214
|
-
const {broadcastValidation} = this.opts;
|
|
215
|
-
|
|
216
237
|
// Publish the block first so it propagates as soon as possible. This reduces the chance other nodes
|
|
217
238
|
// see the payload envelope before the block over gossip and have to queue it. There's also plenty of
|
|
218
239
|
// time left in the slot to propagate the payload, so publishing it in parallel is unnecessary.
|
|
@@ -224,63 +245,105 @@ export class BlockProposingService {
|
|
|
224
245
|
})
|
|
225
246
|
.catch((e: Error) => {
|
|
226
247
|
this.metrics?.blockProposingErrors.inc({error: "publish"});
|
|
227
|
-
throw extendError(e,
|
|
248
|
+
throw extendError(e, `Failed to publish block slot=${slot} blockRoot=${blockRootHex}`);
|
|
228
249
|
})
|
|
229
250
|
).assertOk();
|
|
230
251
|
|
|
231
|
-
this.logger.
|
|
252
|
+
this.logger.info("Published beacon block", {
|
|
253
|
+
...logCtx,
|
|
254
|
+
graffiti,
|
|
255
|
+
executionPayloadValue: prettyWeiToEth(blockMeta.executionPayloadValue),
|
|
256
|
+
consensusBlockValue: prettyWeiToEth(blockMeta.consensusBlockValue),
|
|
257
|
+
totalBlockValue: prettyWeiToEth(blockMeta.executionPayloadValue + blockMeta.consensusBlockValue),
|
|
258
|
+
blockRoot: blockRootHex,
|
|
259
|
+
broadcastValidation,
|
|
260
|
+
});
|
|
261
|
+
this.metrics?.proposerStepCallPublishBlock.observe(this.clock.secFromSlot(slot));
|
|
262
|
+
this.metrics?.blocksPublished.inc();
|
|
232
263
|
|
|
233
264
|
const isSelfBuild = block.body.signedExecutionPayloadBid.message.builderIndex === BUILDER_INDEX_SELF_BUILD;
|
|
234
265
|
|
|
235
266
|
if (isSelfBuild) {
|
|
236
267
|
// Self-build: proposer is responsible for building and publishing the execution payload envelope
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
268
|
+
const flow = executionPayloadIncluded ? "stateless" : "stateful";
|
|
269
|
+
if (executionPayloadIncluded) {
|
|
270
|
+
// Stateless flow: envelope and blobs are already available from block production
|
|
271
|
+
const {executionPayloadEnvelope, kzgProofs, blobs} = blockOrContents as BlockContents<ForkPostGloas>;
|
|
272
|
+
|
|
273
|
+
// Step 3: Sign and publish the envelope with blobs and KZG proofs
|
|
274
|
+
const signedEnvelope = await this.validatorStore.signExecutionPayloadEnvelope(
|
|
275
|
+
pubkey,
|
|
276
|
+
executionPayloadEnvelope,
|
|
277
|
+
slot,
|
|
278
|
+
this.logger
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
(
|
|
282
|
+
await this.api.beacon
|
|
283
|
+
.publishExecutionPayloadEnvelope({
|
|
284
|
+
signedEnvelopeOrContents: {signedExecutionPayloadEnvelope: signedEnvelope, kzgProofs, blobs},
|
|
285
|
+
broadcastValidation,
|
|
286
|
+
})
|
|
287
|
+
.catch((e: Error) => {
|
|
288
|
+
this.metrics?.payloadEnvelopeProposingErrors.inc({error: "publish"});
|
|
289
|
+
throw extendError(
|
|
290
|
+
e,
|
|
291
|
+
`Failed to publish execution payload envelope slot=${slot} blockRoot=${blockRootHex} flow=${flow}`
|
|
292
|
+
);
|
|
293
|
+
})
|
|
294
|
+
).assertOk();
|
|
295
|
+
} else {
|
|
296
|
+
// Stateful flow: fetch the envelope from the same beacon node that produced the block
|
|
297
|
+
const envelopeRes = await this.api.validator
|
|
298
|
+
.getExecutionPayloadEnvelope({
|
|
299
|
+
slot,
|
|
300
|
+
beaconBlockRoot,
|
|
258
301
|
})
|
|
259
302
|
.catch((e: Error) => {
|
|
260
|
-
this.metrics?.
|
|
261
|
-
throw extendError(e,
|
|
262
|
-
})
|
|
263
|
-
|
|
303
|
+
this.metrics?.payloadEnvelopeProposingErrors.inc({error: "produce"});
|
|
304
|
+
throw extendError(e, `Failed to get execution payload envelope slot=${slot} blockRoot=${blockRootHex}`);
|
|
305
|
+
});
|
|
306
|
+
const envelope = envelopeRes.value();
|
|
307
|
+
|
|
308
|
+
this.logger.debug("Retrieved execution payload envelope", debugLogCtx);
|
|
309
|
+
|
|
310
|
+
// Step 3: Sign and publish the envelope, beacon node attaches blobs and KZG proofs from its cache
|
|
311
|
+
const signedEnvelope = await this.validatorStore.signExecutionPayloadEnvelope(
|
|
312
|
+
pubkey,
|
|
313
|
+
envelope,
|
|
314
|
+
slot,
|
|
315
|
+
this.logger
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
(
|
|
319
|
+
await this.api.beacon
|
|
320
|
+
.publishExecutionPayloadEnvelope({
|
|
321
|
+
signedEnvelopeOrContents: signedEnvelope,
|
|
322
|
+
broadcastValidation,
|
|
323
|
+
})
|
|
324
|
+
.catch((e: Error) => {
|
|
325
|
+
this.metrics?.payloadEnvelopeProposingErrors.inc({error: "publish"});
|
|
326
|
+
throw extendError(
|
|
327
|
+
e,
|
|
328
|
+
`Failed to publish execution payload envelope slot=${slot} blockRoot=${blockRootHex} flow=${flow}`
|
|
329
|
+
);
|
|
330
|
+
})
|
|
331
|
+
).assertOk();
|
|
332
|
+
}
|
|
264
333
|
|
|
265
|
-
this.logger.info("Published
|
|
334
|
+
this.logger.info("Published execution payload envelope", {
|
|
266
335
|
...logCtx,
|
|
267
|
-
graffiti,
|
|
268
|
-
consensusBlockValue: prettyWeiToEth(blockMeta.consensusBlockValue),
|
|
269
336
|
blockRoot: blockRootHex,
|
|
337
|
+
flow,
|
|
270
338
|
});
|
|
271
339
|
} else {
|
|
272
|
-
//
|
|
273
|
-
this.logger.info("
|
|
340
|
+
// Committed to a builder bid, the builder is responsible for revealing the execution payload envelope
|
|
341
|
+
this.logger.info("Execution payload envelope to be revealed by builder", {
|
|
274
342
|
...logCtx,
|
|
275
|
-
graffiti,
|
|
276
343
|
builderIndex: block.body.signedExecutionPayloadBid.message.builderIndex,
|
|
277
|
-
consensusBlockValue: prettyWeiToEth(blockMeta.consensusBlockValue),
|
|
278
344
|
blockRoot: blockRootHex,
|
|
279
345
|
});
|
|
280
346
|
}
|
|
281
|
-
|
|
282
|
-
this.metrics?.proposerStepCallPublishBlock.observe(this.clock.secFromSlot(slot));
|
|
283
|
-
this.metrics?.blocksPublished.inc();
|
|
284
347
|
}
|
|
285
348
|
|
|
286
349
|
private publishBlockWrapper = async (
|
|
@@ -353,10 +416,8 @@ function parseProduceBlockResponse(
|
|
|
353
416
|
const executionPayloadSource = response.executionPayloadSource;
|
|
354
417
|
|
|
355
418
|
if (
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
(builderSelection === routes.validator.BuilderSelection.ExecutionOnly &&
|
|
359
|
-
executionPayloadSource === ProducedBlockSource.builder)
|
|
419
|
+
builderSelection === routes.validator.BuilderSelection.ExecutionOnly &&
|
|
420
|
+
executionPayloadSource === ProducedBlockSource.builder
|
|
360
421
|
) {
|
|
361
422
|
throw Error(
|
|
362
423
|
`Block not produced as per desired builderSelection=${builderSelection} executionPayloadSource=${executionPayloadSource}`
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {ApiClient, routes} from "@lodestar/api";
|
|
2
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
3
3
|
import {isForkPostGloas} from "@lodestar/params";
|
|
4
|
-
import {computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition";
|
|
4
|
+
import {IClock, computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition";
|
|
5
5
|
import {BLSPubkey, Epoch, RootHex, Slot} from "@lodestar/types";
|
|
6
6
|
import {sleep, toPubkeyHex} from "@lodestar/utils";
|
|
7
7
|
import {Metrics} from "../metrics.js";
|
|
8
8
|
import {PubkeyHex} from "../types.js";
|
|
9
|
-
import {
|
|
9
|
+
import {LoggerVc} from "../util/index.js";
|
|
10
10
|
import {ChainHeaderTracker, HeadEventData} from "./chainHeaderTracker.js";
|
|
11
11
|
import {ValidatorStore} from "./validatorStore.js";
|
|
12
12
|
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import {ApiClient, routes} from "@lodestar/api";
|
|
2
|
-
import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
|
|
2
|
+
import {IClock, computeStartSlotAtEpoch} from "@lodestar/state-transition";
|
|
3
3
|
import {Epoch, ValidatorIndex} from "@lodestar/types";
|
|
4
4
|
import {Logger, fromHex, sleep, truncBytes} from "@lodestar/utils";
|
|
5
5
|
import {Metrics} from "../metrics.js";
|
|
6
6
|
import {ISlashingProtection} from "../slashingProtection/index.js";
|
|
7
7
|
import {ProcessShutdownCallback, PubkeyHex} from "../types.js";
|
|
8
|
-
import {IClock} from "../util/index.js";
|
|
9
8
|
import {IndicesService} from "./indices.js";
|
|
10
9
|
|
|
11
10
|
// The number of epochs that must be checked before we assume that there are
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import {ApiClient, routes} from "@lodestar/api";
|
|
2
2
|
import {BeaconConfig} from "@lodestar/config";
|
|
3
3
|
import {GENESIS_EPOCH, SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
4
|
+
import {IClock} from "@lodestar/state-transition";
|
|
4
5
|
import {Epoch, bellatrix} from "@lodestar/types";
|
|
5
6
|
import {Metrics} from "../metrics.js";
|
|
6
|
-
import {
|
|
7
|
+
import {LoggerVc, batchItems} from "../util/index.js";
|
|
7
8
|
import {ValidatorStore} from "./validatorStore.js";
|
|
8
9
|
|
|
9
10
|
const REGISTRATION_CHUNK_SIZE = 512;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {ApiClient} from "@lodestar/api";
|
|
2
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
3
3
|
import {SLOTS_PER_EPOCH, isForkPostGloas} from "@lodestar/params";
|
|
4
|
-
import {computeEpochAtSlot} from "@lodestar/state-transition";
|
|
4
|
+
import {IClock, computeEpochAtSlot} from "@lodestar/state-transition";
|
|
5
5
|
import {Epoch, RootHex, Slot, gloas} from "@lodestar/types";
|
|
6
6
|
import {fromHex, toPubkeyHex} from "@lodestar/utils";
|
|
7
7
|
import {Metrics} from "../metrics.js";
|
|
8
|
-
import {
|
|
8
|
+
import {LoggerVc} from "../util/index.js";
|
|
9
9
|
import {BlockDutiesService} from "./blockDuties.js";
|
|
10
10
|
import {ValidatorStore} from "./validatorStore.js";
|
|
11
11
|
|
package/src/services/ptc.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {ApiClient, routes} from "@lodestar/api";
|
|
2
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
3
3
|
import {isForkPostGloas} from "@lodestar/params";
|
|
4
|
+
import {IClock} from "@lodestar/state-transition";
|
|
4
5
|
import {Slot, gloas} from "@lodestar/types";
|
|
5
6
|
import {prettyBytes, sleep, toRootHex} from "@lodestar/utils";
|
|
6
7
|
import {Metrics} from "../metrics.js";
|
|
7
8
|
import {PubkeyHex} from "../types.js";
|
|
8
|
-
import {
|
|
9
|
+
import {LoggerVc} from "../util/index.js";
|
|
9
10
|
import {ChainHeaderTracker} from "./chainHeaderTracker.js";
|
|
10
11
|
import {ExecutionPayloadAvailableEventData, ValidatorEvent, ValidatorEventEmitter} from "./emitter.js";
|
|
11
12
|
import {PtcDutiesService} from "./ptcDuties.js";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {ApiClient, routes} from "@lodestar/api";
|
|
2
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
3
3
|
import {SLOTS_PER_EPOCH, isForkPostGloas} from "@lodestar/params";
|
|
4
|
-
import {computeEpochAtSlot, isStartSlotOfEpoch} from "@lodestar/state-transition";
|
|
4
|
+
import {IClock, computeEpochAtSlot, isStartSlotOfEpoch} from "@lodestar/state-transition";
|
|
5
5
|
import {Epoch, RootHex, Slot, ValidatorIndex} from "@lodestar/types";
|
|
6
6
|
import {toPubkeyHex} from "@lodestar/utils";
|
|
7
7
|
import {Metrics} from "../metrics.js";
|
|
8
8
|
import {PubkeyHex} from "../types.js";
|
|
9
|
-
import {
|
|
9
|
+
import {LoggerVc} from "../util/index.js";
|
|
10
10
|
import {ChainHeaderTracker, HeadEventData} from "./chainHeaderTracker.js";
|
|
11
11
|
import {SyncingStatusTracker} from "./syncingStatusTracker.js";
|
|
12
12
|
import {ValidatorStore} from "./validatorStore.js";
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {ApiClient} from "@lodestar/api";
|
|
2
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
3
3
|
import {ForkName, isForkPostAltair} from "@lodestar/params";
|
|
4
|
+
import {IClock} from "@lodestar/state-transition";
|
|
4
5
|
import {CommitteeIndex, Root, Slot, altair} from "@lodestar/types";
|
|
5
6
|
import {sleep} from "@lodestar/utils";
|
|
6
7
|
import {Metrics} from "../metrics.js";
|
|
7
8
|
import {PubkeyHex} from "../types.js";
|
|
8
|
-
import {
|
|
9
|
+
import {LoggerVc} from "../util/index.js";
|
|
9
10
|
import {ChainHeaderTracker} from "./chainHeaderTracker.js";
|
|
10
11
|
import {ValidatorEventEmitter} from "./emitter.js";
|
|
11
12
|
import {SyncCommitteeDutiesService, SyncDutyAndProofs} from "./syncCommitteeDuties.js";
|
|
@@ -2,6 +2,7 @@ import {ApiClient, routes} from "@lodestar/api";
|
|
|
2
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
3
3
|
import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SYNC_COMMITTEE_SUBNET_SIZE} from "@lodestar/params";
|
|
4
4
|
import {
|
|
5
|
+
IClock,
|
|
5
6
|
computeEpochAtSlot,
|
|
6
7
|
computeSyncPeriodAtEpoch,
|
|
7
8
|
computeSyncPeriodAtSlot,
|
|
@@ -12,7 +13,7 @@ import {BLSSignature, Epoch, Slot, SyncPeriod, ValidatorIndex} from "@lodestar/t
|
|
|
12
13
|
import {toPubkeyHex} from "@lodestar/utils";
|
|
13
14
|
import {Metrics} from "../metrics.js";
|
|
14
15
|
import {PubkeyHex} from "../types.js";
|
|
15
|
-
import {
|
|
16
|
+
import {LoggerVc} from "../util/index.js";
|
|
16
17
|
import {SyncingStatusTracker} from "./syncingStatusTracker.js";
|
|
17
18
|
import {syncCommitteeIndicesToSubnets} from "./utils.js";
|
|
18
19
|
import {ValidatorStore} from "./validatorStore.js";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {ApiClient, routes} from "@lodestar/api";
|
|
2
|
+
import {IClock} from "@lodestar/state-transition";
|
|
2
3
|
import {Slot} from "@lodestar/types";
|
|
3
4
|
import {Logger} from "@lodestar/utils";
|
|
4
5
|
import {BeaconHealth, Metrics} from "../metrics.js";
|
|
5
|
-
import {IClock} from "../util/clock.js";
|
|
6
6
|
|
|
7
7
|
export type SyncingStatus = routes.node.SyncingStatus;
|
|
8
8
|
|
|
@@ -81,7 +81,8 @@ type DefaultProposerConfig = {
|
|
|
81
81
|
feeRecipient: ExecutionAddress;
|
|
82
82
|
builder: {
|
|
83
83
|
gasLimit: number;
|
|
84
|
-
|
|
84
|
+
// Left undefined when not configured so the fork-appropriate default can be resolved per slot
|
|
85
|
+
selection?: routes.validator.BuilderSelection;
|
|
85
86
|
boostFactor: bigint;
|
|
86
87
|
};
|
|
87
88
|
};
|
|
@@ -182,7 +183,7 @@ export class ValidatorStore {
|
|
|
182
183
|
feeRecipient: defaultConfig.feeRecipient ?? defaultOptions.suggestedFeeRecipient,
|
|
183
184
|
builder: {
|
|
184
185
|
gasLimit: defaultConfig.builder?.gasLimit ?? defaultOptions.defaultGasLimit,
|
|
185
|
-
selection: defaultConfig.builder?.selection
|
|
186
|
+
selection: defaultConfig.builder?.selection,
|
|
186
187
|
boostFactor: builderBoostFactor,
|
|
187
188
|
},
|
|
188
189
|
};
|
|
@@ -278,9 +279,21 @@ export class ValidatorStore {
|
|
|
278
279
|
delete validatorData.graffiti;
|
|
279
280
|
}
|
|
280
281
|
|
|
281
|
-
getBuilderSelectionParams(
|
|
282
|
+
getBuilderSelectionParams(
|
|
283
|
+
pubkeyHex: PubkeyHex,
|
|
284
|
+
slot?: Slot
|
|
285
|
+
): {selection: routes.validator.BuilderSelection; boostFactor: bigint} {
|
|
286
|
+
// Builder bids post-gloas are in-protocol over p2p, so the default strategy uses them
|
|
287
|
+
// (as if `--builder` was set), unless the validator explicitly opted out. Pre-gloas
|
|
288
|
+
// there is no in-protocol builder, so the default remains local-only (executiononly).
|
|
289
|
+
const defaultSelection =
|
|
290
|
+
slot !== undefined && this.config.getForkSeq(slot) >= ForkSeq.gloas
|
|
291
|
+
? defaultOptions.builderAliasSelection
|
|
292
|
+
: defaultOptions.builderSelection;
|
|
282
293
|
const selection =
|
|
283
|
-
this.validators.get(pubkeyHex)?.builder?.selection ??
|
|
294
|
+
this.validators.get(pubkeyHex)?.builder?.selection ??
|
|
295
|
+
this.defaultProposerConfig.builder.selection ??
|
|
296
|
+
defaultSelection;
|
|
284
297
|
|
|
285
298
|
let boostFactor: bigint;
|
|
286
299
|
switch (selection) {
|
|
@@ -607,9 +620,11 @@ export class ValidatorStore {
|
|
|
607
620
|
const signingSlot = aggregate.data.slot;
|
|
608
621
|
const domain = this.config.getDomain(signingSlot, DOMAIN_AGGREGATE_AND_PROOF);
|
|
609
622
|
const isPostElectra = this.config.getForkSeq(signingSlot) >= ForkSeq.electra;
|
|
610
|
-
const signingRoot =
|
|
611
|
-
|
|
612
|
-
|
|
623
|
+
const signingRoot = computeSigningRoot(
|
|
624
|
+
this.config.getForkTypes(signingSlot).AggregateAndProof,
|
|
625
|
+
aggregateAndProof,
|
|
626
|
+
domain
|
|
627
|
+
);
|
|
613
628
|
|
|
614
629
|
const signableMessage: SignableMessage = {
|
|
615
630
|
type: isPostElectra ? SignableMessageType.AGGREGATE_AND_PROOF_V2 : SignableMessageType.AGGREGATE_AND_PROOF,
|
package/src/util/index.ts
CHANGED
package/src/util/logger.ts
CHANGED
package/src/validator.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import {ApiClient, ApiRequestInit, defaultInit, getClient, routes} from "@lodestar/api";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
BeaconConfig,
|
|
4
|
+
ChainForkConfig,
|
|
5
|
+
NotEqualParamsError,
|
|
6
|
+
assertEqualParams,
|
|
7
|
+
createBeaconConfig,
|
|
8
|
+
} from "@lodestar/config";
|
|
9
|
+
import {Clock, ClockOptions, IClock, computeEpochAtSlot, getCurrentSlot} from "@lodestar/state-transition";
|
|
4
10
|
import {BLSPubkey, phase0, ssz} from "@lodestar/types";
|
|
5
11
|
import {Genesis} from "@lodestar/types/phase0";
|
|
6
12
|
import {Logger, toPrintableUrl, toRootHex} from "@lodestar/utils";
|
|
@@ -23,8 +29,7 @@ import {SyncingStatusTracker} from "./services/syncingStatusTracker.js";
|
|
|
23
29
|
import {Signer, ValidatorProposerConfig, ValidatorStore, defaultOptions} from "./services/validatorStore.js";
|
|
24
30
|
import {ISlashingProtection, Interchange, InterchangeFormatVersion} from "./slashingProtection/index.js";
|
|
25
31
|
import {LodestarValidatorDatabaseController, ProcessShutdownCallback, PubkeyHex} from "./types.js";
|
|
26
|
-
import {
|
|
27
|
-
import {NotEqualParamsError, assertEqualParams, getLoggerVc} from "./util/index.js";
|
|
32
|
+
import {getLoggerVc} from "./util/index.js";
|
|
28
33
|
|
|
29
34
|
export type ValidatorModules = {
|
|
30
35
|
opts: ValidatorOptions;
|
|
@@ -66,6 +71,7 @@ export type ValidatorOptions = {
|
|
|
66
71
|
distributed?: boolean;
|
|
67
72
|
broadcastValidation?: routes.beacon.BroadcastValidation;
|
|
68
73
|
blindedLocal?: boolean;
|
|
74
|
+
payloadLocal?: boolean;
|
|
69
75
|
externalSigner?: ExternalSignerOptions;
|
|
70
76
|
clock?: ClockOptions;
|
|
71
77
|
};
|
|
@@ -256,6 +262,9 @@ export class Validator {
|
|
|
256
262
|
{
|
|
257
263
|
broadcastValidation: opts.broadcastValidation ?? defaultOptions.broadcastValidation,
|
|
258
264
|
blindedLocal: opts.blindedLocal ?? defaultOptions.blindedLocal,
|
|
265
|
+
// Default to keeping the payload local to the beacon node if only a single node is
|
|
266
|
+
// configured, with multiple nodes the stateless flow allows publishing via any of them
|
|
267
|
+
payloadLocal: opts.payloadLocal ?? api.httpClient.urlsInits.length <= 1,
|
|
259
268
|
}
|
|
260
269
|
);
|
|
261
270
|
|
|
@@ -352,7 +361,7 @@ export class Validator {
|
|
|
352
361
|
|
|
353
362
|
const res = await api.config.getSpec();
|
|
354
363
|
assertEqualParams(config, res.value());
|
|
355
|
-
logger.info("Verified connected beacon node and validator have same
|
|
364
|
+
logger.info("Verified connected beacon node and validator have the same config");
|
|
356
365
|
|
|
357
366
|
await assertEqualGenesis(opts, genesis);
|
|
358
367
|
logger.info("Verified connected beacon node and validator have the same genesisValidatorRoot");
|
package/lib/util/clock.d.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { ChainForkConfig } from "@lodestar/config";
|
|
2
|
-
import { Epoch, Slot, TimeSeconds } from "@lodestar/types";
|
|
3
|
-
import { Logger } from "@lodestar/utils";
|
|
4
|
-
type RunEveryFn = (slot: Slot, signal: AbortSignal) => Promise<void>;
|
|
5
|
-
export type ClockOptions = {
|
|
6
|
-
skipSlots?: boolean;
|
|
7
|
-
};
|
|
8
|
-
export interface IClock {
|
|
9
|
-
readonly genesisTime: number;
|
|
10
|
-
readonly secondsPerSlot: number;
|
|
11
|
-
readonly currentEpoch: number;
|
|
12
|
-
start(signal: AbortSignal): void;
|
|
13
|
-
runEverySlot(fn: (slot: Slot, signal: AbortSignal) => Promise<void>): void;
|
|
14
|
-
runEveryEpoch(fn: (epoch: Epoch, signal: AbortSignal) => Promise<void>): void;
|
|
15
|
-
msToSlot(slot: Slot): number;
|
|
16
|
-
msFromSlot(slot: Slot): number;
|
|
17
|
-
secFromSlot(slot: Slot): number;
|
|
18
|
-
getCurrentSlot(): Slot;
|
|
19
|
-
getCurrentEpoch(): Epoch;
|
|
20
|
-
}
|
|
21
|
-
export declare enum TimeItem {
|
|
22
|
-
Slot = 0,
|
|
23
|
-
Epoch = 1
|
|
24
|
-
}
|
|
25
|
-
export declare class Clock implements IClock {
|
|
26
|
-
private readonly opts;
|
|
27
|
-
readonly genesisTime: number;
|
|
28
|
-
readonly secondsPerSlot: number;
|
|
29
|
-
private readonly config;
|
|
30
|
-
private readonly logger;
|
|
31
|
-
private readonly fns;
|
|
32
|
-
constructor(config: ChainForkConfig, logger: Logger, opts: {
|
|
33
|
-
genesisTime: number;
|
|
34
|
-
} & ClockOptions);
|
|
35
|
-
get currentEpoch(): Epoch;
|
|
36
|
-
start(signal: AbortSignal): void;
|
|
37
|
-
getCurrentSlot(): Slot;
|
|
38
|
-
getCurrentEpoch(): Epoch;
|
|
39
|
-
runEverySlot(fn: RunEveryFn): void;
|
|
40
|
-
runEveryEpoch(fn: RunEveryFn): void;
|
|
41
|
-
/** Milliseconds from now to a specific slot */
|
|
42
|
-
msToSlot(slot: Slot): number;
|
|
43
|
-
/** Milliseconds elapsed from a specific slot to now */
|
|
44
|
-
msFromSlot(slot: Slot): number;
|
|
45
|
-
/** Seconds elapsed from a specific slot to now */
|
|
46
|
-
secFromSlot(slot: Slot): number;
|
|
47
|
-
private runAtMostEvery;
|
|
48
|
-
private timeUntilNext;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Same to the spec but we use Math.round instead of Math.floor.
|
|
52
|
-
*/
|
|
53
|
-
export declare function getCurrentSlotAround(config: ChainForkConfig, genesisTime: TimeSeconds): Slot;
|
|
54
|
-
export {};
|
|
55
|
-
//# sourceMappingURL=clock.d.ts.map
|
package/lib/util/clock.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"clock.d.ts","sourceRoot":"","sources":["../../src/util/clock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAAC,KAAK,EAAE,IAAI,EAAE,WAAW,EAAC,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAe,MAAM,EAAwB,MAAM,iBAAiB,CAAC;AAE5E,KAAK,UAAU,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAErE,MAAM,MAAM,YAAY,GAAG;IACzB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAEhC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAE9B,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IACjC,YAAY,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC3E,aAAa,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9E,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAAC;IAC7B,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAAC;IAC/B,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAAC;IAChC,cAAc,IAAI,IAAI,CAAC;IACvB,eAAe,IAAI,KAAK,CAAC;CAC1B;AAED,oBAAY,QAAQ;IAClB,IAAI,IAAA;IACJ,KAAK,IAAA;CACN;AAED,qBAAa,KAAM,YAAW,MAAM;IAUhC,OAAO,CAAC,QAAQ,CAAC,IAAI;IATvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA8C;IAElE,YACE,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,MAAM,EACG,IAAI,EAAE;QAAC,WAAW,EAAE,MAAM,CAAA;KAAC,GAAG,YAAY,EAM5D;IAED,IAAI,YAAY,IAAI,KAAK,CAExB;IAED,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAQ/B;IAED,cAAc,IAAI,IAAI,CAErB;IAED,eAAe,IAAI,KAAK,CAEvB;IAED,YAAY,CAAC,EAAE,EAAE,UAAU,GAAG,IAAI,CAEjC;IAED,aAAa,CAAC,EAAE,EAAE,UAAU,GAAG,IAAI,CAElC;IAED,+CAA+C;IAC/C,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE3B;IAED,uDAAuD;IACvD,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE7B;IAED,kDAAkD;IAClD,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE9B;YAQa,cAAc;IA2C5B,OAAO,CAAC,aAAa;CAgBtB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,eAAe,EAAE,WAAW,EAAE,WAAW,GAAG,IAAI,CAI5F"}
|