@lodestar/beacon-node 1.47.0-dev.92bd4efe9b → 1.47.0-dev.931ecbec99
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 +3 -6
- 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 +4 -0
- 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/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.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.js +1 -1
- package/lib/chain/blocks/importExecutionPayload.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/chain.d.ts +2 -1
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +6 -4
- package/lib/chain/chain.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/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/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/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/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/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/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +7 -2
- 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/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/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 +93 -9
- package/lib/sync/unknownBlock.js.map +1 -1
- package/package.json +15 -15
- package/src/api/impl/beacon/blocks/index.ts +4 -6
- package/src/api/impl/beacon/pool/index.ts +5 -0
- package/src/api/impl/beacon/state/utils.ts +2 -1
- package/src/api/impl/events/index.ts +10 -4
- package/src/chain/archiveStore/historicalState/metrics.ts +22 -0
- package/src/chain/blocks/importBlock.ts +1 -6
- package/src/chain/blocks/importExecutionPayload.ts +0 -1
- 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/chain.ts +7 -5
- 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/seenCache/seenAttesters.ts +31 -5
- package/src/chain/validation/attestation.ts +1 -7
- package/src/chain/validation/attesterSlashing.ts +1 -8
- 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/metrics/metrics/lodestar.ts +101 -51
- package/src/network/libp2p/index.ts +11 -2
- package/src/network/processor/gossipHandlers.ts +9 -0
- package/src/network/reqresp/score.ts +5 -11
- package/src/node/nodejs.ts +2 -1
- package/src/sync/types.ts +3 -1
- package/src/sync/unknownBlock.ts +108 -12
- 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
|
@@ -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,
|
|
@@ -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({
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {getCiphers} from "node:crypto";
|
|
1
2
|
import {bootstrap} from "@libp2p/bootstrap";
|
|
2
3
|
import {identify} from "@libp2p/identify";
|
|
3
4
|
import type {PrivateKey} from "@libp2p/interface";
|
|
@@ -9,12 +10,20 @@ import {Libp2pInit, createLibp2p} from "libp2p";
|
|
|
9
10
|
import {Registry} from "prom-client";
|
|
10
11
|
import {ENR} from "@chainsafe/enr";
|
|
11
12
|
import {noise} from "@chainsafe/libp2p-noise";
|
|
12
|
-
import {defaultCrypto} from "@chainsafe/libp2p-noise/crypto";
|
|
13
|
+
import {asCrypto, defaultCrypto} from "@chainsafe/libp2p-noise/crypto";
|
|
13
14
|
import {quic} from "@chainsafe/libp2p-quic";
|
|
14
15
|
import {Libp2p, LodestarComponents} from "../interface.js";
|
|
15
16
|
import {NetworkOptions, defaultNetworkOptions} from "../options.js";
|
|
16
17
|
import {Eth2PeerDataStore} from "../peers/datastore.js";
|
|
17
18
|
|
|
19
|
+
const noiseCrypto = getCiphers().includes("chacha20-poly1305")
|
|
20
|
+
? defaultCrypto
|
|
21
|
+
: {
|
|
22
|
+
...defaultCrypto,
|
|
23
|
+
chaCha20Poly1305Encrypt: asCrypto.chaCha20Poly1305Encrypt,
|
|
24
|
+
chaCha20Poly1305Decrypt: asCrypto.chaCha20Poly1305Decrypt,
|
|
25
|
+
};
|
|
26
|
+
|
|
18
27
|
export type NodeJsLibp2pOpts = {
|
|
19
28
|
peerStoreDir?: string;
|
|
20
29
|
disablePeerDiscovery?: boolean;
|
|
@@ -122,7 +131,7 @@ export async function createNodeJsLibp2p(
|
|
|
122
131
|
listen: localMultiaddrs,
|
|
123
132
|
announce: [],
|
|
124
133
|
},
|
|
125
|
-
connectionEncrypters: [noise({crypto:
|
|
134
|
+
connectionEncrypters: [noise({crypto: noiseCrypto})],
|
|
126
135
|
transports,
|
|
127
136
|
streamMuxers: [mplex({disconnectThreshold})],
|
|
128
137
|
peerDiscovery,
|
|
@@ -1255,11 +1255,15 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1255
1255
|
[GossipType.payload_attestation_message]: async ({
|
|
1256
1256
|
gossipData,
|
|
1257
1257
|
topic,
|
|
1258
|
+
seenTimestampSec,
|
|
1258
1259
|
}: GossipHandlerParamGeneric<GossipType.payload_attestation_message>) => {
|
|
1259
1260
|
const {serializedData} = gossipData;
|
|
1260
1261
|
const payloadAttestationMessage = sszDeserialize(topic, serializedData);
|
|
1261
1262
|
const validationResult = await validateGossipPayloadAttestationMessage(chain, payloadAttestationMessage);
|
|
1262
1263
|
|
|
1264
|
+
const delaySec = chain.clock.secFromSlot(payloadAttestationMessage.data.slot, seenTimestampSec);
|
|
1265
|
+
metrics?.gossipPayloadAttestationMessage.elapsedTimeTillReceived.observe({source: OpSource.gossip}, delaySec);
|
|
1266
|
+
|
|
1263
1267
|
try {
|
|
1264
1268
|
const insertOutcome = chain.payloadAttestationPool.add(
|
|
1265
1269
|
payloadAttestationMessage,
|
|
@@ -1286,11 +1290,16 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1286
1290
|
[GossipType.execution_payload_bid]: async ({
|
|
1287
1291
|
gossipData,
|
|
1288
1292
|
topic,
|
|
1293
|
+
seenTimestampSec,
|
|
1289
1294
|
}: GossipHandlerParamGeneric<GossipType.execution_payload_bid>) => {
|
|
1290
1295
|
const {serializedData} = gossipData;
|
|
1291
1296
|
const executionPayloadBid = sszDeserialize(topic, serializedData);
|
|
1292
1297
|
const {proposerIndex} = await validateGossipExecutionPayloadBid(chain, executionPayloadBid);
|
|
1293
1298
|
|
|
1299
|
+
// this could be negative, because it's most likely the bid of next slot comes at this clock slot
|
|
1300
|
+
const elapsedSec = chain.clock.secFromSlot(executionPayloadBid.message.slot, seenTimestampSec);
|
|
1301
|
+
metrics?.gossipExecutionPayloadBid.elapsedTimeTillReceived.observe({source: OpSource.gossip}, elapsedSec);
|
|
1302
|
+
|
|
1294
1303
|
// Handle valid payload bid by storing in a bid pool
|
|
1295
1304
|
try {
|
|
1296
1305
|
const insertOutcome = chain.executionPayloadBidPool.add(executionPayloadBid);
|
|
@@ -44,17 +44,11 @@ export function onOutgoingReqRespError(e: RequestError, method: ReqRespMethod):
|
|
|
44
44
|
// failure, so keep the stronger penalty (Fatal for Ping, as before).
|
|
45
45
|
return method === ReqRespMethod.Ping ? PeerAction.Fatal : PeerAction.LowToleranceError;
|
|
46
46
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
case ReqRespMethod.Ping:
|
|
53
|
-
case ReqRespMethod.Status:
|
|
54
|
-
return PeerAction.HighToleranceError;
|
|
55
|
-
default:
|
|
56
|
-
return PeerAction.LowToleranceError;
|
|
57
|
-
}
|
|
47
|
+
// A dial failure means we could not open a stream. That is evidence about the transport, not
|
|
48
|
+
// about the peer's behavior, and it is dominated by transient congestion on our side, so
|
|
49
|
+
// penalize leniently for every method to avoid self-inflicted peer starvation (#9562). A
|
|
50
|
+
// genuinely dead peer still accumulates penalty and is eventually evicted, freeing the slot.
|
|
51
|
+
return PeerAction.HighToleranceError;
|
|
58
52
|
// TODO: Detect SSZDecodeError and return PeerAction.Fatal
|
|
59
53
|
|
|
60
54
|
case RequestErrorCode.RESP_TIMEOUT:
|
package/src/node/nodejs.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import {setMaxListeners} from "node:events";
|
|
2
2
|
import {PrivateKey} from "@libp2p/interface";
|
|
3
3
|
import {Registry} from "prom-client";
|
|
4
|
+
import {type PubkeyCache} from "@chainsafe/lodestar-z/pubkeys";
|
|
4
5
|
import {hasher} from "@chainsafe/persistent-merkle-tree";
|
|
5
6
|
import {BeaconApiMethods} from "@lodestar/api/beacon/server";
|
|
6
7
|
import {BeaconConfig} from "@lodestar/config";
|
|
7
8
|
import type {LoggerNode} from "@lodestar/logger/node";
|
|
8
9
|
import {ZERO_HASH_HEX} from "@lodestar/params";
|
|
9
|
-
import {IBeaconStateView,
|
|
10
|
+
import {IBeaconStateView, isStatePostBellatrix, isStatePostGloas} from "@lodestar/state-transition";
|
|
10
11
|
import {phase0} from "@lodestar/types";
|
|
11
12
|
import {sleep, toRootHex} from "@lodestar/utils";
|
|
12
13
|
import {ProcessShutdownCallback} from "@lodestar/validator";
|
package/src/sync/types.ts
CHANGED
|
@@ -77,7 +77,9 @@ export type PendingPayloadInput = {
|
|
|
77
77
|
export type PendingPayloadRootHex = {
|
|
78
78
|
status: PendingPayloadInputStatus.pending | PendingPayloadInputStatus.fetching;
|
|
79
79
|
rootHex: RootHex;
|
|
80
|
-
//
|
|
80
|
+
// Trusted slot only (fork choice / validated data), may be missing until resolved. NOT the gossip
|
|
81
|
+
// message slot from ChainEvent.unknownEnvelopeBlockRoot, which is untrusted and not necessarily the
|
|
82
|
+
// payload/block slot. See BlockInputSync.resolvePayloadSlot.
|
|
81
83
|
slot?: Slot;
|
|
82
84
|
timeAddedSec: number;
|
|
83
85
|
timeSyncedSec?: number;
|
package/src/sync/unknownBlock.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
3
|
+
import {CheckpointWithHex} from "@lodestar/fork-choice";
|
|
3
4
|
import {ForkSeq, isForkPostGloas} from "@lodestar/params";
|
|
4
5
|
import {RequestError, RequestErrorCode} from "@lodestar/reqresp";
|
|
5
6
|
import {computeTimeAtSlot} from "@lodestar/state-transition";
|
|
@@ -154,6 +155,7 @@ export class BlockInputSync {
|
|
|
154
155
|
this.chain.emitter.on(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
|
|
155
156
|
this.chain.emitter.on(ChainEvent.incompletePayloadEnvelope, this.onIncompletePayloadEnvelope);
|
|
156
157
|
this.chain.emitter.on(ChainEvent.blockUnknownParent, this.onUnknownParent);
|
|
158
|
+
this.chain.emitter.on(ChainEvent.forkChoiceFinalized, this.pruneFinalized);
|
|
157
159
|
this.chain.emitter.on(routes.events.EventType.block, this.onBlockImported);
|
|
158
160
|
this.chain.emitter.on(routes.events.EventType.executionPayload, this.onPayloadImported);
|
|
159
161
|
this.network.events.on(NetworkEvent.peerConnected, this.onPeerConnected);
|
|
@@ -170,6 +172,7 @@ export class BlockInputSync {
|
|
|
170
172
|
this.chain.emitter.off(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
|
|
171
173
|
this.chain.emitter.off(ChainEvent.incompletePayloadEnvelope, this.onIncompletePayloadEnvelope);
|
|
172
174
|
this.chain.emitter.off(ChainEvent.blockUnknownParent, this.onUnknownParent);
|
|
175
|
+
this.chain.emitter.off(ChainEvent.forkChoiceFinalized, this.pruneFinalized);
|
|
173
176
|
this.chain.emitter.off(routes.events.EventType.block, this.onBlockImported);
|
|
174
177
|
this.chain.emitter.off(routes.events.EventType.executionPayload, this.onPayloadImported);
|
|
175
178
|
this.network.events.off(NetworkEvent.peerConnected, this.onPeerConnected);
|
|
@@ -215,7 +218,7 @@ export class BlockInputSync {
|
|
|
215
218
|
|
|
216
219
|
private onUnknownEnvelopeBlockRoot = (data: ChainEventData[ChainEvent.unknownEnvelopeBlockRoot]): void => {
|
|
217
220
|
try {
|
|
218
|
-
this.addByPayloadRootHex(data.rootHex, data.peer, data.
|
|
221
|
+
this.addByPayloadRootHex(data.rootHex, data.peer, this.resolvePayloadSlot(data.rootHex));
|
|
219
222
|
this.triggerUnknownBlockSearch();
|
|
220
223
|
this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.UNKNOWN_PAYLOAD_BLOCK_ROOT});
|
|
221
224
|
this.metrics?.blockInputSync.payloadSource.inc({source: data.source});
|
|
@@ -258,7 +261,7 @@ export class BlockInputSync {
|
|
|
258
261
|
}
|
|
259
262
|
|
|
260
263
|
if (missingDependency.kind === "parentPayload") {
|
|
261
|
-
this.addByPayloadRootHex(missingDependency.rootHex, data.peer);
|
|
264
|
+
this.addByPayloadRootHex(missingDependency.rootHex, data.peer, missingDependency.slot);
|
|
262
265
|
} else if (missingDependency.kind === "parentBlock") {
|
|
263
266
|
this.addByRootHex(missingDependency.rootHex, data.peer);
|
|
264
267
|
}
|
|
@@ -284,6 +287,61 @@ export class BlockInputSync {
|
|
|
284
287
|
this.triggerUnknownBlockSearch();
|
|
285
288
|
};
|
|
286
289
|
|
|
290
|
+
/**
|
|
291
|
+
* Drop pending payloads and blocks that fell below the finalized slot.
|
|
292
|
+
* See https://github.com/ChainSafe/lodestar/issues/9800
|
|
293
|
+
*/
|
|
294
|
+
private pruneFinalized = (checkpoint: CheckpointWithHex): void => {
|
|
295
|
+
// Use the actual finalized block slot, not computeStartSlotAtEpoch(checkpoint.epoch)
|
|
296
|
+
// because the payload at the finalized block is not finalized
|
|
297
|
+
const finalizedSlot = this.chain.forkChoice.getFinalizedBlock().slot;
|
|
298
|
+
|
|
299
|
+
let deletedPayloads = 0;
|
|
300
|
+
let unresolvedSlotPayloads = 0;
|
|
301
|
+
for (const [rootHex, payload] of this.pendingPayloads) {
|
|
302
|
+
// Last-effort resolve for a slot-less PendingPayloadRootHex, and store it back for later passes.
|
|
303
|
+
if (!isPendingPayloadInput(payload) && !isPendingPayloadEnvelope(payload) && payload.slot === undefined) {
|
|
304
|
+
payload.slot = this.resolvePayloadSlot(rootHex);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const slot = getPayloadSyncCacheItemSlot(payload);
|
|
308
|
+
if (typeof slot !== "number") {
|
|
309
|
+
unresolvedSlotPayloads++;
|
|
310
|
+
this.logger.debug("BlockInputSync.pruneFinalized: pending payload with unresolved slot", {
|
|
311
|
+
root: rootHex,
|
|
312
|
+
finalizedSlot,
|
|
313
|
+
});
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (slot < finalizedSlot) {
|
|
318
|
+
this.pendingPayloads.delete(rootHex);
|
|
319
|
+
deletedPayloads++;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
let deletedBlocks = 0;
|
|
324
|
+
for (const [rootHex, block] of this.pendingBlocks) {
|
|
325
|
+
const slot = getBlockInputSyncCacheItemSlot(block);
|
|
326
|
+
if (typeof slot === "number" && slot < finalizedSlot) {
|
|
327
|
+
this.pendingBlocks.delete(rootHex);
|
|
328
|
+
deletedBlocks++;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (deletedPayloads > 0 || deletedBlocks > 0) {
|
|
333
|
+
this.metrics?.blockInputSync.removedBlocks.inc(deletedPayloads + deletedBlocks);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
this.logger.debug("BlockInputSync.pruneFinalized dropped pre-finalized pending items", {
|
|
337
|
+
finalizedSlot,
|
|
338
|
+
finalizedRoot: checkpoint.rootHex,
|
|
339
|
+
deletedPayloads,
|
|
340
|
+
deletedBlocks,
|
|
341
|
+
unresolvedSlotPayloads,
|
|
342
|
+
});
|
|
343
|
+
};
|
|
344
|
+
|
|
287
345
|
private addByRootHex = (rootHex: RootHex, peerIdStr?: PeerIdStr): boolean => {
|
|
288
346
|
let pendingBlock = this.pendingBlocks.get(rootHex);
|
|
289
347
|
let added = false;
|
|
@@ -382,6 +440,29 @@ export class BlockInputSync {
|
|
|
382
440
|
return added;
|
|
383
441
|
};
|
|
384
442
|
|
|
443
|
+
/**
|
|
444
|
+
* Resolve the block slot for a payload root.
|
|
445
|
+
*/
|
|
446
|
+
private resolvePayloadSlot(rootHex: RootHex): Slot | undefined {
|
|
447
|
+
// a pending block of the same root
|
|
448
|
+
const pendingBlock = this.pendingBlocks.get(rootHex);
|
|
449
|
+
if (pendingBlock) {
|
|
450
|
+
const pendingBlockSlot = getBlockInputSyncCacheItemSlot(pendingBlock);
|
|
451
|
+
if (typeof pendingBlockSlot === "number") {
|
|
452
|
+
return pendingBlockSlot;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// the block is in fork choice
|
|
457
|
+
const forkChoiceSlot = this.chain.forkChoice.getBlockHexDefaultStatus(rootHex)?.slot;
|
|
458
|
+
if (forkChoiceSlot !== undefined) {
|
|
459
|
+
return forkChoiceSlot;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// a seen payload envelope input
|
|
463
|
+
return this.chain.seenPayloadEnvelopeInputCache.get(rootHex)?.slot;
|
|
464
|
+
}
|
|
465
|
+
|
|
385
466
|
private addByPayloadInput = (
|
|
386
467
|
payloadInput: PayloadEnvelopeInput,
|
|
387
468
|
peerIdStr?: PeerIdStr,
|
|
@@ -436,10 +517,12 @@ export class BlockInputSync {
|
|
|
436
517
|
blockInput: IBlockInput
|
|
437
518
|
):
|
|
438
519
|
| {kind: "ready"}
|
|
439
|
-
| {kind: "block" | "parentBlock"
|
|
520
|
+
| {kind: "block" | "parentBlock"; rootHex: RootHex}
|
|
521
|
+
| {kind: "parentPayload"; rootHex: RootHex; slot: Slot}
|
|
440
522
|
| {kind: "invalidParentPayload"; parentRootHex: RootHex; parentBlockHashHex: RootHex} {
|
|
441
523
|
const parentRootHex = blockInput.parentRootHex;
|
|
442
|
-
|
|
524
|
+
const parentBlock = this.chain.forkChoice.getBlockHexDefaultStatus(parentRootHex);
|
|
525
|
+
if (!parentBlock) {
|
|
443
526
|
return {kind: "parentBlock", rootHex: parentRootHex};
|
|
444
527
|
}
|
|
445
528
|
|
|
@@ -464,13 +547,13 @@ export class BlockInputSync {
|
|
|
464
547
|
const parentPayloadInput = this.chain.seenPayloadEnvelopeInputCache.get(parentRootHex);
|
|
465
548
|
if (parentPayloadInput) {
|
|
466
549
|
if (parentPayloadInput.getBlockHashHex() === parentBlockHashHex) {
|
|
467
|
-
return {kind: "parentPayload", rootHex: parentRootHex};
|
|
550
|
+
return {kind: "parentPayload", rootHex: parentRootHex, slot: parentBlock.slot};
|
|
468
551
|
}
|
|
469
552
|
|
|
470
553
|
return {kind: "invalidParentPayload", parentRootHex, parentBlockHashHex};
|
|
471
554
|
}
|
|
472
555
|
|
|
473
|
-
return {kind: "parentPayload", rootHex: parentRootHex};
|
|
556
|
+
return {kind: "parentPayload", rootHex: parentRootHex, slot: parentBlock.slot};
|
|
474
557
|
}
|
|
475
558
|
|
|
476
559
|
private advancePendingBlock(pendingBlock: PendingBlockInput): AdvancePendingBlockResult {
|
|
@@ -493,9 +576,9 @@ export class BlockInputSync {
|
|
|
493
576
|
}
|
|
494
577
|
|
|
495
578
|
case "parentPayload": {
|
|
496
|
-
let added = this.addByPayloadRootHex(missingDependency.rootHex);
|
|
579
|
+
let added = this.addByPayloadRootHex(missingDependency.rootHex, undefined, missingDependency.slot);
|
|
497
580
|
for (const peerIdStr of pendingBlock.peerIdStrings) {
|
|
498
|
-
added = this.addByPayloadRootHex(missingDependency.rootHex, peerIdStr) || added;
|
|
581
|
+
added = this.addByPayloadRootHex(missingDependency.rootHex, peerIdStr, missingDependency.slot) || added;
|
|
499
582
|
}
|
|
500
583
|
return added ? "queued_parent_payload" : "blocked";
|
|
501
584
|
}
|
|
@@ -928,6 +1011,7 @@ export class BlockInputSync {
|
|
|
928
1011
|
const pendingPayloadByRoot: PendingPayloadRootHex = {
|
|
929
1012
|
status: PendingPayloadInputStatus.pending,
|
|
930
1013
|
rootHex,
|
|
1014
|
+
slot: pendingPayload.envelope.message.payload.slotNumber,
|
|
931
1015
|
timeAddedSec: pendingPayload.timeAddedSec,
|
|
932
1016
|
peerIdStrings: new Set(pendingPayload.peerIdStrings),
|
|
933
1017
|
};
|
|
@@ -967,6 +1051,10 @@ export class BlockInputSync {
|
|
|
967
1051
|
return;
|
|
968
1052
|
}
|
|
969
1053
|
|
|
1054
|
+
if (!isPendingPayloadInput(payload) && payload.slot === undefined) {
|
|
1055
|
+
payload.slot = this.resolvePayloadSlot(rootHex);
|
|
1056
|
+
}
|
|
1057
|
+
|
|
970
1058
|
const payloadSlot = getPayloadSyncCacheItemSlot(payload);
|
|
971
1059
|
const logCtx = {
|
|
972
1060
|
slot: payloadSlot,
|
|
@@ -982,7 +1070,13 @@ export class BlockInputSync {
|
|
|
982
1070
|
const res = await wrapError(this.fetchPayloadInput(payload));
|
|
983
1071
|
if (!res.err) {
|
|
984
1072
|
const pendingPayload = res.result;
|
|
985
|
-
|
|
1073
|
+
const resultRootHex = getPayloadSyncCacheItemRootHex(pendingPayload);
|
|
1074
|
+
// finalization may have deleted this entry while we were awaiting the network, do not resurrect it via the set below
|
|
1075
|
+
if (!this.pendingPayloads.has(resultRootHex)) {
|
|
1076
|
+
this.logger.verbose("Dropping downloaded payload, entry pruned during fetch", logCtx);
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
this.pendingPayloads.set(resultRootHex, pendingPayload);
|
|
986
1080
|
|
|
987
1081
|
if (isPendingPayloadEnvelope(pendingPayload)) {
|
|
988
1082
|
await this.reconcilePayloadEnvelope(pendingPayload);
|
|
@@ -1110,9 +1204,11 @@ export class BlockInputSync {
|
|
|
1110
1204
|
);
|
|
1111
1205
|
}
|
|
1112
1206
|
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1207
|
+
const reason =
|
|
1208
|
+
pendingColumns.size > 0
|
|
1209
|
+
? `cannot find peer with needed columns=${prettyPrintIndices(Array.from(pendingColumns))}`
|
|
1210
|
+
: "no peer available to download pending payload";
|
|
1211
|
+
throw Error(`Error fetching payload by root slot=${slot} root=${rootHex} after ${i}: ${reason}`);
|
|
1116
1212
|
}
|
|
1117
1213
|
|
|
1118
1214
|
const {peerId, client: peerClient} = peerMeta;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { PublicKey } from "@chainsafe/blst";
|
|
2
|
-
export type SignatureSetDeserialized = {
|
|
3
|
-
publicKey: PublicKey;
|
|
4
|
-
message: Uint8Array;
|
|
5
|
-
signature: Uint8Array;
|
|
6
|
-
};
|
|
7
|
-
/**
|
|
8
|
-
* Verify signatures sets with batch verification or regular core verify depending on the set count.
|
|
9
|
-
* Abstracted in a separate file to be consumed by the threaded pool and the main thread implementation.
|
|
10
|
-
*/
|
|
11
|
-
export declare function verifySignatureSetsMaybeBatch(sets: SignatureSetDeserialized[]): boolean;
|
|
12
|
-
//# sourceMappingURL=maybeBatch.d.ts.map
|