@lodestar/beacon-node 1.47.0-dev.2a04194b90 → 1.47.0-dev.2fba076c28
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 +6 -8
- 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 +25 -2
- 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 +12 -3
- package/lib/api/impl/events/index.js.map +1 -1
- package/lib/api/impl/lodestar/index.js +1 -1
- package/lib/api/impl/lodestar/index.js.map +1 -1
- package/lib/api/impl/validator/index.js +1 -1
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/api/rest/base.d.ts.map +1 -1
- package/lib/api/rest/base.js +7 -0
- package/lib/api/rest/base.js.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js +1 -1
- package/lib/chain/archiveStore/archiveStore.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 +14 -6
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +2 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +6 -2
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +14 -5
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/types.js +5 -0
- package/lib/chain/blocks/payloadEnvelopeInput/types.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 -6
- package/lib/chain/builderCircuitBreaker.d.ts.map +1 -1
- package/lib/chain/builderCircuitBreaker.js +19 -17
- package/lib/chain/builderCircuitBreaker.js.map +1 -1
- package/lib/chain/chain.d.ts +4 -2
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +16 -6
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/errors/blockError.d.ts +1 -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/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +4 -0
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/interface.d.ts +4 -2
- 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/deferredVoluntaryExitPool.d.ts +16 -0
- package/lib/chain/opPools/deferredVoluntaryExitPool.d.ts.map +1 -0
- package/lib/chain/opPools/deferredVoluntaryExitPool.js +57 -0
- package/lib/chain/opPools/deferredVoluntaryExitPool.js.map +1 -0
- package/lib/chain/opPools/index.d.ts +1 -0
- package/lib/chain/opPools/index.d.ts.map +1 -1
- package/lib/chain/opPools/index.js +1 -0
- package/lib/chain/opPools/index.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.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +24 -6
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/regen/interface.d.ts +4 -2
- package/lib/chain/regen/interface.d.ts.map +1 -1
- package/lib/chain/regen/interface.js +2 -0
- package/lib/chain/regen/interface.js.map +1 -1
- package/lib/chain/regen/queued.d.ts +2 -2
- package/lib/chain/regen/queued.d.ts.map +1 -1
- package/lib/chain/regen/queued.js +5 -5
- package/lib/chain/regen/queued.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/seenPayloadEnvelopeInput.d.ts +28 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +121 -13
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
- package/lib/chain/stateCache/fifoBlockStateCache.d.ts +5 -1
- package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
- package/lib/chain/stateCache/fifoBlockStateCache.js +6 -0
- package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +47 -5
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +117 -7
- package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
- package/lib/chain/stateCache/types.d.ts +3 -3
- package/lib/chain/stateCache/types.d.ts.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/chain/validation/voluntaryExit.d.ts +9 -1
- package/lib/chain/validation/voluntaryExit.d.ts.map +1 -1
- package/lib/chain/validation/voluntaryExit.js +46 -1
- package/lib/chain/validation/voluntaryExit.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 +72 -22
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +130 -52
- 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 +12 -3
- 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/deferredVoluntaryExitPublisher.d.ts +15 -0
- package/lib/node/deferredVoluntaryExitPublisher.d.ts.map +1 -0
- package/lib/node/deferredVoluntaryExitPublisher.js +38 -0
- package/lib/node/deferredVoluntaryExitPublisher.js.map +1 -0
- package/lib/node/nodejs.d.ts +2 -1
- package/lib/node/nodejs.d.ts.map +1 -1
- package/lib/node/nodejs.js +2 -0
- 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 +32 -0
- package/lib/sync/types.d.ts.map +1 -1
- package/lib/sync/types.js +33 -0
- 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 +173 -45
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRange.js +16 -11
- package/lib/sync/utils/downloadByRange.js.map +1 -1
- package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRoot.js +3 -1
- package/lib/sync/utils/downloadByRoot.js.map +1 -1
- package/package.json +35 -35
- package/src/api/impl/beacon/blocks/index.ts +7 -8
- package/src/api/impl/beacon/pool/index.ts +27 -2
- package/src/api/impl/beacon/state/utils.ts +2 -1
- package/src/api/impl/events/index.ts +12 -4
- package/src/api/impl/lodestar/index.ts +1 -1
- package/src/api/impl/validator/index.ts +1 -1
- package/src/api/rest/base.ts +7 -0
- package/src/chain/archiveStore/archiveStore.ts +1 -1
- 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 +18 -6
- package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +8 -2
- package/src/chain/blocks/payloadEnvelopeInput/types.ts +17 -4
- 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 +22 -19
- package/src/chain/chain.ts +17 -6
- package/src/chain/errors/blockError.ts +8 -2
- package/src/chain/errors/proposerPreferences.ts +7 -0
- package/src/chain/forkChoice/index.ts +4 -0
- package/src/chain/interface.ts +4 -1
- package/src/chain/opPools/aggregatedAttestationPool.ts +1 -1
- package/src/chain/opPools/attestationPool.ts +1 -1
- package/src/chain/opPools/deferredVoluntaryExitPool.ts +65 -0
- package/src/chain/opPools/index.ts +1 -0
- 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 +24 -6
- package/src/chain/regen/interface.ts +4 -2
- package/src/chain/regen/queued.ts +5 -5
- package/src/chain/seenCache/seenAttesters.ts +31 -5
- package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +143 -14
- package/src/chain/stateCache/fifoBlockStateCache.ts +8 -1
- package/src/chain/stateCache/persistentCheckpointsCache.ts +133 -8
- package/src/chain/stateCache/types.ts +3 -3
- 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/chain/validation/voluntaryExit.ts +59 -2
- package/src/metrics/metrics/beacon.ts +9 -9
- package/src/metrics/metrics/lodestar.ts +142 -57
- 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 +14 -1
- package/src/network/reqresp/score.ts +5 -11
- package/src/network/util.ts +0 -5
- package/src/node/deferredVoluntaryExitPublisher.ts +54 -0
- package/src/node/nodejs.ts +5 -1
- package/src/sync/range/batch.ts +83 -28
- package/src/sync/range/chain.ts +26 -11
- package/src/sync/types.ts +36 -1
- package/src/sync/unknownBlock.ts +197 -51
- package/src/sync/utils/downloadByRange.ts +21 -12
- package/src/sync/utils/downloadByRoot.ts +3 -1
- 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
package/lib/sync/unknownBlock.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { routes } from "@lodestar/api";
|
|
2
|
-
import { ForkSeq, isForkPostGloas } from "@lodestar/params";
|
|
2
|
+
import { ForkSeq, SLOTS_PER_EPOCH, isForkPostGloas } from "@lodestar/params";
|
|
3
3
|
import { RequestError, RequestErrorCode } from "@lodestar/reqresp";
|
|
4
4
|
import { computeTimeAtSlot } from "@lodestar/state-transition";
|
|
5
5
|
import { fromHex, prettyPrintIndices, pruneSetToMax, sleep, toRootHex } from "@lodestar/utils";
|
|
@@ -16,13 +16,17 @@ import { shuffle } from "../util/shuffle.js";
|
|
|
16
16
|
import { sortBy } from "../util/sortBy.js";
|
|
17
17
|
import { wrapError } from "../util/wrapError.js";
|
|
18
18
|
import { MAX_CONCURRENT_REQUESTS } from "./constants.js";
|
|
19
|
-
import { PendingBlockInputStatus, PendingBlockType, PendingPayloadInputStatus, getBlockInputSyncCacheItemRootHex, getBlockInputSyncCacheItemSlot, getPayloadSyncCacheItemRootHex, getPayloadSyncCacheItemSlot, isPendingBlockInput, isPendingPayloadEnvelope, isPendingPayloadInput, } from "./types.js";
|
|
19
|
+
import { DroppedItemReason, PendingBlockInputStatus, PendingBlockType, PendingPayloadInputStatus, getBlockInputSyncCacheItemRootHex, getBlockInputSyncCacheItemSlot, getPayloadSyncCacheItemRootHex, getPayloadSyncCacheItemSlot, isPendingBlockInput, isPendingPayloadEnvelope, isPendingPayloadInput, } from "./types.js";
|
|
20
20
|
import { DownloadByRootError, downloadByRoot } from "./utils/downloadByRoot.js";
|
|
21
21
|
import { getAllDescendantBlocks, getUnknownAndAncestorBlocks } from "./utils/pendingBlocksTree.js";
|
|
22
22
|
import { getRateLimitedUntilMs } from "./utils/rateLimit.js";
|
|
23
23
|
const MAX_ATTEMPTS_PER_BLOCK = 5;
|
|
24
24
|
const MAX_KNOWN_BAD_BLOCKS = 500;
|
|
25
25
|
const MAX_PENDING_BLOCKS = 100;
|
|
26
|
+
/**
|
|
27
|
+
* A pending payload without slot can only stay at most 2 epochs.
|
|
28
|
+
*/
|
|
29
|
+
const PRUNE_UNRESOLVED_SLOT_EPOCHS = 2;
|
|
26
30
|
var FetchResult;
|
|
27
31
|
(function (FetchResult) {
|
|
28
32
|
FetchResult["SuccessResolved"] = "success_resolved";
|
|
@@ -115,6 +119,7 @@ export class BlockInputSync {
|
|
|
115
119
|
this.chain.emitter.on(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
|
|
116
120
|
this.chain.emitter.on(ChainEvent.incompletePayloadEnvelope, this.onIncompletePayloadEnvelope);
|
|
117
121
|
this.chain.emitter.on(ChainEvent.blockUnknownParent, this.onUnknownParent);
|
|
122
|
+
this.chain.emitter.on(ChainEvent.forkChoiceFinalized, this.pruneFinalized);
|
|
118
123
|
this.chain.emitter.on(routes.events.EventType.block, this.onBlockImported);
|
|
119
124
|
this.chain.emitter.on(routes.events.EventType.executionPayload, this.onPayloadImported);
|
|
120
125
|
this.network.events.on(NetworkEvent.peerConnected, this.onPeerConnected);
|
|
@@ -130,6 +135,7 @@ export class BlockInputSync {
|
|
|
130
135
|
this.chain.emitter.off(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
|
|
131
136
|
this.chain.emitter.off(ChainEvent.incompletePayloadEnvelope, this.onIncompletePayloadEnvelope);
|
|
132
137
|
this.chain.emitter.off(ChainEvent.blockUnknownParent, this.onUnknownParent);
|
|
138
|
+
this.chain.emitter.off(ChainEvent.forkChoiceFinalized, this.pruneFinalized);
|
|
133
139
|
this.chain.emitter.off(routes.events.EventType.block, this.onBlockImported);
|
|
134
140
|
this.chain.emitter.off(routes.events.EventType.executionPayload, this.onPayloadImported);
|
|
135
141
|
this.network.events.off(NetworkEvent.peerConnected, this.onPeerConnected);
|
|
@@ -172,7 +178,7 @@ export class BlockInputSync {
|
|
|
172
178
|
};
|
|
173
179
|
onUnknownEnvelopeBlockRoot = (data) => {
|
|
174
180
|
try {
|
|
175
|
-
this.addByPayloadRootHex(data.rootHex, data.peer, data.
|
|
181
|
+
this.addByPayloadRootHex(data.rootHex, data.peer, this.resolvePayloadSlot(data.rootHex));
|
|
176
182
|
this.triggerUnknownBlockSearch();
|
|
177
183
|
this.metrics?.blockInputSync.requests.inc({ type: PendingBlockType.UNKNOWN_PAYLOAD_BLOCK_ROOT });
|
|
178
184
|
this.metrics?.blockInputSync.payloadSource.inc({ source: data.source });
|
|
@@ -208,12 +214,12 @@ export class BlockInputSync {
|
|
|
208
214
|
parentRoot: missingDependency.parentRootHex,
|
|
209
215
|
parentBlockHash: missingDependency.parentBlockHashHex,
|
|
210
216
|
});
|
|
211
|
-
this.removeAndDownScoreAllDescendants(pendingBlock);
|
|
217
|
+
this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidParentPayload);
|
|
212
218
|
}
|
|
213
219
|
return;
|
|
214
220
|
}
|
|
215
221
|
if (missingDependency.kind === "parentPayload") {
|
|
216
|
-
this.addByPayloadRootHex(missingDependency.rootHex, data.peer);
|
|
222
|
+
this.addByPayloadRootHex(missingDependency.rootHex, data.peer, missingDependency.slot);
|
|
217
223
|
}
|
|
218
224
|
else if (missingDependency.kind === "parentBlock") {
|
|
219
225
|
this.addByRootHex(missingDependency.rootHex, data.peer);
|
|
@@ -236,6 +242,71 @@ export class BlockInputSync {
|
|
|
236
242
|
this.pendingPayloads.delete(blockRoot);
|
|
237
243
|
this.triggerUnknownBlockSearch();
|
|
238
244
|
};
|
|
245
|
+
/**
|
|
246
|
+
* Drop pending payloads and blocks that fell below the finalized slot.
|
|
247
|
+
* See https://github.com/ChainSafe/lodestar/issues/9800
|
|
248
|
+
*/
|
|
249
|
+
pruneFinalized = (checkpoint) => {
|
|
250
|
+
// Use the actual finalized block slot, not computeStartSlotAtEpoch(checkpoint.epoch)
|
|
251
|
+
// because the payload at the finalized block is not finalized
|
|
252
|
+
const finalizedSlot = this.chain.forkChoice.getFinalizedBlock().slot;
|
|
253
|
+
const nowSec = Date.now() / 1000;
|
|
254
|
+
const maxSecInCache = (PRUNE_UNRESOLVED_SLOT_EPOCHS * SLOTS_PER_EPOCH * this.config.SLOT_DURATION_MS) / 1000;
|
|
255
|
+
let belowFinalizedPayloads = 0;
|
|
256
|
+
let agedOutPayloads = 0;
|
|
257
|
+
let unresolvedSlotPayloads = 0;
|
|
258
|
+
for (const [rootHex, payload] of this.pendingPayloads) {
|
|
259
|
+
// Last-effort resolve for a slot-less PendingPayloadRootHex, and store it back for later passes.
|
|
260
|
+
if (!isPendingPayloadInput(payload) && !isPendingPayloadEnvelope(payload) && payload.slot === undefined) {
|
|
261
|
+
payload.slot = this.resolvePayloadSlot(rootHex);
|
|
262
|
+
if (payload.slot === undefined) {
|
|
263
|
+
// Still unresolvable: age it out so the MAX_PENDING_BLOCKS cap cannot stay saturated.
|
|
264
|
+
if (nowSec - payload.timeAddedSec > maxSecInCache) {
|
|
265
|
+
this.pendingPayloads.delete(rootHex);
|
|
266
|
+
agedOutPayloads++;
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
unresolvedSlotPayloads++;
|
|
270
|
+
this.logger.debug("BlockInputSync.pruneFinalized: pending payload with unresolved slot", {
|
|
271
|
+
root: rootHex,
|
|
272
|
+
finalizedSlot,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
const slot = getPayloadSyncCacheItemSlot(payload);
|
|
279
|
+
if (typeof slot === "number" && slot < finalizedSlot) {
|
|
280
|
+
this.pendingPayloads.delete(rootHex);
|
|
281
|
+
belowFinalizedPayloads++;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
let deletedBlocks = 0;
|
|
285
|
+
for (const [rootHex, block] of this.pendingBlocks) {
|
|
286
|
+
const slot = getBlockInputSyncCacheItemSlot(block);
|
|
287
|
+
if (typeof slot === "number" && slot < finalizedSlot) {
|
|
288
|
+
this.pendingBlocks.delete(rootHex);
|
|
289
|
+
deletedBlocks++;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if (belowFinalizedPayloads > 0) {
|
|
293
|
+
this.metrics?.blockInputSync.removedPayloads.inc({ reason: DroppedItemReason.belowFinalized }, belowFinalizedPayloads);
|
|
294
|
+
}
|
|
295
|
+
if (agedOutPayloads > 0) {
|
|
296
|
+
this.metrics?.blockInputSync.removedPayloads.inc({ reason: DroppedItemReason.agedOut }, agedOutPayloads);
|
|
297
|
+
}
|
|
298
|
+
if (deletedBlocks > 0) {
|
|
299
|
+
this.metrics?.blockInputSync.removedBlocks.inc({ reason: DroppedItemReason.belowFinalized }, deletedBlocks);
|
|
300
|
+
}
|
|
301
|
+
this.logger.debug("BlockInputSync.pruneFinalized dropped pre-finalized pending items", {
|
|
302
|
+
finalizedSlot,
|
|
303
|
+
finalizedRoot: checkpoint.rootHex,
|
|
304
|
+
belowFinalizedPayloads,
|
|
305
|
+
agedOutPayloads,
|
|
306
|
+
deletedBlocks,
|
|
307
|
+
unresolvedSlotPayloads,
|
|
308
|
+
});
|
|
309
|
+
};
|
|
239
310
|
addByRootHex = (rootHex, peerIdStr) => {
|
|
240
311
|
let pendingBlock = this.pendingBlocks.get(rootHex);
|
|
241
312
|
let added = false;
|
|
@@ -260,6 +331,7 @@ export class BlockInputSync {
|
|
|
260
331
|
// Limit pending blocks to prevent DOS attacks that cause OOM
|
|
261
332
|
const prunedItemCount = pruneSetToMax(this.pendingBlocks, this.maxPendingBlocks);
|
|
262
333
|
if (prunedItemCount > 0) {
|
|
334
|
+
this.metrics?.blockInputSync.removedBlocks.inc({ reason: DroppedItemReason.capacity }, prunedItemCount);
|
|
263
335
|
this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingBlocks`);
|
|
264
336
|
}
|
|
265
337
|
return added;
|
|
@@ -290,6 +362,7 @@ export class BlockInputSync {
|
|
|
290
362
|
// Limit pending blocks to prevent DOS attacks that cause OOM
|
|
291
363
|
const prunedItemCount = pruneSetToMax(this.pendingBlocks, this.maxPendingBlocks);
|
|
292
364
|
if (prunedItemCount > 0) {
|
|
365
|
+
this.metrics?.blockInputSync.removedBlocks.inc({ reason: DroppedItemReason.capacity }, prunedItemCount);
|
|
293
366
|
this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingBlocks`);
|
|
294
367
|
}
|
|
295
368
|
};
|
|
@@ -313,15 +386,44 @@ export class BlockInputSync {
|
|
|
313
386
|
peerIdStr: peerIdStr ?? "unknown peer",
|
|
314
387
|
});
|
|
315
388
|
}
|
|
389
|
+
else if (
|
|
390
|
+
// update a previously slot-less entry once a slot becomes available
|
|
391
|
+
slot !== undefined &&
|
|
392
|
+
!isPendingPayloadInput(pendingPayload) &&
|
|
393
|
+
!isPendingPayloadEnvelope(pendingPayload) &&
|
|
394
|
+
pendingPayload.slot === undefined) {
|
|
395
|
+
pendingPayload.slot = slot;
|
|
396
|
+
}
|
|
316
397
|
if (peerIdStr) {
|
|
317
398
|
pendingPayload.peerIdStrings.add(peerIdStr);
|
|
318
399
|
}
|
|
319
400
|
const prunedItemCount = pruneSetToMax(this.pendingPayloads, this.maxPendingBlocks);
|
|
320
401
|
if (prunedItemCount > 0) {
|
|
402
|
+
this.metrics?.blockInputSync.removedPayloads.inc({ reason: DroppedItemReason.capacity }, prunedItemCount);
|
|
321
403
|
this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingPayloads`);
|
|
322
404
|
}
|
|
323
405
|
return added;
|
|
324
406
|
};
|
|
407
|
+
/**
|
|
408
|
+
* Resolve the block slot for a payload root.
|
|
409
|
+
*/
|
|
410
|
+
resolvePayloadSlot(rootHex) {
|
|
411
|
+
// a pending block of the same root
|
|
412
|
+
const pendingBlock = this.pendingBlocks.get(rootHex);
|
|
413
|
+
if (pendingBlock) {
|
|
414
|
+
const pendingBlockSlot = getBlockInputSyncCacheItemSlot(pendingBlock);
|
|
415
|
+
if (typeof pendingBlockSlot === "number") {
|
|
416
|
+
return pendingBlockSlot;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
// the block is in fork choice
|
|
420
|
+
const forkChoiceSlot = this.chain.forkChoice.getBlockHexDefaultStatus(rootHex)?.slot;
|
|
421
|
+
if (forkChoiceSlot !== undefined) {
|
|
422
|
+
return forkChoiceSlot;
|
|
423
|
+
}
|
|
424
|
+
// a seen payload envelope input
|
|
425
|
+
return this.chain.seenPayloadEnvelopeInputCache.get(rootHex)?.slot;
|
|
426
|
+
}
|
|
325
427
|
addByPayloadInput = (payloadInput, peerIdStr, envelope) => {
|
|
326
428
|
const pendingPayload = this.toPendingPayloadInput(payloadInput, this.pendingPayloads.get(payloadInput.blockRootHex), envelope);
|
|
327
429
|
if (peerIdStr) {
|
|
@@ -335,6 +437,7 @@ export class BlockInputSync {
|
|
|
335
437
|
});
|
|
336
438
|
const prunedItemCount = pruneSetToMax(this.pendingPayloads, this.maxPendingBlocks);
|
|
337
439
|
if (prunedItemCount > 0) {
|
|
440
|
+
this.metrics?.blockInputSync.removedPayloads.inc({ reason: DroppedItemReason.capacity }, prunedItemCount);
|
|
338
441
|
this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingPayloads`);
|
|
339
442
|
}
|
|
340
443
|
};
|
|
@@ -360,7 +463,8 @@ export class BlockInputSync {
|
|
|
360
463
|
*/
|
|
361
464
|
getMissingBlockDependency(blockInput) {
|
|
362
465
|
const parentRootHex = blockInput.parentRootHex;
|
|
363
|
-
|
|
466
|
+
const parentBlock = this.chain.forkChoice.getBlockHexDefaultStatus(parentRootHex);
|
|
467
|
+
if (!parentBlock) {
|
|
364
468
|
return { kind: "parentBlock", rootHex: parentRootHex };
|
|
365
469
|
}
|
|
366
470
|
if (!blockInput.hasBlock()) {
|
|
@@ -377,14 +481,8 @@ export class BlockInputSync {
|
|
|
377
481
|
if (this.chain.forkChoice.hasPayloadHexUnsafe(parentRootHex)) {
|
|
378
482
|
return { kind: "invalidParentPayload", parentRootHex, parentBlockHashHex };
|
|
379
483
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
if (parentPayloadInput.getBlockHashHex() === parentBlockHashHex) {
|
|
383
|
-
return { kind: "parentPayload", rootHex: parentRootHex };
|
|
384
|
-
}
|
|
385
|
-
return { kind: "invalidParentPayload", parentRootHex, parentBlockHashHex };
|
|
386
|
-
}
|
|
387
|
-
return { kind: "parentPayload", rootHex: parentRootHex };
|
|
484
|
+
// Parent is in fork choice but its payload `parentBlockHashHex` isn't revealed yet
|
|
485
|
+
return { kind: "parentPayload", rootHex: parentRootHex, slot: parentBlock.slot };
|
|
388
486
|
}
|
|
389
487
|
advancePendingBlock(pendingBlock) {
|
|
390
488
|
const missingDependency = this.getMissingBlockDependency(pendingBlock.blockInput);
|
|
@@ -402,9 +500,9 @@ export class BlockInputSync {
|
|
|
402
500
|
return added ? "queued_parent_block" : "blocked";
|
|
403
501
|
}
|
|
404
502
|
case "parentPayload": {
|
|
405
|
-
let added = this.addByPayloadRootHex(missingDependency.rootHex);
|
|
503
|
+
let added = this.addByPayloadRootHex(missingDependency.rootHex, undefined, missingDependency.slot);
|
|
406
504
|
for (const peerIdStr of pendingBlock.peerIdStrings) {
|
|
407
|
-
added = this.addByPayloadRootHex(missingDependency.rootHex, peerIdStr) || added;
|
|
505
|
+
added = this.addByPayloadRootHex(missingDependency.rootHex, peerIdStr, missingDependency.slot) || added;
|
|
408
506
|
}
|
|
409
507
|
return added ? "queued_parent_payload" : "blocked";
|
|
410
508
|
}
|
|
@@ -415,7 +513,7 @@ export class BlockInputSync {
|
|
|
415
513
|
parentRoot: missingDependency.parentRootHex,
|
|
416
514
|
parentBlockHash: missingDependency.parentBlockHashHex,
|
|
417
515
|
});
|
|
418
|
-
this.removeAndDownScoreAllDescendants(pendingBlock);
|
|
516
|
+
this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidParentPayload);
|
|
419
517
|
return "removed";
|
|
420
518
|
}
|
|
421
519
|
}
|
|
@@ -604,7 +702,7 @@ export class BlockInputSync {
|
|
|
604
702
|
...logCtx2,
|
|
605
703
|
finalizedSlot,
|
|
606
704
|
});
|
|
607
|
-
this.removeAndDownScoreAllDescendants(block);
|
|
705
|
+
this.removeAndDownScoreAllDescendants(block, DroppedItemReason.belowFinalized);
|
|
608
706
|
}
|
|
609
707
|
else {
|
|
610
708
|
this.onUnknownBlockRoot({ rootHex: pending.blockInput.parentRootHex, source: BlockInputSource.byRoot });
|
|
@@ -622,7 +720,7 @@ export class BlockInputSync {
|
|
|
622
720
|
}
|
|
623
721
|
this.metrics?.blockInputSync.downloadedBlocksError.inc();
|
|
624
722
|
this.logger.debug("Ignoring unknown block root after many failed downloads", logCtx, res.err);
|
|
625
|
-
this.removeAndDownScoreAllDescendants(block);
|
|
723
|
+
this.removeAndDownScoreAllDescendants(block, DroppedItemReason.unavailable);
|
|
626
724
|
}
|
|
627
725
|
}
|
|
628
726
|
/**
|
|
@@ -679,9 +777,9 @@ export class BlockInputSync {
|
|
|
679
777
|
// no need to update status to "processed", delete anyway
|
|
680
778
|
this.pendingBlocks.delete(blockRootHex);
|
|
681
779
|
if (isForkPostGloas(fork)) {
|
|
682
|
-
const payloadInput = this.chain.seenPayloadEnvelopeInputCache.
|
|
780
|
+
const payloadInput = await this.chain.seenPayloadEnvelopeInputCache.getOrReload(blockRootHex);
|
|
683
781
|
if (!payloadInput) {
|
|
684
|
-
this.logger.
|
|
782
|
+
this.logger.debug("PayloadEnvelopeInput unavailable during unknown sync processReadyBlock()", logCtx);
|
|
685
783
|
}
|
|
686
784
|
else {
|
|
687
785
|
// Similar to the gossip path: immediately attempt fetch of data columns from the execution engine.
|
|
@@ -717,17 +815,17 @@ export class BlockInputSync {
|
|
|
717
815
|
case BlockErrorCode.EXECUTION_ENGINE_ERROR:
|
|
718
816
|
// Removing the block(s) without penalizing the peers, hoping for EL to
|
|
719
817
|
// recover on a latter download + verify attempt.
|
|
720
|
-
this.removeAllDescendants(pendingBlock);
|
|
818
|
+
this.removeAllDescendants(pendingBlock, DroppedItemReason.elError, DroppedItemReason.elError);
|
|
721
819
|
break;
|
|
722
820
|
case BlockErrorCode.EXECUTION_ENGINE_INVALID:
|
|
723
821
|
// the peer served a bad block
|
|
724
822
|
this.logger.debug("Execution engine rejected block from unknown parent sync", errorData, res.err);
|
|
725
|
-
this.removeAndDownScoreAllDescendants(pendingBlock);
|
|
823
|
+
this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.elInvalid);
|
|
726
824
|
break;
|
|
727
825
|
default:
|
|
728
826
|
// Block is not correct with respect to our chain. Log error loudly
|
|
729
827
|
this.logger.debug("Error processing block from unknown parent sync", errorData, res.err);
|
|
730
|
-
this.removeAndDownScoreAllDescendants(pendingBlock);
|
|
828
|
+
this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidBlock);
|
|
731
829
|
}
|
|
732
830
|
}
|
|
733
831
|
// Probably a queue error or something unwanted happened, mark as pending to try again latter
|
|
@@ -748,7 +846,6 @@ export class BlockInputSync {
|
|
|
748
846
|
this.pendingPayloads.delete(rootHex);
|
|
749
847
|
return;
|
|
750
848
|
}
|
|
751
|
-
const payloadInput = this.chain.seenPayloadEnvelopeInputCache.get(rootHex);
|
|
752
849
|
if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
|
|
753
850
|
// Block not in fork choice yet. payloadInput may be seeded from the block body during download, so a
|
|
754
851
|
// non-null payloadInput does not imply the block is imported; defer regardless and pull the block first.
|
|
@@ -762,8 +859,9 @@ export class BlockInputSync {
|
|
|
762
859
|
}
|
|
763
860
|
return;
|
|
764
861
|
}
|
|
862
|
+
const payloadInput = await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
|
|
765
863
|
if (!payloadInput) {
|
|
766
|
-
this.logger.debug("
|
|
864
|
+
this.logger.debug("PayloadEnvelopeInput not yet reloadable for imported block, will retry", {
|
|
767
865
|
root: rootHex,
|
|
768
866
|
});
|
|
769
867
|
return;
|
|
@@ -775,6 +873,7 @@ export class BlockInputSync {
|
|
|
775
873
|
const pendingPayloadByRoot = {
|
|
776
874
|
status: PendingPayloadInputStatus.pending,
|
|
777
875
|
rootHex,
|
|
876
|
+
slot: pendingPayload.envelope.message.payload.slotNumber,
|
|
778
877
|
timeAddedSec: pendingPayload.timeAddedSec,
|
|
779
878
|
peerIdStrings: new Set(pendingPayload.peerIdStrings),
|
|
780
879
|
};
|
|
@@ -806,6 +905,9 @@ export class BlockInputSync {
|
|
|
806
905
|
if (payload.status !== PendingPayloadInputStatus.pending) {
|
|
807
906
|
return;
|
|
808
907
|
}
|
|
908
|
+
if (!isPendingPayloadInput(payload) && payload.slot === undefined) {
|
|
909
|
+
payload.slot = this.resolvePayloadSlot(rootHex);
|
|
910
|
+
}
|
|
809
911
|
const payloadSlot = getPayloadSyncCacheItemSlot(payload);
|
|
810
912
|
const logCtx = {
|
|
811
913
|
slot: payloadSlot,
|
|
@@ -818,7 +920,13 @@ export class BlockInputSync {
|
|
|
818
920
|
const res = await wrapError(this.fetchPayloadInput(payload));
|
|
819
921
|
if (!res.err) {
|
|
820
922
|
const pendingPayload = res.result;
|
|
821
|
-
|
|
923
|
+
const resultRootHex = getPayloadSyncCacheItemRootHex(pendingPayload);
|
|
924
|
+
// finalization may have deleted this entry while we were awaiting the network, do not resurrect it via the set below
|
|
925
|
+
if (!this.pendingPayloads.has(resultRootHex)) {
|
|
926
|
+
this.logger.verbose("Dropping downloaded payload, entry pruned during fetch", logCtx);
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
this.pendingPayloads.set(resultRootHex, pendingPayload);
|
|
822
930
|
if (isPendingPayloadEnvelope(pendingPayload)) {
|
|
823
931
|
await this.reconcilePayloadEnvelope(pendingPayload);
|
|
824
932
|
}
|
|
@@ -885,16 +993,24 @@ export class BlockInputSync {
|
|
|
885
993
|
pendingPayload.status = PendingPayloadInputStatus.downloaded;
|
|
886
994
|
break;
|
|
887
995
|
case PayloadErrorCode.EXECUTION_ENGINE_INVALID:
|
|
996
|
+
this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
|
|
997
|
+
this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.elInvalid);
|
|
998
|
+
break;
|
|
888
999
|
case PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR:
|
|
1000
|
+
this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
|
|
1001
|
+
this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.invalidEnvelope);
|
|
1002
|
+
break;
|
|
889
1003
|
case PayloadErrorCode.INVALID_SIGNATURE:
|
|
890
1004
|
// TODO GLOAS: Decide how invalid payload inputs should eventually leave memory without
|
|
891
1005
|
// reintroducing envelope replacement / recreation flows.
|
|
892
1006
|
this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
|
|
893
|
-
this.removePendingPayloadAndDescendants(rootHex);
|
|
1007
|
+
this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.invalidSignature);
|
|
894
1008
|
break;
|
|
895
1009
|
default:
|
|
896
1010
|
this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
|
|
897
|
-
this.pendingPayloads.delete(rootHex)
|
|
1011
|
+
if (this.pendingPayloads.delete(rootHex)) {
|
|
1012
|
+
this.metrics?.blockInputSync.removedPayloads.inc({ reason: DroppedItemReason.unknown }, 1);
|
|
1013
|
+
}
|
|
898
1014
|
}
|
|
899
1015
|
return;
|
|
900
1016
|
}
|
|
@@ -913,7 +1029,7 @@ export class BlockInputSync {
|
|
|
913
1029
|
let slot = getPayloadSyncCacheItemSlot(cacheItem);
|
|
914
1030
|
let payloadInput = isPendingPayloadInput(cacheItem)
|
|
915
1031
|
? cacheItem.payloadInput
|
|
916
|
-
: this.chain.seenPayloadEnvelopeInputCache.
|
|
1032
|
+
: await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
|
|
917
1033
|
let envelope = payloadInput?.hasPayloadEnvelope() ? payloadInput.getPayloadEnvelope() : undefined;
|
|
918
1034
|
let i = 0;
|
|
919
1035
|
let deferredByRateLimit = false;
|
|
@@ -926,7 +1042,10 @@ export class BlockInputSync {
|
|
|
926
1042
|
if (this.peerBalancer.getNextRateLimitRetryAt(pendingColumns, excludedPeers) !== null) {
|
|
927
1043
|
throw new UnknownBlockRateLimitedError(`Error fetching payload by root slot=${slot} root=${rootHex} after ${i}: peers with needed columns are rate-limited`);
|
|
928
1044
|
}
|
|
929
|
-
|
|
1045
|
+
const reason = pendingColumns.size > 0
|
|
1046
|
+
? `cannot find peer with needed columns=${prettyPrintIndices(Array.from(pendingColumns))}`
|
|
1047
|
+
: "no peer available to download pending payload";
|
|
1048
|
+
throw Error(`Error fetching payload by root slot=${slot} root=${rootHex} after ${i}: ${reason}`);
|
|
930
1049
|
}
|
|
931
1050
|
const { peerId, client: peerClient } = peerMeta;
|
|
932
1051
|
cacheItem.peerIdStrings.add(peerId);
|
|
@@ -935,7 +1054,7 @@ export class BlockInputSync {
|
|
|
935
1054
|
envelope = await this.fetchExecutionPayloadEnvelope(peerId, blockRoot, rootHex);
|
|
936
1055
|
slot = envelope.message.payload.slotNumber;
|
|
937
1056
|
}
|
|
938
|
-
payloadInput ??= this.chain.seenPayloadEnvelopeInputCache.
|
|
1057
|
+
payloadInput ??= await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
|
|
939
1058
|
if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
|
|
940
1059
|
// Block not in fork choice yet. Validating now would throw BLOCK_ROOT_UNKNOWN, so keep the downloaded
|
|
941
1060
|
// envelope and wait for the block body; reconcilePayloadEnvelope validates once the block lands.
|
|
@@ -1206,9 +1325,9 @@ export class BlockInputSync {
|
|
|
1206
1325
|
* Downscore all peers that have referenced any of this bad blocks. May report peers multiple times if they have
|
|
1207
1326
|
* referenced more than one bad block.
|
|
1208
1327
|
*/
|
|
1209
|
-
removeAndDownScoreAllDescendants(block) {
|
|
1328
|
+
removeAndDownScoreAllDescendants(block, headReason) {
|
|
1210
1329
|
// Get all blocks that are a descendant of this one
|
|
1211
|
-
const badPendingBlocks = this.removeAllDescendants(block);
|
|
1330
|
+
const badPendingBlocks = this.removeAllDescendants(block, headReason, DroppedItemReason.invalidParent);
|
|
1212
1331
|
// just console log and do not penalize on pending/bad blocks for debugging
|
|
1213
1332
|
// console.log("removeAndDownscoreAllDescendants", {block});
|
|
1214
1333
|
for (const block of badPendingBlocks) {
|
|
@@ -1232,16 +1351,21 @@ export class BlockInputSync {
|
|
|
1232
1351
|
pruneSetToMax(this.knownBadBlocks, MAX_KNOWN_BAD_BLOCKS);
|
|
1233
1352
|
}
|
|
1234
1353
|
// Once a parent payload is invalid, every descendant waiting on that payload lineage becomes unrecoverable too.
|
|
1235
|
-
removePendingPayloadAndDescendants(rootHex) {
|
|
1354
|
+
removePendingPayloadAndDescendants(rootHex, headReason) {
|
|
1236
1355
|
// Keep PayloadEnvelopeInput resident in the seen cache. importBlock() owns that object and
|
|
1237
1356
|
// later validation/finalization logic decides when it can leave memory.
|
|
1238
|
-
this.pendingPayloads.delete(rootHex)
|
|
1357
|
+
if (this.pendingPayloads.delete(rootHex)) {
|
|
1358
|
+
this.metrics?.blockInputSync.removedPayloads.inc({ reason: headReason }, 1);
|
|
1359
|
+
}
|
|
1239
1360
|
const badPendingBlocks = getAllDescendantBlocks(rootHex, this.pendingBlocks);
|
|
1240
|
-
this.metrics?.blockInputSync.removedBlocks.inc(badPendingBlocks.length);
|
|
1241
1361
|
for (const block of badPendingBlocks) {
|
|
1242
1362
|
const descendantRootHex = getBlockInputSyncCacheItemRootHex(block);
|
|
1243
|
-
this.pendingBlocks.delete(descendantRootHex)
|
|
1244
|
-
|
|
1363
|
+
if (this.pendingBlocks.delete(descendantRootHex)) {
|
|
1364
|
+
this.metrics?.blockInputSync.removedBlocks.inc({ reason: DroppedItemReason.invalidParent }, 1);
|
|
1365
|
+
}
|
|
1366
|
+
if (this.pendingPayloads.delete(descendantRootHex)) {
|
|
1367
|
+
this.metrics?.blockInputSync.removedPayloads.inc({ reason: DroppedItemReason.invalidParent }, 1);
|
|
1368
|
+
}
|
|
1245
1369
|
this.chain.seenBlockInputCache.prune(descendantRootHex);
|
|
1246
1370
|
this.logger.debug("Removing pending descendant after invalid parent payload", {
|
|
1247
1371
|
slot: getBlockInputSyncCacheItemSlot(block),
|
|
@@ -1250,16 +1374,20 @@ export class BlockInputSync {
|
|
|
1250
1374
|
});
|
|
1251
1375
|
}
|
|
1252
1376
|
}
|
|
1253
|
-
removeAllDescendants(block) {
|
|
1377
|
+
removeAllDescendants(block, headReason, descendantReason = DroppedItemReason.invalidParent) {
|
|
1254
1378
|
const rootHex = getBlockInputSyncCacheItemRootHex(block);
|
|
1255
1379
|
const slot = getBlockInputSyncCacheItemSlot(block);
|
|
1256
|
-
// Get all blocks that are a descendant of this one
|
|
1380
|
+
// Get all blocks that are a descendant of this one (index 0 is the head item itself)
|
|
1257
1381
|
const badPendingBlocks = [block, ...getAllDescendantBlocks(rootHex, this.pendingBlocks)];
|
|
1258
|
-
|
|
1259
|
-
for (const block of badPendingBlocks) {
|
|
1382
|
+
for (const [i, block] of badPendingBlocks.entries()) {
|
|
1260
1383
|
const rootHex = getBlockInputSyncCacheItemRootHex(block);
|
|
1261
|
-
|
|
1262
|
-
this.
|
|
1384
|
+
const reason = i === 0 ? headReason : descendantReason;
|
|
1385
|
+
if (this.pendingBlocks.delete(rootHex)) {
|
|
1386
|
+
this.metrics?.blockInputSync.removedBlocks.inc({ reason }, 1);
|
|
1387
|
+
}
|
|
1388
|
+
if (this.pendingPayloads.delete(rootHex)) {
|
|
1389
|
+
this.metrics?.blockInputSync.removedPayloads.inc({ reason }, 1);
|
|
1390
|
+
}
|
|
1263
1391
|
this.chain.seenBlockInputCache.prune(rootHex);
|
|
1264
1392
|
// Keep PayloadEnvelopeInput resident in the seen cache for consistency with the
|
|
1265
1393
|
// importBlock()-owned lifecycle.
|