@lodestar/beacon-node 1.43.0-dev.bc569affb9 → 1.43.0-dev.c98da75ec7
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 +16 -5
- 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 +86 -2
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/api/impl/debug/index.d.ts.map +1 -1
- package/lib/api/impl/debug/index.js +0 -1
- package/lib/api/impl/debug/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 +68 -2
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/blocks/blockInput/blockInput.d.ts +3 -0
- package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
- package/lib/chain/blocks/blockInput/blockInput.js +4 -1
- package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +16 -28
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts +23 -6
- package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.js +57 -24
- package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
- package/lib/chain/blocks/index.d.ts +5 -3
- package/lib/chain/blocks/index.d.ts.map +1 -1
- package/lib/chain/blocks/index.js +58 -25
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +12 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +28 -2
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +17 -0
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeProcessor.js +2 -2
- package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
- package/lib/chain/blocks/types.d.ts +4 -3
- package/lib/chain/blocks/types.d.ts.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.d.ts +21 -2
- package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.js +92 -12
- package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
- package/lib/chain/blocks/verifyBlock.d.ts +5 -3
- package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.js +50 -7
- package/lib/chain/blocks/verifyBlock.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts +0 -4
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +5 -2
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts +2 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.js +25 -5
- package/lib/chain/blocks/verifyBlocksSanityChecks.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 +12 -8
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
- package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -1
- package/lib/chain/blocks/verifyPayloadsDataAvailability.js +8 -3
- package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -1
- package/lib/chain/chain.d.ts +5 -3
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +38 -13
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/emitter.d.ts +0 -11
- package/lib/chain/emitter.d.ts.map +1 -1
- package/lib/chain/emitter.js +0 -4
- package/lib/chain/emitter.js.map +1 -1
- package/lib/chain/errors/blockError.d.ts +8 -1
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +2 -0
- package/lib/chain/errors/blockError.js.map +1 -1
- package/lib/chain/errors/executionPayloadBid.d.ts +19 -1
- package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadBid.js +3 -0
- package/lib/chain/errors/executionPayloadBid.js.map +1 -1
- package/lib/chain/errors/index.d.ts +1 -0
- package/lib/chain/errors/index.d.ts.map +1 -1
- package/lib/chain/errors/index.js +1 -0
- package/lib/chain/errors/index.js.map +1 -1
- package/lib/chain/errors/proposerPreferences.d.ts +40 -0
- package/lib/chain/errors/proposerPreferences.d.ts.map +1 -0
- package/lib/chain/errors/proposerPreferences.js +14 -0
- package/lib/chain/errors/proposerPreferences.js.map +1 -0
- package/lib/chain/initState.d.ts.map +1 -1
- package/lib/chain/initState.js +6 -1
- package/lib/chain/initState.js.map +1 -1
- package/lib/chain/interface.d.ts +5 -3
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/interface.js.map +1 -1
- package/lib/chain/lightClient/index.d.ts.map +1 -1
- package/lib/chain/lightClient/index.js +1 -1
- package/lib/chain/lightClient/index.js.map +1 -1
- package/lib/chain/opPools/index.d.ts +1 -0
- package/lib/chain/opPools/index.d.ts.map +1 -1
- package/lib/chain/opPools/index.js +1 -0
- package/lib/chain/opPools/index.js.map +1 -1
- package/lib/chain/opPools/payloadAttestationPool.d.ts +4 -3
- package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
- package/lib/chain/opPools/payloadAttestationPool.js +56 -14
- package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
- package/lib/chain/opPools/proposerPreferencesPool.d.ts +29 -0
- package/lib/chain/opPools/proposerPreferencesPool.d.ts.map +1 -0
- package/lib/chain/opPools/proposerPreferencesPool.js +56 -0
- package/lib/chain/opPools/proposerPreferencesPool.js.map +1 -0
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +16 -18
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +12 -3
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +35 -17
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/regen/interface.d.ts +1 -0
- package/lib/chain/regen/interface.d.ts.map +1 -1
- package/lib/chain/regen/interface.js +1 -0
- package/lib/chain/regen/interface.js.map +1 -1
- package/lib/chain/regen/queued.d.ts.map +1 -1
- package/lib/chain/regen/queued.js +1 -4
- package/lib/chain/regen/queued.js.map +1 -1
- package/lib/chain/regen/regen.d.ts.map +1 -1
- package/lib/chain/regen/regen.js +1 -4
- package/lib/chain/regen/regen.js.map +1 -1
- package/lib/chain/seenCache/index.d.ts +1 -0
- package/lib/chain/seenCache/index.d.ts.map +1 -1
- package/lib/chain/seenCache/index.js +1 -0
- package/lib/chain/seenCache/index.js.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +21 -11
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +70 -20
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
- package/lib/chain/seenCache/seenProposerPreferences.d.ts +16 -0
- package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +1 -0
- package/lib/chain/seenCache/seenProposerPreferences.js +26 -0
- package/lib/chain/seenCache/seenProposerPreferences.js.map +1 -0
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +1 -0
- package/lib/chain/validation/block.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +68 -17
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.d.ts +1 -1
- package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.js +5 -3
- package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
- package/lib/chain/validation/proposerPreferences.d.ts +8 -0
- package/lib/chain/validation/proposerPreferences.d.ts.map +1 -0
- package/lib/chain/validation/proposerPreferences.js +91 -0
- package/lib/chain/validation/proposerPreferences.js.map +1 -0
- package/lib/metrics/metrics/lodestar.d.ts +5 -0
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +9 -0
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/gossip/interface.d.ts +7 -1
- package/lib/network/gossip/interface.d.ts.map +1 -1
- package/lib/network/gossip/interface.js +1 -0
- package/lib/network/gossip/interface.js.map +1 -1
- package/lib/network/gossip/scoringParameters.d.ts.map +1 -1
- package/lib/network/gossip/scoringParameters.js +12 -1
- package/lib/network/gossip/scoringParameters.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +29 -766
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/gossip/topic.js +6 -0
- package/lib/network/gossip/topic.js.map +1 -1
- package/lib/network/interface.d.ts +3 -0
- package/lib/network/interface.d.ts.map +1 -1
- package/lib/network/network.d.ts +3 -0
- package/lib/network/network.d.ts.map +1 -1
- package/lib/network/network.js +13 -0
- package/lib/network/network.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +77 -20
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/processor/gossipQueues/index.d.ts.map +1 -1
- package/lib/network/processor/gossipQueues/index.js +5 -0
- package/lib/network/processor/gossipQueues/index.js.map +1 -1
- package/lib/network/processor/index.d.ts.map +1 -1
- package/lib/network/processor/index.js +6 -5
- package/lib/network/processor/index.js.map +1 -1
- package/lib/network/reqresp/ReqRespBeaconNode.d.ts.map +1 -1
- package/lib/network/reqresp/ReqRespBeaconNode.js +1 -1
- package/lib/network/reqresp/ReqRespBeaconNode.js.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByHead.d.ts +9 -0
- package/lib/network/reqresp/handlers/beaconBlocksByHead.d.ts.map +1 -0
- package/lib/network/reqresp/handlers/beaconBlocksByHead.js +61 -0
- package/lib/network/reqresp/handlers/beaconBlocksByHead.js.map +1 -0
- package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js +14 -6
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRange.js +11 -5
- package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +17 -5
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +7 -4
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/index.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/index.js +5 -0
- package/lib/network/reqresp/handlers/index.js.map +1 -1
- package/lib/network/reqresp/interface.d.ts +1 -1
- package/lib/network/reqresp/interface.js +1 -1
- package/lib/network/reqresp/protocols.d.ts +1 -0
- package/lib/network/reqresp/protocols.d.ts.map +1 -1
- package/lib/network/reqresp/protocols.js +5 -0
- package/lib/network/reqresp/protocols.js.map +1 -1
- package/lib/network/reqresp/rateLimit.d.ts.map +1 -1
- package/lib/network/reqresp/rateLimit.js +4 -0
- package/lib/network/reqresp/rateLimit.js.map +1 -1
- package/lib/network/reqresp/score.d.ts.map +1 -1
- package/lib/network/reqresp/score.js +1 -0
- package/lib/network/reqresp/score.js.map +1 -1
- package/lib/network/reqresp/types.d.ts +3 -0
- package/lib/network/reqresp/types.d.ts.map +1 -1
- package/lib/network/reqresp/types.js +3 -0
- package/lib/network/reqresp/types.js.map +1 -1
- package/lib/node/nodejs.js +2 -2
- package/lib/node/nodejs.js.map +1 -1
- package/lib/sync/constants.d.ts +7 -1
- package/lib/sync/constants.d.ts.map +1 -1
- package/lib/sync/constants.js +7 -4
- package/lib/sync/constants.js.map +1 -1
- package/lib/sync/range/batch.d.ts +55 -8
- package/lib/sync/range/batch.d.ts.map +1 -1
- package/lib/sync/range/batch.js +291 -66
- package/lib/sync/range/batch.js.map +1 -1
- package/lib/sync/range/chain.d.ts +22 -4
- package/lib/sync/range/chain.d.ts.map +1 -1
- package/lib/sync/range/chain.js +103 -11
- package/lib/sync/range/chain.js.map +1 -1
- package/lib/sync/range/range.d.ts.map +1 -1
- package/lib/sync/range/range.js +71 -11
- package/lib/sync/range/range.js.map +1 -1
- package/lib/sync/range/utils/peerBalancer.d.ts +2 -1
- package/lib/sync/range/utils/peerBalancer.d.ts.map +1 -1
- package/lib/sync/range/utils/peerBalancer.js +8 -4
- package/lib/sync/range/utils/peerBalancer.js.map +1 -1
- package/lib/sync/sync.d.ts.map +1 -1
- package/lib/sync/sync.js +13 -0
- package/lib/sync/sync.js.map +1 -1
- package/lib/sync/types.d.ts +34 -0
- package/lib/sync/types.d.ts.map +1 -1
- package/lib/sync/types.js +34 -0
- package/lib/sync/types.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts +29 -1
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +727 -61
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/sync/utils/downloadByRange.d.ts +73 -10
- package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRange.js +213 -26
- 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 +16 -2
- package/lib/sync/utils/downloadByRoot.js.map +1 -1
- package/lib/sync/utils/pendingBlocksTree.d.ts +0 -1
- package/lib/sync/utils/pendingBlocksTree.d.ts.map +1 -1
- package/lib/sync/utils/pendingBlocksTree.js +0 -9
- package/lib/sync/utils/pendingBlocksTree.js.map +1 -1
- package/lib/sync/utils/rateLimit.d.ts +2 -0
- package/lib/sync/utils/rateLimit.d.ts.map +1 -0
- package/lib/sync/utils/rateLimit.js +15 -0
- package/lib/sync/utils/rateLimit.js.map +1 -0
- package/lib/util/dependentRoot.d.ts +6 -2
- package/lib/util/dependentRoot.d.ts.map +1 -1
- package/lib/util/dependentRoot.js +20 -16
- package/lib/util/dependentRoot.js.map +1 -1
- package/lib/util/sszBytes.d.ts.map +1 -1
- package/lib/util/sszBytes.js +8 -6
- package/lib/util/sszBytes.js.map +1 -1
- package/package.json +15 -16
- package/src/api/impl/beacon/blocks/index.ts +21 -5
- package/src/api/impl/beacon/pool/index.ts +136 -1
- package/src/api/impl/debug/index.ts +0 -1
- package/src/api/impl/lodestar/index.ts +1 -1
- package/src/api/impl/validator/index.ts +82 -1
- package/src/chain/blocks/blockInput/blockInput.ts +4 -1
- package/src/chain/blocks/importBlock.ts +16 -48
- package/src/chain/blocks/importExecutionPayload.ts +76 -30
- package/src/chain/blocks/index.ts +71 -22
- package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +37 -3
- package/src/chain/blocks/payloadEnvelopeInput/types.ts +18 -0
- package/src/chain/blocks/payloadEnvelopeProcessor.ts +2 -2
- package/src/chain/blocks/types.ts +4 -3
- package/src/chain/blocks/utils/chainSegment.ts +117 -17
- package/src/chain/blocks/verifyBlock.ts +70 -9
- package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +6 -4
- package/src/chain/blocks/verifyBlocksSanityChecks.ts +26 -7
- package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +16 -8
- package/src/chain/blocks/verifyPayloadsDataAvailability.ts +7 -4
- package/src/chain/chain.ts +46 -10
- package/src/chain/emitter.ts +0 -11
- package/src/chain/errors/blockError.ts +4 -1
- package/src/chain/errors/executionPayloadBid.ts +22 -1
- package/src/chain/errors/index.ts +1 -0
- package/src/chain/errors/proposerPreferences.ts +47 -0
- package/src/chain/initState.ts +9 -1
- package/src/chain/interface.ts +9 -1
- package/src/chain/lightClient/index.ts +6 -6
- package/src/chain/opPools/index.ts +1 -0
- package/src/chain/opPools/payloadAttestationPool.ts +63 -18
- package/src/chain/opPools/proposerPreferencesPool.ts +59 -0
- package/src/chain/prepareNextSlot.ts +21 -29
- package/src/chain/produceBlock/produceBlockBody.ts +46 -22
- package/src/chain/regen/interface.ts +1 -0
- package/src/chain/regen/queued.ts +2 -7
- package/src/chain/regen/regen.ts +2 -7
- package/src/chain/seenCache/index.ts +1 -0
- package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +90 -24
- package/src/chain/seenCache/seenProposerPreferences.ts +32 -0
- package/src/chain/validation/block.ts +1 -0
- package/src/chain/validation/executionPayloadBid.ts +71 -18
- package/src/chain/validation/payloadAttestationMessage.ts +6 -4
- package/src/chain/validation/proposerPreferences.ts +110 -0
- package/src/metrics/metrics/lodestar.ts +10 -0
- package/src/network/gossip/interface.ts +6 -0
- package/src/network/gossip/scoringParameters.ts +14 -1
- package/src/network/gossip/topic.ts +6 -0
- package/src/network/interface.ts +3 -0
- package/src/network/network.ts +34 -0
- package/src/network/processor/gossipHandlers.ts +96 -20
- package/src/network/processor/gossipQueues/index.ts +5 -0
- package/src/network/processor/index.ts +6 -5
- package/src/network/reqresp/ReqRespBeaconNode.ts +1 -0
- package/src/network/reqresp/handlers/beaconBlocksByHead.ts +91 -0
- package/src/network/reqresp/handlers/beaconBlocksByRange.ts +14 -6
- package/src/network/reqresp/handlers/blobSidecarsByRange.ts +11 -5
- package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -5
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +7 -4
- package/src/network/reqresp/handlers/index.ts +5 -0
- package/src/network/reqresp/interface.ts +1 -1
- package/src/network/reqresp/protocols.ts +6 -0
- package/src/network/reqresp/rateLimit.ts +4 -0
- package/src/network/reqresp/score.ts +1 -0
- package/src/network/reqresp/types.ts +5 -0
- package/src/node/nodejs.ts +2 -2
- package/src/sync/constants.ts +8 -4
- package/src/sync/range/batch.ts +388 -75
- package/src/sync/range/chain.ts +131 -14
- package/src/sync/range/range.ts +86 -11
- package/src/sync/range/utils/peerBalancer.ts +9 -3
- package/src/sync/sync.ts +13 -1
- package/src/sync/types.ts +72 -0
- package/src/sync/unknownBlock.ts +915 -65
- package/src/sync/utils/downloadByRange.ts +386 -39
- package/src/sync/utils/downloadByRoot.ts +24 -2
- package/src/sync/utils/pendingBlocksTree.ts +0 -15
- package/src/sync/utils/rateLimit.ts +16 -0
- package/src/util/dependentRoot.ts +22 -18
- package/src/util/sszBytes.ts +8 -6
package/src/sync/range/chain.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
-
import {Epoch, Root, Slot} from "@lodestar/types";
|
|
3
|
-
import {ErrorAborted, LodestarError, Logger, toRootHex} from "@lodestar/utils";
|
|
2
|
+
import {Epoch, Root, Slot, gloas} from "@lodestar/types";
|
|
3
|
+
import {ErrorAborted, LodestarError, Logger, prettyPrintIndices, toRootHex} from "@lodestar/utils";
|
|
4
4
|
import {isBlockInputBlobs, isBlockInputColumns} from "../../chain/blocks/blockInput/blockInput.js";
|
|
5
5
|
import {BlockInputErrorCode} from "../../chain/blocks/blockInput/errors.js";
|
|
6
6
|
import {IBlockInput} from "../../chain/blocks/blockInput/types.js";
|
|
7
|
+
import {PayloadEnvelopeInput} from "../../chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js";
|
|
7
8
|
import {BlobSidecarErrorCode} from "../../chain/errors/blobSidecarError.js";
|
|
8
9
|
import {DataColumnSidecarErrorCode} from "../../chain/errors/dataColumnSidecarError.js";
|
|
9
10
|
import {Metrics} from "../../metrics/metrics.js";
|
|
@@ -16,6 +17,7 @@ import {PeerIdStr} from "../../util/peerId.js";
|
|
|
16
17
|
import {WarnResult, wrapError} from "../../util/wrapError.js";
|
|
17
18
|
import {BATCH_BUFFER_SIZE, EPOCHS_PER_BATCH, MAX_LOOK_AHEAD_EPOCHS} from "../constants.js";
|
|
18
19
|
import {DownloadByRangeError, DownloadByRangeErrorCode} from "../utils/downloadByRange.js";
|
|
20
|
+
import {getRateLimitedUntilMs} from "../utils/rateLimit.js";
|
|
19
21
|
import {RangeSyncType} from "../utils/remoteSyncType.js";
|
|
20
22
|
import {Batch, BatchError, BatchErrorCode, BatchMetadata, BatchStatus} from "./batch.js";
|
|
21
23
|
import {
|
|
@@ -44,13 +46,19 @@ export type SyncChainFns = {
|
|
|
44
46
|
* Must return if ALL blocks are processed successfully
|
|
45
47
|
* If SOME blocks are processed must throw BlockProcessorError()
|
|
46
48
|
*/
|
|
47
|
-
processChainSegment: (
|
|
49
|
+
processChainSegment: (
|
|
50
|
+
blocks: IBlockInput[],
|
|
51
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
|
|
52
|
+
syncType: RangeSyncType
|
|
53
|
+
) => Promise<void>;
|
|
48
54
|
/** Must download blocks, and validate their range */
|
|
49
55
|
downloadByRange: (
|
|
50
56
|
peer: PeerSyncMeta,
|
|
51
57
|
batch: Batch,
|
|
52
58
|
syncType: RangeSyncType
|
|
53
|
-
) => Promise<
|
|
59
|
+
) => Promise<
|
|
60
|
+
WarnResult<{blocks: IBlockInput[]; payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null}, DownloadByRangeError>
|
|
61
|
+
>;
|
|
54
62
|
/** Report peer for negative actions. Decouples from the full network instance */
|
|
55
63
|
reportPeer: (peer: PeerIdStr, action: PeerAction, actionName: string) => void;
|
|
56
64
|
/** Gets current peer custodyColumns and earliestAvailableSlot */
|
|
@@ -132,20 +140,33 @@ export class SyncChain {
|
|
|
132
140
|
private readonly batchProcessor = new ItTrigger();
|
|
133
141
|
/** Sorted map of batches undergoing some kind of processing. */
|
|
134
142
|
private readonly batches = new Map<Epoch, Batch>();
|
|
143
|
+
/**
|
|
144
|
+
* `true` until the first `Batch` is constructed via `includeNextBatch`
|
|
145
|
+
*/
|
|
146
|
+
private isFirstBatch = true;
|
|
135
147
|
private readonly peerset = new Map<PeerIdStr, ChainTarget>();
|
|
148
|
+
/**
|
|
149
|
+
* Tracks peers that have rate-limited us, mapped to the timestamp (ms) until which we should avoid them.
|
|
150
|
+
* This is a sync-layer optimization to avoid assigning batches to backed-off peers.
|
|
151
|
+
* The reqresp SelfRateLimiter independently enforces backoff at the protocol level as a safety net.
|
|
152
|
+
*/
|
|
153
|
+
private readonly rateLimitedPeers = new Map<PeerIdStr, number>();
|
|
154
|
+
private rateLimitBackoffTimeout: NodeJS.Timeout | undefined;
|
|
136
155
|
|
|
137
156
|
private readonly logger: Logger;
|
|
138
157
|
private readonly config: ChainForkConfig;
|
|
139
158
|
private readonly clock: IClock;
|
|
140
159
|
private readonly metrics: Metrics | null;
|
|
141
160
|
private readonly custodyConfig: CustodyConfig;
|
|
161
|
+
private readonly latestBid: gloas.ExecutionPayloadBid | undefined;
|
|
142
162
|
|
|
143
163
|
constructor(
|
|
144
164
|
initialBatchEpoch: Epoch,
|
|
145
165
|
initialTarget: ChainTarget,
|
|
146
166
|
syncType: RangeSyncType,
|
|
147
167
|
fns: SyncChainFns,
|
|
148
|
-
modules: SyncChainModules
|
|
168
|
+
modules: SyncChainModules,
|
|
169
|
+
latestBid: gloas.ExecutionPayloadBid | undefined
|
|
149
170
|
) {
|
|
150
171
|
const {config, clock, custodyConfig, logger, metrics} = modules;
|
|
151
172
|
this.firstBatchEpoch = initialBatchEpoch;
|
|
@@ -161,6 +182,7 @@ export class SyncChain {
|
|
|
161
182
|
this.clock = clock;
|
|
162
183
|
this.metrics = metrics;
|
|
163
184
|
this.custodyConfig = custodyConfig;
|
|
185
|
+
this.latestBid = latestBid;
|
|
164
186
|
this.logger = logger;
|
|
165
187
|
this.logId = `${syncType}-${nextChainId++}`;
|
|
166
188
|
|
|
@@ -215,12 +237,16 @@ export class SyncChain {
|
|
|
215
237
|
*/
|
|
216
238
|
stopSyncing(): void {
|
|
217
239
|
this.status = SyncChainStatus.Stopped;
|
|
240
|
+
this.clearRateLimitBackoffTimer();
|
|
241
|
+
this.logger.debug("SyncChain stopSyncing", {id: this.logId});
|
|
218
242
|
}
|
|
219
243
|
|
|
220
244
|
/**
|
|
221
245
|
* Permanently remove this chain. Throws the main AsyncIterable
|
|
222
246
|
*/
|
|
223
247
|
remove(): void {
|
|
248
|
+
this.logger.debug("SyncChain remove", {id: this.logId});
|
|
249
|
+
this.clearRateLimitBackoffTimer();
|
|
224
250
|
this.batchProcessor.end(new ErrorAborted("SyncChain"));
|
|
225
251
|
}
|
|
226
252
|
|
|
@@ -239,6 +265,7 @@ export class SyncChain {
|
|
|
239
265
|
*/
|
|
240
266
|
removePeer(peerId: PeerIdStr): boolean {
|
|
241
267
|
const deleted = this.peerset.delete(peerId);
|
|
268
|
+
this.rateLimitedPeers.delete(peerId);
|
|
242
269
|
this.computeTarget();
|
|
243
270
|
return deleted;
|
|
244
271
|
}
|
|
@@ -342,6 +369,8 @@ export class SyncChain {
|
|
|
342
369
|
}
|
|
343
370
|
|
|
344
371
|
throw e;
|
|
372
|
+
} finally {
|
|
373
|
+
this.clearRateLimitBackoffTimer();
|
|
345
374
|
}
|
|
346
375
|
}
|
|
347
376
|
|
|
@@ -365,6 +394,44 @@ export class SyncChain {
|
|
|
365
394
|
}
|
|
366
395
|
}
|
|
367
396
|
|
|
397
|
+
private scheduleRateLimitBackoffRetry(): void {
|
|
398
|
+
this.clearRateLimitBackoffTimer();
|
|
399
|
+
|
|
400
|
+
if (this.status !== SyncChainStatus.Syncing || this.rateLimitedPeers.size === 0) {
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const now = Date.now();
|
|
405
|
+
let retryAt: number | null = null;
|
|
406
|
+
for (const [peerId, rateLimitedUntil] of this.rateLimitedPeers.entries()) {
|
|
407
|
+
if (rateLimitedUntil <= now) {
|
|
408
|
+
this.rateLimitedPeers.delete(peerId);
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
retryAt = Math.min(retryAt ?? rateLimitedUntil, rateLimitedUntil);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
if (retryAt === null) {
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
this.rateLimitBackoffTimeout = setTimeout(
|
|
419
|
+
() => {
|
|
420
|
+
this.rateLimitBackoffTimeout = undefined;
|
|
421
|
+
this.triggerBatchDownloader();
|
|
422
|
+
this.scheduleRateLimitBackoffRetry();
|
|
423
|
+
},
|
|
424
|
+
Math.max(0, retryAt - now)
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
private clearRateLimitBackoffTimer(): void {
|
|
429
|
+
if (this.rateLimitBackoffTimeout !== undefined) {
|
|
430
|
+
clearTimeout(this.rateLimitBackoffTimeout);
|
|
431
|
+
this.rateLimitBackoffTimeout = undefined;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
368
435
|
/**
|
|
369
436
|
* Attempts to request the next required batches from the peer pool if the chain is syncing.
|
|
370
437
|
* It will exhaust the peer pool and left over batches until the batch buffer is reached.
|
|
@@ -374,8 +441,18 @@ export class SyncChain {
|
|
|
374
441
|
return;
|
|
375
442
|
}
|
|
376
443
|
|
|
444
|
+
const now = Date.now();
|
|
377
445
|
const peersSyncInfo: PeerSyncInfo[] = [];
|
|
378
446
|
for (const [peerId, target] of this.peerset.entries()) {
|
|
447
|
+
// Skip peers that are currently in rate-limit backoff
|
|
448
|
+
const rateLimitedUntil = this.rateLimitedPeers.get(peerId);
|
|
449
|
+
if (rateLimitedUntil !== undefined) {
|
|
450
|
+
if (now < rateLimitedUntil) {
|
|
451
|
+
continue;
|
|
452
|
+
}
|
|
453
|
+
this.rateLimitedPeers.delete(peerId);
|
|
454
|
+
}
|
|
455
|
+
|
|
379
456
|
try {
|
|
380
457
|
peersSyncInfo.push({...this.getConnectedPeerSyncMeta(peerId), target});
|
|
381
458
|
} catch (e) {
|
|
@@ -449,7 +526,17 @@ export class SyncChain {
|
|
|
449
526
|
return null;
|
|
450
527
|
}
|
|
451
528
|
|
|
452
|
-
const batch = new Batch(
|
|
529
|
+
const batch = new Batch(
|
|
530
|
+
startEpoch,
|
|
531
|
+
this.config,
|
|
532
|
+
this.clock,
|
|
533
|
+
this.custodyConfig,
|
|
534
|
+
this.isFirstBatch,
|
|
535
|
+
// `latestBid` is only meaningful for the first batch's parent-payload check
|
|
536
|
+
this.isFirstBatch ? this.latestBid : undefined,
|
|
537
|
+
this.target.slot
|
|
538
|
+
);
|
|
539
|
+
this.isFirstBatch = false;
|
|
453
540
|
this.batches.set(startEpoch, batch);
|
|
454
541
|
return batch;
|
|
455
542
|
}
|
|
@@ -464,7 +551,7 @@ export class SyncChain {
|
|
|
464
551
|
peer: prettyPrintPeerIdStr(peer.peerId),
|
|
465
552
|
});
|
|
466
553
|
try {
|
|
467
|
-
batch.startDownloading(peer
|
|
554
|
+
batch.startDownloading(peer);
|
|
468
555
|
|
|
469
556
|
// wrapError ensures to never call both batch success() and batch error()
|
|
470
557
|
const res = await wrapError(this.downloadByRange(peer, batch, this.syncType));
|
|
@@ -494,6 +581,8 @@ export class SyncChain {
|
|
|
494
581
|
case DownloadByRangeErrorCode.OUT_OF_ORDER_BLOCKS:
|
|
495
582
|
case DownloadByRangeErrorCode.OUT_OF_RANGE_BLOCKS:
|
|
496
583
|
case DownloadByRangeErrorCode.PARENT_ROOT_MISMATCH:
|
|
584
|
+
case DownloadByRangeErrorCode.INVALID_ENVELOPE_BEACON_BLOCK_ROOT:
|
|
585
|
+
case DownloadByRangeErrorCode.INVALID_CHAIN_SEGMENT:
|
|
497
586
|
case BlobSidecarErrorCode.INCLUSION_PROOF_INVALID:
|
|
498
587
|
case BlobSidecarErrorCode.INVALID_KZG_PROOF_BATCH:
|
|
499
588
|
case DataColumnSidecarErrorCode.INCORRECT_KZG_COMMITMENTS_COUNT:
|
|
@@ -507,7 +596,16 @@ export class SyncChain {
|
|
|
507
596
|
{id: this.logId, ...batch.getMetadata(), peer: prettyPrintPeerIdStr(peer.peerId)},
|
|
508
597
|
res.err
|
|
509
598
|
);
|
|
510
|
-
|
|
599
|
+
const rateLimitedUntilMs = getRateLimitedUntilMs(res.err);
|
|
600
|
+
if (rateLimitedUntilMs !== null) {
|
|
601
|
+
// Peer rate-limited us — don't count as a failed download attempt and mark peer for backoff
|
|
602
|
+
this.rateLimitedPeers.set(peer.peerId, rateLimitedUntilMs);
|
|
603
|
+
this.scheduleRateLimitBackoffRetry();
|
|
604
|
+
batch.downloadingRateLimited();
|
|
605
|
+
this.triggerBatchDownloader();
|
|
606
|
+
} else {
|
|
607
|
+
batch.downloadingError(peer.peerId); // Throws after MAX_DOWNLOAD_ATTEMPTS
|
|
608
|
+
}
|
|
511
609
|
} else {
|
|
512
610
|
this.logger.verbose("Batch download success", {
|
|
513
611
|
id: this.logId,
|
|
@@ -516,7 +614,8 @@ export class SyncChain {
|
|
|
516
614
|
});
|
|
517
615
|
this.metrics?.syncRange.downloadByRange.success.inc();
|
|
518
616
|
const {warnings, result} = res.result;
|
|
519
|
-
const
|
|
617
|
+
const {blocks: downloadedBlocks, payloadEnvelopes} = result;
|
|
618
|
+
const downloadSuccessOutput = batch.downloadingSuccess(peer.peerId, downloadedBlocks, payloadEnvelopes);
|
|
520
619
|
const logMeta: Record<string, number> = {
|
|
521
620
|
blockCount: downloadSuccessOutput.blocks.length,
|
|
522
621
|
};
|
|
@@ -526,7 +625,7 @@ export class SyncChain {
|
|
|
526
625
|
this.metrics?.syncRange.downloadByRange.warn.inc({client: peer.client, code: warning.type.code});
|
|
527
626
|
this.logger.debug(
|
|
528
627
|
"Batch downloaded with warning",
|
|
529
|
-
{id: this.logId,
|
|
628
|
+
{id: this.logId, ...batch.getMetadata(), ...logMeta, peer: prettyPrintPeerIdStr(peer.peerId)},
|
|
530
629
|
warning
|
|
531
630
|
);
|
|
532
631
|
}
|
|
@@ -552,10 +651,17 @@ export class SyncChain {
|
|
|
552
651
|
// the flow will continue to call triggerBatchDownloader() below
|
|
553
652
|
}
|
|
554
653
|
|
|
654
|
+
const blockSlots = downloadSuccessOutput.blocks.map((b) => b.slot);
|
|
655
|
+
const envelopeSlots = downloadSuccessOutput.payloadEnvelopes
|
|
656
|
+
? Array.from(downloadSuccessOutput.payloadEnvelopes.keys())
|
|
657
|
+
: null;
|
|
658
|
+
|
|
555
659
|
this.logger.debug(logMessage, {
|
|
556
660
|
id: this.logId,
|
|
557
|
-
|
|
661
|
+
...batch.getMetadata(),
|
|
558
662
|
...logMeta,
|
|
663
|
+
blockSlots: prettyPrintIndices(blockSlots),
|
|
664
|
+
...(envelopeSlots ? {envelopeSlots: prettyPrintIndices(envelopeSlots)} : {}),
|
|
559
665
|
peer: prettyPrintPeerIdStr(peer.peerId),
|
|
560
666
|
});
|
|
561
667
|
}
|
|
@@ -578,13 +684,24 @@ export class SyncChain {
|
|
|
578
684
|
* Sends `batch` to the processor. Note: batch may be empty
|
|
579
685
|
*/
|
|
580
686
|
private async processBatch(batch: Batch): Promise<void> {
|
|
581
|
-
const blocks = batch.startProcessing();
|
|
687
|
+
const {blocks, payloadEnvelopes, peers} = batch.startProcessing();
|
|
688
|
+
|
|
689
|
+
const logCtx = {
|
|
690
|
+
id: this.logId,
|
|
691
|
+
...batch.getMetadata(),
|
|
692
|
+
blockCount: blocks.length,
|
|
693
|
+
blockSlots: prettyPrintIndices(blocks.map((b) => b.slot)),
|
|
694
|
+
...(payloadEnvelopes ? {envelopeSlots: prettyPrintIndices(Array.from(payloadEnvelopes.keys()))} : {}),
|
|
695
|
+
peers: peers.map(prettyPrintPeerIdStr).join(","),
|
|
696
|
+
};
|
|
697
|
+
this.logger.verbose("Processing batch", logCtx);
|
|
582
698
|
|
|
583
699
|
// wrapError ensures to never call both batch success() and batch error()
|
|
584
|
-
const res = await wrapError(this.processChainSegment(blocks, this.syncType));
|
|
700
|
+
const res = await wrapError(this.processChainSegment(blocks, payloadEnvelopes, this.syncType));
|
|
585
701
|
|
|
586
702
|
if (!res.err) {
|
|
587
703
|
batch.processingSuccess();
|
|
704
|
+
this.logger.verbose("Processed batch", {...logCtx, ...batch.getMetadata()});
|
|
588
705
|
|
|
589
706
|
// If the processed batch is not empty, validate previous AwaitingValidation blocks.
|
|
590
707
|
if (blocks.length > 0) {
|
|
@@ -594,7 +711,7 @@ export class SyncChain {
|
|
|
594
711
|
// Potentially process next AwaitingProcessing batch
|
|
595
712
|
this.triggerBatchProcessor();
|
|
596
713
|
} else {
|
|
597
|
-
this.logger.verbose("Batch process error",
|
|
714
|
+
this.logger.verbose("Batch process error", logCtx, res.err);
|
|
598
715
|
batch.processingError(res.err); // Throws after MAX_BATCH_PROCESSING_ATTEMPTS
|
|
599
716
|
|
|
600
717
|
// At least one block was successfully verified and imported, so we can be sure all
|
package/src/sync/range/range.ts
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
import {EventEmitter} from "node:events";
|
|
2
2
|
import {StrictEventEmitter} from "strict-event-emitter-types";
|
|
3
3
|
import {BeaconConfig} from "@lodestar/config";
|
|
4
|
-
import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
|
|
4
|
+
import {IBeaconStateViewGloas, computeStartSlotAtEpoch, isStatePostGloas} from "@lodestar/state-transition";
|
|
5
5
|
import {Epoch, Status, fulu} from "@lodestar/types";
|
|
6
|
-
import {Logger, toRootHex} from "@lodestar/utils";
|
|
6
|
+
import {Logger, prettyPrintIndices, toRootHex} from "@lodestar/utils";
|
|
7
7
|
import {IBlockInput} from "../../chain/blocks/blockInput/types.js";
|
|
8
8
|
import {AttestationImportOpt, ImportBlockOpts} from "../../chain/blocks/index.js";
|
|
9
|
+
import {assertLinearChainSegment} from "../../chain/blocks/utils/chainSegment.js";
|
|
10
|
+
import {BlockError} from "../../chain/errors/index.js";
|
|
9
11
|
import {IBeaconChain} from "../../chain/index.js";
|
|
10
12
|
import {Metrics} from "../../metrics/index.js";
|
|
11
13
|
import {INetwork} from "../../network/index.js";
|
|
12
14
|
import {PeerIdStr} from "../../util/peerId.js";
|
|
13
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
DownloadByRangeError,
|
|
17
|
+
DownloadByRangeErrorCode,
|
|
18
|
+
cacheByRangeResponses,
|
|
19
|
+
downloadByRange,
|
|
20
|
+
} from "../utils/downloadByRange.js";
|
|
14
21
|
import {RangeSyncType, getRangeSyncTarget, rangeSyncTypes} from "../utils/remoteSyncType.js";
|
|
15
22
|
import {ChainTarget, SyncChain, SyncChainDebugState, SyncChainFns} from "./chain.js";
|
|
16
23
|
import {updateChains} from "./utils/index.js";
|
|
@@ -172,7 +179,7 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
|
|
|
172
179
|
}
|
|
173
180
|
|
|
174
181
|
/** Convenience method for `SyncChain` */
|
|
175
|
-
private processChainSegment: SyncChainFns["processChainSegment"] = async (blocks, syncType) => {
|
|
182
|
+
private processChainSegment: SyncChainFns["processChainSegment"] = async (blocks, payloadEnvelopes, syncType) => {
|
|
176
183
|
// Not trusted, verify signatures
|
|
177
184
|
const flags: ImportBlockOpts = {
|
|
178
185
|
// Only skip importing attestations for finalized sync. For head sync attestation are valuable.
|
|
@@ -192,30 +199,89 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
|
|
|
192
199
|
|
|
193
200
|
if (this.opts?.disableProcessAsChainSegment) {
|
|
194
201
|
// Should only be used for debugging or testing
|
|
195
|
-
for (const block of blocks)
|
|
202
|
+
for (const block of blocks) {
|
|
203
|
+
await this.chain.processBlock(block, flags);
|
|
204
|
+
const payloadEnvelope = payloadEnvelopes?.get(block.slot);
|
|
205
|
+
if (payloadEnvelope) {
|
|
206
|
+
await this.chain.processExecutionPayload(payloadEnvelope);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
196
209
|
} else {
|
|
197
|
-
await this.chain.processChainSegment(blocks, flags);
|
|
210
|
+
await this.chain.processChainSegment(blocks, payloadEnvelopes, flags);
|
|
198
211
|
}
|
|
199
212
|
};
|
|
200
213
|
|
|
201
214
|
private downloadByRange: SyncChainFns["downloadByRange"] = async (peer, batch) => {
|
|
202
215
|
const batchBlocks = batch.getBlocks();
|
|
216
|
+
const requests = batch.getRequestsForPeer(peer);
|
|
217
|
+
const parentRoot = requests.parentPayloadRequest?.envelopeBlockRoot ?? requests.parentPayloadRequest?.blockRoot;
|
|
218
|
+
const parentPayloadCommitments = parentRoot ? batch.getParentPayloadCommitments(parentRoot) : undefined;
|
|
203
219
|
const {result, warnings} = await downloadByRange({
|
|
204
220
|
config: this.config,
|
|
205
221
|
network: this.network,
|
|
206
222
|
logger: this.logger,
|
|
207
223
|
peerIdStr: peer.peerId,
|
|
208
224
|
batchBlocks,
|
|
225
|
+
parentPayloadCommitments,
|
|
209
226
|
peerDasMetrics: this.chain.metrics?.peerDas,
|
|
210
|
-
...
|
|
227
|
+
...requests,
|
|
211
228
|
});
|
|
212
|
-
const
|
|
229
|
+
const {responses, payloadEnvelopes: downloadedPayloadEnvelopes} = result;
|
|
230
|
+
const {blocks, payloadEnvelopes} = cacheByRangeResponses({
|
|
213
231
|
cache: this.chain.seenBlockInputCache,
|
|
232
|
+
seenPayloadEnvelopeInputCache: this.chain.seenPayloadEnvelopeInputCache,
|
|
214
233
|
peerIdStr: peer.peerId,
|
|
215
|
-
responses
|
|
234
|
+
responses,
|
|
216
235
|
batchBlocks,
|
|
236
|
+
downloadedPayloadEnvelopes,
|
|
237
|
+
existingPayloadEnvelopes: batch.getPayloadEnvelopes(),
|
|
238
|
+
custodyConfig: this.chain.custodyConfig,
|
|
239
|
+
seenTimestampSec: Date.now() / 1000,
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
const segmentBlocks = blocks.filter((b) => b.hasBlock()).sort((a, b) => a.slot - b.slot);
|
|
243
|
+
const envelopeSlots = payloadEnvelopes
|
|
244
|
+
? Array.from(payloadEnvelopes.entries())
|
|
245
|
+
.filter(([, pi]) => pi.hasPayloadEnvelope())
|
|
246
|
+
.map(([slot]) => slot)
|
|
247
|
+
.sort((a, b) => a - b)
|
|
248
|
+
: [];
|
|
249
|
+
this.logger.verbose("downloadByRange batch ready", {
|
|
250
|
+
peer: peer.peerId,
|
|
251
|
+
blockSlots: prettyPrintIndices(segmentBlocks.map((b) => b.slot)),
|
|
252
|
+
envelopeSlots: prettyPrintIndices(envelopeSlots),
|
|
253
|
+
...batch.getMetadata(),
|
|
217
254
|
});
|
|
218
|
-
|
|
255
|
+
|
|
256
|
+
if (segmentBlocks.length > 1) {
|
|
257
|
+
try {
|
|
258
|
+
assertLinearChainSegment(this.config, segmentBlocks, payloadEnvelopes, null);
|
|
259
|
+
} catch (err) {
|
|
260
|
+
if (err instanceof BlockError) {
|
|
261
|
+
this.logger.debug(
|
|
262
|
+
"downloadByRange segment validation failed",
|
|
263
|
+
{
|
|
264
|
+
peer: peer.peerId,
|
|
265
|
+
reason: err.type.code,
|
|
266
|
+
slot: err.signedBlock.message.slot,
|
|
267
|
+
detail: JSON.stringify(err.type),
|
|
268
|
+
...batch.getMetadata(),
|
|
269
|
+
},
|
|
270
|
+
err
|
|
271
|
+
);
|
|
272
|
+
// with this error, the peer will be penalized inside SyncChain
|
|
273
|
+
throw new DownloadByRangeError({
|
|
274
|
+
code: DownloadByRangeErrorCode.INVALID_CHAIN_SEGMENT,
|
|
275
|
+
slot: err.signedBlock.message.slot,
|
|
276
|
+
reason: err.type.code,
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
throw err;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return {result: {blocks, payloadEnvelopes}, warnings};
|
|
219
285
|
};
|
|
220
286
|
|
|
221
287
|
private pruneBlockInputs: SyncChainFns["pruneBlockInputs"] = (blocks: IBlockInput[]) => {
|
|
@@ -246,6 +312,14 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
|
|
|
246
312
|
private addPeerOrCreateChain(startEpoch: Epoch, target: ChainTarget, peer: PeerIdStr, syncType: RangeSyncType): void {
|
|
247
313
|
let syncChain = this.chains.get(syncType);
|
|
248
314
|
if (!syncChain) {
|
|
315
|
+
// The first batch of a new sync chain may need to detect whether the parent block was an
|
|
316
|
+
// gloas "empty" block (no envelope produced). It does so by comparing the first
|
|
317
|
+
// downloaded block's `bid.parentBlockHash` against the head state's `latestExecutionPayloadBid.blockHash`.
|
|
318
|
+
const headState = this.chain.getHeadState();
|
|
319
|
+
const latestBid = isStatePostGloas(headState)
|
|
320
|
+
? (headState as IBeaconStateViewGloas).latestExecutionPayloadBid
|
|
321
|
+
: undefined;
|
|
322
|
+
|
|
249
323
|
syncChain = new SyncChain(
|
|
250
324
|
startEpoch,
|
|
251
325
|
target,
|
|
@@ -264,7 +338,8 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
|
|
|
264
338
|
logger: this.logger,
|
|
265
339
|
custodyConfig: this.chain.custodyConfig,
|
|
266
340
|
metrics: this.metrics,
|
|
267
|
-
}
|
|
341
|
+
},
|
|
342
|
+
latestBid
|
|
268
343
|
);
|
|
269
344
|
this.chains.set(syncType, syncChain);
|
|
270
345
|
|
|
@@ -52,7 +52,8 @@ export class ChainPeersBalancer {
|
|
|
52
52
|
|
|
53
53
|
/**
|
|
54
54
|
* Return the most suitable peer to retry
|
|
55
|
-
* Sort peers by (1)
|
|
55
|
+
* Sort peers by (1) less active requests (2) most columns we need.
|
|
56
|
+
* Peers that failed this batch or already succeeded for the same request are excluded inside `filterPeers`.
|
|
56
57
|
*/
|
|
57
58
|
bestPeerToRetryBatch(batch: Batch): PeerSyncMeta | undefined {
|
|
58
59
|
if (batch.state.status !== BatchStatus.AwaitingDownload) {
|
|
@@ -63,10 +64,8 @@ export class ChainPeersBalancer {
|
|
|
63
64
|
const pendingDataColumns = columnsRequest?.columns ?? this.custodyConfig.sampledColumns;
|
|
64
65
|
const eligiblePeers = this.filterPeers(batch, pendingDataColumns, false);
|
|
65
66
|
|
|
66
|
-
const failedPeers = new Set(batch.getFailedPeers());
|
|
67
67
|
const sortedBestPeers = sortBy(
|
|
68
68
|
eligiblePeers,
|
|
69
|
-
({syncInfo}) => (failedPeers.has(syncInfo.peerId) ? 1 : 0), // prefer peers without failed requests
|
|
70
69
|
({syncInfo}) => this.activeRequestsByPeer.get(syncInfo.peerId) ?? 0, // prefer peers with least active req
|
|
71
70
|
({columns}) => -1 * columns // prefer peers with the most columns
|
|
72
71
|
);
|
|
@@ -117,9 +116,16 @@ export class ChainPeersBalancer {
|
|
|
117
116
|
return eligiblePeers;
|
|
118
117
|
}
|
|
119
118
|
|
|
119
|
+
// Skip peers that failed this batch, or that already returned the exact current request shape.
|
|
120
|
+
const failedPeers = new Set<PeerIdStr>(batch.getFailedPeers());
|
|
121
|
+
|
|
120
122
|
for (const peer of this.peers) {
|
|
121
123
|
const {earliestAvailableSlot, target, peerId} = peer;
|
|
122
124
|
|
|
125
|
+
if (failedPeers.has(peerId) || batch.hasPeerSucceededCurrentRequest(peer)) {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
|
|
123
129
|
const activeRequest = this.activeRequestsByPeer.get(peerId) ?? 0;
|
|
124
130
|
if (noActiveRequest && activeRequest > 0) {
|
|
125
131
|
// consumer wants to find peer with no active request, but this peer has active request
|
package/src/sync/sync.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
2
2
|
import {Slot} from "@lodestar/types";
|
|
3
|
-
import {Logger} from "@lodestar/utils";
|
|
3
|
+
import {Logger, toRootHex} from "@lodestar/utils";
|
|
4
4
|
import {IBeaconChain} from "../chain/index.js";
|
|
5
5
|
import {GENESIS_SLOT} from "../constants/constants.js";
|
|
6
6
|
import {ExecutionEngineState} from "../execution/index.js";
|
|
@@ -188,6 +188,18 @@ export class BeaconSync implements IBeaconSync {
|
|
|
188
188
|
private addPeer = (data: NetworkEventData[NetworkEvent.peerConnected]): void => {
|
|
189
189
|
const localStatus = this.chain.getStatus();
|
|
190
190
|
const syncType = getPeerSyncType(localStatus, data.status, this.chain.forkChoice, this.slotImportTolerance);
|
|
191
|
+
this.logger.verbose("Peer sync type classified", {
|
|
192
|
+
peer: data.peer,
|
|
193
|
+
syncType,
|
|
194
|
+
localFinalizedEpoch: localStatus.finalizedEpoch,
|
|
195
|
+
localFinalizedRoot: toRootHex(localStatus.finalizedRoot),
|
|
196
|
+
localHeadSlot: localStatus.headSlot,
|
|
197
|
+
localHeadRoot: toRootHex(localStatus.headRoot),
|
|
198
|
+
remoteFinalizedEpoch: data.status.finalizedEpoch,
|
|
199
|
+
remoteFinalizedRoot: toRootHex(data.status.finalizedRoot),
|
|
200
|
+
remoteHeadSlot: data.status.headSlot,
|
|
201
|
+
remoteHeadRoot: toRootHex(data.status.headRoot),
|
|
202
|
+
});
|
|
191
203
|
|
|
192
204
|
// For metrics only
|
|
193
205
|
this.peerSyncType.set(data.peer, syncType);
|
package/src/sync/types.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import {RootHex, Slot} from "@lodestar/types";
|
|
2
|
+
import {SignedExecutionPayloadEnvelope} from "@lodestar/types/gloas";
|
|
3
|
+
import {toRootHex} from "@lodestar/utils";
|
|
2
4
|
import {IBlockInput} from "../chain/blocks/blockInput/index.js";
|
|
5
|
+
import {PayloadEnvelopeInput} from "../chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js";
|
|
3
6
|
|
|
4
7
|
export enum PendingBlockType {
|
|
5
8
|
/**
|
|
@@ -26,6 +29,14 @@ export enum PendingBlockInputStatus {
|
|
|
26
29
|
processing = "processing",
|
|
27
30
|
}
|
|
28
31
|
|
|
32
|
+
export enum PendingPayloadInputStatus {
|
|
33
|
+
pending = "pending",
|
|
34
|
+
fetching = "fetching",
|
|
35
|
+
waitingForBlock = "waiting_for_block",
|
|
36
|
+
downloaded = "downloaded",
|
|
37
|
+
processing = "processing",
|
|
38
|
+
}
|
|
39
|
+
|
|
29
40
|
export type PendingBlockInput = {
|
|
30
41
|
status: PendingBlockInputStatus;
|
|
31
42
|
blockInput: IBlockInput;
|
|
@@ -44,10 +55,47 @@ export type PendingRootHex = {
|
|
|
44
55
|
|
|
45
56
|
export type BlockInputSyncCacheItem = PendingBlockInput | PendingRootHex;
|
|
46
57
|
|
|
58
|
+
export type PendingPayloadInput = {
|
|
59
|
+
status:
|
|
60
|
+
| PendingPayloadInputStatus.pending
|
|
61
|
+
| PendingPayloadInputStatus.fetching
|
|
62
|
+
| PendingPayloadInputStatus.downloaded
|
|
63
|
+
| PendingPayloadInputStatus.processing;
|
|
64
|
+
payloadInput: PayloadEnvelopeInput;
|
|
65
|
+
timeAddedSec: number;
|
|
66
|
+
timeSyncedSec?: number;
|
|
67
|
+
peerIdStrings: Set<string>;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export type PendingPayloadRootHex = {
|
|
71
|
+
status: PendingPayloadInputStatus.pending | PendingPayloadInputStatus.fetching;
|
|
72
|
+
rootHex: RootHex;
|
|
73
|
+
timeAddedSec: number;
|
|
74
|
+
timeSyncedSec?: number;
|
|
75
|
+
peerIdStrings: Set<string>;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export type PendingPayloadEnvelope = {
|
|
79
|
+
status: PendingPayloadInputStatus.waitingForBlock;
|
|
80
|
+
envelope: SignedExecutionPayloadEnvelope;
|
|
81
|
+
timeAddedSec: number;
|
|
82
|
+
peerIdStrings: Set<string>;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export type PayloadSyncCacheItem = PendingPayloadInput | PendingPayloadRootHex | PendingPayloadEnvelope;
|
|
86
|
+
|
|
47
87
|
export function isPendingBlockInput(pending: BlockInputSyncCacheItem): pending is PendingBlockInput {
|
|
48
88
|
return "blockInput" in pending;
|
|
49
89
|
}
|
|
50
90
|
|
|
91
|
+
export function isPendingPayloadInput(pending: PayloadSyncCacheItem): pending is PendingPayloadInput {
|
|
92
|
+
return "payloadInput" in pending;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function isPendingPayloadEnvelope(pending: PayloadSyncCacheItem): pending is PendingPayloadEnvelope {
|
|
96
|
+
return "envelope" in pending;
|
|
97
|
+
}
|
|
98
|
+
|
|
51
99
|
export function getBlockInputSyncCacheItemRootHex(block: BlockInputSyncCacheItem): RootHex {
|
|
52
100
|
return isPendingBlockInput(block) ? block.blockInput.blockRootHex : block.rootHex;
|
|
53
101
|
}
|
|
@@ -55,3 +103,27 @@ export function getBlockInputSyncCacheItemRootHex(block: BlockInputSyncCacheItem
|
|
|
55
103
|
export function getBlockInputSyncCacheItemSlot(block: BlockInputSyncCacheItem): Slot | string {
|
|
56
104
|
return isPendingBlockInput(block) ? block.blockInput.slot : "unknown";
|
|
57
105
|
}
|
|
106
|
+
|
|
107
|
+
export function getPayloadSyncCacheItemRootHex(payload: PayloadSyncCacheItem): RootHex {
|
|
108
|
+
if (isPendingPayloadInput(payload)) {
|
|
109
|
+
return payload.payloadInput.blockRootHex;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (isPendingPayloadEnvelope(payload)) {
|
|
113
|
+
return toRootHex(payload.envelope.message.beaconBlockRoot);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return payload.rootHex;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function getPayloadSyncCacheItemSlot(payload: PayloadSyncCacheItem): Slot | string {
|
|
120
|
+
if (isPendingPayloadInput(payload)) {
|
|
121
|
+
return payload.payloadInput.slot;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (isPendingPayloadEnvelope(payload)) {
|
|
125
|
+
return payload.envelope.message.payload.slotNumber;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return "unknown";
|
|
129
|
+
}
|