@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/src/sync/unknownBlock.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
3
|
-
import {
|
|
3
|
+
import {CheckpointWithHex} from "@lodestar/fork-choice";
|
|
4
|
+
import {ForkSeq, SLOTS_PER_EPOCH, isForkPostGloas} from "@lodestar/params";
|
|
4
5
|
import {RequestError, RequestErrorCode} from "@lodestar/reqresp";
|
|
5
6
|
import {computeTimeAtSlot} from "@lodestar/state-transition";
|
|
6
7
|
import {RootHex, Slot, gloas} from "@lodestar/types";
|
|
@@ -24,6 +25,7 @@ import {MAX_CONCURRENT_REQUESTS} from "./constants.js";
|
|
|
24
25
|
import {SyncOptions} from "./options.js";
|
|
25
26
|
import {
|
|
26
27
|
BlockInputSyncCacheItem,
|
|
28
|
+
DroppedItemReason,
|
|
27
29
|
PayloadSyncCacheItem,
|
|
28
30
|
PendingBlockInput,
|
|
29
31
|
PendingBlockInputStatus,
|
|
@@ -47,6 +49,10 @@ import {getRateLimitedUntilMs} from "./utils/rateLimit.js";
|
|
|
47
49
|
const MAX_ATTEMPTS_PER_BLOCK = 5;
|
|
48
50
|
const MAX_KNOWN_BAD_BLOCKS = 500;
|
|
49
51
|
const MAX_PENDING_BLOCKS = 100;
|
|
52
|
+
/**
|
|
53
|
+
* A pending payload without slot can only stay at most 2 epochs.
|
|
54
|
+
*/
|
|
55
|
+
const PRUNE_UNRESOLVED_SLOT_EPOCHS = 2;
|
|
50
56
|
|
|
51
57
|
type AdvancePendingBlockResult =
|
|
52
58
|
| "ready"
|
|
@@ -154,6 +160,7 @@ export class BlockInputSync {
|
|
|
154
160
|
this.chain.emitter.on(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
|
|
155
161
|
this.chain.emitter.on(ChainEvent.incompletePayloadEnvelope, this.onIncompletePayloadEnvelope);
|
|
156
162
|
this.chain.emitter.on(ChainEvent.blockUnknownParent, this.onUnknownParent);
|
|
163
|
+
this.chain.emitter.on(ChainEvent.forkChoiceFinalized, this.pruneFinalized);
|
|
157
164
|
this.chain.emitter.on(routes.events.EventType.block, this.onBlockImported);
|
|
158
165
|
this.chain.emitter.on(routes.events.EventType.executionPayload, this.onPayloadImported);
|
|
159
166
|
this.network.events.on(NetworkEvent.peerConnected, this.onPeerConnected);
|
|
@@ -170,6 +177,7 @@ export class BlockInputSync {
|
|
|
170
177
|
this.chain.emitter.off(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
|
|
171
178
|
this.chain.emitter.off(ChainEvent.incompletePayloadEnvelope, this.onIncompletePayloadEnvelope);
|
|
172
179
|
this.chain.emitter.off(ChainEvent.blockUnknownParent, this.onUnknownParent);
|
|
180
|
+
this.chain.emitter.off(ChainEvent.forkChoiceFinalized, this.pruneFinalized);
|
|
173
181
|
this.chain.emitter.off(routes.events.EventType.block, this.onBlockImported);
|
|
174
182
|
this.chain.emitter.off(routes.events.EventType.executionPayload, this.onPayloadImported);
|
|
175
183
|
this.network.events.off(NetworkEvent.peerConnected, this.onPeerConnected);
|
|
@@ -215,7 +223,7 @@ export class BlockInputSync {
|
|
|
215
223
|
|
|
216
224
|
private onUnknownEnvelopeBlockRoot = (data: ChainEventData[ChainEvent.unknownEnvelopeBlockRoot]): void => {
|
|
217
225
|
try {
|
|
218
|
-
this.addByPayloadRootHex(data.rootHex, data.peer, data.
|
|
226
|
+
this.addByPayloadRootHex(data.rootHex, data.peer, this.resolvePayloadSlot(data.rootHex));
|
|
219
227
|
this.triggerUnknownBlockSearch();
|
|
220
228
|
this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.UNKNOWN_PAYLOAD_BLOCK_ROOT});
|
|
221
229
|
this.metrics?.blockInputSync.payloadSource.inc({source: data.source});
|
|
@@ -252,13 +260,13 @@ export class BlockInputSync {
|
|
|
252
260
|
parentRoot: missingDependency.parentRootHex,
|
|
253
261
|
parentBlockHash: missingDependency.parentBlockHashHex,
|
|
254
262
|
});
|
|
255
|
-
this.removeAndDownScoreAllDescendants(pendingBlock);
|
|
263
|
+
this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidParentPayload);
|
|
256
264
|
}
|
|
257
265
|
return;
|
|
258
266
|
}
|
|
259
267
|
|
|
260
268
|
if (missingDependency.kind === "parentPayload") {
|
|
261
|
-
this.addByPayloadRootHex(missingDependency.rootHex, data.peer);
|
|
269
|
+
this.addByPayloadRootHex(missingDependency.rootHex, data.peer, missingDependency.slot);
|
|
262
270
|
} else if (missingDependency.kind === "parentBlock") {
|
|
263
271
|
this.addByRootHex(missingDependency.rootHex, data.peer);
|
|
264
272
|
}
|
|
@@ -284,6 +292,80 @@ export class BlockInputSync {
|
|
|
284
292
|
this.triggerUnknownBlockSearch();
|
|
285
293
|
};
|
|
286
294
|
|
|
295
|
+
/**
|
|
296
|
+
* Drop pending payloads and blocks that fell below the finalized slot.
|
|
297
|
+
* See https://github.com/ChainSafe/lodestar/issues/9800
|
|
298
|
+
*/
|
|
299
|
+
private pruneFinalized = (checkpoint: CheckpointWithHex): void => {
|
|
300
|
+
// Use the actual finalized block slot, not computeStartSlotAtEpoch(checkpoint.epoch)
|
|
301
|
+
// because the payload at the finalized block is not finalized
|
|
302
|
+
const finalizedSlot = this.chain.forkChoice.getFinalizedBlock().slot;
|
|
303
|
+
const nowSec = Date.now() / 1000;
|
|
304
|
+
const maxSecInCache = (PRUNE_UNRESOLVED_SLOT_EPOCHS * SLOTS_PER_EPOCH * this.config.SLOT_DURATION_MS) / 1000;
|
|
305
|
+
|
|
306
|
+
let belowFinalizedPayloads = 0;
|
|
307
|
+
let agedOutPayloads = 0;
|
|
308
|
+
let unresolvedSlotPayloads = 0;
|
|
309
|
+
|
|
310
|
+
for (const [rootHex, payload] of this.pendingPayloads) {
|
|
311
|
+
// Last-effort resolve for a slot-less PendingPayloadRootHex, and store it back for later passes.
|
|
312
|
+
if (!isPendingPayloadInput(payload) && !isPendingPayloadEnvelope(payload) && payload.slot === undefined) {
|
|
313
|
+
payload.slot = this.resolvePayloadSlot(rootHex);
|
|
314
|
+
if (payload.slot === undefined) {
|
|
315
|
+
// Still unresolvable: age it out so the MAX_PENDING_BLOCKS cap cannot stay saturated.
|
|
316
|
+
if (nowSec - payload.timeAddedSec > maxSecInCache) {
|
|
317
|
+
this.pendingPayloads.delete(rootHex);
|
|
318
|
+
agedOutPayloads++;
|
|
319
|
+
} else {
|
|
320
|
+
unresolvedSlotPayloads++;
|
|
321
|
+
this.logger.debug("BlockInputSync.pruneFinalized: pending payload with unresolved slot", {
|
|
322
|
+
root: rootHex,
|
|
323
|
+
finalizedSlot,
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const slot = getPayloadSyncCacheItemSlot(payload);
|
|
331
|
+
if (typeof slot === "number" && slot < finalizedSlot) {
|
|
332
|
+
this.pendingPayloads.delete(rootHex);
|
|
333
|
+
belowFinalizedPayloads++;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
let deletedBlocks = 0;
|
|
338
|
+
for (const [rootHex, block] of this.pendingBlocks) {
|
|
339
|
+
const slot = getBlockInputSyncCacheItemSlot(block);
|
|
340
|
+
if (typeof slot === "number" && slot < finalizedSlot) {
|
|
341
|
+
this.pendingBlocks.delete(rootHex);
|
|
342
|
+
deletedBlocks++;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (belowFinalizedPayloads > 0) {
|
|
347
|
+
this.metrics?.blockInputSync.removedPayloads.inc(
|
|
348
|
+
{reason: DroppedItemReason.belowFinalized},
|
|
349
|
+
belowFinalizedPayloads
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
if (agedOutPayloads > 0) {
|
|
353
|
+
this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.agedOut}, agedOutPayloads);
|
|
354
|
+
}
|
|
355
|
+
if (deletedBlocks > 0) {
|
|
356
|
+
this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.belowFinalized}, deletedBlocks);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
this.logger.debug("BlockInputSync.pruneFinalized dropped pre-finalized pending items", {
|
|
360
|
+
finalizedSlot,
|
|
361
|
+
finalizedRoot: checkpoint.rootHex,
|
|
362
|
+
belowFinalizedPayloads,
|
|
363
|
+
agedOutPayloads,
|
|
364
|
+
deletedBlocks,
|
|
365
|
+
unresolvedSlotPayloads,
|
|
366
|
+
});
|
|
367
|
+
};
|
|
368
|
+
|
|
287
369
|
private addByRootHex = (rootHex: RootHex, peerIdStr?: PeerIdStr): boolean => {
|
|
288
370
|
let pendingBlock = this.pendingBlocks.get(rootHex);
|
|
289
371
|
let added = false;
|
|
@@ -311,6 +393,7 @@ export class BlockInputSync {
|
|
|
311
393
|
// Limit pending blocks to prevent DOS attacks that cause OOM
|
|
312
394
|
const prunedItemCount = pruneSetToMax(this.pendingBlocks, this.maxPendingBlocks);
|
|
313
395
|
if (prunedItemCount > 0) {
|
|
396
|
+
this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
|
|
314
397
|
this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingBlocks`);
|
|
315
398
|
}
|
|
316
399
|
return added;
|
|
@@ -345,6 +428,7 @@ export class BlockInputSync {
|
|
|
345
428
|
// Limit pending blocks to prevent DOS attacks that cause OOM
|
|
346
429
|
const prunedItemCount = pruneSetToMax(this.pendingBlocks, this.maxPendingBlocks);
|
|
347
430
|
if (prunedItemCount > 0) {
|
|
431
|
+
this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
|
|
348
432
|
this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingBlocks`);
|
|
349
433
|
}
|
|
350
434
|
};
|
|
@@ -369,6 +453,14 @@ export class BlockInputSync {
|
|
|
369
453
|
root: rootHex,
|
|
370
454
|
peerIdStr: peerIdStr ?? "unknown peer",
|
|
371
455
|
});
|
|
456
|
+
} else if (
|
|
457
|
+
// update a previously slot-less entry once a slot becomes available
|
|
458
|
+
slot !== undefined &&
|
|
459
|
+
!isPendingPayloadInput(pendingPayload) &&
|
|
460
|
+
!isPendingPayloadEnvelope(pendingPayload) &&
|
|
461
|
+
pendingPayload.slot === undefined
|
|
462
|
+
) {
|
|
463
|
+
pendingPayload.slot = slot;
|
|
372
464
|
}
|
|
373
465
|
|
|
374
466
|
if (peerIdStr) {
|
|
@@ -377,11 +469,35 @@ export class BlockInputSync {
|
|
|
377
469
|
|
|
378
470
|
const prunedItemCount = pruneSetToMax(this.pendingPayloads, this.maxPendingBlocks);
|
|
379
471
|
if (prunedItemCount > 0) {
|
|
472
|
+
this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
|
|
380
473
|
this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingPayloads`);
|
|
381
474
|
}
|
|
382
475
|
return added;
|
|
383
476
|
};
|
|
384
477
|
|
|
478
|
+
/**
|
|
479
|
+
* Resolve the block slot for a payload root.
|
|
480
|
+
*/
|
|
481
|
+
private resolvePayloadSlot(rootHex: RootHex): Slot | undefined {
|
|
482
|
+
// a pending block of the same root
|
|
483
|
+
const pendingBlock = this.pendingBlocks.get(rootHex);
|
|
484
|
+
if (pendingBlock) {
|
|
485
|
+
const pendingBlockSlot = getBlockInputSyncCacheItemSlot(pendingBlock);
|
|
486
|
+
if (typeof pendingBlockSlot === "number") {
|
|
487
|
+
return pendingBlockSlot;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// the block is in fork choice
|
|
492
|
+
const forkChoiceSlot = this.chain.forkChoice.getBlockHexDefaultStatus(rootHex)?.slot;
|
|
493
|
+
if (forkChoiceSlot !== undefined) {
|
|
494
|
+
return forkChoiceSlot;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// a seen payload envelope input
|
|
498
|
+
return this.chain.seenPayloadEnvelopeInputCache.get(rootHex)?.slot;
|
|
499
|
+
}
|
|
500
|
+
|
|
385
501
|
private addByPayloadInput = (
|
|
386
502
|
payloadInput: PayloadEnvelopeInput,
|
|
387
503
|
peerIdStr?: PeerIdStr,
|
|
@@ -407,6 +523,7 @@ export class BlockInputSync {
|
|
|
407
523
|
|
|
408
524
|
const prunedItemCount = pruneSetToMax(this.pendingPayloads, this.maxPendingBlocks);
|
|
409
525
|
if (prunedItemCount > 0) {
|
|
526
|
+
this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
|
|
410
527
|
this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingPayloads`);
|
|
411
528
|
}
|
|
412
529
|
};
|
|
@@ -436,10 +553,12 @@ export class BlockInputSync {
|
|
|
436
553
|
blockInput: IBlockInput
|
|
437
554
|
):
|
|
438
555
|
| {kind: "ready"}
|
|
439
|
-
| {kind: "block" | "parentBlock"
|
|
556
|
+
| {kind: "block" | "parentBlock"; rootHex: RootHex}
|
|
557
|
+
| {kind: "parentPayload"; rootHex: RootHex; slot: Slot}
|
|
440
558
|
| {kind: "invalidParentPayload"; parentRootHex: RootHex; parentBlockHashHex: RootHex} {
|
|
441
559
|
const parentRootHex = blockInput.parentRootHex;
|
|
442
|
-
|
|
560
|
+
const parentBlock = this.chain.forkChoice.getBlockHexDefaultStatus(parentRootHex);
|
|
561
|
+
if (!parentBlock) {
|
|
443
562
|
return {kind: "parentBlock", rootHex: parentRootHex};
|
|
444
563
|
}
|
|
445
564
|
|
|
@@ -461,16 +580,8 @@ export class BlockInputSync {
|
|
|
461
580
|
return {kind: "invalidParentPayload", parentRootHex, parentBlockHashHex};
|
|
462
581
|
}
|
|
463
582
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
if (parentPayloadInput.getBlockHashHex() === parentBlockHashHex) {
|
|
467
|
-
return {kind: "parentPayload", rootHex: parentRootHex};
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
return {kind: "invalidParentPayload", parentRootHex, parentBlockHashHex};
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
return {kind: "parentPayload", rootHex: parentRootHex};
|
|
583
|
+
// Parent is in fork choice but its payload `parentBlockHashHex` isn't revealed yet
|
|
584
|
+
return {kind: "parentPayload", rootHex: parentRootHex, slot: parentBlock.slot};
|
|
474
585
|
}
|
|
475
586
|
|
|
476
587
|
private advancePendingBlock(pendingBlock: PendingBlockInput): AdvancePendingBlockResult {
|
|
@@ -493,9 +604,9 @@ export class BlockInputSync {
|
|
|
493
604
|
}
|
|
494
605
|
|
|
495
606
|
case "parentPayload": {
|
|
496
|
-
let added = this.addByPayloadRootHex(missingDependency.rootHex);
|
|
607
|
+
let added = this.addByPayloadRootHex(missingDependency.rootHex, undefined, missingDependency.slot);
|
|
497
608
|
for (const peerIdStr of pendingBlock.peerIdStrings) {
|
|
498
|
-
added = this.addByPayloadRootHex(missingDependency.rootHex, peerIdStr) || added;
|
|
609
|
+
added = this.addByPayloadRootHex(missingDependency.rootHex, peerIdStr, missingDependency.slot) || added;
|
|
499
610
|
}
|
|
500
611
|
return added ? "queued_parent_payload" : "blocked";
|
|
501
612
|
}
|
|
@@ -507,7 +618,7 @@ export class BlockInputSync {
|
|
|
507
618
|
parentRoot: missingDependency.parentRootHex,
|
|
508
619
|
parentBlockHash: missingDependency.parentBlockHashHex,
|
|
509
620
|
});
|
|
510
|
-
this.removeAndDownScoreAllDescendants(pendingBlock);
|
|
621
|
+
this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidParentPayload);
|
|
511
622
|
return "removed";
|
|
512
623
|
}
|
|
513
624
|
}
|
|
@@ -730,7 +841,7 @@ export class BlockInputSync {
|
|
|
730
841
|
...logCtx2,
|
|
731
842
|
finalizedSlot,
|
|
732
843
|
});
|
|
733
|
-
this.removeAndDownScoreAllDescendants(block);
|
|
844
|
+
this.removeAndDownScoreAllDescendants(block, DroppedItemReason.belowFinalized);
|
|
734
845
|
} else {
|
|
735
846
|
this.onUnknownBlockRoot({rootHex: pending.blockInput.parentRootHex, source: BlockInputSource.byRoot});
|
|
736
847
|
}
|
|
@@ -747,7 +858,7 @@ export class BlockInputSync {
|
|
|
747
858
|
|
|
748
859
|
this.metrics?.blockInputSync.downloadedBlocksError.inc();
|
|
749
860
|
this.logger.debug("Ignoring unknown block root after many failed downloads", logCtx, res.err);
|
|
750
|
-
this.removeAndDownScoreAllDescendants(block);
|
|
861
|
+
this.removeAndDownScoreAllDescendants(block, DroppedItemReason.unavailable);
|
|
751
862
|
}
|
|
752
863
|
}
|
|
753
864
|
|
|
@@ -764,9 +875,10 @@ export class BlockInputSync {
|
|
|
764
875
|
// this prevents unbundling attack
|
|
765
876
|
// see https://lighthouse-blog.sigmaprime.io/mev-unbundling-rpc.html
|
|
766
877
|
const {slot: blockSlot, proposerIndex} = pendingBlock.blockInput.getBlock().message;
|
|
878
|
+
const blockRootHex = pendingBlock.blockInput.blockRootHex;
|
|
767
879
|
const logCtx = {
|
|
768
880
|
slot: blockSlot,
|
|
769
|
-
root:
|
|
881
|
+
root: blockRootHex,
|
|
770
882
|
delaySec: this.chain.clock.secFromSlot(blockSlot),
|
|
771
883
|
};
|
|
772
884
|
this.logger.verbose("Processing downloaded block", logCtx);
|
|
@@ -780,7 +892,7 @@ export class BlockInputSync {
|
|
|
780
892
|
// eligible for proposer boost to prevent unbundling attack
|
|
781
893
|
this.logger.verbose("Avoid proposer boost for this block of known proposer", {
|
|
782
894
|
slot: blockSlot,
|
|
783
|
-
root:
|
|
895
|
+
root: blockRootHex,
|
|
784
896
|
proposerIndex,
|
|
785
897
|
});
|
|
786
898
|
await sleep(proposerBoostWindowMs);
|
|
@@ -807,12 +919,24 @@ export class BlockInputSync {
|
|
|
807
919
|
if (!res.err) {
|
|
808
920
|
this.logger.verbose("Processed block from unknown sync", logCtx);
|
|
809
921
|
// no need to update status to "processed", delete anyway
|
|
810
|
-
this.pendingBlocks.delete(
|
|
922
|
+
this.pendingBlocks.delete(blockRootHex);
|
|
923
|
+
|
|
924
|
+
if (isForkPostGloas(fork)) {
|
|
925
|
+
const payloadInput = await this.chain.seenPayloadEnvelopeInputCache.getOrReload(blockRootHex);
|
|
926
|
+
if (!payloadInput) {
|
|
927
|
+
this.logger.debug("PayloadEnvelopeInput unavailable during unknown sync processReadyBlock()", logCtx);
|
|
928
|
+
} else {
|
|
929
|
+
// Similar to the gossip path: immediately attempt fetch of data columns from the execution engine.
|
|
930
|
+
// The bid already carries the kzg commitments, so there is no reason to wait for the payload to arrive.
|
|
931
|
+
this.chain.getBlobsTracker.triggerGetBlobs(payloadInput);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
|
|
811
935
|
// Re-enter the scheduler so descendants blocked on either parent blocks or parent payloads
|
|
812
936
|
// are advanced through the same dependency checks as every other pending item.
|
|
813
937
|
this.triggerUnknownBlockSearch();
|
|
814
938
|
} else {
|
|
815
|
-
const errorData = {slot: pendingBlock.blockInput.slot, root:
|
|
939
|
+
const errorData = {slot: pendingBlock.blockInput.slot, root: blockRootHex};
|
|
816
940
|
if (res.err instanceof BlockError) {
|
|
817
941
|
switch (res.err.type.code) {
|
|
818
942
|
// This cases are already handled with `{ignoreIfKnown: true}`
|
|
@@ -842,19 +966,19 @@ export class BlockInputSync {
|
|
|
842
966
|
case BlockErrorCode.EXECUTION_ENGINE_ERROR:
|
|
843
967
|
// Removing the block(s) without penalizing the peers, hoping for EL to
|
|
844
968
|
// recover on a latter download + verify attempt.
|
|
845
|
-
this.removeAllDescendants(pendingBlock);
|
|
969
|
+
this.removeAllDescendants(pendingBlock, DroppedItemReason.elError, DroppedItemReason.elError);
|
|
846
970
|
break;
|
|
847
971
|
|
|
848
972
|
case BlockErrorCode.EXECUTION_ENGINE_INVALID:
|
|
849
973
|
// the peer served a bad block
|
|
850
974
|
this.logger.debug("Execution engine rejected block from unknown parent sync", errorData, res.err);
|
|
851
|
-
this.removeAndDownScoreAllDescendants(pendingBlock);
|
|
975
|
+
this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.elInvalid);
|
|
852
976
|
break;
|
|
853
977
|
|
|
854
978
|
default:
|
|
855
979
|
// Block is not correct with respect to our chain. Log error loudly
|
|
856
980
|
this.logger.debug("Error processing block from unknown parent sync", errorData, res.err);
|
|
857
|
-
this.removeAndDownScoreAllDescendants(pendingBlock);
|
|
981
|
+
this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidBlock);
|
|
858
982
|
}
|
|
859
983
|
}
|
|
860
984
|
|
|
@@ -873,12 +997,12 @@ export class BlockInputSync {
|
|
|
873
997
|
*/
|
|
874
998
|
private async reconcilePayloadEnvelope(pendingPayload: PendingPayloadEnvelope): Promise<void> {
|
|
875
999
|
const rootHex = getPayloadSyncCacheItemRootHex(pendingPayload);
|
|
1000
|
+
|
|
876
1001
|
if (this.chain.forkChoice.hasPayloadHexUnsafe(rootHex)) {
|
|
877
1002
|
this.pendingPayloads.delete(rootHex);
|
|
878
1003
|
return;
|
|
879
1004
|
}
|
|
880
1005
|
|
|
881
|
-
const payloadInput = this.chain.seenPayloadEnvelopeInputCache.get(rootHex);
|
|
882
1006
|
if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
|
|
883
1007
|
// Block not in fork choice yet. payloadInput may be seeded from the block body during download, so a
|
|
884
1008
|
// non-null payloadInput does not imply the block is imported; defer regardless and pull the block first.
|
|
@@ -894,8 +1018,9 @@ export class BlockInputSync {
|
|
|
894
1018
|
return;
|
|
895
1019
|
}
|
|
896
1020
|
|
|
1021
|
+
const payloadInput = await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
|
|
897
1022
|
if (!payloadInput) {
|
|
898
|
-
this.logger.debug("
|
|
1023
|
+
this.logger.debug("PayloadEnvelopeInput not yet reloadable for imported block, will retry", {
|
|
899
1024
|
root: rootHex,
|
|
900
1025
|
});
|
|
901
1026
|
return;
|
|
@@ -915,6 +1040,7 @@ export class BlockInputSync {
|
|
|
915
1040
|
const pendingPayloadByRoot: PendingPayloadRootHex = {
|
|
916
1041
|
status: PendingPayloadInputStatus.pending,
|
|
917
1042
|
rootHex,
|
|
1043
|
+
slot: pendingPayload.envelope.message.payload.slotNumber,
|
|
918
1044
|
timeAddedSec: pendingPayload.timeAddedSec,
|
|
919
1045
|
peerIdStrings: new Set(pendingPayload.peerIdStrings),
|
|
920
1046
|
};
|
|
@@ -954,6 +1080,10 @@ export class BlockInputSync {
|
|
|
954
1080
|
return;
|
|
955
1081
|
}
|
|
956
1082
|
|
|
1083
|
+
if (!isPendingPayloadInput(payload) && payload.slot === undefined) {
|
|
1084
|
+
payload.slot = this.resolvePayloadSlot(rootHex);
|
|
1085
|
+
}
|
|
1086
|
+
|
|
957
1087
|
const payloadSlot = getPayloadSyncCacheItemSlot(payload);
|
|
958
1088
|
const logCtx = {
|
|
959
1089
|
slot: payloadSlot,
|
|
@@ -969,7 +1099,13 @@ export class BlockInputSync {
|
|
|
969
1099
|
const res = await wrapError(this.fetchPayloadInput(payload));
|
|
970
1100
|
if (!res.err) {
|
|
971
1101
|
const pendingPayload = res.result;
|
|
972
|
-
|
|
1102
|
+
const resultRootHex = getPayloadSyncCacheItemRootHex(pendingPayload);
|
|
1103
|
+
// finalization may have deleted this entry while we were awaiting the network, do not resurrect it via the set below
|
|
1104
|
+
if (!this.pendingPayloads.has(resultRootHex)) {
|
|
1105
|
+
this.logger.verbose("Dropping downloaded payload, entry pruned during fetch", logCtx);
|
|
1106
|
+
return;
|
|
1107
|
+
}
|
|
1108
|
+
this.pendingPayloads.set(resultRootHex, pendingPayload);
|
|
973
1109
|
|
|
974
1110
|
if (isPendingPayloadEnvelope(pendingPayload)) {
|
|
975
1111
|
await this.reconcilePayloadEnvelope(pendingPayload);
|
|
@@ -1046,17 +1182,27 @@ export class BlockInputSync {
|
|
|
1046
1182
|
break;
|
|
1047
1183
|
|
|
1048
1184
|
case PayloadErrorCode.EXECUTION_ENGINE_INVALID:
|
|
1185
|
+
this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
|
|
1186
|
+
this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.elInvalid);
|
|
1187
|
+
break;
|
|
1188
|
+
|
|
1049
1189
|
case PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR:
|
|
1190
|
+
this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
|
|
1191
|
+
this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.invalidEnvelope);
|
|
1192
|
+
break;
|
|
1193
|
+
|
|
1050
1194
|
case PayloadErrorCode.INVALID_SIGNATURE:
|
|
1051
1195
|
// TODO GLOAS: Decide how invalid payload inputs should eventually leave memory without
|
|
1052
1196
|
// reintroducing envelope replacement / recreation flows.
|
|
1053
1197
|
this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
|
|
1054
|
-
this.removePendingPayloadAndDescendants(rootHex);
|
|
1198
|
+
this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.invalidSignature);
|
|
1055
1199
|
break;
|
|
1056
1200
|
|
|
1057
1201
|
default:
|
|
1058
1202
|
this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
|
|
1059
|
-
this.pendingPayloads.delete(rootHex)
|
|
1203
|
+
if (this.pendingPayloads.delete(rootHex)) {
|
|
1204
|
+
this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.unknown}, 1);
|
|
1205
|
+
}
|
|
1060
1206
|
}
|
|
1061
1207
|
return;
|
|
1062
1208
|
}
|
|
@@ -1080,7 +1226,7 @@ export class BlockInputSync {
|
|
|
1080
1226
|
let slot = getPayloadSyncCacheItemSlot(cacheItem);
|
|
1081
1227
|
let payloadInput = isPendingPayloadInput(cacheItem)
|
|
1082
1228
|
? cacheItem.payloadInput
|
|
1083
|
-
: this.chain.seenPayloadEnvelopeInputCache.
|
|
1229
|
+
: await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
|
|
1084
1230
|
let envelope = payloadInput?.hasPayloadEnvelope() ? payloadInput.getPayloadEnvelope() : undefined;
|
|
1085
1231
|
|
|
1086
1232
|
let i = 0;
|
|
@@ -1097,9 +1243,11 @@ export class BlockInputSync {
|
|
|
1097
1243
|
);
|
|
1098
1244
|
}
|
|
1099
1245
|
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1246
|
+
const reason =
|
|
1247
|
+
pendingColumns.size > 0
|
|
1248
|
+
? `cannot find peer with needed columns=${prettyPrintIndices(Array.from(pendingColumns))}`
|
|
1249
|
+
: "no peer available to download pending payload";
|
|
1250
|
+
throw Error(`Error fetching payload by root slot=${slot} root=${rootHex} after ${i}: ${reason}`);
|
|
1103
1251
|
}
|
|
1104
1252
|
|
|
1105
1253
|
const {peerId, client: peerClient} = peerMeta;
|
|
@@ -1111,7 +1259,7 @@ export class BlockInputSync {
|
|
|
1111
1259
|
slot = envelope.message.payload.slotNumber;
|
|
1112
1260
|
}
|
|
1113
1261
|
|
|
1114
|
-
payloadInput ??= this.chain.seenPayloadEnvelopeInputCache.
|
|
1262
|
+
payloadInput ??= await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
|
|
1115
1263
|
if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
|
|
1116
1264
|
// Block not in fork choice yet. Validating now would throw BLOCK_ROOT_UNKNOWN, so keep the downloaded
|
|
1117
1265
|
// envelope and wait for the block body; reconcilePayloadEnvelope validates once the block lands.
|
|
@@ -1444,9 +1592,9 @@ export class BlockInputSync {
|
|
|
1444
1592
|
* Downscore all peers that have referenced any of this bad blocks. May report peers multiple times if they have
|
|
1445
1593
|
* referenced more than one bad block.
|
|
1446
1594
|
*/
|
|
1447
|
-
private removeAndDownScoreAllDescendants(block: BlockInputSyncCacheItem): void {
|
|
1595
|
+
private removeAndDownScoreAllDescendants(block: BlockInputSyncCacheItem, headReason: DroppedItemReason): void {
|
|
1448
1596
|
// Get all blocks that are a descendant of this one
|
|
1449
|
-
const badPendingBlocks = this.removeAllDescendants(block);
|
|
1597
|
+
const badPendingBlocks = this.removeAllDescendants(block, headReason, DroppedItemReason.invalidParent);
|
|
1450
1598
|
// just console log and do not penalize on pending/bad blocks for debugging
|
|
1451
1599
|
// console.log("removeAndDownscoreAllDescendants", {block});
|
|
1452
1600
|
|
|
@@ -1473,18 +1621,22 @@ export class BlockInputSync {
|
|
|
1473
1621
|
}
|
|
1474
1622
|
|
|
1475
1623
|
// Once a parent payload is invalid, every descendant waiting on that payload lineage becomes unrecoverable too.
|
|
1476
|
-
private removePendingPayloadAndDescendants(rootHex: RootHex): void {
|
|
1624
|
+
private removePendingPayloadAndDescendants(rootHex: RootHex, headReason: DroppedItemReason): void {
|
|
1477
1625
|
// Keep PayloadEnvelopeInput resident in the seen cache. importBlock() owns that object and
|
|
1478
1626
|
// later validation/finalization logic decides when it can leave memory.
|
|
1479
|
-
this.pendingPayloads.delete(rootHex)
|
|
1627
|
+
if (this.pendingPayloads.delete(rootHex)) {
|
|
1628
|
+
this.metrics?.blockInputSync.removedPayloads.inc({reason: headReason}, 1);
|
|
1629
|
+
}
|
|
1480
1630
|
|
|
1481
1631
|
const badPendingBlocks = getAllDescendantBlocks(rootHex, this.pendingBlocks);
|
|
1482
|
-
this.metrics?.blockInputSync.removedBlocks.inc(badPendingBlocks.length);
|
|
1483
|
-
|
|
1484
1632
|
for (const block of badPendingBlocks) {
|
|
1485
1633
|
const descendantRootHex = getBlockInputSyncCacheItemRootHex(block);
|
|
1486
|
-
this.pendingBlocks.delete(descendantRootHex)
|
|
1487
|
-
|
|
1634
|
+
if (this.pendingBlocks.delete(descendantRootHex)) {
|
|
1635
|
+
this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.invalidParent}, 1);
|
|
1636
|
+
}
|
|
1637
|
+
if (this.pendingPayloads.delete(descendantRootHex)) {
|
|
1638
|
+
this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.invalidParent}, 1);
|
|
1639
|
+
}
|
|
1488
1640
|
this.chain.seenBlockInputCache.prune(descendantRootHex);
|
|
1489
1641
|
this.logger.debug("Removing pending descendant after invalid parent payload", {
|
|
1490
1642
|
slot: getBlockInputSyncCacheItemSlot(block),
|
|
@@ -1494,18 +1646,25 @@ export class BlockInputSync {
|
|
|
1494
1646
|
}
|
|
1495
1647
|
}
|
|
1496
1648
|
|
|
1497
|
-
private removeAllDescendants(
|
|
1649
|
+
private removeAllDescendants(
|
|
1650
|
+
block: BlockInputSyncCacheItem,
|
|
1651
|
+
headReason: DroppedItemReason,
|
|
1652
|
+
descendantReason: DroppedItemReason = DroppedItemReason.invalidParent
|
|
1653
|
+
): BlockInputSyncCacheItem[] {
|
|
1498
1654
|
const rootHex = getBlockInputSyncCacheItemRootHex(block);
|
|
1499
1655
|
const slot = getBlockInputSyncCacheItemSlot(block);
|
|
1500
|
-
// Get all blocks that are a descendant of this one
|
|
1656
|
+
// Get all blocks that are a descendant of this one (index 0 is the head item itself)
|
|
1501
1657
|
const badPendingBlocks = [block, ...getAllDescendantBlocks(rootHex, this.pendingBlocks)];
|
|
1502
1658
|
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
for (const block of badPendingBlocks) {
|
|
1659
|
+
for (const [i, block] of badPendingBlocks.entries()) {
|
|
1506
1660
|
const rootHex = getBlockInputSyncCacheItemRootHex(block);
|
|
1507
|
-
|
|
1508
|
-
this.
|
|
1661
|
+
const reason = i === 0 ? headReason : descendantReason;
|
|
1662
|
+
if (this.pendingBlocks.delete(rootHex)) {
|
|
1663
|
+
this.metrics?.blockInputSync.removedBlocks.inc({reason}, 1);
|
|
1664
|
+
}
|
|
1665
|
+
if (this.pendingPayloads.delete(rootHex)) {
|
|
1666
|
+
this.metrics?.blockInputSync.removedPayloads.inc({reason}, 1);
|
|
1667
|
+
}
|
|
1509
1668
|
this.chain.seenBlockInputCache.prune(rootHex);
|
|
1510
1669
|
// Keep PayloadEnvelopeInput resident in the seen cache for consistency with the
|
|
1511
1670
|
// importBlock()-owned lifecycle.
|
|
@@ -136,6 +136,8 @@ export function cacheByRangeResponses({
|
|
|
136
136
|
const source = BlockInputSource.byRange;
|
|
137
137
|
const updatedBatchBlocks = new Map<Slot, IBlockInput>(batchBlocks.map((block) => [block.slot, block]));
|
|
138
138
|
|
|
139
|
+
const payloadEnvelopes = new Map<Slot, PayloadEnvelopeInput>(existingPayloadEnvelopes);
|
|
140
|
+
|
|
139
141
|
const blocks = responses.validatedBlocks ?? [];
|
|
140
142
|
for (let i = 0; i < blocks.length; i++) {
|
|
141
143
|
const {block, blockRoot} = blocks[i];
|
|
@@ -172,15 +174,17 @@ export function cacheByRangeResponses({
|
|
|
172
174
|
// later step) can throw and abort the batch — otherwise a gloas block would sit in
|
|
173
175
|
// seenBlockInputCache but unseeded here, and payload-by-root sync would later throw "Missing
|
|
174
176
|
// PayloadEnvelopeInput for known block" (see issue #9306). add() is idempotent.
|
|
175
|
-
if (isForkPostGloas(blockInput.forkName)) {
|
|
176
|
-
seenPayloadEnvelopeInputCache.add({
|
|
177
|
+
if (isForkPostGloas(blockInput.forkName) && !payloadEnvelopes.has(blockInput.slot)) {
|
|
178
|
+
const payloadInput = seenPayloadEnvelopeInputCache.add({
|
|
177
179
|
blockRootHex: blockInput.blockRootHex,
|
|
178
180
|
block: blockInput.getBlock() as SignedBeaconBlock<ForkPostGloas>,
|
|
179
181
|
forkName: blockInput.forkName,
|
|
180
182
|
sampledColumns: custodyConfig.sampledColumns,
|
|
181
183
|
custodyColumns: custodyConfig.custodyColumns,
|
|
182
|
-
|
|
184
|
+
seenTimestampSec,
|
|
185
|
+
source: PayloadEnvelopeInputSource.byRange,
|
|
183
186
|
});
|
|
187
|
+
payloadEnvelopes.set(blockInput.slot, payloadInput);
|
|
184
188
|
}
|
|
185
189
|
}
|
|
186
190
|
|
|
@@ -222,17 +226,22 @@ export function cacheByRangeResponses({
|
|
|
222
226
|
}
|
|
223
227
|
}
|
|
224
228
|
|
|
225
|
-
let payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null =
|
|
226
|
-
existingPayloadEnvelopes !== null ? new Map(existingPayloadEnvelopes) : null;
|
|
227
229
|
if (downloadedPayloadEnvelopes !== null) {
|
|
228
|
-
payloadEnvelopes ??= new Map();
|
|
229
230
|
for (const [slot, envelope] of downloadedPayloadEnvelopes) {
|
|
230
|
-
|
|
231
|
-
|
|
231
|
+
// the only PayloadEnvelopeInput miss is the dangling parent, which we can get from the seen cache
|
|
232
|
+
let payloadInput = payloadEnvelopes.get(slot);
|
|
232
233
|
if (payloadInput === undefined) {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
234
|
+
if (updatedBatchBlocks.has(slot)) {
|
|
235
|
+
throw new Error(
|
|
236
|
+
`Missing PayloadEnvelopeInput for in-batch slot ${slot} root ${toRootHex(envelope.message.beaconBlockRoot)}`
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
payloadInput = seenPayloadEnvelopeInputCache.get(toRootHex(envelope.message.beaconBlockRoot));
|
|
240
|
+
}
|
|
241
|
+
if (payloadInput === undefined) {
|
|
242
|
+
throw new Error(
|
|
243
|
+
`Missing PayloadEnvelopeInput for slot ${slot} root ${toRootHex(envelope.message.beaconBlockRoot)}`
|
|
244
|
+
);
|
|
236
245
|
}
|
|
237
246
|
|
|
238
247
|
if (!payloadInput.hasPayloadEnvelope()) {
|
|
@@ -262,7 +271,7 @@ export function cacheByRangeResponses({
|
|
|
262
271
|
// Gloas columns are attached to the matching PayloadEnvelopeInput, NOT to IBlockInput.
|
|
263
272
|
// Gloas DataColumnSidecar has `slot` directly (no signedBlockHeader).
|
|
264
273
|
const dataSlot = firstColumn.slot;
|
|
265
|
-
const payloadInput = payloadEnvelopes
|
|
274
|
+
const payloadInput = payloadEnvelopes.get(dataSlot);
|
|
266
275
|
if (!payloadInput) {
|
|
267
276
|
// Should not happen: we built payloadInputs for all gloas blocks above
|
|
268
277
|
continue;
|
|
@@ -13,6 +13,7 @@ import {BlobIndex, ColumnIndex, SignedBeaconBlock, Slot, deneb, fulu} from "@lod
|
|
|
13
13
|
import {LodestarError, byteArrayEquals, fromHex, prettyPrintIndices, toHex, toRootHex} from "@lodestar/utils";
|
|
14
14
|
import {isBlockInputBlobs, isBlockInputColumns} from "../../chain/blocks/blockInput/blockInput.js";
|
|
15
15
|
import {BlockInputSource, IBlockInput} from "../../chain/blocks/blockInput/types.js";
|
|
16
|
+
import {PayloadEnvelopeInputSource} from "../../chain/blocks/payloadEnvelopeInput/index.js";
|
|
16
17
|
import {ChainEventEmitter} from "../../chain/emitter.js";
|
|
17
18
|
import {IBeaconChain} from "../../chain/interface.js";
|
|
18
19
|
import {validateBlockBlobSidecars} from "../../chain/validation/blobSidecar.js";
|
|
@@ -122,7 +123,8 @@ export async function downloadByRoot({
|
|
|
122
123
|
forkName: blockInput.forkName,
|
|
123
124
|
sampledColumns: chain.custodyConfig.sampledColumns,
|
|
124
125
|
custodyColumns: chain.custodyConfig.custodyColumns,
|
|
125
|
-
|
|
126
|
+
seenTimestampSec: Date.now() / 1000,
|
|
127
|
+
source: PayloadEnvelopeInputSource.byRoot,
|
|
126
128
|
});
|
|
127
129
|
}
|
|
128
130
|
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { PublicKey } from "@chainsafe/blst";
|
|
2
|
-
export type SignatureSetDeserialized = {
|
|
3
|
-
publicKey: PublicKey;
|
|
4
|
-
message: Uint8Array;
|
|
5
|
-
signature: Uint8Array;
|
|
6
|
-
};
|
|
7
|
-
/**
|
|
8
|
-
* Verify signatures sets with batch verification or regular core verify depending on the set count.
|
|
9
|
-
* Abstracted in a separate file to be consumed by the threaded pool and the main thread implementation.
|
|
10
|
-
*/
|
|
11
|
-
export declare function verifySignatureSetsMaybeBatch(sets: SignatureSetDeserialized[]): boolean;
|
|
12
|
-
//# sourceMappingURL=maybeBatch.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"maybeBatch.d.ts","sourceRoot":"","sources":["../../../src/chain/bls/maybeBatch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAuD,MAAM,iBAAiB,CAAC;AAIhG,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,UAAU,CAAC;IACpB,SAAS,EAAE,UAAU,CAAC;CACvB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,wBAAwB,EAAE,GAAG,OAAO,CA8BvF"}
|