@lodestar/beacon-node 1.47.0-dev.ec596194e2 → 1.47.0-dev.f0f26cd2b6
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 +47 -18
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/pool/index.js +25 -2
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/api/impl/beacon/state/utils.d.ts +2 -1
- package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/utils.js.map +1 -1
- package/lib/api/impl/events/index.d.ts +1 -1
- package/lib/api/impl/events/index.d.ts.map +1 -1
- package/lib/api/impl/events/index.js +12 -3
- package/lib/api/impl/events/index.js.map +1 -1
- package/lib/api/impl/lodestar/index.js +1 -1
- package/lib/api/impl/lodestar/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +232 -49
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/api/impl/validator/utils.js +1 -1
- 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 +2 -7
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts +3 -2
- package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.js +11 -9
- package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
- package/lib/chain/blocks/index.d.ts.map +1 -1
- package/lib/chain/blocks/index.js +21 -13
- 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 +5 -2
- 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/chain.d.ts +9 -4
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +22 -8
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/errors/blockError.d.ts +1 -0
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +6 -1
- package/lib/chain/errors/blockError.js.map +1 -1
- package/lib/chain/errors/proposerPreferences.d.ts +6 -0
- package/lib/chain/errors/proposerPreferences.d.ts.map +1 -1
- package/lib/chain/errors/proposerPreferences.js +1 -0
- package/lib/chain/errors/proposerPreferences.js.map +1 -1
- package/lib/chain/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +4 -0
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/interface.d.ts +8 -4
- 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/executionPayloadBidPool.d.ts +7 -2
- package/lib/chain/opPools/executionPayloadBidPool.d.ts.map +1 -1
- package/lib/chain/opPools/executionPayloadBidPool.js +4 -4
- package/lib/chain/opPools/executionPayloadBidPool.js.map +1 -1
- package/lib/chain/opPools/index.d.ts +2 -1
- 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/prepareNextSlot.d.ts +5 -0
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +47 -6
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.js +3 -25
- package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/regen/interface.d.ts +5 -2
- package/lib/chain/regen/interface.d.ts.map +1 -1
- package/lib/chain/regen/interface.js +3 -0
- package/lib/chain/regen/interface.js.map +1 -1
- package/lib/chain/regen/queued.d.ts +2 -2
- package/lib/chain/regen/queued.d.ts.map +1 -1
- package/lib/chain/regen/queued.js +5 -5
- package/lib/chain/regen/queued.js.map +1 -1
- package/lib/chain/seenCache/seenAttesters.d.ts +9 -5
- package/lib/chain/seenCache/seenAttesters.d.ts.map +1 -1
- package/lib/chain/seenCache/seenAttesters.js +25 -4
- package/lib/chain/seenCache/seenAttesters.js.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +28 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +121 -13
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
- package/lib/chain/stateCache/fifoBlockStateCache.d.ts +5 -1
- package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
- package/lib/chain/stateCache/fifoBlockStateCache.js +6 -0
- package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +47 -5
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +117 -7
- package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
- package/lib/chain/stateCache/types.d.ts +3 -3
- package/lib/chain/stateCache/types.d.ts.map +1 -1
- package/lib/chain/validation/attestation.d.ts.map +1 -1
- package/lib/chain/validation/attestation.js +1 -4
- package/lib/chain/validation/attestation.js.map +1 -1
- package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
- package/lib/chain/validation/attesterSlashing.js +1 -1
- package/lib/chain/validation/attesterSlashing.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +40 -10
- package/lib/chain/validation/block.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.d.ts +13 -3
- package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +147 -12
- 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/apiClient.d.ts +70 -0
- package/lib/execution/builder/apiClient.d.ts.map +1 -0
- package/lib/execution/builder/apiClient.js +202 -0
- package/lib/execution/builder/apiClient.js.map +1 -0
- package/lib/execution/builder/validateBid.d.ts +22 -0
- package/lib/execution/builder/validateBid.d.ts.map +1 -0
- package/lib/execution/builder/validateBid.js +111 -0
- package/lib/execution/builder/validateBid.js.map +1 -0
- package/lib/metrics/metrics/lodestar.d.ts +94 -23
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +177 -55
- 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 +23 -43
- package/lib/network/network.js.map +1 -1
- package/lib/network/processor/constants.d.ts +7 -0
- package/lib/network/processor/constants.d.ts.map +1 -0
- package/lib/network/processor/constants.js +7 -0
- package/lib/network/processor/constants.js.map +1 -0
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +13 -4
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/processor/gossipQueues/indexed.d.ts.map +1 -1
- package/lib/network/processor/gossipQueues/indexed.js +0 -1
- package/lib/network/processor/gossipQueues/indexed.js.map +1 -1
- package/lib/network/processor/index.d.ts +3 -0
- package/lib/network/processor/index.d.ts.map +1 -1
- package/lib/network/processor/index.js +52 -23
- package/lib/network/processor/index.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 +7 -0
- package/lib/node/nodejs.js.map +1 -1
- package/lib/sync/range/batch.d.ts +23 -5
- package/lib/sync/range/batch.d.ts.map +1 -1
- package/lib/sync/range/batch.js +61 -22
- package/lib/sync/range/batch.js.map +1 -1
- package/lib/sync/range/chain.d.ts +2 -1
- package/lib/sync/range/chain.d.ts.map +1 -1
- package/lib/sync/range/chain.js +32 -12
- package/lib/sync/range/chain.js.map +1 -1
- package/lib/sync/range/range.js +1 -1
- package/lib/sync/range/range.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 +15 -2
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +220 -61
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRange.js +16 -11
- package/lib/sync/utils/downloadByRange.js.map +1 -1
- package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRoot.js +3 -1
- package/lib/sync/utils/downloadByRoot.js.map +1 -1
- package/package.json +35 -35
- package/src/api/impl/beacon/blocks/index.ts +55 -21
- package/src/api/impl/beacon/pool/index.ts +27 -2
- package/src/api/impl/beacon/state/utils.ts +2 -1
- package/src/api/impl/events/index.ts +12 -4
- package/src/api/impl/lodestar/index.ts +1 -1
- package/src/api/impl/validator/index.ts +285 -49
- package/src/api/impl/validator/utils.ts +1 -1
- package/src/api/rest/base.ts +7 -0
- package/src/chain/archiveStore/archiveStore.ts +1 -1
- package/src/chain/archiveStore/historicalState/metrics.ts +22 -0
- package/src/chain/blocks/importBlock.ts +1 -6
- package/src/chain/blocks/importExecutionPayload.ts +12 -11
- package/src/chain/blocks/index.ts +25 -13
- package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +8 -2
- package/src/chain/blocks/payloadEnvelopeInput/types.ts +17 -4
- package/src/chain/blocks/verifyBlock.ts +5 -2
- 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/chain.ts +25 -7
- package/src/chain/errors/blockError.ts +8 -2
- package/src/chain/errors/proposerPreferences.ts +7 -0
- package/src/chain/forkChoice/index.ts +4 -0
- package/src/chain/interface.ts +8 -3
- 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/executionPayloadBidPool.ts +13 -7
- package/src/chain/opPools/index.ts +2 -1
- package/src/chain/opPools/payloadAttestationPool.ts +3 -3
- package/src/chain/opPools/syncCommitteeMessagePool.ts +1 -1
- package/src/chain/opPools/syncContributionAndProofPool.ts +1 -1
- package/src/chain/opPools/utils.ts +1 -1
- package/src/chain/prepareNextSlot.ts +49 -6
- package/src/chain/produceBlock/computeNewStateRoot.ts +3 -38
- package/src/chain/produceBlock/produceBlockBody.ts +1 -1
- package/src/chain/regen/interface.ts +5 -2
- package/src/chain/regen/queued.ts +5 -5
- package/src/chain/seenCache/seenAttesters.ts +31 -5
- package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +143 -14
- package/src/chain/stateCache/fifoBlockStateCache.ts +8 -1
- package/src/chain/stateCache/persistentCheckpointsCache.ts +133 -8
- package/src/chain/stateCache/types.ts +3 -3
- package/src/chain/validation/attestation.ts +1 -7
- package/src/chain/validation/attesterSlashing.ts +1 -8
- package/src/chain/validation/block.ts +43 -10
- package/src/chain/validation/executionPayloadBid.ts +168 -14
- 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/apiClient.ts +264 -0
- package/src/execution/builder/validateBid.ts +166 -0
- package/src/metrics/metrics/lodestar.ts +192 -61
- package/src/network/gossip/topic.ts +38 -0
- package/src/network/libp2p/index.ts +11 -2
- package/src/network/network.ts +29 -54
- package/src/network/processor/constants.ts +6 -0
- package/src/network/processor/gossipHandlers.ts +15 -2
- package/src/network/processor/gossipQueues/indexed.ts +0 -1
- package/src/network/processor/index.ts +67 -30
- 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 +10 -1
- package/src/sync/range/batch.ts +83 -28
- package/src/sync/range/chain.ts +35 -13
- package/src/sync/range/range.ts +1 -1
- package/src/sync/types.ts +36 -1
- package/src/sync/unknownBlock.ts +258 -68
- 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";
|
|
@@ -16,6 +17,7 @@ import {validateGossipExecutionPayloadEnvelope} from "../chain/validation/execut
|
|
|
16
17
|
import {Metrics} from "../metrics/index.js";
|
|
17
18
|
import {INetwork, NetworkEvent, NetworkEventData, prettyPrintPeerIdStr} from "../network/index.js";
|
|
18
19
|
import {PeerSyncMeta} from "../network/peers/peersData.js";
|
|
20
|
+
import {MAX_PEERS_PER_ROOT} from "../network/processor/constants.js";
|
|
19
21
|
import {PeerIdStr} from "../util/peerId.js";
|
|
20
22
|
import {shuffle} from "../util/shuffle.js";
|
|
21
23
|
import {sortBy} from "../util/sortBy.js";
|
|
@@ -24,6 +26,7 @@ import {MAX_CONCURRENT_REQUESTS} from "./constants.js";
|
|
|
24
26
|
import {SyncOptions} from "./options.js";
|
|
25
27
|
import {
|
|
26
28
|
BlockInputSyncCacheItem,
|
|
29
|
+
DroppedItemReason,
|
|
27
30
|
PayloadSyncCacheItem,
|
|
28
31
|
PendingBlockInput,
|
|
29
32
|
PendingBlockInputStatus,
|
|
@@ -47,6 +50,10 @@ import {getRateLimitedUntilMs} from "./utils/rateLimit.js";
|
|
|
47
50
|
const MAX_ATTEMPTS_PER_BLOCK = 5;
|
|
48
51
|
const MAX_KNOWN_BAD_BLOCKS = 500;
|
|
49
52
|
const MAX_PENDING_BLOCKS = 100;
|
|
53
|
+
/**
|
|
54
|
+
* A pending payload without slot can only stay at most 2 epochs.
|
|
55
|
+
*/
|
|
56
|
+
const PRUNE_UNRESOLVED_SLOT_EPOCHS = 2;
|
|
50
57
|
|
|
51
58
|
type AdvancePendingBlockResult =
|
|
52
59
|
| "ready"
|
|
@@ -154,10 +161,21 @@ export class BlockInputSync {
|
|
|
154
161
|
this.chain.emitter.on(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
|
|
155
162
|
this.chain.emitter.on(ChainEvent.incompletePayloadEnvelope, this.onIncompletePayloadEnvelope);
|
|
156
163
|
this.chain.emitter.on(ChainEvent.blockUnknownParent, this.onUnknownParent);
|
|
164
|
+
this.chain.emitter.on(ChainEvent.forkChoiceFinalized, this.pruneFinalized);
|
|
157
165
|
this.chain.emitter.on(routes.events.EventType.block, this.onBlockImported);
|
|
158
166
|
this.chain.emitter.on(routes.events.EventType.executionPayload, this.onPayloadImported);
|
|
159
167
|
this.network.events.on(NetworkEvent.peerConnected, this.onPeerConnected);
|
|
160
168
|
this.network.events.on(NetworkEvent.peerDisconnected, this.onPeerDisconnected);
|
|
169
|
+
|
|
170
|
+
// Seed the balancer with peers that connected before we subscribed
|
|
171
|
+
for (const peerId of this.network.getConnectedPeers()) {
|
|
172
|
+
try {
|
|
173
|
+
this.peerBalancer.onPeerConnected(peerId, this.network.getConnectedPeerSyncMeta(peerId));
|
|
174
|
+
} catch (e) {
|
|
175
|
+
this.logger.debug("Failed to seed connected peer into BlockInputSync balancer", {peerId}, e as Error);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
161
179
|
this.subscribedToNetworkEvents = true;
|
|
162
180
|
}
|
|
163
181
|
}
|
|
@@ -170,10 +188,12 @@ export class BlockInputSync {
|
|
|
170
188
|
this.chain.emitter.off(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
|
|
171
189
|
this.chain.emitter.off(ChainEvent.incompletePayloadEnvelope, this.onIncompletePayloadEnvelope);
|
|
172
190
|
this.chain.emitter.off(ChainEvent.blockUnknownParent, this.onUnknownParent);
|
|
191
|
+
this.chain.emitter.off(ChainEvent.forkChoiceFinalized, this.pruneFinalized);
|
|
173
192
|
this.chain.emitter.off(routes.events.EventType.block, this.onBlockImported);
|
|
174
193
|
this.chain.emitter.off(routes.events.EventType.executionPayload, this.onPayloadImported);
|
|
175
194
|
this.network.events.off(NetworkEvent.peerConnected, this.onPeerConnected);
|
|
176
195
|
this.network.events.off(NetworkEvent.peerDisconnected, this.onPeerDisconnected);
|
|
196
|
+
this.peerBalancer.clear();
|
|
177
197
|
this.subscribedToNetworkEvents = false;
|
|
178
198
|
}
|
|
179
199
|
|
|
@@ -190,10 +210,12 @@ export class BlockInputSync {
|
|
|
190
210
|
*/
|
|
191
211
|
private onUnknownBlockRoot = (data: ChainEventData[ChainEvent.unknownBlockRoot]): void => {
|
|
192
212
|
try {
|
|
193
|
-
this.addByRootHex(data.rootHex, data.peer);
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
213
|
+
const isNewRoot = this.addByRootHex(data.rootHex, data.peer);
|
|
214
|
+
if (isNewRoot) {
|
|
215
|
+
this.triggerUnknownBlockSearch();
|
|
216
|
+
this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.UNKNOWN_BLOCK_ROOT});
|
|
217
|
+
this.metrics?.blockInputSync.source.inc({source: data.source});
|
|
218
|
+
}
|
|
197
219
|
} catch (e) {
|
|
198
220
|
this.logger.debug("Error handling unknownBlockRoot event", {}, e as Error);
|
|
199
221
|
}
|
|
@@ -215,10 +237,12 @@ export class BlockInputSync {
|
|
|
215
237
|
|
|
216
238
|
private onUnknownEnvelopeBlockRoot = (data: ChainEventData[ChainEvent.unknownEnvelopeBlockRoot]): void => {
|
|
217
239
|
try {
|
|
218
|
-
this.addByPayloadRootHex(data.rootHex, data.peer, data.
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
240
|
+
const isNewRoot = this.addByPayloadRootHex(data.rootHex, data.peer, this.resolvePayloadSlot(data.rootHex));
|
|
241
|
+
if (isNewRoot) {
|
|
242
|
+
this.triggerUnknownBlockSearch();
|
|
243
|
+
this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.UNKNOWN_PAYLOAD_BLOCK_ROOT});
|
|
244
|
+
this.metrics?.blockInputSync.payloadSource.inc({source: data.source});
|
|
245
|
+
}
|
|
222
246
|
} catch (e) {
|
|
223
247
|
this.logger.debug("Error handling unknownEnvelopeBlockRoot event", {}, e as Error);
|
|
224
248
|
}
|
|
@@ -252,13 +276,13 @@ export class BlockInputSync {
|
|
|
252
276
|
parentRoot: missingDependency.parentRootHex,
|
|
253
277
|
parentBlockHash: missingDependency.parentBlockHashHex,
|
|
254
278
|
});
|
|
255
|
-
this.removeAndDownScoreAllDescendants(pendingBlock);
|
|
279
|
+
this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidParentPayload);
|
|
256
280
|
}
|
|
257
281
|
return;
|
|
258
282
|
}
|
|
259
283
|
|
|
260
284
|
if (missingDependency.kind === "parentPayload") {
|
|
261
|
-
this.addByPayloadRootHex(missingDependency.rootHex, data.peer);
|
|
285
|
+
this.addByPayloadRootHex(missingDependency.rootHex, data.peer, missingDependency.slot);
|
|
262
286
|
} else if (missingDependency.kind === "parentBlock") {
|
|
263
287
|
this.addByRootHex(missingDependency.rootHex, data.peer);
|
|
264
288
|
}
|
|
@@ -284,6 +308,80 @@ export class BlockInputSync {
|
|
|
284
308
|
this.triggerUnknownBlockSearch();
|
|
285
309
|
};
|
|
286
310
|
|
|
311
|
+
/**
|
|
312
|
+
* Drop pending payloads and blocks that fell below the finalized slot.
|
|
313
|
+
* See https://github.com/ChainSafe/lodestar/issues/9800
|
|
314
|
+
*/
|
|
315
|
+
private pruneFinalized = (checkpoint: CheckpointWithHex): void => {
|
|
316
|
+
// Use the actual finalized block slot, not computeStartSlotAtEpoch(checkpoint.epoch)
|
|
317
|
+
// because the payload at the finalized block is not finalized
|
|
318
|
+
const finalizedSlot = this.chain.forkChoice.getFinalizedBlock().slot;
|
|
319
|
+
const nowSec = Date.now() / 1000;
|
|
320
|
+
const maxSecInCache = (PRUNE_UNRESOLVED_SLOT_EPOCHS * SLOTS_PER_EPOCH * this.config.SLOT_DURATION_MS) / 1000;
|
|
321
|
+
|
|
322
|
+
let belowFinalizedPayloads = 0;
|
|
323
|
+
let agedOutPayloads = 0;
|
|
324
|
+
let unresolvedSlotPayloads = 0;
|
|
325
|
+
|
|
326
|
+
for (const [rootHex, payload] of this.pendingPayloads) {
|
|
327
|
+
// Last-effort resolve for a slot-less PendingPayloadRootHex, and store it back for later passes.
|
|
328
|
+
if (!isPendingPayloadInput(payload) && !isPendingPayloadEnvelope(payload) && payload.slot === undefined) {
|
|
329
|
+
payload.slot = this.resolvePayloadSlot(rootHex);
|
|
330
|
+
if (payload.slot === undefined) {
|
|
331
|
+
// Still unresolvable: age it out so the MAX_PENDING_BLOCKS cap cannot stay saturated.
|
|
332
|
+
if (nowSec - payload.timeAddedSec > maxSecInCache) {
|
|
333
|
+
this.pendingPayloads.delete(rootHex);
|
|
334
|
+
agedOutPayloads++;
|
|
335
|
+
} else {
|
|
336
|
+
unresolvedSlotPayloads++;
|
|
337
|
+
this.logger.debug("BlockInputSync.pruneFinalized: pending payload with unresolved slot", {
|
|
338
|
+
root: rootHex,
|
|
339
|
+
finalizedSlot,
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const slot = getPayloadSyncCacheItemSlot(payload);
|
|
347
|
+
if (typeof slot === "number" && slot < finalizedSlot) {
|
|
348
|
+
this.pendingPayloads.delete(rootHex);
|
|
349
|
+
belowFinalizedPayloads++;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
let deletedBlocks = 0;
|
|
354
|
+
for (const [rootHex, block] of this.pendingBlocks) {
|
|
355
|
+
const slot = getBlockInputSyncCacheItemSlot(block);
|
|
356
|
+
if (typeof slot === "number" && slot < finalizedSlot) {
|
|
357
|
+
this.pendingBlocks.delete(rootHex);
|
|
358
|
+
deletedBlocks++;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (belowFinalizedPayloads > 0) {
|
|
363
|
+
this.metrics?.blockInputSync.removedPayloads.inc(
|
|
364
|
+
{reason: DroppedItemReason.belowFinalized},
|
|
365
|
+
belowFinalizedPayloads
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
if (agedOutPayloads > 0) {
|
|
369
|
+
this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.agedOut}, agedOutPayloads);
|
|
370
|
+
}
|
|
371
|
+
if (deletedBlocks > 0) {
|
|
372
|
+
this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.belowFinalized}, deletedBlocks);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
this.logger.debug("BlockInputSync.pruneFinalized dropped pre-finalized pending items", {
|
|
376
|
+
finalizedSlot,
|
|
377
|
+
finalizedRoot: checkpoint.rootHex,
|
|
378
|
+
belowFinalizedPayloads,
|
|
379
|
+
agedOutPayloads,
|
|
380
|
+
deletedBlocks,
|
|
381
|
+
unresolvedSlotPayloads,
|
|
382
|
+
});
|
|
383
|
+
};
|
|
384
|
+
|
|
287
385
|
private addByRootHex = (rootHex: RootHex, peerIdStr?: PeerIdStr): boolean => {
|
|
288
386
|
let pendingBlock = this.pendingBlocks.get(rootHex);
|
|
289
387
|
let added = false;
|
|
@@ -303,7 +401,9 @@ export class BlockInputSync {
|
|
|
303
401
|
});
|
|
304
402
|
}
|
|
305
403
|
|
|
306
|
-
|
|
404
|
+
// bound peers tracked per root: propagationSource is recorded pre-validation, so cap the set (#9923).
|
|
405
|
+
// Once at the cap, ignore further peers rather than evicting already-tracked ones.
|
|
406
|
+
if (peerIdStr && pendingBlock.peerIdStrings.size < MAX_PEERS_PER_ROOT) {
|
|
307
407
|
pendingBlock.peerIdStrings.add(peerIdStr);
|
|
308
408
|
}
|
|
309
409
|
|
|
@@ -311,6 +411,7 @@ export class BlockInputSync {
|
|
|
311
411
|
// Limit pending blocks to prevent DOS attacks that cause OOM
|
|
312
412
|
const prunedItemCount = pruneSetToMax(this.pendingBlocks, this.maxPendingBlocks);
|
|
313
413
|
if (prunedItemCount > 0) {
|
|
414
|
+
this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
|
|
314
415
|
this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingBlocks`);
|
|
315
416
|
}
|
|
316
417
|
return added;
|
|
@@ -337,7 +438,9 @@ export class BlockInputSync {
|
|
|
337
438
|
});
|
|
338
439
|
}
|
|
339
440
|
|
|
340
|
-
|
|
441
|
+
// bound peers tracked per root: propagationSource is recorded pre-validation, so cap the set (#9923).
|
|
442
|
+
// Once at the cap, ignore further peers rather than evicting already-tracked ones.
|
|
443
|
+
if (peerIdStr && pendingBlock.peerIdStrings.size < MAX_PEERS_PER_ROOT) {
|
|
341
444
|
pendingBlock.peerIdStrings.add(peerIdStr);
|
|
342
445
|
}
|
|
343
446
|
|
|
@@ -345,6 +448,7 @@ export class BlockInputSync {
|
|
|
345
448
|
// Limit pending blocks to prevent DOS attacks that cause OOM
|
|
346
449
|
const prunedItemCount = pruneSetToMax(this.pendingBlocks, this.maxPendingBlocks);
|
|
347
450
|
if (prunedItemCount > 0) {
|
|
451
|
+
this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
|
|
348
452
|
this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingBlocks`);
|
|
349
453
|
}
|
|
350
454
|
};
|
|
@@ -369,19 +473,50 @@ export class BlockInputSync {
|
|
|
369
473
|
root: rootHex,
|
|
370
474
|
peerIdStr: peerIdStr ?? "unknown peer",
|
|
371
475
|
});
|
|
476
|
+
} else if (
|
|
477
|
+
// update a previously slot-less entry once a slot becomes available
|
|
478
|
+
slot !== undefined &&
|
|
479
|
+
!isPendingPayloadInput(pendingPayload) &&
|
|
480
|
+
!isPendingPayloadEnvelope(pendingPayload) &&
|
|
481
|
+
pendingPayload.slot === undefined
|
|
482
|
+
) {
|
|
483
|
+
pendingPayload.slot = slot;
|
|
372
484
|
}
|
|
373
|
-
|
|
374
|
-
if (peerIdStr) {
|
|
485
|
+
if (peerIdStr && pendingPayload.peerIdStrings.size < MAX_PEERS_PER_ROOT) {
|
|
375
486
|
pendingPayload.peerIdStrings.add(peerIdStr);
|
|
376
487
|
}
|
|
377
488
|
|
|
378
489
|
const prunedItemCount = pruneSetToMax(this.pendingPayloads, this.maxPendingBlocks);
|
|
379
490
|
if (prunedItemCount > 0) {
|
|
491
|
+
this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
|
|
380
492
|
this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingPayloads`);
|
|
381
493
|
}
|
|
382
494
|
return added;
|
|
383
495
|
};
|
|
384
496
|
|
|
497
|
+
/**
|
|
498
|
+
* Resolve the block slot for a payload root.
|
|
499
|
+
*/
|
|
500
|
+
private resolvePayloadSlot(rootHex: RootHex): Slot | undefined {
|
|
501
|
+
// a pending block of the same root
|
|
502
|
+
const pendingBlock = this.pendingBlocks.get(rootHex);
|
|
503
|
+
if (pendingBlock) {
|
|
504
|
+
const pendingBlockSlot = getBlockInputSyncCacheItemSlot(pendingBlock);
|
|
505
|
+
if (typeof pendingBlockSlot === "number") {
|
|
506
|
+
return pendingBlockSlot;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// the block is in fork choice
|
|
511
|
+
const forkChoiceSlot = this.chain.forkChoice.getBlockHexDefaultStatus(rootHex)?.slot;
|
|
512
|
+
if (forkChoiceSlot !== undefined) {
|
|
513
|
+
return forkChoiceSlot;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// a seen payload envelope input
|
|
517
|
+
return this.chain.seenPayloadEnvelopeInputCache.get(rootHex)?.slot;
|
|
518
|
+
}
|
|
519
|
+
|
|
385
520
|
private addByPayloadInput = (
|
|
386
521
|
payloadInput: PayloadEnvelopeInput,
|
|
387
522
|
peerIdStr?: PeerIdStr,
|
|
@@ -393,7 +528,7 @@ export class BlockInputSync {
|
|
|
393
528
|
envelope
|
|
394
529
|
);
|
|
395
530
|
|
|
396
|
-
if (peerIdStr) {
|
|
531
|
+
if (peerIdStr && pendingPayload.peerIdStrings.size < MAX_PEERS_PER_ROOT) {
|
|
397
532
|
pendingPayload.peerIdStrings.add(peerIdStr);
|
|
398
533
|
}
|
|
399
534
|
|
|
@@ -407,6 +542,7 @@ export class BlockInputSync {
|
|
|
407
542
|
|
|
408
543
|
const prunedItemCount = pruneSetToMax(this.pendingPayloads, this.maxPendingBlocks);
|
|
409
544
|
if (prunedItemCount > 0) {
|
|
545
|
+
this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
|
|
410
546
|
this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingPayloads`);
|
|
411
547
|
}
|
|
412
548
|
};
|
|
@@ -436,10 +572,12 @@ export class BlockInputSync {
|
|
|
436
572
|
blockInput: IBlockInput
|
|
437
573
|
):
|
|
438
574
|
| {kind: "ready"}
|
|
439
|
-
| {kind: "block" | "parentBlock"
|
|
575
|
+
| {kind: "block" | "parentBlock"; rootHex: RootHex}
|
|
576
|
+
| {kind: "parentPayload"; rootHex: RootHex; slot: Slot}
|
|
440
577
|
| {kind: "invalidParentPayload"; parentRootHex: RootHex; parentBlockHashHex: RootHex} {
|
|
441
578
|
const parentRootHex = blockInput.parentRootHex;
|
|
442
|
-
|
|
579
|
+
const parentBlock = this.chain.forkChoice.getBlockHexDefaultStatus(parentRootHex);
|
|
580
|
+
if (!parentBlock) {
|
|
443
581
|
return {kind: "parentBlock", rootHex: parentRootHex};
|
|
444
582
|
}
|
|
445
583
|
|
|
@@ -461,16 +599,8 @@ export class BlockInputSync {
|
|
|
461
599
|
return {kind: "invalidParentPayload", parentRootHex, parentBlockHashHex};
|
|
462
600
|
}
|
|
463
601
|
|
|
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};
|
|
602
|
+
// Parent is in fork choice but its payload `parentBlockHashHex` isn't revealed yet
|
|
603
|
+
return {kind: "parentPayload", rootHex: parentRootHex, slot: parentBlock.slot};
|
|
474
604
|
}
|
|
475
605
|
|
|
476
606
|
private advancePendingBlock(pendingBlock: PendingBlockInput): AdvancePendingBlockResult {
|
|
@@ -493,9 +623,9 @@ export class BlockInputSync {
|
|
|
493
623
|
}
|
|
494
624
|
|
|
495
625
|
case "parentPayload": {
|
|
496
|
-
let added = this.addByPayloadRootHex(missingDependency.rootHex);
|
|
626
|
+
let added = this.addByPayloadRootHex(missingDependency.rootHex, undefined, missingDependency.slot);
|
|
497
627
|
for (const peerIdStr of pendingBlock.peerIdStrings) {
|
|
498
|
-
added = this.addByPayloadRootHex(missingDependency.rootHex, peerIdStr) || added;
|
|
628
|
+
added = this.addByPayloadRootHex(missingDependency.rootHex, peerIdStr, missingDependency.slot) || added;
|
|
499
629
|
}
|
|
500
630
|
return added ? "queued_parent_payload" : "blocked";
|
|
501
631
|
}
|
|
@@ -507,7 +637,7 @@ export class BlockInputSync {
|
|
|
507
637
|
parentRoot: missingDependency.parentRootHex,
|
|
508
638
|
parentBlockHash: missingDependency.parentBlockHashHex,
|
|
509
639
|
});
|
|
510
|
-
this.removeAndDownScoreAllDescendants(pendingBlock);
|
|
640
|
+
this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidParentPayload);
|
|
511
641
|
return "removed";
|
|
512
642
|
}
|
|
513
643
|
}
|
|
@@ -730,7 +860,7 @@ export class BlockInputSync {
|
|
|
730
860
|
...logCtx2,
|
|
731
861
|
finalizedSlot,
|
|
732
862
|
});
|
|
733
|
-
this.removeAndDownScoreAllDescendants(block);
|
|
863
|
+
this.removeAndDownScoreAllDescendants(block, DroppedItemReason.belowFinalized);
|
|
734
864
|
} else {
|
|
735
865
|
this.onUnknownBlockRoot({rootHex: pending.blockInput.parentRootHex, source: BlockInputSource.byRoot});
|
|
736
866
|
}
|
|
@@ -747,7 +877,7 @@ export class BlockInputSync {
|
|
|
747
877
|
|
|
748
878
|
this.metrics?.blockInputSync.downloadedBlocksError.inc();
|
|
749
879
|
this.logger.debug("Ignoring unknown block root after many failed downloads", logCtx, res.err);
|
|
750
|
-
this.removeAndDownScoreAllDescendants(block);
|
|
880
|
+
this.removeAndDownScoreAllDescendants(block, DroppedItemReason.unavailable);
|
|
751
881
|
}
|
|
752
882
|
}
|
|
753
883
|
|
|
@@ -811,9 +941,9 @@ export class BlockInputSync {
|
|
|
811
941
|
this.pendingBlocks.delete(blockRootHex);
|
|
812
942
|
|
|
813
943
|
if (isForkPostGloas(fork)) {
|
|
814
|
-
const payloadInput = this.chain.seenPayloadEnvelopeInputCache.
|
|
944
|
+
const payloadInput = await this.chain.seenPayloadEnvelopeInputCache.getOrReload(blockRootHex);
|
|
815
945
|
if (!payloadInput) {
|
|
816
|
-
this.logger.
|
|
946
|
+
this.logger.debug("PayloadEnvelopeInput unavailable during unknown sync processReadyBlock()", logCtx);
|
|
817
947
|
} else {
|
|
818
948
|
// Similar to the gossip path: immediately attempt fetch of data columns from the execution engine.
|
|
819
949
|
// The bid already carries the kzg commitments, so there is no reason to wait for the payload to arrive.
|
|
@@ -855,19 +985,19 @@ export class BlockInputSync {
|
|
|
855
985
|
case BlockErrorCode.EXECUTION_ENGINE_ERROR:
|
|
856
986
|
// Removing the block(s) without penalizing the peers, hoping for EL to
|
|
857
987
|
// recover on a latter download + verify attempt.
|
|
858
|
-
this.removeAllDescendants(pendingBlock);
|
|
988
|
+
this.removeAllDescendants(pendingBlock, DroppedItemReason.elError, DroppedItemReason.elError);
|
|
859
989
|
break;
|
|
860
990
|
|
|
861
991
|
case BlockErrorCode.EXECUTION_ENGINE_INVALID:
|
|
862
992
|
// the peer served a bad block
|
|
863
993
|
this.logger.debug("Execution engine rejected block from unknown parent sync", errorData, res.err);
|
|
864
|
-
this.removeAndDownScoreAllDescendants(pendingBlock);
|
|
994
|
+
this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.elInvalid);
|
|
865
995
|
break;
|
|
866
996
|
|
|
867
997
|
default:
|
|
868
998
|
// Block is not correct with respect to our chain. Log error loudly
|
|
869
999
|
this.logger.debug("Error processing block from unknown parent sync", errorData, res.err);
|
|
870
|
-
this.removeAndDownScoreAllDescendants(pendingBlock);
|
|
1000
|
+
this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidBlock);
|
|
871
1001
|
}
|
|
872
1002
|
}
|
|
873
1003
|
|
|
@@ -886,12 +1016,12 @@ export class BlockInputSync {
|
|
|
886
1016
|
*/
|
|
887
1017
|
private async reconcilePayloadEnvelope(pendingPayload: PendingPayloadEnvelope): Promise<void> {
|
|
888
1018
|
const rootHex = getPayloadSyncCacheItemRootHex(pendingPayload);
|
|
1019
|
+
|
|
889
1020
|
if (this.chain.forkChoice.hasPayloadHexUnsafe(rootHex)) {
|
|
890
1021
|
this.pendingPayloads.delete(rootHex);
|
|
891
1022
|
return;
|
|
892
1023
|
}
|
|
893
1024
|
|
|
894
|
-
const payloadInput = this.chain.seenPayloadEnvelopeInputCache.get(rootHex);
|
|
895
1025
|
if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
|
|
896
1026
|
// Block not in fork choice yet. payloadInput may be seeded from the block body during download, so a
|
|
897
1027
|
// non-null payloadInput does not imply the block is imported; defer regardless and pull the block first.
|
|
@@ -907,8 +1037,9 @@ export class BlockInputSync {
|
|
|
907
1037
|
return;
|
|
908
1038
|
}
|
|
909
1039
|
|
|
1040
|
+
const payloadInput = await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
|
|
910
1041
|
if (!payloadInput) {
|
|
911
|
-
this.logger.debug("
|
|
1042
|
+
this.logger.debug("PayloadEnvelopeInput not yet reloadable for imported block, will retry", {
|
|
912
1043
|
root: rootHex,
|
|
913
1044
|
});
|
|
914
1045
|
return;
|
|
@@ -928,6 +1059,7 @@ export class BlockInputSync {
|
|
|
928
1059
|
const pendingPayloadByRoot: PendingPayloadRootHex = {
|
|
929
1060
|
status: PendingPayloadInputStatus.pending,
|
|
930
1061
|
rootHex,
|
|
1062
|
+
slot: pendingPayload.envelope.message.payload.slotNumber,
|
|
931
1063
|
timeAddedSec: pendingPayload.timeAddedSec,
|
|
932
1064
|
peerIdStrings: new Set(pendingPayload.peerIdStrings),
|
|
933
1065
|
};
|
|
@@ -967,6 +1099,10 @@ export class BlockInputSync {
|
|
|
967
1099
|
return;
|
|
968
1100
|
}
|
|
969
1101
|
|
|
1102
|
+
if (!isPendingPayloadInput(payload) && payload.slot === undefined) {
|
|
1103
|
+
payload.slot = this.resolvePayloadSlot(rootHex);
|
|
1104
|
+
}
|
|
1105
|
+
|
|
970
1106
|
const payloadSlot = getPayloadSyncCacheItemSlot(payload);
|
|
971
1107
|
const logCtx = {
|
|
972
1108
|
slot: payloadSlot,
|
|
@@ -982,7 +1118,13 @@ export class BlockInputSync {
|
|
|
982
1118
|
const res = await wrapError(this.fetchPayloadInput(payload));
|
|
983
1119
|
if (!res.err) {
|
|
984
1120
|
const pendingPayload = res.result;
|
|
985
|
-
|
|
1121
|
+
const resultRootHex = getPayloadSyncCacheItemRootHex(pendingPayload);
|
|
1122
|
+
// finalization may have deleted this entry while we were awaiting the network, do not resurrect it via the set below
|
|
1123
|
+
if (!this.pendingPayloads.has(resultRootHex)) {
|
|
1124
|
+
this.logger.verbose("Dropping downloaded payload, entry pruned during fetch", logCtx);
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
this.pendingPayloads.set(resultRootHex, pendingPayload);
|
|
986
1128
|
|
|
987
1129
|
if (isPendingPayloadEnvelope(pendingPayload)) {
|
|
988
1130
|
await this.reconcilePayloadEnvelope(pendingPayload);
|
|
@@ -1059,17 +1201,27 @@ export class BlockInputSync {
|
|
|
1059
1201
|
break;
|
|
1060
1202
|
|
|
1061
1203
|
case PayloadErrorCode.EXECUTION_ENGINE_INVALID:
|
|
1204
|
+
this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
|
|
1205
|
+
this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.elInvalid);
|
|
1206
|
+
break;
|
|
1207
|
+
|
|
1062
1208
|
case PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR:
|
|
1209
|
+
this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
|
|
1210
|
+
this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.invalidEnvelope);
|
|
1211
|
+
break;
|
|
1212
|
+
|
|
1063
1213
|
case PayloadErrorCode.INVALID_SIGNATURE:
|
|
1064
1214
|
// TODO GLOAS: Decide how invalid payload inputs should eventually leave memory without
|
|
1065
1215
|
// reintroducing envelope replacement / recreation flows.
|
|
1066
1216
|
this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
|
|
1067
|
-
this.removePendingPayloadAndDescendants(rootHex);
|
|
1217
|
+
this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.invalidSignature);
|
|
1068
1218
|
break;
|
|
1069
1219
|
|
|
1070
1220
|
default:
|
|
1071
1221
|
this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
|
|
1072
|
-
this.pendingPayloads.delete(rootHex)
|
|
1222
|
+
if (this.pendingPayloads.delete(rootHex)) {
|
|
1223
|
+
this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.unknown}, 1);
|
|
1224
|
+
}
|
|
1073
1225
|
}
|
|
1074
1226
|
return;
|
|
1075
1227
|
}
|
|
@@ -1093,7 +1245,7 @@ export class BlockInputSync {
|
|
|
1093
1245
|
let slot = getPayloadSyncCacheItemSlot(cacheItem);
|
|
1094
1246
|
let payloadInput = isPendingPayloadInput(cacheItem)
|
|
1095
1247
|
? cacheItem.payloadInput
|
|
1096
|
-
: this.chain.seenPayloadEnvelopeInputCache.
|
|
1248
|
+
: await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
|
|
1097
1249
|
let envelope = payloadInput?.hasPayloadEnvelope() ? payloadInput.getPayloadEnvelope() : undefined;
|
|
1098
1250
|
|
|
1099
1251
|
let i = 0;
|
|
@@ -1102,7 +1254,12 @@ export class BlockInputSync {
|
|
|
1102
1254
|
const pendingColumns = payloadInput?.hasAllData()
|
|
1103
1255
|
? new Set<number>()
|
|
1104
1256
|
: new Set(payloadInput?.getMissingSampledColumnMeta().missing ?? []);
|
|
1105
|
-
|
|
1257
|
+
// prefer peers that gossiped this payload root to us (#9923)
|
|
1258
|
+
const peerMeta = this.peerBalancer.bestPeerForPendingColumns(
|
|
1259
|
+
pendingColumns,
|
|
1260
|
+
excludedPeers,
|
|
1261
|
+
cacheItem.peerIdStrings
|
|
1262
|
+
);
|
|
1106
1263
|
if (peerMeta === null) {
|
|
1107
1264
|
if (this.peerBalancer.getNextRateLimitRetryAt(pendingColumns, excludedPeers) !== null) {
|
|
1108
1265
|
throw new UnknownBlockRateLimitedError(
|
|
@@ -1110,9 +1267,11 @@ export class BlockInputSync {
|
|
|
1110
1267
|
);
|
|
1111
1268
|
}
|
|
1112
1269
|
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1270
|
+
const reason =
|
|
1271
|
+
pendingColumns.size > 0
|
|
1272
|
+
? `cannot find peer with needed columns=${prettyPrintIndices(Array.from(pendingColumns))}`
|
|
1273
|
+
: "no peer available to download pending payload";
|
|
1274
|
+
throw Error(`Error fetching payload by root slot=${slot} root=${rootHex} after ${i}: ${reason}`);
|
|
1116
1275
|
}
|
|
1117
1276
|
|
|
1118
1277
|
const {peerId, client: peerClient} = peerMeta;
|
|
@@ -1124,7 +1283,7 @@ export class BlockInputSync {
|
|
|
1124
1283
|
slot = envelope.message.payload.slotNumber;
|
|
1125
1284
|
}
|
|
1126
1285
|
|
|
1127
|
-
payloadInput ??= this.chain.seenPayloadEnvelopeInputCache.
|
|
1286
|
+
payloadInput ??= await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
|
|
1128
1287
|
if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
|
|
1129
1288
|
// Block not in fork choice yet. Validating now would throw BLOCK_ROOT_UNKNOWN, so keep the downloaded
|
|
1130
1289
|
// envelope and wait for the block body; reconcilePayloadEnvelope validates once the block lands.
|
|
@@ -1309,7 +1468,12 @@ export class BlockInputSync {
|
|
|
1309
1468
|
isPendingBlockInput(cacheItem) && isBlockInputColumns(cacheItem.blockInput)
|
|
1310
1469
|
? new Set(cacheItem.blockInput.getMissingSampledColumnMeta().missing)
|
|
1311
1470
|
: defaultPendingColumns;
|
|
1312
|
-
|
|
1471
|
+
// prefer peers that gossiped this block root to us (#9923)
|
|
1472
|
+
const peerMeta = this.peerBalancer.bestPeerForPendingColumns(
|
|
1473
|
+
pendingColumns,
|
|
1474
|
+
excludedPeers,
|
|
1475
|
+
cacheItem.peerIdStrings
|
|
1476
|
+
);
|
|
1313
1477
|
if (peerMeta === null) {
|
|
1314
1478
|
if (this.peerBalancer.getNextRateLimitRetryAt(pendingColumns, excludedPeers) !== null) {
|
|
1315
1479
|
throw new UnknownBlockRateLimitedError(
|
|
@@ -1457,9 +1621,9 @@ export class BlockInputSync {
|
|
|
1457
1621
|
* Downscore all peers that have referenced any of this bad blocks. May report peers multiple times if they have
|
|
1458
1622
|
* referenced more than one bad block.
|
|
1459
1623
|
*/
|
|
1460
|
-
private removeAndDownScoreAllDescendants(block: BlockInputSyncCacheItem): void {
|
|
1624
|
+
private removeAndDownScoreAllDescendants(block: BlockInputSyncCacheItem, headReason: DroppedItemReason): void {
|
|
1461
1625
|
// Get all blocks that are a descendant of this one
|
|
1462
|
-
const badPendingBlocks = this.removeAllDescendants(block);
|
|
1626
|
+
const badPendingBlocks = this.removeAllDescendants(block, headReason, DroppedItemReason.invalidParent);
|
|
1463
1627
|
// just console log and do not penalize on pending/bad blocks for debugging
|
|
1464
1628
|
// console.log("removeAndDownscoreAllDescendants", {block});
|
|
1465
1629
|
|
|
@@ -1486,18 +1650,22 @@ export class BlockInputSync {
|
|
|
1486
1650
|
}
|
|
1487
1651
|
|
|
1488
1652
|
// Once a parent payload is invalid, every descendant waiting on that payload lineage becomes unrecoverable too.
|
|
1489
|
-
private removePendingPayloadAndDescendants(rootHex: RootHex): void {
|
|
1653
|
+
private removePendingPayloadAndDescendants(rootHex: RootHex, headReason: DroppedItemReason): void {
|
|
1490
1654
|
// Keep PayloadEnvelopeInput resident in the seen cache. importBlock() owns that object and
|
|
1491
1655
|
// later validation/finalization logic decides when it can leave memory.
|
|
1492
|
-
this.pendingPayloads.delete(rootHex)
|
|
1656
|
+
if (this.pendingPayloads.delete(rootHex)) {
|
|
1657
|
+
this.metrics?.blockInputSync.removedPayloads.inc({reason: headReason}, 1);
|
|
1658
|
+
}
|
|
1493
1659
|
|
|
1494
1660
|
const badPendingBlocks = getAllDescendantBlocks(rootHex, this.pendingBlocks);
|
|
1495
|
-
this.metrics?.blockInputSync.removedBlocks.inc(badPendingBlocks.length);
|
|
1496
|
-
|
|
1497
1661
|
for (const block of badPendingBlocks) {
|
|
1498
1662
|
const descendantRootHex = getBlockInputSyncCacheItemRootHex(block);
|
|
1499
|
-
this.pendingBlocks.delete(descendantRootHex)
|
|
1500
|
-
|
|
1663
|
+
if (this.pendingBlocks.delete(descendantRootHex)) {
|
|
1664
|
+
this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.invalidParent}, 1);
|
|
1665
|
+
}
|
|
1666
|
+
if (this.pendingPayloads.delete(descendantRootHex)) {
|
|
1667
|
+
this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.invalidParent}, 1);
|
|
1668
|
+
}
|
|
1501
1669
|
this.chain.seenBlockInputCache.prune(descendantRootHex);
|
|
1502
1670
|
this.logger.debug("Removing pending descendant after invalid parent payload", {
|
|
1503
1671
|
slot: getBlockInputSyncCacheItemSlot(block),
|
|
@@ -1507,18 +1675,25 @@ export class BlockInputSync {
|
|
|
1507
1675
|
}
|
|
1508
1676
|
}
|
|
1509
1677
|
|
|
1510
|
-
private removeAllDescendants(
|
|
1678
|
+
private removeAllDescendants(
|
|
1679
|
+
block: BlockInputSyncCacheItem,
|
|
1680
|
+
headReason: DroppedItemReason,
|
|
1681
|
+
descendantReason: DroppedItemReason = DroppedItemReason.invalidParent
|
|
1682
|
+
): BlockInputSyncCacheItem[] {
|
|
1511
1683
|
const rootHex = getBlockInputSyncCacheItemRootHex(block);
|
|
1512
1684
|
const slot = getBlockInputSyncCacheItemSlot(block);
|
|
1513
|
-
// Get all blocks that are a descendant of this one
|
|
1685
|
+
// Get all blocks that are a descendant of this one (index 0 is the head item itself)
|
|
1514
1686
|
const badPendingBlocks = [block, ...getAllDescendantBlocks(rootHex, this.pendingBlocks)];
|
|
1515
1687
|
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
for (const block of badPendingBlocks) {
|
|
1688
|
+
for (const [i, block] of badPendingBlocks.entries()) {
|
|
1519
1689
|
const rootHex = getBlockInputSyncCacheItemRootHex(block);
|
|
1520
|
-
|
|
1521
|
-
this.
|
|
1690
|
+
const reason = i === 0 ? headReason : descendantReason;
|
|
1691
|
+
if (this.pendingBlocks.delete(rootHex)) {
|
|
1692
|
+
this.metrics?.blockInputSync.removedBlocks.inc({reason}, 1);
|
|
1693
|
+
}
|
|
1694
|
+
if (this.pendingPayloads.delete(rootHex)) {
|
|
1695
|
+
this.metrics?.blockInputSync.removedPayloads.inc({reason}, 1);
|
|
1696
|
+
}
|
|
1522
1697
|
this.chain.seenBlockInputCache.prune(rootHex);
|
|
1523
1698
|
// Keep PayloadEnvelopeInput resident in the seen cache for consistency with the
|
|
1524
1699
|
// importBlock()-owned lifecycle.
|
|
@@ -1574,6 +1749,13 @@ export class UnknownBlockPeerBalancer {
|
|
|
1574
1749
|
this.rateLimitedUntilByPeer.delete(peerId);
|
|
1575
1750
|
}
|
|
1576
1751
|
|
|
1752
|
+
/** Reset all tracked peer state, e.g. when BlockInputSync unsubscribes from the network. */
|
|
1753
|
+
clear(): void {
|
|
1754
|
+
this.peersMeta.clear();
|
|
1755
|
+
this.activeRequests.clear();
|
|
1756
|
+
this.rateLimitedUntilByPeer.clear();
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1577
1759
|
onRateLimited(peerId: PeerIdStr, rateLimitedUntilMs: number): void {
|
|
1578
1760
|
this.rateLimitedUntilByPeer.set(peerId, rateLimitedUntilMs);
|
|
1579
1761
|
}
|
|
@@ -1609,11 +1791,17 @@ export class UnknownBlockPeerBalancer {
|
|
|
1609
1791
|
}
|
|
1610
1792
|
|
|
1611
1793
|
/**
|
|
1612
|
-
* called from fetchBlockInput()
|
|
1794
|
+
* called from fetchBlockInput()/fetchPayloadInput() with a block/payload root.
|
|
1613
1795
|
* excludedPeers are the peers that we requested already so we don't want to try again
|
|
1614
1796
|
* pendingColumns is empty for prefulu, or the 1st time we we download a block by root
|
|
1797
|
+
* preferredPeers are the peers NetworkProcessor told us gossiped this root (from
|
|
1798
|
+
* pendingBlock/cacheItem.peerIdStrings). They are preferred but not required.
|
|
1615
1799
|
*/
|
|
1616
|
-
bestPeerForPendingColumns(
|
|
1800
|
+
bestPeerForPendingColumns(
|
|
1801
|
+
pendingColumns: Set<number>,
|
|
1802
|
+
excludedPeers: Set<PeerIdStr>,
|
|
1803
|
+
preferredPeers?: Set<PeerIdStr>
|
|
1804
|
+
): PeerSyncMeta | null {
|
|
1617
1805
|
const eligiblePeers = this.filterPeers(pendingColumns, excludedPeers);
|
|
1618
1806
|
if (eligiblePeers.length === 0) {
|
|
1619
1807
|
return null;
|
|
@@ -1621,7 +1809,9 @@ export class UnknownBlockPeerBalancer {
|
|
|
1621
1809
|
|
|
1622
1810
|
const sortedEligiblePeers = sortBy(
|
|
1623
1811
|
shuffle(eligiblePeers),
|
|
1624
|
-
// prefer peers
|
|
1812
|
+
// 1st key: prefer peers we heard about this root from
|
|
1813
|
+
(peerId) => (preferredPeers?.has(peerId) ? 0 : 1),
|
|
1814
|
+
// 2nd key (tiebreak): prefer peers with least active req
|
|
1625
1815
|
(peerId) => this.activeRequests.get(peerId) ?? 0
|
|
1626
1816
|
);
|
|
1627
1817
|
|