@lodestar/beacon-node 1.47.0-dev.f591cb177e → 1.48.0-dev.67344272c0
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 +44 -12
- 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 +21 -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.map +1 -1
- package/lib/api/impl/events/index.js +2 -0
- 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 +237 -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/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/executionPayloadBid.d.ts +5 -0
- package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadBid.js +1 -0
- package/lib/chain/errors/executionPayloadBid.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 +15 -3
- package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +166 -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.js +2 -2
- 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 +23 -0
- package/lib/execution/builder/validateBid.d.ts.map +1 -0
- package/lib/execution/builder/validateBid.js +119 -0
- package/lib/execution/builder/validateBid.js.map +1 -0
- package/lib/metrics/metrics/lodestar.d.ts +84 -23
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +161 -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/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 +6 -2
- 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 +6 -2
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +143 -68
- 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 +51 -15
- package/src/api/impl/beacon/pool/index.ts +22 -2
- package/src/api/impl/beacon/state/utils.ts +2 -1
- package/src/api/impl/events/index.ts +3 -1
- package/src/api/impl/lodestar/index.ts +1 -1
- package/src/api/impl/validator/index.ts +290 -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/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/executionPayloadBid.ts +6 -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 +193 -14
- package/src/chain/validation/executionPayloadEnvelope.ts +0 -1
- package/src/chain/validation/payloadAttestationMessage.ts +6 -17
- package/src/chain/validation/proposerPreferences.ts +3 -3
- 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 +181 -0
- package/src/metrics/metrics/lodestar.ts +176 -61
- package/src/network/gossip/topic.ts +38 -0
- package/src/network/network.ts +29 -54
- package/src/network/processor/constants.ts +6 -0
- package/src/network/processor/gossipHandlers.ts +6 -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 +33 -0
- package/src/sync/unknownBlock.ts +167 -73
- 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,7 +1,7 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
3
3
|
import {CheckpointWithHex} from "@lodestar/fork-choice";
|
|
4
|
-
import {ForkSeq, isForkPostGloas} from "@lodestar/params";
|
|
4
|
+
import {ForkSeq, SLOTS_PER_EPOCH, isForkPostGloas} from "@lodestar/params";
|
|
5
5
|
import {RequestError, RequestErrorCode} from "@lodestar/reqresp";
|
|
6
6
|
import {computeTimeAtSlot} from "@lodestar/state-transition";
|
|
7
7
|
import {RootHex, Slot, gloas} from "@lodestar/types";
|
|
@@ -17,6 +17,7 @@ import {validateGossipExecutionPayloadEnvelope} from "../chain/validation/execut
|
|
|
17
17
|
import {Metrics} from "../metrics/index.js";
|
|
18
18
|
import {INetwork, NetworkEvent, NetworkEventData, prettyPrintPeerIdStr} from "../network/index.js";
|
|
19
19
|
import {PeerSyncMeta} from "../network/peers/peersData.js";
|
|
20
|
+
import {MAX_PEERS_PER_ROOT} from "../network/processor/constants.js";
|
|
20
21
|
import {PeerIdStr} from "../util/peerId.js";
|
|
21
22
|
import {shuffle} from "../util/shuffle.js";
|
|
22
23
|
import {sortBy} from "../util/sortBy.js";
|
|
@@ -25,6 +26,7 @@ import {MAX_CONCURRENT_REQUESTS} from "./constants.js";
|
|
|
25
26
|
import {SyncOptions} from "./options.js";
|
|
26
27
|
import {
|
|
27
28
|
BlockInputSyncCacheItem,
|
|
29
|
+
DroppedItemReason,
|
|
28
30
|
PayloadSyncCacheItem,
|
|
29
31
|
PendingBlockInput,
|
|
30
32
|
PendingBlockInputStatus,
|
|
@@ -48,6 +50,10 @@ import {getRateLimitedUntilMs} from "./utils/rateLimit.js";
|
|
|
48
50
|
const MAX_ATTEMPTS_PER_BLOCK = 5;
|
|
49
51
|
const MAX_KNOWN_BAD_BLOCKS = 500;
|
|
50
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;
|
|
51
57
|
|
|
52
58
|
type AdvancePendingBlockResult =
|
|
53
59
|
| "ready"
|
|
@@ -160,6 +166,16 @@ export class BlockInputSync {
|
|
|
160
166
|
this.chain.emitter.on(routes.events.EventType.executionPayload, this.onPayloadImported);
|
|
161
167
|
this.network.events.on(NetworkEvent.peerConnected, this.onPeerConnected);
|
|
162
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
|
+
|
|
163
179
|
this.subscribedToNetworkEvents = true;
|
|
164
180
|
}
|
|
165
181
|
}
|
|
@@ -177,6 +193,7 @@ export class BlockInputSync {
|
|
|
177
193
|
this.chain.emitter.off(routes.events.EventType.executionPayload, this.onPayloadImported);
|
|
178
194
|
this.network.events.off(NetworkEvent.peerConnected, this.onPeerConnected);
|
|
179
195
|
this.network.events.off(NetworkEvent.peerDisconnected, this.onPeerDisconnected);
|
|
196
|
+
this.peerBalancer.clear();
|
|
180
197
|
this.subscribedToNetworkEvents = false;
|
|
181
198
|
}
|
|
182
199
|
|
|
@@ -193,10 +210,12 @@ export class BlockInputSync {
|
|
|
193
210
|
*/
|
|
194
211
|
private onUnknownBlockRoot = (data: ChainEventData[ChainEvent.unknownBlockRoot]): void => {
|
|
195
212
|
try {
|
|
196
|
-
this.addByRootHex(data.rootHex, data.peer);
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
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
|
+
}
|
|
200
219
|
} catch (e) {
|
|
201
220
|
this.logger.debug("Error handling unknownBlockRoot event", {}, e as Error);
|
|
202
221
|
}
|
|
@@ -218,10 +237,12 @@ export class BlockInputSync {
|
|
|
218
237
|
|
|
219
238
|
private onUnknownEnvelopeBlockRoot = (data: ChainEventData[ChainEvent.unknownEnvelopeBlockRoot]): void => {
|
|
220
239
|
try {
|
|
221
|
-
this.addByPayloadRootHex(data.rootHex, data.peer, this.resolvePayloadSlot(data.rootHex));
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|
+
}
|
|
225
246
|
} catch (e) {
|
|
226
247
|
this.logger.debug("Error handling unknownEnvelopeBlockRoot event", {}, e as Error);
|
|
227
248
|
}
|
|
@@ -255,7 +276,7 @@ export class BlockInputSync {
|
|
|
255
276
|
parentRoot: missingDependency.parentRootHex,
|
|
256
277
|
parentBlockHash: missingDependency.parentBlockHashHex,
|
|
257
278
|
});
|
|
258
|
-
this.removeAndDownScoreAllDescendants(pendingBlock);
|
|
279
|
+
this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidParentPayload);
|
|
259
280
|
}
|
|
260
281
|
return;
|
|
261
282
|
}
|
|
@@ -295,28 +316,37 @@ export class BlockInputSync {
|
|
|
295
316
|
// Use the actual finalized block slot, not computeStartSlotAtEpoch(checkpoint.epoch)
|
|
296
317
|
// because the payload at the finalized block is not finalized
|
|
297
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;
|
|
298
321
|
|
|
299
|
-
let
|
|
322
|
+
let belowFinalizedPayloads = 0;
|
|
323
|
+
let agedOutPayloads = 0;
|
|
300
324
|
let unresolvedSlotPayloads = 0;
|
|
325
|
+
|
|
301
326
|
for (const [rootHex, payload] of this.pendingPayloads) {
|
|
302
327
|
// Last-effort resolve for a slot-less PendingPayloadRootHex, and store it back for later passes.
|
|
303
328
|
if (!isPendingPayloadInput(payload) && !isPendingPayloadEnvelope(payload) && payload.slot === undefined) {
|
|
304
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
|
+
}
|
|
305
344
|
}
|
|
306
345
|
|
|
307
346
|
const slot = getPayloadSyncCacheItemSlot(payload);
|
|
308
|
-
if (typeof slot
|
|
309
|
-
unresolvedSlotPayloads++;
|
|
310
|
-
this.logger.debug("BlockInputSync.pruneFinalized: pending payload with unresolved slot", {
|
|
311
|
-
root: rootHex,
|
|
312
|
-
finalizedSlot,
|
|
313
|
-
});
|
|
314
|
-
continue;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
if (slot < finalizedSlot) {
|
|
347
|
+
if (typeof slot === "number" && slot < finalizedSlot) {
|
|
318
348
|
this.pendingPayloads.delete(rootHex);
|
|
319
|
-
|
|
349
|
+
belowFinalizedPayloads++;
|
|
320
350
|
}
|
|
321
351
|
}
|
|
322
352
|
|
|
@@ -329,14 +359,24 @@ export class BlockInputSync {
|
|
|
329
359
|
}
|
|
330
360
|
}
|
|
331
361
|
|
|
332
|
-
if (
|
|
333
|
-
this.metrics?.blockInputSync.
|
|
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);
|
|
334
373
|
}
|
|
335
374
|
|
|
336
375
|
this.logger.debug("BlockInputSync.pruneFinalized dropped pre-finalized pending items", {
|
|
337
376
|
finalizedSlot,
|
|
338
377
|
finalizedRoot: checkpoint.rootHex,
|
|
339
|
-
|
|
378
|
+
belowFinalizedPayloads,
|
|
379
|
+
agedOutPayloads,
|
|
340
380
|
deletedBlocks,
|
|
341
381
|
unresolvedSlotPayloads,
|
|
342
382
|
});
|
|
@@ -361,7 +401,9 @@ export class BlockInputSync {
|
|
|
361
401
|
});
|
|
362
402
|
}
|
|
363
403
|
|
|
364
|
-
|
|
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) {
|
|
365
407
|
pendingBlock.peerIdStrings.add(peerIdStr);
|
|
366
408
|
}
|
|
367
409
|
|
|
@@ -369,6 +411,7 @@ export class BlockInputSync {
|
|
|
369
411
|
// Limit pending blocks to prevent DOS attacks that cause OOM
|
|
370
412
|
const prunedItemCount = pruneSetToMax(this.pendingBlocks, this.maxPendingBlocks);
|
|
371
413
|
if (prunedItemCount > 0) {
|
|
414
|
+
this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
|
|
372
415
|
this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingBlocks`);
|
|
373
416
|
}
|
|
374
417
|
return added;
|
|
@@ -395,7 +438,9 @@ export class BlockInputSync {
|
|
|
395
438
|
});
|
|
396
439
|
}
|
|
397
440
|
|
|
398
|
-
|
|
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) {
|
|
399
444
|
pendingBlock.peerIdStrings.add(peerIdStr);
|
|
400
445
|
}
|
|
401
446
|
|
|
@@ -403,6 +448,7 @@ export class BlockInputSync {
|
|
|
403
448
|
// Limit pending blocks to prevent DOS attacks that cause OOM
|
|
404
449
|
const prunedItemCount = pruneSetToMax(this.pendingBlocks, this.maxPendingBlocks);
|
|
405
450
|
if (prunedItemCount > 0) {
|
|
451
|
+
this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
|
|
406
452
|
this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingBlocks`);
|
|
407
453
|
}
|
|
408
454
|
};
|
|
@@ -427,14 +473,22 @@ export class BlockInputSync {
|
|
|
427
473
|
root: rootHex,
|
|
428
474
|
peerIdStr: peerIdStr ?? "unknown peer",
|
|
429
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;
|
|
430
484
|
}
|
|
431
|
-
|
|
432
|
-
if (peerIdStr) {
|
|
485
|
+
if (peerIdStr && pendingPayload.peerIdStrings.size < MAX_PEERS_PER_ROOT) {
|
|
433
486
|
pendingPayload.peerIdStrings.add(peerIdStr);
|
|
434
487
|
}
|
|
435
488
|
|
|
436
489
|
const prunedItemCount = pruneSetToMax(this.pendingPayloads, this.maxPendingBlocks);
|
|
437
490
|
if (prunedItemCount > 0) {
|
|
491
|
+
this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
|
|
438
492
|
this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingPayloads`);
|
|
439
493
|
}
|
|
440
494
|
return added;
|
|
@@ -474,7 +528,7 @@ export class BlockInputSync {
|
|
|
474
528
|
envelope
|
|
475
529
|
);
|
|
476
530
|
|
|
477
|
-
if (peerIdStr) {
|
|
531
|
+
if (peerIdStr && pendingPayload.peerIdStrings.size < MAX_PEERS_PER_ROOT) {
|
|
478
532
|
pendingPayload.peerIdStrings.add(peerIdStr);
|
|
479
533
|
}
|
|
480
534
|
|
|
@@ -488,6 +542,7 @@ export class BlockInputSync {
|
|
|
488
542
|
|
|
489
543
|
const prunedItemCount = pruneSetToMax(this.pendingPayloads, this.maxPendingBlocks);
|
|
490
544
|
if (prunedItemCount > 0) {
|
|
545
|
+
this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
|
|
491
546
|
this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingPayloads`);
|
|
492
547
|
}
|
|
493
548
|
};
|
|
@@ -544,15 +599,7 @@ export class BlockInputSync {
|
|
|
544
599
|
return {kind: "invalidParentPayload", parentRootHex, parentBlockHashHex};
|
|
545
600
|
}
|
|
546
601
|
|
|
547
|
-
|
|
548
|
-
if (parentPayloadInput) {
|
|
549
|
-
if (parentPayloadInput.getBlockHashHex() === parentBlockHashHex) {
|
|
550
|
-
return {kind: "parentPayload", rootHex: parentRootHex, slot: parentBlock.slot};
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
return {kind: "invalidParentPayload", parentRootHex, parentBlockHashHex};
|
|
554
|
-
}
|
|
555
|
-
|
|
602
|
+
// Parent is in fork choice but its payload `parentBlockHashHex` isn't revealed yet
|
|
556
603
|
return {kind: "parentPayload", rootHex: parentRootHex, slot: parentBlock.slot};
|
|
557
604
|
}
|
|
558
605
|
|
|
@@ -590,7 +637,7 @@ export class BlockInputSync {
|
|
|
590
637
|
parentRoot: missingDependency.parentRootHex,
|
|
591
638
|
parentBlockHash: missingDependency.parentBlockHashHex,
|
|
592
639
|
});
|
|
593
|
-
this.removeAndDownScoreAllDescendants(pendingBlock);
|
|
640
|
+
this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidParentPayload);
|
|
594
641
|
return "removed";
|
|
595
642
|
}
|
|
596
643
|
}
|
|
@@ -813,7 +860,7 @@ export class BlockInputSync {
|
|
|
813
860
|
...logCtx2,
|
|
814
861
|
finalizedSlot,
|
|
815
862
|
});
|
|
816
|
-
this.removeAndDownScoreAllDescendants(block);
|
|
863
|
+
this.removeAndDownScoreAllDescendants(block, DroppedItemReason.belowFinalized);
|
|
817
864
|
} else {
|
|
818
865
|
this.onUnknownBlockRoot({rootHex: pending.blockInput.parentRootHex, source: BlockInputSource.byRoot});
|
|
819
866
|
}
|
|
@@ -830,7 +877,7 @@ export class BlockInputSync {
|
|
|
830
877
|
|
|
831
878
|
this.metrics?.blockInputSync.downloadedBlocksError.inc();
|
|
832
879
|
this.logger.debug("Ignoring unknown block root after many failed downloads", logCtx, res.err);
|
|
833
|
-
this.removeAndDownScoreAllDescendants(block);
|
|
880
|
+
this.removeAndDownScoreAllDescendants(block, DroppedItemReason.unavailable);
|
|
834
881
|
}
|
|
835
882
|
}
|
|
836
883
|
|
|
@@ -894,9 +941,9 @@ export class BlockInputSync {
|
|
|
894
941
|
this.pendingBlocks.delete(blockRootHex);
|
|
895
942
|
|
|
896
943
|
if (isForkPostGloas(fork)) {
|
|
897
|
-
const payloadInput = this.chain.seenPayloadEnvelopeInputCache.
|
|
944
|
+
const payloadInput = await this.chain.seenPayloadEnvelopeInputCache.getOrReload(blockRootHex);
|
|
898
945
|
if (!payloadInput) {
|
|
899
|
-
this.logger.
|
|
946
|
+
this.logger.debug("PayloadEnvelopeInput unavailable during unknown sync processReadyBlock()", logCtx);
|
|
900
947
|
} else {
|
|
901
948
|
// Similar to the gossip path: immediately attempt fetch of data columns from the execution engine.
|
|
902
949
|
// The bid already carries the kzg commitments, so there is no reason to wait for the payload to arrive.
|
|
@@ -938,19 +985,19 @@ export class BlockInputSync {
|
|
|
938
985
|
case BlockErrorCode.EXECUTION_ENGINE_ERROR:
|
|
939
986
|
// Removing the block(s) without penalizing the peers, hoping for EL to
|
|
940
987
|
// recover on a latter download + verify attempt.
|
|
941
|
-
this.removeAllDescendants(pendingBlock);
|
|
988
|
+
this.removeAllDescendants(pendingBlock, DroppedItemReason.elError, DroppedItemReason.elError);
|
|
942
989
|
break;
|
|
943
990
|
|
|
944
991
|
case BlockErrorCode.EXECUTION_ENGINE_INVALID:
|
|
945
992
|
// the peer served a bad block
|
|
946
993
|
this.logger.debug("Execution engine rejected block from unknown parent sync", errorData, res.err);
|
|
947
|
-
this.removeAndDownScoreAllDescendants(pendingBlock);
|
|
994
|
+
this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.elInvalid);
|
|
948
995
|
break;
|
|
949
996
|
|
|
950
997
|
default:
|
|
951
998
|
// Block is not correct with respect to our chain. Log error loudly
|
|
952
999
|
this.logger.debug("Error processing block from unknown parent sync", errorData, res.err);
|
|
953
|
-
this.removeAndDownScoreAllDescendants(pendingBlock);
|
|
1000
|
+
this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidBlock);
|
|
954
1001
|
}
|
|
955
1002
|
}
|
|
956
1003
|
|
|
@@ -969,12 +1016,12 @@ export class BlockInputSync {
|
|
|
969
1016
|
*/
|
|
970
1017
|
private async reconcilePayloadEnvelope(pendingPayload: PendingPayloadEnvelope): Promise<void> {
|
|
971
1018
|
const rootHex = getPayloadSyncCacheItemRootHex(pendingPayload);
|
|
1019
|
+
|
|
972
1020
|
if (this.chain.forkChoice.hasPayloadHexUnsafe(rootHex)) {
|
|
973
1021
|
this.pendingPayloads.delete(rootHex);
|
|
974
1022
|
return;
|
|
975
1023
|
}
|
|
976
1024
|
|
|
977
|
-
const payloadInput = this.chain.seenPayloadEnvelopeInputCache.get(rootHex);
|
|
978
1025
|
if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
|
|
979
1026
|
// Block not in fork choice yet. payloadInput may be seeded from the block body during download, so a
|
|
980
1027
|
// non-null payloadInput does not imply the block is imported; defer regardless and pull the block first.
|
|
@@ -990,8 +1037,9 @@ export class BlockInputSync {
|
|
|
990
1037
|
return;
|
|
991
1038
|
}
|
|
992
1039
|
|
|
1040
|
+
const payloadInput = await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
|
|
993
1041
|
if (!payloadInput) {
|
|
994
|
-
this.logger.debug("
|
|
1042
|
+
this.logger.debug("PayloadEnvelopeInput not yet reloadable for imported block, will retry", {
|
|
995
1043
|
root: rootHex,
|
|
996
1044
|
});
|
|
997
1045
|
return;
|
|
@@ -1153,17 +1201,27 @@ export class BlockInputSync {
|
|
|
1153
1201
|
break;
|
|
1154
1202
|
|
|
1155
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
|
+
|
|
1156
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
|
+
|
|
1157
1213
|
case PayloadErrorCode.INVALID_SIGNATURE:
|
|
1158
1214
|
// TODO GLOAS: Decide how invalid payload inputs should eventually leave memory without
|
|
1159
1215
|
// reintroducing envelope replacement / recreation flows.
|
|
1160
1216
|
this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
|
|
1161
|
-
this.removePendingPayloadAndDescendants(rootHex);
|
|
1217
|
+
this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.invalidSignature);
|
|
1162
1218
|
break;
|
|
1163
1219
|
|
|
1164
1220
|
default:
|
|
1165
1221
|
this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
|
|
1166
|
-
this.pendingPayloads.delete(rootHex)
|
|
1222
|
+
if (this.pendingPayloads.delete(rootHex)) {
|
|
1223
|
+
this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.unknown}, 1);
|
|
1224
|
+
}
|
|
1167
1225
|
}
|
|
1168
1226
|
return;
|
|
1169
1227
|
}
|
|
@@ -1187,7 +1245,7 @@ export class BlockInputSync {
|
|
|
1187
1245
|
let slot = getPayloadSyncCacheItemSlot(cacheItem);
|
|
1188
1246
|
let payloadInput = isPendingPayloadInput(cacheItem)
|
|
1189
1247
|
? cacheItem.payloadInput
|
|
1190
|
-
: this.chain.seenPayloadEnvelopeInputCache.
|
|
1248
|
+
: await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
|
|
1191
1249
|
let envelope = payloadInput?.hasPayloadEnvelope() ? payloadInput.getPayloadEnvelope() : undefined;
|
|
1192
1250
|
|
|
1193
1251
|
let i = 0;
|
|
@@ -1196,7 +1254,12 @@ export class BlockInputSync {
|
|
|
1196
1254
|
const pendingColumns = payloadInput?.hasAllData()
|
|
1197
1255
|
? new Set<number>()
|
|
1198
1256
|
: new Set(payloadInput?.getMissingSampledColumnMeta().missing ?? []);
|
|
1199
|
-
|
|
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
|
+
);
|
|
1200
1263
|
if (peerMeta === null) {
|
|
1201
1264
|
if (this.peerBalancer.getNextRateLimitRetryAt(pendingColumns, excludedPeers) !== null) {
|
|
1202
1265
|
throw new UnknownBlockRateLimitedError(
|
|
@@ -1220,7 +1283,7 @@ export class BlockInputSync {
|
|
|
1220
1283
|
slot = envelope.message.payload.slotNumber;
|
|
1221
1284
|
}
|
|
1222
1285
|
|
|
1223
|
-
payloadInput ??= this.chain.seenPayloadEnvelopeInputCache.
|
|
1286
|
+
payloadInput ??= await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
|
|
1224
1287
|
if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
|
|
1225
1288
|
// Block not in fork choice yet. Validating now would throw BLOCK_ROOT_UNKNOWN, so keep the downloaded
|
|
1226
1289
|
// envelope and wait for the block body; reconcilePayloadEnvelope validates once the block lands.
|
|
@@ -1405,7 +1468,12 @@ export class BlockInputSync {
|
|
|
1405
1468
|
isPendingBlockInput(cacheItem) && isBlockInputColumns(cacheItem.blockInput)
|
|
1406
1469
|
? new Set(cacheItem.blockInput.getMissingSampledColumnMeta().missing)
|
|
1407
1470
|
: defaultPendingColumns;
|
|
1408
|
-
|
|
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
|
+
);
|
|
1409
1477
|
if (peerMeta === null) {
|
|
1410
1478
|
if (this.peerBalancer.getNextRateLimitRetryAt(pendingColumns, excludedPeers) !== null) {
|
|
1411
1479
|
throw new UnknownBlockRateLimitedError(
|
|
@@ -1553,9 +1621,9 @@ export class BlockInputSync {
|
|
|
1553
1621
|
* Downscore all peers that have referenced any of this bad blocks. May report peers multiple times if they have
|
|
1554
1622
|
* referenced more than one bad block.
|
|
1555
1623
|
*/
|
|
1556
|
-
private removeAndDownScoreAllDescendants(block: BlockInputSyncCacheItem): void {
|
|
1624
|
+
private removeAndDownScoreAllDescendants(block: BlockInputSyncCacheItem, headReason: DroppedItemReason): void {
|
|
1557
1625
|
// Get all blocks that are a descendant of this one
|
|
1558
|
-
const badPendingBlocks = this.removeAllDescendants(block);
|
|
1626
|
+
const badPendingBlocks = this.removeAllDescendants(block, headReason, DroppedItemReason.invalidParent);
|
|
1559
1627
|
// just console log and do not penalize on pending/bad blocks for debugging
|
|
1560
1628
|
// console.log("removeAndDownscoreAllDescendants", {block});
|
|
1561
1629
|
|
|
@@ -1582,18 +1650,22 @@ export class BlockInputSync {
|
|
|
1582
1650
|
}
|
|
1583
1651
|
|
|
1584
1652
|
// Once a parent payload is invalid, every descendant waiting on that payload lineage becomes unrecoverable too.
|
|
1585
|
-
private removePendingPayloadAndDescendants(rootHex: RootHex): void {
|
|
1653
|
+
private removePendingPayloadAndDescendants(rootHex: RootHex, headReason: DroppedItemReason): void {
|
|
1586
1654
|
// Keep PayloadEnvelopeInput resident in the seen cache. importBlock() owns that object and
|
|
1587
1655
|
// later validation/finalization logic decides when it can leave memory.
|
|
1588
|
-
this.pendingPayloads.delete(rootHex)
|
|
1656
|
+
if (this.pendingPayloads.delete(rootHex)) {
|
|
1657
|
+
this.metrics?.blockInputSync.removedPayloads.inc({reason: headReason}, 1);
|
|
1658
|
+
}
|
|
1589
1659
|
|
|
1590
1660
|
const badPendingBlocks = getAllDescendantBlocks(rootHex, this.pendingBlocks);
|
|
1591
|
-
this.metrics?.blockInputSync.removedBlocks.inc(badPendingBlocks.length);
|
|
1592
|
-
|
|
1593
1661
|
for (const block of badPendingBlocks) {
|
|
1594
1662
|
const descendantRootHex = getBlockInputSyncCacheItemRootHex(block);
|
|
1595
|
-
this.pendingBlocks.delete(descendantRootHex)
|
|
1596
|
-
|
|
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
|
+
}
|
|
1597
1669
|
this.chain.seenBlockInputCache.prune(descendantRootHex);
|
|
1598
1670
|
this.logger.debug("Removing pending descendant after invalid parent payload", {
|
|
1599
1671
|
slot: getBlockInputSyncCacheItemSlot(block),
|
|
@@ -1603,18 +1675,25 @@ export class BlockInputSync {
|
|
|
1603
1675
|
}
|
|
1604
1676
|
}
|
|
1605
1677
|
|
|
1606
|
-
private removeAllDescendants(
|
|
1678
|
+
private removeAllDescendants(
|
|
1679
|
+
block: BlockInputSyncCacheItem,
|
|
1680
|
+
headReason: DroppedItemReason,
|
|
1681
|
+
descendantReason: DroppedItemReason = DroppedItemReason.invalidParent
|
|
1682
|
+
): BlockInputSyncCacheItem[] {
|
|
1607
1683
|
const rootHex = getBlockInputSyncCacheItemRootHex(block);
|
|
1608
1684
|
const slot = getBlockInputSyncCacheItemSlot(block);
|
|
1609
|
-
// 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)
|
|
1610
1686
|
const badPendingBlocks = [block, ...getAllDescendantBlocks(rootHex, this.pendingBlocks)];
|
|
1611
1687
|
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
for (const block of badPendingBlocks) {
|
|
1688
|
+
for (const [i, block] of badPendingBlocks.entries()) {
|
|
1615
1689
|
const rootHex = getBlockInputSyncCacheItemRootHex(block);
|
|
1616
|
-
|
|
1617
|
-
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
|
+
}
|
|
1618
1697
|
this.chain.seenBlockInputCache.prune(rootHex);
|
|
1619
1698
|
// Keep PayloadEnvelopeInput resident in the seen cache for consistency with the
|
|
1620
1699
|
// importBlock()-owned lifecycle.
|
|
@@ -1670,6 +1749,13 @@ export class UnknownBlockPeerBalancer {
|
|
|
1670
1749
|
this.rateLimitedUntilByPeer.delete(peerId);
|
|
1671
1750
|
}
|
|
1672
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
|
+
|
|
1673
1759
|
onRateLimited(peerId: PeerIdStr, rateLimitedUntilMs: number): void {
|
|
1674
1760
|
this.rateLimitedUntilByPeer.set(peerId, rateLimitedUntilMs);
|
|
1675
1761
|
}
|
|
@@ -1705,11 +1791,17 @@ export class UnknownBlockPeerBalancer {
|
|
|
1705
1791
|
}
|
|
1706
1792
|
|
|
1707
1793
|
/**
|
|
1708
|
-
* called from fetchBlockInput()
|
|
1794
|
+
* called from fetchBlockInput()/fetchPayloadInput() with a block/payload root.
|
|
1709
1795
|
* excludedPeers are the peers that we requested already so we don't want to try again
|
|
1710
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.
|
|
1711
1799
|
*/
|
|
1712
|
-
bestPeerForPendingColumns(
|
|
1800
|
+
bestPeerForPendingColumns(
|
|
1801
|
+
pendingColumns: Set<number>,
|
|
1802
|
+
excludedPeers: Set<PeerIdStr>,
|
|
1803
|
+
preferredPeers?: Set<PeerIdStr>
|
|
1804
|
+
): PeerSyncMeta | null {
|
|
1713
1805
|
const eligiblePeers = this.filterPeers(pendingColumns, excludedPeers);
|
|
1714
1806
|
if (eligiblePeers.length === 0) {
|
|
1715
1807
|
return null;
|
|
@@ -1717,7 +1809,9 @@ export class UnknownBlockPeerBalancer {
|
|
|
1717
1809
|
|
|
1718
1810
|
const sortedEligiblePeers = sortBy(
|
|
1719
1811
|
shuffle(eligiblePeers),
|
|
1720
|
-
// 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
|
|
1721
1815
|
(peerId) => this.activeRequests.get(peerId) ?? 0
|
|
1722
1816
|
);
|
|
1723
1817
|
|
|
@@ -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"}
|