@lodestar/beacon-node 1.46.0 → 1.47.0-dev.02d2dbea03
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.d.ts.map +1 -1
- package/lib/api/impl/lodestar/index.js +12 -13
- package/lib/api/impl/lodestar/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/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 +3 -8
- 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 +12 -10
- 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 +17 -11
- 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/verifyBlock.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.js +11 -16
- package/lib/chain/blocks/verifyBlock.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 +5 -3
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +24 -8
- 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 +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 -3
- package/lib/chain/options.d.ts.map +1 -1
- package/lib/chain/options.js.map +1 -1
- package/lib/chain/prepareNextSlot.js +2 -2
- 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 +8 -3
- package/lib/chain/produceBlock/produceBlockBody.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/seenBlockProposers.d.ts +5 -1
- package/lib/chain/seenCache/seenBlockProposers.d.ts.map +1 -1
- package/lib/chain/seenCache/seenBlockProposers.js +17 -7
- package/lib/chain/seenCache/seenBlockProposers.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/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/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/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 +71 -22
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +126 -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 +37 -6
- 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 +62 -23
- 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/range/utils/hashBlocks.d.ts +16 -4
- package/lib/sync/range/utils/hashBlocks.d.ts.map +1 -1
- package/lib/sync/range/utils/hashBlocks.js +49 -18
- package/lib/sync/range/utils/hashBlocks.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 +187 -47
- 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 +37 -37
- 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 +12 -13
- package/src/api/impl/validator/index.ts +22 -27
- package/src/api/impl/validator/utils.ts +30 -15
- 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 +2 -7
- package/src/chain/blocks/importExecutionPayload.ts +13 -12
- package/src/chain/blocks/index.ts +21 -11
- package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +8 -2
- package/src/chain/blocks/payloadEnvelopeInput/types.ts +17 -4
- package/src/chain/blocks/verifyBlock.ts +21 -25
- 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 +25 -7
- package/src/chain/errors/blockError.ts +9 -3
- package/src/chain/errors/proposerPreferences.ts +7 -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 -3
- package/src/chain/prepareNextSlot.ts +2 -2
- package/src/chain/produceBlock/produceBlockBody.ts +15 -2
- 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/seenBlockProposers.ts +24 -7
- 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/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/chain/validation/voluntaryExit.ts +59 -2
- package/src/execution/builder/http.ts +11 -11
- package/src/metrics/metrics/beacon.ts +9 -9
- package/src/metrics/metrics/lodestar.ts +138 -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 +40 -4
- 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 +84 -29
- package/src/sync/range/chain.ts +26 -11
- package/src/sync/range/utils/hashBlocks.ts +56 -21
- package/src/sync/types.ts +36 -1
- package/src/sync/unknownBlock.ts +212 -53
- 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 } 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
|
/**
|
|
@@ -637,9 +735,10 @@ export class BlockInputSync {
|
|
|
637
735
|
// this prevents unbundling attack
|
|
638
736
|
// see https://lighthouse-blog.sigmaprime.io/mev-unbundling-rpc.html
|
|
639
737
|
const { slot: blockSlot, proposerIndex } = pendingBlock.blockInput.getBlock().message;
|
|
738
|
+
const blockRootHex = pendingBlock.blockInput.blockRootHex;
|
|
640
739
|
const logCtx = {
|
|
641
740
|
slot: blockSlot,
|
|
642
|
-
root:
|
|
741
|
+
root: blockRootHex,
|
|
643
742
|
delaySec: this.chain.clock.secFromSlot(blockSlot),
|
|
644
743
|
};
|
|
645
744
|
this.logger.verbose("Processing downloaded block", logCtx);
|
|
@@ -651,7 +750,7 @@ export class BlockInputSync {
|
|
|
651
750
|
// eligible for proposer boost to prevent unbundling attack
|
|
652
751
|
this.logger.verbose("Avoid proposer boost for this block of known proposer", {
|
|
653
752
|
slot: blockSlot,
|
|
654
|
-
root:
|
|
753
|
+
root: blockRootHex,
|
|
655
754
|
proposerIndex,
|
|
656
755
|
});
|
|
657
756
|
await sleep(proposerBoostWindowMs);
|
|
@@ -676,13 +775,24 @@ export class BlockInputSync {
|
|
|
676
775
|
if (!res.err) {
|
|
677
776
|
this.logger.verbose("Processed block from unknown sync", logCtx);
|
|
678
777
|
// no need to update status to "processed", delete anyway
|
|
679
|
-
this.pendingBlocks.delete(
|
|
778
|
+
this.pendingBlocks.delete(blockRootHex);
|
|
779
|
+
if (isForkPostGloas(fork)) {
|
|
780
|
+
const payloadInput = await this.chain.seenPayloadEnvelopeInputCache.getOrReload(blockRootHex);
|
|
781
|
+
if (!payloadInput) {
|
|
782
|
+
this.logger.debug("PayloadEnvelopeInput unavailable during unknown sync processReadyBlock()", logCtx);
|
|
783
|
+
}
|
|
784
|
+
else {
|
|
785
|
+
// Similar to the gossip path: immediately attempt fetch of data columns from the execution engine.
|
|
786
|
+
// The bid already carries the kzg commitments, so there is no reason to wait for the payload to arrive.
|
|
787
|
+
this.chain.getBlobsTracker.triggerGetBlobs(payloadInput);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
680
790
|
// Re-enter the scheduler so descendants blocked on either parent blocks or parent payloads
|
|
681
791
|
// are advanced through the same dependency checks as every other pending item.
|
|
682
792
|
this.triggerUnknownBlockSearch();
|
|
683
793
|
}
|
|
684
794
|
else {
|
|
685
|
-
const errorData = { slot: pendingBlock.blockInput.slot, root:
|
|
795
|
+
const errorData = { slot: pendingBlock.blockInput.slot, root: blockRootHex };
|
|
686
796
|
if (res.err instanceof BlockError) {
|
|
687
797
|
switch (res.err.type.code) {
|
|
688
798
|
// This cases are already handled with `{ignoreIfKnown: true}`
|
|
@@ -705,17 +815,17 @@ export class BlockInputSync {
|
|
|
705
815
|
case BlockErrorCode.EXECUTION_ENGINE_ERROR:
|
|
706
816
|
// Removing the block(s) without penalizing the peers, hoping for EL to
|
|
707
817
|
// recover on a latter download + verify attempt.
|
|
708
|
-
this.removeAllDescendants(pendingBlock);
|
|
818
|
+
this.removeAllDescendants(pendingBlock, DroppedItemReason.elError, DroppedItemReason.elError);
|
|
709
819
|
break;
|
|
710
820
|
case BlockErrorCode.EXECUTION_ENGINE_INVALID:
|
|
711
821
|
// the peer served a bad block
|
|
712
822
|
this.logger.debug("Execution engine rejected block from unknown parent sync", errorData, res.err);
|
|
713
|
-
this.removeAndDownScoreAllDescendants(pendingBlock);
|
|
823
|
+
this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.elInvalid);
|
|
714
824
|
break;
|
|
715
825
|
default:
|
|
716
826
|
// Block is not correct with respect to our chain. Log error loudly
|
|
717
827
|
this.logger.debug("Error processing block from unknown parent sync", errorData, res.err);
|
|
718
|
-
this.removeAndDownScoreAllDescendants(pendingBlock);
|
|
828
|
+
this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidBlock);
|
|
719
829
|
}
|
|
720
830
|
}
|
|
721
831
|
// Probably a queue error or something unwanted happened, mark as pending to try again latter
|
|
@@ -736,7 +846,6 @@ export class BlockInputSync {
|
|
|
736
846
|
this.pendingPayloads.delete(rootHex);
|
|
737
847
|
return;
|
|
738
848
|
}
|
|
739
|
-
const payloadInput = this.chain.seenPayloadEnvelopeInputCache.get(rootHex);
|
|
740
849
|
if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
|
|
741
850
|
// Block not in fork choice yet. payloadInput may be seeded from the block body during download, so a
|
|
742
851
|
// non-null payloadInput does not imply the block is imported; defer regardless and pull the block first.
|
|
@@ -750,8 +859,9 @@ export class BlockInputSync {
|
|
|
750
859
|
}
|
|
751
860
|
return;
|
|
752
861
|
}
|
|
862
|
+
const payloadInput = await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
|
|
753
863
|
if (!payloadInput) {
|
|
754
|
-
this.logger.debug("
|
|
864
|
+
this.logger.debug("PayloadEnvelopeInput not yet reloadable for imported block, will retry", {
|
|
755
865
|
root: rootHex,
|
|
756
866
|
});
|
|
757
867
|
return;
|
|
@@ -763,6 +873,7 @@ export class BlockInputSync {
|
|
|
763
873
|
const pendingPayloadByRoot = {
|
|
764
874
|
status: PendingPayloadInputStatus.pending,
|
|
765
875
|
rootHex,
|
|
876
|
+
slot: pendingPayload.envelope.message.payload.slotNumber,
|
|
766
877
|
timeAddedSec: pendingPayload.timeAddedSec,
|
|
767
878
|
peerIdStrings: new Set(pendingPayload.peerIdStrings),
|
|
768
879
|
};
|
|
@@ -794,6 +905,9 @@ export class BlockInputSync {
|
|
|
794
905
|
if (payload.status !== PendingPayloadInputStatus.pending) {
|
|
795
906
|
return;
|
|
796
907
|
}
|
|
908
|
+
if (!isPendingPayloadInput(payload) && payload.slot === undefined) {
|
|
909
|
+
payload.slot = this.resolvePayloadSlot(rootHex);
|
|
910
|
+
}
|
|
797
911
|
const payloadSlot = getPayloadSyncCacheItemSlot(payload);
|
|
798
912
|
const logCtx = {
|
|
799
913
|
slot: payloadSlot,
|
|
@@ -806,7 +920,13 @@ export class BlockInputSync {
|
|
|
806
920
|
const res = await wrapError(this.fetchPayloadInput(payload));
|
|
807
921
|
if (!res.err) {
|
|
808
922
|
const pendingPayload = res.result;
|
|
809
|
-
|
|
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);
|
|
810
930
|
if (isPendingPayloadEnvelope(pendingPayload)) {
|
|
811
931
|
await this.reconcilePayloadEnvelope(pendingPayload);
|
|
812
932
|
}
|
|
@@ -873,16 +993,24 @@ export class BlockInputSync {
|
|
|
873
993
|
pendingPayload.status = PendingPayloadInputStatus.downloaded;
|
|
874
994
|
break;
|
|
875
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;
|
|
876
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;
|
|
877
1003
|
case PayloadErrorCode.INVALID_SIGNATURE:
|
|
878
1004
|
// TODO GLOAS: Decide how invalid payload inputs should eventually leave memory without
|
|
879
1005
|
// reintroducing envelope replacement / recreation flows.
|
|
880
1006
|
this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
|
|
881
|
-
this.removePendingPayloadAndDescendants(rootHex);
|
|
1007
|
+
this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.invalidSignature);
|
|
882
1008
|
break;
|
|
883
1009
|
default:
|
|
884
1010
|
this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
|
|
885
|
-
this.pendingPayloads.delete(rootHex)
|
|
1011
|
+
if (this.pendingPayloads.delete(rootHex)) {
|
|
1012
|
+
this.metrics?.blockInputSync.removedPayloads.inc({ reason: DroppedItemReason.unknown }, 1);
|
|
1013
|
+
}
|
|
886
1014
|
}
|
|
887
1015
|
return;
|
|
888
1016
|
}
|
|
@@ -901,7 +1029,7 @@ export class BlockInputSync {
|
|
|
901
1029
|
let slot = getPayloadSyncCacheItemSlot(cacheItem);
|
|
902
1030
|
let payloadInput = isPendingPayloadInput(cacheItem)
|
|
903
1031
|
? cacheItem.payloadInput
|
|
904
|
-
: this.chain.seenPayloadEnvelopeInputCache.
|
|
1032
|
+
: await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
|
|
905
1033
|
let envelope = payloadInput?.hasPayloadEnvelope() ? payloadInput.getPayloadEnvelope() : undefined;
|
|
906
1034
|
let i = 0;
|
|
907
1035
|
let deferredByRateLimit = false;
|
|
@@ -914,7 +1042,10 @@ export class BlockInputSync {
|
|
|
914
1042
|
if (this.peerBalancer.getNextRateLimitRetryAt(pendingColumns, excludedPeers) !== null) {
|
|
915
1043
|
throw new UnknownBlockRateLimitedError(`Error fetching payload by root slot=${slot} root=${rootHex} after ${i}: peers with needed columns are rate-limited`);
|
|
916
1044
|
}
|
|
917
|
-
|
|
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}`);
|
|
918
1049
|
}
|
|
919
1050
|
const { peerId, client: peerClient } = peerMeta;
|
|
920
1051
|
cacheItem.peerIdStrings.add(peerId);
|
|
@@ -923,7 +1054,7 @@ export class BlockInputSync {
|
|
|
923
1054
|
envelope = await this.fetchExecutionPayloadEnvelope(peerId, blockRoot, rootHex);
|
|
924
1055
|
slot = envelope.message.payload.slotNumber;
|
|
925
1056
|
}
|
|
926
|
-
payloadInput ??= this.chain.seenPayloadEnvelopeInputCache.
|
|
1057
|
+
payloadInput ??= await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
|
|
927
1058
|
if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
|
|
928
1059
|
// Block not in fork choice yet. Validating now would throw BLOCK_ROOT_UNKNOWN, so keep the downloaded
|
|
929
1060
|
// envelope and wait for the block body; reconcilePayloadEnvelope validates once the block lands.
|
|
@@ -1194,9 +1325,9 @@ export class BlockInputSync {
|
|
|
1194
1325
|
* Downscore all peers that have referenced any of this bad blocks. May report peers multiple times if they have
|
|
1195
1326
|
* referenced more than one bad block.
|
|
1196
1327
|
*/
|
|
1197
|
-
removeAndDownScoreAllDescendants(block) {
|
|
1328
|
+
removeAndDownScoreAllDescendants(block, headReason) {
|
|
1198
1329
|
// Get all blocks that are a descendant of this one
|
|
1199
|
-
const badPendingBlocks = this.removeAllDescendants(block);
|
|
1330
|
+
const badPendingBlocks = this.removeAllDescendants(block, headReason, DroppedItemReason.invalidParent);
|
|
1200
1331
|
// just console log and do not penalize on pending/bad blocks for debugging
|
|
1201
1332
|
// console.log("removeAndDownscoreAllDescendants", {block});
|
|
1202
1333
|
for (const block of badPendingBlocks) {
|
|
@@ -1220,16 +1351,21 @@ export class BlockInputSync {
|
|
|
1220
1351
|
pruneSetToMax(this.knownBadBlocks, MAX_KNOWN_BAD_BLOCKS);
|
|
1221
1352
|
}
|
|
1222
1353
|
// Once a parent payload is invalid, every descendant waiting on that payload lineage becomes unrecoverable too.
|
|
1223
|
-
removePendingPayloadAndDescendants(rootHex) {
|
|
1354
|
+
removePendingPayloadAndDescendants(rootHex, headReason) {
|
|
1224
1355
|
// Keep PayloadEnvelopeInput resident in the seen cache. importBlock() owns that object and
|
|
1225
1356
|
// later validation/finalization logic decides when it can leave memory.
|
|
1226
|
-
this.pendingPayloads.delete(rootHex)
|
|
1357
|
+
if (this.pendingPayloads.delete(rootHex)) {
|
|
1358
|
+
this.metrics?.blockInputSync.removedPayloads.inc({ reason: headReason }, 1);
|
|
1359
|
+
}
|
|
1227
1360
|
const badPendingBlocks = getAllDescendantBlocks(rootHex, this.pendingBlocks);
|
|
1228
|
-
this.metrics?.blockInputSync.removedBlocks.inc(badPendingBlocks.length);
|
|
1229
1361
|
for (const block of badPendingBlocks) {
|
|
1230
1362
|
const descendantRootHex = getBlockInputSyncCacheItemRootHex(block);
|
|
1231
|
-
this.pendingBlocks.delete(descendantRootHex)
|
|
1232
|
-
|
|
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
|
+
}
|
|
1233
1369
|
this.chain.seenBlockInputCache.prune(descendantRootHex);
|
|
1234
1370
|
this.logger.debug("Removing pending descendant after invalid parent payload", {
|
|
1235
1371
|
slot: getBlockInputSyncCacheItemSlot(block),
|
|
@@ -1238,16 +1374,20 @@ export class BlockInputSync {
|
|
|
1238
1374
|
});
|
|
1239
1375
|
}
|
|
1240
1376
|
}
|
|
1241
|
-
removeAllDescendants(block) {
|
|
1377
|
+
removeAllDescendants(block, headReason, descendantReason = DroppedItemReason.invalidParent) {
|
|
1242
1378
|
const rootHex = getBlockInputSyncCacheItemRootHex(block);
|
|
1243
1379
|
const slot = getBlockInputSyncCacheItemSlot(block);
|
|
1244
|
-
// 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)
|
|
1245
1381
|
const badPendingBlocks = [block, ...getAllDescendantBlocks(rootHex, this.pendingBlocks)];
|
|
1246
|
-
|
|
1247
|
-
for (const block of badPendingBlocks) {
|
|
1382
|
+
for (const [i, block] of badPendingBlocks.entries()) {
|
|
1248
1383
|
const rootHex = getBlockInputSyncCacheItemRootHex(block);
|
|
1249
|
-
|
|
1250
|
-
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
|
+
}
|
|
1251
1391
|
this.chain.seenBlockInputCache.prune(rootHex);
|
|
1252
1392
|
// Keep PayloadEnvelopeInput resident in the seen cache for consistency with the
|
|
1253
1393
|
// importBlock()-owned lifecycle.
|