@lodestar/beacon-node 1.47.0-dev.d9c16ea16f → 1.47.0-dev.da8dfeabda
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/api/impl/beacon/blocks/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/blocks/index.js +4 -7
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/pool/index.js +12 -1
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/api/impl/beacon/state/utils.d.ts +2 -1
- package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/utils.js.map +1 -1
- package/lib/api/impl/events/index.d.ts +1 -1
- package/lib/api/impl/events/index.d.ts.map +1 -1
- package/lib/api/impl/events/index.js +10 -3
- package/lib/api/impl/events/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +12 -22
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/api/impl/validator/utils.d.ts +5 -0
- package/lib/api/impl/validator/utils.d.ts.map +1 -1
- package/lib/api/impl/validator/utils.js +18 -12
- package/lib/api/impl/validator/utils.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/metrics.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/metrics.js +21 -0
- package/lib/chain/archiveStore/historicalState/metrics.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +2 -7
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts +3 -2
- package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.js +11 -9
- package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
- package/lib/chain/blocks/index.d.ts.map +1 -1
- package/lib/chain/blocks/index.js +15 -7
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +22 -12
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +2 -2
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +2 -2
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
- package/lib/chain/bls/index.d.ts +1 -1
- package/lib/chain/bls/index.d.ts.map +1 -1
- package/lib/chain/bls/interface.d.ts +5 -5
- package/lib/chain/bls/interface.d.ts.map +1 -1
- package/lib/chain/bls/multithread/index.d.ts +5 -11
- package/lib/chain/bls/multithread/index.d.ts.map +1 -1
- package/lib/chain/bls/multithread/index.js +116 -101
- package/lib/chain/bls/multithread/index.js.map +1 -1
- package/lib/chain/bls/multithread/jobItem.d.ts +5 -19
- package/lib/chain/bls/multithread/jobItem.d.ts.map +1 -1
- package/lib/chain/bls/multithread/jobItem.js +10 -65
- package/lib/chain/bls/multithread/jobItem.js.map +1 -1
- package/lib/chain/bls/multithread/types.d.ts +29 -8
- package/lib/chain/bls/multithread/types.d.ts.map +1 -1
- package/lib/chain/bls/multithread/types.js +12 -0
- package/lib/chain/bls/multithread/types.js.map +1 -1
- package/lib/chain/bls/multithread/utils.d.ts +4 -0
- package/lib/chain/bls/multithread/utils.d.ts.map +1 -1
- package/lib/chain/bls/multithread/utils.js +10 -0
- package/lib/chain/bls/multithread/utils.js.map +1 -1
- package/lib/chain/bls/multithread/worker.js +49 -23
- package/lib/chain/bls/multithread/worker.js.map +1 -1
- package/lib/chain/bls/singleThread.d.ts +4 -10
- package/lib/chain/bls/singleThread.d.ts.map +1 -1
- package/lib/chain/bls/singleThread.js +8 -45
- package/lib/chain/bls/singleThread.js.map +1 -1
- package/lib/chain/bls/utils.d.ts +4 -4
- package/lib/chain/bls/utils.d.ts.map +1 -1
- package/lib/chain/bls/utils.js +18 -19
- package/lib/chain/bls/utils.js.map +1 -1
- package/lib/chain/builderCircuitBreaker.d.ts +6 -5
- package/lib/chain/builderCircuitBreaker.d.ts.map +1 -1
- package/lib/chain/builderCircuitBreaker.js +28 -15
- package/lib/chain/builderCircuitBreaker.js.map +1 -1
- package/lib/chain/chain.d.ts +3 -2
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +8 -5
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/errors/blockError.d.ts +2 -0
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +6 -1
- package/lib/chain/errors/blockError.js.map +1 -1
- package/lib/chain/errors/proposerPreferences.d.ts +6 -0
- package/lib/chain/errors/proposerPreferences.d.ts.map +1 -1
- package/lib/chain/errors/proposerPreferences.js +1 -0
- package/lib/chain/errors/proposerPreferences.js.map +1 -1
- package/lib/chain/interface.d.ts +2 -1
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/interface.js.map +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
- package/lib/chain/opPools/attestationPool.d.ts +1 -1
- package/lib/chain/opPools/attestationPool.d.ts.map +1 -1
- package/lib/chain/opPools/attestationPool.js +1 -1
- package/lib/chain/opPools/attestationPool.js.map +1 -1
- package/lib/chain/opPools/payloadAttestationPool.js +3 -3
- package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
- package/lib/chain/opPools/syncCommitteeMessagePool.js +1 -1
- package/lib/chain/opPools/syncCommitteeMessagePool.js.map +1 -1
- package/lib/chain/opPools/syncContributionAndProofPool.js +1 -1
- package/lib/chain/opPools/syncContributionAndProofPool.js.map +1 -1
- package/lib/chain/opPools/utils.d.ts +1 -1
- package/lib/chain/opPools/utils.d.ts.map +1 -1
- package/lib/chain/opPools/utils.js +1 -1
- package/lib/chain/opPools/utils.js.map +1 -1
- package/lib/chain/options.d.ts +1 -1
- package/lib/chain/options.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +1 -1
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +2 -0
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +6 -1
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/seenCache/seenAttesters.d.ts +9 -5
- package/lib/chain/seenCache/seenAttesters.d.ts.map +1 -1
- package/lib/chain/seenCache/seenAttesters.js +25 -4
- package/lib/chain/seenCache/seenAttesters.js.map +1 -1
- package/lib/chain/seenCache/seenBlockProposers.d.ts +5 -1
- package/lib/chain/seenCache/seenBlockProposers.d.ts.map +1 -1
- package/lib/chain/seenCache/seenBlockProposers.js +10 -3
- package/lib/chain/seenCache/seenBlockProposers.js.map +1 -1
- package/lib/chain/validation/attestation.d.ts.map +1 -1
- package/lib/chain/validation/attestation.js +1 -4
- package/lib/chain/validation/attestation.js.map +1 -1
- package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
- package/lib/chain/validation/attesterSlashing.js +1 -1
- package/lib/chain/validation/attesterSlashing.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +21 -7
- package/lib/chain/validation/block.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +1 -2
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.js +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.js +5 -14
- package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
- package/lib/chain/validation/proposerPreferences.d.ts +1 -1
- package/lib/chain/validation/proposerPreferences.d.ts.map +1 -1
- package/lib/chain/validation/proposerPreferences.js +13 -4
- package/lib/chain/validation/proposerPreferences.js.map +1 -1
- package/lib/chain/validation/proposerSlashing.js +1 -1
- package/lib/chain/validation/proposerSlashing.js.map +1 -1
- package/lib/execution/builder/http.d.ts +10 -7
- package/lib/execution/builder/http.d.ts.map +1 -1
- package/lib/execution/builder/http.js +11 -8
- package/lib/execution/builder/http.js.map +1 -1
- package/lib/metrics/metrics/beacon.d.ts +3 -3
- package/lib/metrics/metrics/beacon.d.ts.map +1 -1
- package/lib/metrics/metrics/beacon.js +9 -9
- package/lib/metrics/metrics/beacon.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +48 -18
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +96 -50
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +13 -0
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/gossip/topic.js +37 -0
- package/lib/network/gossip/topic.js.map +1 -1
- package/lib/network/libp2p/index.d.ts.map +1 -1
- package/lib/network/libp2p/index.js +10 -2
- package/lib/network/libp2p/index.js.map +1 -1
- package/lib/network/network.d.ts.map +1 -1
- package/lib/network/network.js +22 -43
- package/lib/network/network.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +32 -5
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/reqresp/score.d.ts.map +1 -1
- package/lib/network/reqresp/score.js +5 -11
- package/lib/network/reqresp/score.js.map +1 -1
- package/lib/network/util.d.ts +0 -1
- package/lib/network/util.d.ts.map +1 -1
- package/lib/network/util.js +0 -4
- package/lib/network/util.js.map +1 -1
- package/lib/node/nodejs.d.ts +2 -1
- package/lib/node/nodejs.d.ts.map +1 -1
- package/lib/node/nodejs.js.map +1 -1
- package/lib/sync/range/batch.d.ts +23 -5
- package/lib/sync/range/batch.d.ts.map +1 -1
- package/lib/sync/range/batch.js +61 -22
- package/lib/sync/range/batch.js.map +1 -1
- package/lib/sync/range/chain.d.ts +2 -1
- package/lib/sync/range/chain.d.ts.map +1 -1
- package/lib/sync/range/chain.js +23 -10
- package/lib/sync/range/chain.js.map +1 -1
- package/lib/sync/types.d.ts.map +1 -1
- package/lib/sync/types.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts +9 -0
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +110 -14
- package/lib/sync/unknownBlock.js.map +1 -1
- package/package.json +18 -18
- package/src/api/impl/beacon/blocks/index.ts +5 -7
- package/src/api/impl/beacon/pool/index.ts +12 -1
- package/src/api/impl/beacon/state/utils.ts +2 -1
- package/src/api/impl/events/index.ts +10 -4
- package/src/api/impl/validator/index.ts +22 -27
- package/src/api/impl/validator/utils.ts +30 -15
- package/src/chain/archiveStore/historicalState/metrics.ts +22 -0
- package/src/chain/blocks/importBlock.ts +1 -6
- package/src/chain/blocks/importExecutionPayload.ts +12 -11
- package/src/chain/blocks/index.ts +19 -7
- package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +25 -16
- package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +1 -9
- package/src/chain/bls/index.ts +1 -1
- package/src/chain/bls/interface.ts +7 -3
- package/src/chain/bls/multithread/index.ts +148 -120
- package/src/chain/bls/multithread/jobItem.ts +12 -82
- package/src/chain/bls/multithread/types.ts +33 -8
- package/src/chain/bls/multithread/utils.ts +11 -0
- package/src/chain/bls/multithread/worker.ts +85 -27
- package/src/chain/bls/singleThread.ts +11 -55
- package/src/chain/bls/utils.ts +23 -24
- package/src/chain/builderCircuitBreaker.ts +31 -17
- package/src/chain/chain.ts +9 -5
- package/src/chain/errors/blockError.ts +9 -3
- package/src/chain/errors/proposerPreferences.ts +7 -0
- package/src/chain/interface.ts +2 -1
- package/src/chain/opPools/aggregatedAttestationPool.ts +1 -1
- package/src/chain/opPools/attestationPool.ts +1 -1
- package/src/chain/opPools/payloadAttestationPool.ts +3 -3
- package/src/chain/opPools/syncCommitteeMessagePool.ts +1 -1
- package/src/chain/opPools/syncContributionAndProofPool.ts +1 -1
- package/src/chain/opPools/utils.ts +1 -1
- package/src/chain/options.ts +1 -1
- package/src/chain/prepareNextSlot.ts +1 -1
- package/src/chain/produceBlock/produceBlockBody.ts +13 -0
- package/src/chain/seenCache/seenAttesters.ts +31 -5
- package/src/chain/seenCache/seenBlockProposers.ts +13 -3
- package/src/chain/validation/attestation.ts +1 -7
- package/src/chain/validation/attesterSlashing.ts +1 -8
- package/src/chain/validation/block.ts +21 -7
- package/src/chain/validation/executionPayloadBid.ts +1 -2
- package/src/chain/validation/executionPayloadEnvelope.ts +0 -1
- package/src/chain/validation/payloadAttestationMessage.ts +6 -17
- package/src/chain/validation/proposerPreferences.ts +15 -5
- package/src/chain/validation/proposerSlashing.ts +1 -1
- package/src/execution/builder/http.ts +11 -11
- package/src/metrics/metrics/beacon.ts +9 -9
- package/src/metrics/metrics/lodestar.ts +101 -51
- package/src/network/gossip/topic.ts +38 -0
- package/src/network/libp2p/index.ts +11 -2
- package/src/network/network.ts +27 -55
- package/src/network/processor/gossipHandlers.ts +35 -3
- package/src/network/reqresp/score.ts +5 -11
- package/src/network/util.ts +0 -5
- package/src/node/nodejs.ts +2 -1
- package/src/sync/range/batch.ts +83 -28
- package/src/sync/range/chain.ts +26 -11
- package/src/sync/types.ts +3 -1
- package/src/sync/unknownBlock.ts +126 -17
- package/lib/chain/bls/maybeBatch.d.ts +0 -12
- package/lib/chain/bls/maybeBatch.d.ts.map +0 -1
- package/lib/chain/bls/maybeBatch.js +0 -35
- package/lib/chain/bls/maybeBatch.js.map +0 -1
- package/src/chain/bls/maybeBatch.ts +0 -45
|
@@ -100,6 +100,8 @@ export type BlockAttributes = {
|
|
|
100
100
|
slot: Slot;
|
|
101
101
|
parentBlock: ProtoBlock;
|
|
102
102
|
feeRecipient?: string;
|
|
103
|
+
/** Verify that a locally produced execution payload uses `feeRecipient`. */
|
|
104
|
+
strictFeeRecipientCheck?: boolean;
|
|
103
105
|
/** When provided, build block with this builder bid instead of a self-build bid */
|
|
104
106
|
builderBid?: gloas.SignedExecutionPayloadBid;
|
|
105
107
|
};
|
|
@@ -201,6 +203,7 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
201
203
|
const {
|
|
202
204
|
slot: blockSlot,
|
|
203
205
|
feeRecipient: requestedFeeRecipient,
|
|
206
|
+
strictFeeRecipientCheck,
|
|
204
207
|
parentBlock,
|
|
205
208
|
proposerIndex,
|
|
206
209
|
proposerPubKey,
|
|
@@ -334,6 +337,16 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
334
337
|
executionPayloadValue = payloadRes.executionPayloadValue;
|
|
335
338
|
shouldOverrideBuilder = payloadRes.shouldOverrideBuilder;
|
|
336
339
|
|
|
340
|
+
if (
|
|
341
|
+
strictFeeRecipientCheck &&
|
|
342
|
+
requestedFeeRecipient &&
|
|
343
|
+
!byteArrayEquals(executionPayload.feeRecipient, fromHex(requestedFeeRecipient))
|
|
344
|
+
) {
|
|
345
|
+
throw Error(
|
|
346
|
+
`Invalid feeRecipient set in engine payload expected=${requestedFeeRecipient} actual=${toHex(executionPayload.feeRecipient)}`
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
|
|
337
350
|
if (blobsBundle === undefined) {
|
|
338
351
|
throw Error(`Missing blobsBundle response from getPayload at fork=${fork}`);
|
|
339
352
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {computeEpochAtSlot} from "@lodestar/state-transition";
|
|
2
|
+
import {Epoch, Slot, ValidatorIndex} from "@lodestar/types";
|
|
2
3
|
import {MapDef} from "@lodestar/utils";
|
|
3
4
|
|
|
4
5
|
// How many *non future* epochs we intend to keep for SeenAttesters.
|
|
@@ -57,7 +58,32 @@ export class SeenAttesters {
|
|
|
57
58
|
*/
|
|
58
59
|
export class SeenAggregators extends SeenAttesters {}
|
|
59
60
|
|
|
60
|
-
/**
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
/** Keeps a cache to filter payload attestations from the same validator in the same slot. */
|
|
62
|
+
export class SeenPayloadAttesters {
|
|
63
|
+
private readonly validatorIndexesBySlot = new MapDef<Slot, Set<ValidatorIndex>>(() => new Set<ValidatorIndex>());
|
|
64
|
+
private readonly validatorIndexesByEpoch = new SeenAttesters();
|
|
65
|
+
|
|
66
|
+
isKnown(slot: Slot, validatorIndex: ValidatorIndex): boolean {
|
|
67
|
+
return this.validatorIndexesBySlot.get(slot)?.has(validatorIndex) === true;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
add(slot: Slot, validatorIndex: ValidatorIndex): void {
|
|
71
|
+
const epoch = computeEpochAtSlot(slot);
|
|
72
|
+
this.validatorIndexesByEpoch.add(epoch, validatorIndex);
|
|
73
|
+
this.validatorIndexesBySlot.getOrDefault(slot).add(validatorIndex);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
seenAtEpoch(epoch: Epoch, validatorIndex: ValidatorIndex): boolean {
|
|
77
|
+
return this.validatorIndexesByEpoch.isKnown(epoch, validatorIndex);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
prune(currentEpoch: Epoch): void {
|
|
81
|
+
const lowestPermissibleEpoch = Math.max(currentEpoch - EPOCH_LOOKBACK_LIMIT, 0);
|
|
82
|
+
for (const slot of this.validatorIndexesBySlot.keys()) {
|
|
83
|
+
if (computeEpochAtSlot(slot) < lowestPermissibleEpoch) {
|
|
84
|
+
this.validatorIndexesBySlot.delete(slot);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
this.validatorIndexesByEpoch.prune(currentEpoch);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -19,7 +19,9 @@ const MIN_EQUIVOCATION_BLOCK_ROOTS_PER_PROPOSAL = 2;
|
|
|
19
19
|
* The cache is pruned on finalization and bounds the number of roots stored per proposer and slot
|
|
20
20
|
*/
|
|
21
21
|
export class SeenBlockProposers {
|
|
22
|
-
private readonly proposerIndexesBySlot = new MapDef<Slot,
|
|
22
|
+
private readonly proposerIndexesBySlot = new MapDef<Slot, Map<ValidatorIndex, RootHex>>(
|
|
23
|
+
() => new Map<ValidatorIndex, RootHex>()
|
|
24
|
+
);
|
|
23
25
|
private readonly signedBlockHeadersBySlot = new MapDef<
|
|
24
26
|
Slot,
|
|
25
27
|
MapDef<ValidatorIndex, Map<RootHex, phase0.SignedBeaconBlockHeader>>
|
|
@@ -30,6 +32,14 @@ export class SeenBlockProposers {
|
|
|
30
32
|
return this.proposerIndexesBySlot.get(blockSlot)?.has(proposerIndex) === true;
|
|
31
33
|
}
|
|
32
34
|
|
|
35
|
+
/**
|
|
36
|
+
* The block proposer is known at slot with a different root.
|
|
37
|
+
*/
|
|
38
|
+
isRepeatProposal(blockSlot: Slot, proposerIndex: ValidatorIndex, blockRoot: RootHex): boolean {
|
|
39
|
+
const knownRoot = this.proposerIndexesBySlot.get(blockSlot)?.get(proposerIndex);
|
|
40
|
+
return knownRoot !== undefined && knownRoot !== blockRoot;
|
|
41
|
+
}
|
|
42
|
+
|
|
33
43
|
hasBlockRoot(blockSlot: Slot, proposerIndex: ValidatorIndex, blockRoot: RootHex): boolean {
|
|
34
44
|
return this.signedBlockHeadersBySlot.get(blockSlot)?.get(proposerIndex)?.has(blockRoot) === true;
|
|
35
45
|
}
|
|
@@ -85,12 +95,12 @@ export class SeenBlockProposers {
|
|
|
85
95
|
}
|
|
86
96
|
|
|
87
97
|
/** Mark a block as known from gossip or another block import path */
|
|
88
|
-
add(blockSlot: Slot, proposerIndex: ValidatorIndex): void {
|
|
98
|
+
add(blockSlot: Slot, proposerIndex: ValidatorIndex, blockRoot: RootHex): void {
|
|
89
99
|
if (blockSlot < this.finalizedSlot) {
|
|
90
100
|
throw Error(`blockSlot ${blockSlot} < finalizedSlot ${this.finalizedSlot}`);
|
|
91
101
|
}
|
|
92
102
|
|
|
93
|
-
this.proposerIndexesBySlot.getOrDefault(blockSlot).
|
|
103
|
+
this.proposerIndexesBySlot.getOrDefault(blockSlot).set(proposerIndex, blockRoot);
|
|
94
104
|
}
|
|
95
105
|
|
|
96
106
|
prune(finalizedSlot: Slot): void {
|
|
@@ -142,13 +142,7 @@ export async function validateGossipAttestationsSameAttData(
|
|
|
142
142
|
const batchableBls = signatureSets.length >= chain.opts.minSameMessageSignatureSetsToBatch;
|
|
143
143
|
if (batchableBls) {
|
|
144
144
|
// all signature sets should have same signing root since we filtered in network processor
|
|
145
|
-
signatureValids = await chain.bls.verifySignatureSetsSameMessage(
|
|
146
|
-
signatureSets.map((set) => {
|
|
147
|
-
const publicKey = chain.pubkeyCache.getOrThrow(set.index);
|
|
148
|
-
return {publicKey, signature: set.signature};
|
|
149
|
-
}),
|
|
150
|
-
signatureSets[0].signingRoot
|
|
151
|
-
);
|
|
145
|
+
signatureValids = await chain.bls.verifySignatureSetsSameMessage(signatureSets, signatureSets[0].signingRoot);
|
|
152
146
|
} else {
|
|
153
147
|
// don't want to block the main thread if there are too few signatures
|
|
154
148
|
signatureValids = await Promise.all(
|
|
@@ -44,14 +44,7 @@ export async function validateAttesterSlashing(
|
|
|
44
44
|
// [REJECT] All of the conditions within process_attester_slashing pass validation.
|
|
45
45
|
try {
|
|
46
46
|
// verifySignature = false, verified in batch below
|
|
47
|
-
assertValidAttesterSlashing(
|
|
48
|
-
chain.config,
|
|
49
|
-
chain.pubkeyCache,
|
|
50
|
-
state.slot,
|
|
51
|
-
state.validatorCount,
|
|
52
|
-
attesterSlashing,
|
|
53
|
-
false
|
|
54
|
-
);
|
|
47
|
+
assertValidAttesterSlashing(chain.config, state.slot, state.validatorCount, attesterSlashing, false);
|
|
55
48
|
} catch (e) {
|
|
56
49
|
throw new AttesterSlashingError(GossipAction.REJECT, {
|
|
57
50
|
code: AttesterSlashingErrorCode.INVALID,
|
|
@@ -89,13 +89,20 @@ export async function validateGossipBlock(
|
|
|
89
89
|
|
|
90
90
|
// [IGNORE] The block is the first block with valid signature received for the proposer for the slot, signed_beacon_block.message.slot.
|
|
91
91
|
const proposerIndex = block.proposerIndex;
|
|
92
|
-
const hasBlockRoot = chain.seenBlockProposers.hasBlockRoot(blockSlot, proposerIndex, blockRoot);
|
|
93
92
|
if (chain.seenBlockProposers.isKnown(blockSlot, proposerIndex)) {
|
|
94
|
-
if (
|
|
95
|
-
|
|
96
|
-
chain.seenBlockProposers.
|
|
93
|
+
if (chain.seenBlockProposers.isRepeatProposal(blockSlot, proposerIndex, blockRoot)) {
|
|
94
|
+
const hasBlockRoot = chain.seenBlockProposers.hasBlockRoot(blockSlot, proposerIndex, blockRoot);
|
|
95
|
+
if (!hasBlockRoot && !chain.seenBlockProposers.isEquivocating(blockSlot, proposerIndex)) {
|
|
96
|
+
await verifyBlockProposerSignature(chain, signedBlock, blockRoot, {verifyOnMainThread: false});
|
|
97
|
+
chain.seenBlockProposers.observeBlockRoot(blockSlot, proposerIndex, blockRoot, signedBlockHeader);
|
|
98
|
+
}
|
|
99
|
+
throw new BlockGossipError(GossipAction.IGNORE, {
|
|
100
|
+
code: BlockErrorCode.REPEAT_PROPOSAL,
|
|
101
|
+
proposerIndex,
|
|
102
|
+
root: blockRoot,
|
|
103
|
+
});
|
|
97
104
|
}
|
|
98
|
-
throw new BlockGossipError(GossipAction.IGNORE, {code: BlockErrorCode.
|
|
105
|
+
throw new BlockGossipError(GossipAction.IGNORE, {code: BlockErrorCode.ALREADY_KNOWN, root: blockRoot});
|
|
99
106
|
}
|
|
100
107
|
|
|
101
108
|
// [REJECT] The current finalized_checkpoint is an ancestor of block -- i.e.
|
|
@@ -301,10 +308,17 @@ export async function validateGossipBlock(
|
|
|
301
308
|
|
|
302
309
|
// Check again after all async validation and the early-block delay so concurrent proposals cannot both pass
|
|
303
310
|
if (chain.seenBlockProposers.isKnown(blockSlot, proposerIndex)) {
|
|
304
|
-
|
|
311
|
+
if (chain.seenBlockProposers.isRepeatProposal(blockSlot, proposerIndex, blockRoot)) {
|
|
312
|
+
throw new BlockGossipError(GossipAction.IGNORE, {
|
|
313
|
+
code: BlockErrorCode.REPEAT_PROPOSAL,
|
|
314
|
+
proposerIndex,
|
|
315
|
+
root: blockRoot,
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
throw new BlockGossipError(GossipAction.IGNORE, {code: BlockErrorCode.ALREADY_KNOWN, root: blockRoot});
|
|
305
319
|
}
|
|
306
320
|
|
|
307
|
-
chain.seenBlockProposers.add(blockSlot, proposerIndex);
|
|
321
|
+
chain.seenBlockProposers.add(blockSlot, proposerIndex, blockRoot);
|
|
308
322
|
|
|
309
323
|
return {skippedSlots};
|
|
310
324
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import {PublicKey} from "@chainsafe/blst";
|
|
2
1
|
import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
|
|
3
2
|
import {PAYLOAD_BUILDER_VERSION} from "@lodestar/params";
|
|
4
3
|
import {
|
|
@@ -345,7 +344,7 @@ async function validateExecutionPayloadBid(
|
|
|
345
344
|
|
|
346
345
|
// [REJECT] `signed_execution_payload_bid.signature` is valid with respect to the `bid.builder_index`.
|
|
347
346
|
const signatureSet = createSingleSignatureSetFromComponents(
|
|
348
|
-
|
|
347
|
+
builder.pubkey,
|
|
349
348
|
getExecutionPayloadBidSigningRoot(chain.config, bid),
|
|
350
349
|
signedExecutionPayloadBid.signature
|
|
351
350
|
);
|
|
@@ -170,7 +170,6 @@ async function validateExecutionPayloadEnvelope(
|
|
|
170
170
|
// by `verify_execution_payload_envelope_signature`.
|
|
171
171
|
const signatureSet = getExecutionPayloadEnvelopeSignatureSet(
|
|
172
172
|
chain.config,
|
|
173
|
-
chain.pubkeyCache,
|
|
174
173
|
blockState,
|
|
175
174
|
executionPayloadEnvelope,
|
|
176
175
|
payloadInput.proposerIndex
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
createSingleSignatureSetFromComponents,
|
|
2
|
+
createIndexedSignatureSetFromComponents,
|
|
4
3
|
getPayloadAttestationDataSigningRoot,
|
|
5
4
|
isStatePostGloas,
|
|
6
5
|
} from "@lodestar/state-transition";
|
|
@@ -36,7 +35,6 @@ async function validatePayloadAttestationMessage(
|
|
|
36
35
|
prioritizeBls = false
|
|
37
36
|
): Promise<PayloadAttestationValidationResult> {
|
|
38
37
|
const {data, validatorIndex} = payloadAttestationMessage;
|
|
39
|
-
const epoch = computeEpochAtSlot(data.slot);
|
|
40
38
|
|
|
41
39
|
// [IGNORE] The message's slot is for the current slot (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance), i.e. `data.slot == current_slot`.
|
|
42
40
|
if (!chain.clock.isCurrentSlotGivenGossipDisparity(data.slot)) {
|
|
@@ -48,9 +46,8 @@ async function validatePayloadAttestationMessage(
|
|
|
48
46
|
}
|
|
49
47
|
|
|
50
48
|
// [IGNORE] The `payload_attestation_message` is the first valid message received
|
|
51
|
-
// from the validator with index `payload_attestation_message.validator_index`.
|
|
52
|
-
|
|
53
|
-
if (chain.seenPayloadAttesters.isKnown(epoch, validatorIndex)) {
|
|
49
|
+
// for the slot from the validator with index `payload_attestation_message.validator_index`.
|
|
50
|
+
if (chain.seenPayloadAttesters.isKnown(data.slot, validatorIndex)) {
|
|
54
51
|
throw new PayloadAttestationError(GossipAction.IGNORE, {
|
|
55
52
|
code: PayloadAttestationErrorCode.PAYLOAD_ATTESTATION_ALREADY_KNOWN,
|
|
56
53
|
validatorIndex,
|
|
@@ -114,16 +111,8 @@ async function validatePayloadAttestationMessage(
|
|
|
114
111
|
}
|
|
115
112
|
|
|
116
113
|
// [REJECT] `payload_attestation_message.signature` is valid with respect to the validator's public key.
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
throw new PayloadAttestationError(GossipAction.REJECT, {
|
|
120
|
-
code: PayloadAttestationErrorCode.INVALID_ATTESTER,
|
|
121
|
-
attesterIndex: validatorIndex,
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const signatureSet = createSingleSignatureSetFromComponents(
|
|
126
|
-
validatorPubkey,
|
|
114
|
+
const signatureSet = createIndexedSignatureSetFromComponents(
|
|
115
|
+
validatorIndex,
|
|
127
116
|
getPayloadAttestationDataSigningRoot(chain.config, data),
|
|
128
117
|
payloadAttestationMessage.signature
|
|
129
118
|
);
|
|
@@ -135,7 +124,7 @@ async function validatePayloadAttestationMessage(
|
|
|
135
124
|
}
|
|
136
125
|
|
|
137
126
|
// Valid
|
|
138
|
-
chain.seenPayloadAttesters.add(
|
|
127
|
+
chain.seenPayloadAttesters.add(data.slot, validatorIndex);
|
|
139
128
|
|
|
140
129
|
return {
|
|
141
130
|
attDataRootHex: toRootHex(ssz.gloas.PayloadAttestationData.hashTreeRoot(data)),
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
|
|
2
|
-
import {GENESIS_EPOCH, GENESIS_SLOT, MIN_SEED_LOOKAHEAD, SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
2
|
+
import {GENESIS_EPOCH, GENESIS_SLOT, MIN_SEED_LOOKAHEAD, SLOTS_PER_EPOCH, isForkPostGloas} from "@lodestar/params";
|
|
3
3
|
import {
|
|
4
4
|
computeEpochAtSlot,
|
|
5
5
|
computeStartSlotAtEpoch,
|
|
6
|
-
|
|
6
|
+
createIndexedSignatureSetFromComponents,
|
|
7
7
|
getProposerPreferencesSigningRoot,
|
|
8
8
|
} from "@lodestar/state-transition";
|
|
9
9
|
import {Epoch, Slot, ValidatorIndex, gloas} from "@lodestar/types";
|
|
@@ -13,7 +13,7 @@ import {IBeaconChain} from "../index.js";
|
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Validates a gossiped `SignedProposerPreferences` per
|
|
16
|
-
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.
|
|
16
|
+
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.14/specs/gloas/p2p-interface.md#new-proposer_preferences
|
|
17
17
|
*/
|
|
18
18
|
export async function validateGossipProposerPreferences(
|
|
19
19
|
chain: IBeaconChain,
|
|
@@ -24,6 +24,16 @@ export async function validateGossipProposerPreferences(
|
|
|
24
24
|
const dependentRootHex = toRootHex(dependentRoot);
|
|
25
25
|
const proposalEpoch = computeEpochAtSlot(proposalSlot);
|
|
26
26
|
|
|
27
|
+
// [IGNORE] The proposal epoch is after the Gloas upgrade
|
|
28
|
+
const proposalFork = chain.config.getForkName(proposalSlot);
|
|
29
|
+
if (!isForkPostGloas(proposalFork)) {
|
|
30
|
+
throw new ProposerPreferencesError(GossipAction.IGNORE, {
|
|
31
|
+
code: ProposerPreferencesErrorCode.PRE_GLOAS_PROPOSAL_SLOT,
|
|
32
|
+
proposalSlot,
|
|
33
|
+
proposalFork,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
27
37
|
// [IGNORE] `preferences.proposal_slot` is within the proposer lookahead,
|
|
28
38
|
// allowing for `MAXIMUM_GOSSIP_CLOCK_DISPARITY`.
|
|
29
39
|
const currentEpoch = computeEpochAtSlot(chain.clock.currentSlotWithGossipDisparity);
|
|
@@ -129,8 +139,8 @@ export async function validateGossipProposerPreferences(
|
|
|
129
139
|
}
|
|
130
140
|
|
|
131
141
|
// [REJECT] `signed_proposer_preferences.signature` is valid with respect to the validator's public key.
|
|
132
|
-
const signatureSet =
|
|
133
|
-
|
|
142
|
+
const signatureSet = createIndexedSignatureSetFromComponents(
|
|
143
|
+
validatorIndex,
|
|
134
144
|
getProposerPreferencesSigningRoot(chain.config, preferences),
|
|
135
145
|
signedProposerPreferences.signature
|
|
136
146
|
);
|
|
@@ -37,7 +37,7 @@ async function validateProposerSlashing(
|
|
|
37
37
|
try {
|
|
38
38
|
const proposer = state.getValidator(proposerSlashing.signedHeader1.message.proposerIndex);
|
|
39
39
|
// verifySignature = false, verified in batch below
|
|
40
|
-
assertValidProposerSlashing(chain.config,
|
|
40
|
+
assertValidProposerSlashing(chain.config, state.slot, proposerSlashing, proposer, false);
|
|
41
41
|
} catch (e) {
|
|
42
42
|
throw new ProposerSlashingError(GossipAction.REJECT, {
|
|
43
43
|
code: ProposerSlashingErrorCode.INVALID,
|
|
@@ -71,15 +71,18 @@ export class NoBidReceived extends Error {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
|
-
*
|
|
75
|
-
* the circuit breaker (so at boot time and once for each unique boot).
|
|
74
|
+
* Default circuit breaker parameters:
|
|
76
75
|
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
76
|
+
* SLOTS_PER_EPOCH <= FAULT_INSPECTION_WINDOW < 2 * SLOTS_PER_EPOCH (randomized at initialization)
|
|
77
|
+
* ALLOWED_FAULTS: FAULT_INSPECTION_WINDOW // 4
|
|
79
78
|
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
79
|
+
* e.g. on mainnet SLOTS_PER_EPOCH is 32, so FAULT_INSPECTION_WINDOW is between 32 and 63,
|
|
80
|
+
* and a window of 40 results in ALLOWED_FAULTS = 10.
|
|
81
|
+
*
|
|
82
|
+
* The randomized default window keeps the exact slots under inspection unpredictable per node,
|
|
83
|
+
* so a builder cannot tell when past faults age out of a given proposer's window and time
|
|
84
|
+
* withholding around trip or recovery points. Explicitly configured windows are clamped to at
|
|
85
|
+
* least SLOTS_PER_EPOCH, and configured allowedFaults is capped at the default ~25% budget.
|
|
83
86
|
*/
|
|
84
87
|
export function getFaultInspectionParams(opts: {faultInspectionWindow?: number; allowedFaults?: number}): {
|
|
85
88
|
faultInspectionWindow: number;
|
|
@@ -90,10 +93,7 @@ export function getFaultInspectionParams(opts: {faultInspectionWindow?: number;
|
|
|
90
93
|
SLOTS_PER_EPOCH
|
|
91
94
|
);
|
|
92
95
|
// allowedFaults should be < faultInspectionWindow, limiting them to faultInspectionWindow/4
|
|
93
|
-
const allowedFaults = Math.min(
|
|
94
|
-
opts.allowedFaults ?? Math.floor(faultInspectionWindow / 4),
|
|
95
|
-
Math.floor(faultInspectionWindow / 4)
|
|
96
|
-
);
|
|
96
|
+
const allowedFaults = Math.min(opts.allowedFaults ?? Infinity, Math.floor(faultInspectionWindow / 4));
|
|
97
97
|
return {faultInspectionWindow, allowedFaults};
|
|
98
98
|
}
|
|
99
99
|
|
|
@@ -143,17 +143,17 @@ export function createBeaconMetrics(register: RegistryMetricCreator) {
|
|
|
143
143
|
name: "beacon_builder_circuit_breaker_active",
|
|
144
144
|
help: "Whether the builder circuit breaker is active (1) causing builder bids to be ignored",
|
|
145
145
|
}),
|
|
146
|
-
|
|
147
|
-
name: "
|
|
148
|
-
help: "Count of
|
|
146
|
+
canonicalBlocks: register.gauge({
|
|
147
|
+
name: "beacon_builder_circuit_breaker_canonical_blocks",
|
|
148
|
+
help: "Count of canonical FULL and EMPTY blocks in the fault inspection window",
|
|
149
149
|
}),
|
|
150
|
-
|
|
151
|
-
name: "
|
|
152
|
-
help: "Count of blocks
|
|
150
|
+
fullBlocks: register.gauge({
|
|
151
|
+
name: "beacon_builder_circuit_breaker_full_blocks",
|
|
152
|
+
help: "Count of canonical FULL blocks in the fault inspection window",
|
|
153
153
|
}),
|
|
154
|
-
|
|
155
|
-
name: "
|
|
156
|
-
help: "Count of
|
|
154
|
+
emptyBlocks: register.gauge({
|
|
155
|
+
name: "beacon_builder_circuit_breaker_empty_blocks",
|
|
156
|
+
help: "Count of canonical EMPTY blocks in the fault inspection window",
|
|
157
157
|
}),
|
|
158
158
|
},
|
|
159
159
|
|
|
@@ -31,6 +31,10 @@ import {RegistryMetricCreator} from "../utils/registryMetricCreator.js";
|
|
|
31
31
|
|
|
32
32
|
export type LodestarMetrics = ReturnType<typeof createLodestarMetrics>;
|
|
33
33
|
|
|
34
|
+
type BlsJobOutcome = "valid" | "invalid" | "prepError" | "verifyError" | "workerError";
|
|
35
|
+
type BlsBufferFlushReason = "size" | "timeout";
|
|
36
|
+
type BlsVerificationCallOperation = "batch" | "single" | "fallback" | "same_message";
|
|
37
|
+
|
|
34
38
|
/**
|
|
35
39
|
* Extra Lodestar custom metrics
|
|
36
40
|
*/
|
|
@@ -396,86 +400,108 @@ export function createLodestarMetrics(
|
|
|
396
400
|
// BLS verifier thread pool and queue
|
|
397
401
|
|
|
398
402
|
bls: {
|
|
399
|
-
aggregatedPubkeys: register.
|
|
403
|
+
aggregatedPubkeys: register.counter({
|
|
400
404
|
name: "lodestar_bls_aggregated_pubkeys_total",
|
|
401
|
-
help: "Total
|
|
405
|
+
help: "Total validator public keys used as inputs to aggregate signature sets",
|
|
406
|
+
}),
|
|
407
|
+
pubkeyCacheSize: register.gauge({
|
|
408
|
+
name: "lodestar_bls_pubkey_cache_size",
|
|
409
|
+
help: "Current number of validator public keys in the native cache",
|
|
410
|
+
}),
|
|
411
|
+
pubkeyCacheCapacity: register.gauge({
|
|
412
|
+
name: "lodestar_bls_pubkey_cache_capacity",
|
|
413
|
+
help: "Number of validator public keys the native cache can hold without growing",
|
|
402
414
|
}),
|
|
403
415
|
},
|
|
404
416
|
|
|
405
417
|
blsThreadPool: {
|
|
406
|
-
jobsWorkerTime: register.
|
|
418
|
+
jobsWorkerTime: register.counter<{workerId: number}>({
|
|
407
419
|
name: "lodestar_bls_thread_pool_time_seconds_sum",
|
|
408
|
-
help: "
|
|
420
|
+
help: "Cumulative wall time spent processing BLS dispatch groups by worker",
|
|
409
421
|
labelNames: ["workerId"],
|
|
410
422
|
}),
|
|
411
|
-
successJobsSignatureSetsCount: register.
|
|
423
|
+
successJobsSignatureSetsCount: register.counter({
|
|
412
424
|
name: "lodestar_bls_thread_pool_success_jobs_signature_sets_count",
|
|
413
|
-
help: "Count of
|
|
425
|
+
help: "Count of signature sets completed without an operational error",
|
|
414
426
|
}),
|
|
415
|
-
|
|
416
|
-
name: "lodestar_bls_thread_pool_error_aggregate_signature_sets_count",
|
|
417
|
-
help: "Count of error when aggregating pubkeys or signatures",
|
|
418
|
-
labelNames: ["type"],
|
|
419
|
-
}),
|
|
420
|
-
errorJobsSignatureSetsCount: register.gauge({
|
|
427
|
+
errorJobsSignatureSetsCount: register.counter({
|
|
421
428
|
name: "lodestar_bls_thread_pool_error_jobs_signature_sets_count",
|
|
422
|
-
help: "Count of
|
|
429
|
+
help: "Count of signature sets that ended in an input, binding, or worker error",
|
|
423
430
|
}),
|
|
424
|
-
jobWaitTime: register.histogram({
|
|
431
|
+
jobWaitTime: register.histogram<{type: JobQueueItemType}>({
|
|
425
432
|
name: "lodestar_bls_thread_pool_queue_job_wait_time_seconds",
|
|
426
|
-
help: "Time from job
|
|
427
|
-
|
|
433
|
+
help: "Time from adding a BLS job until it is selected for a worker dispatch group",
|
|
434
|
+
labelNames: ["type"],
|
|
435
|
+
buckets: [0.005, 0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2],
|
|
436
|
+
}),
|
|
437
|
+
jobDuration: register.histogram<{type: JobQueueItemType}>({
|
|
438
|
+
name: "lodestar_bls_thread_pool_job_duration_seconds",
|
|
439
|
+
help: "End-to-end duration of a BLS job from submission through completion",
|
|
440
|
+
labelNames: ["type"],
|
|
441
|
+
buckets: [0.005, 0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2],
|
|
442
|
+
}),
|
|
443
|
+
jobResults: register.counter<{type: JobQueueItemType; outcome: BlsJobOutcome}>({
|
|
444
|
+
name: "lodestar_bls_thread_pool_job_results_total",
|
|
445
|
+
help: "Count of completed BLS jobs by cryptographic or operational outcome",
|
|
446
|
+
labelNames: ["type", "outcome"],
|
|
428
447
|
}),
|
|
429
448
|
queueLength: register.gauge({
|
|
430
449
|
name: "lodestar_bls_thread_pool_queue_length",
|
|
431
|
-
help: "Count of
|
|
450
|
+
help: "Count of ready BLS jobs waiting for a worker",
|
|
451
|
+
}),
|
|
452
|
+
bufferedQueueLength: register.gauge({
|
|
453
|
+
name: "lodestar_bls_thread_pool_buffered_queue_length",
|
|
454
|
+
help: "Count of BLS jobs waiting in the intentional batching buffer",
|
|
432
455
|
}),
|
|
433
456
|
workersBusy: register.gauge({
|
|
434
457
|
name: "lodestar_bls_thread_pool_workers_busy",
|
|
435
458
|
help: "Count of current busy workers",
|
|
436
459
|
}),
|
|
437
|
-
totalJobsGroupsStarted: register.
|
|
460
|
+
totalJobsGroupsStarted: register.counter({
|
|
438
461
|
name: "lodestar_bls_thread_pool_job_groups_started_total",
|
|
439
|
-
help: "Count of
|
|
462
|
+
help: "Count of worker dispatch groups started by the BLS thread pool",
|
|
440
463
|
}),
|
|
441
|
-
totalJobsStarted: register.
|
|
464
|
+
totalJobsStarted: register.counter<{type: JobQueueItemType}>({
|
|
442
465
|
name: "lodestar_bls_thread_pool_jobs_started_total",
|
|
443
|
-
help: "Count of
|
|
466
|
+
help: "Count of jobs started by the BLS thread pool",
|
|
444
467
|
labelNames: ["type"],
|
|
445
468
|
}),
|
|
446
|
-
totalSigSetsStarted: register.
|
|
469
|
+
totalSigSetsStarted: register.counter<{type: JobQueueItemType}>({
|
|
447
470
|
name: "lodestar_bls_thread_pool_sig_sets_started_total",
|
|
448
|
-
help: "Count of
|
|
471
|
+
help: "Count of signature sets started by the BLS thread pool",
|
|
449
472
|
labelNames: ["type"],
|
|
450
473
|
}),
|
|
451
474
|
// Re-verifying a batch means doing double work. This number must be very low or it can be a waste of CPU resources
|
|
452
|
-
batchRetries: register.
|
|
475
|
+
batchRetries: register.counter({
|
|
453
476
|
name: "lodestar_bls_thread_pool_batch_retries_total",
|
|
454
|
-
help: "Count of
|
|
477
|
+
help: "Count of combined batches that failed and required per-job fallback",
|
|
455
478
|
}),
|
|
456
479
|
// To count how many sigs are being validated with the optimization of batching them
|
|
457
|
-
batchSigsSuccess: register.
|
|
480
|
+
batchSigsSuccess: register.counter({
|
|
458
481
|
name: "lodestar_bls_thread_pool_batch_sigs_success_total",
|
|
459
|
-
help: "Count of
|
|
482
|
+
help: "Count of signature sets accepted by combined batch verification without fallback",
|
|
460
483
|
}),
|
|
461
|
-
|
|
462
|
-
name: "
|
|
463
|
-
help: "Count of
|
|
484
|
+
bufferFlushes: register.counter<{reason: BlsBufferFlushReason}>({
|
|
485
|
+
name: "lodestar_bls_thread_pool_buffer_flushes_total",
|
|
486
|
+
help: "Count of batching-buffer flushes by trigger",
|
|
487
|
+
labelNames: ["reason"],
|
|
464
488
|
}),
|
|
465
|
-
|
|
466
|
-
name: "
|
|
467
|
-
help: "Count of
|
|
489
|
+
bufferedSignatureSets: register.histogram({
|
|
490
|
+
name: "lodestar_bls_thread_pool_buffered_signature_sets",
|
|
491
|
+
help: "Count of signature sets included in each batching-buffer flush",
|
|
492
|
+
buckets: [1, 8, 16, 24, 28, 32, 36, 40, 44, 48, 64, 128],
|
|
468
493
|
}),
|
|
469
494
|
// To measure the time cost of main thread <-> worker message passing
|
|
470
495
|
latencyToWorker: register.histogram({
|
|
471
496
|
name: "lodestar_bls_thread_pool_latency_to_worker",
|
|
472
497
|
help: "Time from sending the job to the worker and the worker receiving it",
|
|
473
|
-
|
|
498
|
+
// The dashboard treats 20ms as slow; values above 100ms only need severe-stall classification.
|
|
499
|
+
buckets: [0.00025, 0.001, 0.005, 0.02, 0.1],
|
|
474
500
|
}),
|
|
475
501
|
latencyFromWorker: register.histogram({
|
|
476
502
|
name: "lodestar_bls_thread_pool_latency_from_worker",
|
|
477
503
|
help: "Time from the worker sending the result and the main thread receiving it",
|
|
478
|
-
buckets: [0.
|
|
504
|
+
buckets: [0.00025, 0.001, 0.005, 0.02, 0.1],
|
|
479
505
|
}),
|
|
480
506
|
mainThreadDurationInThreadPool: register.histogram({
|
|
481
507
|
name: "lodestar_bls_thread_pool_main_thread_time_seconds",
|
|
@@ -485,32 +511,40 @@ export function createLodestarMetrics(
|
|
|
485
511
|
}),
|
|
486
512
|
timePerSigSet: register.histogram({
|
|
487
513
|
name: "lodestar_bls_worker_thread_time_per_sigset_seconds",
|
|
488
|
-
help: "
|
|
514
|
+
help: "Average BLS worker dispatch wall time per original signature set",
|
|
489
515
|
// Time per sig ~0.9ms on good machines
|
|
490
|
-
buckets: [0.5e-3, 0.75e-3, 1e-3, 1.5e-3, 2e-3, 5e-3],
|
|
491
|
-
}),
|
|
492
|
-
|
|
516
|
+
buckets: [0.5e-3, 0.75e-3, 1e-3, 1.5e-3, 2e-3, 5e-3, 10e-3, 20e-3, 50e-3, 100e-3],
|
|
517
|
+
}),
|
|
518
|
+
workRequestPreparationDuration: register.histogram({
|
|
519
|
+
name: "lodestar_bls_thread_pool_work_request_preparation_duration_seconds",
|
|
520
|
+
help: "Main-thread time spent converting one worker dispatch group to binding inputs",
|
|
521
|
+
// Normal requests take microseconds; the dashboard treats 1ms as a main-thread stall.
|
|
522
|
+
buckets: [0.000005, 0.000025, 0.0001, 0.0005, 0.001, 0.005, 0.025],
|
|
523
|
+
}),
|
|
524
|
+
verificationCallDuration: register.histogram<{operation: BlsVerificationCallOperation}>({
|
|
525
|
+
name: "lodestar_bls_thread_pool_verification_call_duration_seconds",
|
|
526
|
+
help: "Duration of one worker-side lodestar-z verification binding call, including input conversion",
|
|
527
|
+
labelNames: ["operation"],
|
|
528
|
+
// Verification ranges from sub-millisecond calls to large batches; above 500ms is uniformly severe.
|
|
529
|
+
buckets: [0.00025, 0.001, 0.005, 0.02, 0.1, 0.5],
|
|
530
|
+
}),
|
|
531
|
+
verificationCallSignatureSets: register.counter<{operation: BlsVerificationCallOperation}>({
|
|
532
|
+
name: "lodestar_bls_thread_pool_verification_call_signature_sets_total",
|
|
533
|
+
help: "Count of signature sets passed to worker-side lodestar-z verification binding calls",
|
|
534
|
+
labelNames: ["operation"],
|
|
535
|
+
}),
|
|
536
|
+
totalSigSets: register.counter({
|
|
493
537
|
name: "lodestar_bls_thread_pool_sig_sets_total",
|
|
494
538
|
help: "Count of total signature sets",
|
|
495
539
|
}),
|
|
496
|
-
prioritizedSigSets: register.
|
|
540
|
+
prioritizedSigSets: register.counter({
|
|
497
541
|
name: "lodestar_bls_thread_pool_prioritized_sig_sets_total",
|
|
498
542
|
help: "Count of total prioritized signature sets",
|
|
499
543
|
}),
|
|
500
|
-
batchableSigSets: register.
|
|
544
|
+
batchableSigSets: register.counter({
|
|
501
545
|
name: "lodestar_bls_thread_pool_batchable_sig_sets_total",
|
|
502
546
|
help: "Count of total batchable signature sets",
|
|
503
547
|
}),
|
|
504
|
-
aggregateWithRandomnessAsyncDuration: register.histogram({
|
|
505
|
-
name: "lodestar_bls_thread_pool_aggregate_with_randomness_async_time_seconds",
|
|
506
|
-
help: "Total time performing aggregateWithRandomness async",
|
|
507
|
-
buckets: [0.001, 0.005, 0.01, 0.1, 0.3],
|
|
508
|
-
}),
|
|
509
|
-
pubkeysAggregationMainThreadDuration: register.histogram({
|
|
510
|
-
name: "lodestar_bls_thread_pool_pubkeys_aggregation_main_thread_time_seconds",
|
|
511
|
-
help: "Total time spent aggregating pubkeys on main thread",
|
|
512
|
-
buckets: [0.001, 0.005, 0.01, 0.1],
|
|
513
|
-
}),
|
|
514
548
|
},
|
|
515
549
|
|
|
516
550
|
// BLS time on single thread mode
|
|
@@ -908,6 +942,22 @@ export function createLodestarMetrics(
|
|
|
908
942
|
labelNames: ["error"],
|
|
909
943
|
}),
|
|
910
944
|
},
|
|
945
|
+
gossipExecutionPayloadBid: {
|
|
946
|
+
elapsedTimeTillReceived: register.histogram<{source: OpSource}>({
|
|
947
|
+
name: "lodestar_gossip_execution_payload_bid_elapsed_time_till_received_seconds",
|
|
948
|
+
help: "Time elapsed between the bid's slot start and the time the execution payload bid was received (negative = received before its slot, broadcast in the previous slot; positive = received during its own slot, late)",
|
|
949
|
+
labelNames: ["source"],
|
|
950
|
+
buckets: [-6, -3, -1, 0, 3],
|
|
951
|
+
}),
|
|
952
|
+
},
|
|
953
|
+
gossipPayloadAttestationMessage: {
|
|
954
|
+
elapsedTimeTillReceived: register.histogram<{source: OpSource}>({
|
|
955
|
+
name: "lodestar_gossip_payload_attestation_message_elapsed_time_till_received_seconds",
|
|
956
|
+
help: "Time elapsed between slot time and the time the payload attestation message was received",
|
|
957
|
+
labelNames: ["source"],
|
|
958
|
+
buckets: [3, 6, 9, 12],
|
|
959
|
+
}),
|
|
960
|
+
},
|
|
911
961
|
// recovery in the case of specific blob rows required
|
|
912
962
|
recoverBlobSidecars: {
|
|
913
963
|
blobsReconstructed: register.counter({
|