@lodestar/beacon-node 1.43.0-dev.bc569affb9 → 1.43.0-dev.c9dc2b2332
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 +45 -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 +3 -2
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +35 -12
- 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/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 +3 -2
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/interface.js.map +1 -1
- package/lib/chain/opPools/payloadAttestationPool.d.ts +3 -2
- package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
- package/lib/chain/opPools/payloadAttestationPool.js +26 -4
- package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
- 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.js +11 -8
- package/lib/chain/validation/executionPayloadBid.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 +1 -0
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +4 -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 +2 -0
- package/lib/network/interface.d.ts.map +1 -1
- package/lib/network/network.d.ts +2 -0
- package/lib/network/network.d.ts.map +1 -1
- package/lib/network/network.js +8 -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 +38 -16
- 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/sszBytes.d.ts.map +1 -1
- package/lib/util/sszBytes.js +8 -6
- package/lib/util/sszBytes.js.map +1 -1
- package/package.json +16 -16
- package/src/api/impl/beacon/blocks/index.ts +21 -5
- package/src/api/impl/beacon/pool/index.ts +83 -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 +43 -10
- package/src/chain/emitter.ts +0 -11
- package/src/chain/errors/blockError.ts +4 -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 +7 -1
- package/src/chain/opPools/payloadAttestationPool.ts +29 -8
- 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 +11 -8
- package/src/chain/validation/proposerPreferences.ts +110 -0
- package/src/metrics/metrics/lodestar.ts +4 -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 +2 -0
- package/src/network/network.ts +23 -0
- package/src/network/processor/gossipHandlers.ts +53 -17
- 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/sszBytes.ts +8 -6
package/src/sync/range/batch.ts
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
-
import {ForkName, isForkPostDeneb, isForkPostFulu} from "@lodestar/params";
|
|
3
|
-
import {Epoch, RootHex, Slot, phase0} from "@lodestar/types";
|
|
4
|
-
import {LodestarError} from "@lodestar/utils";
|
|
2
|
+
import {ForkName, isForkPostDeneb, isForkPostFulu, isForkPostGloas} from "@lodestar/params";
|
|
3
|
+
import {Epoch, RootHex, SignedBeaconBlock, Slot, gloas, phase0} from "@lodestar/types";
|
|
4
|
+
import {LodestarError, byteArrayEquals, prettyPrintIndices, toRootHex} from "@lodestar/utils";
|
|
5
5
|
import {isBlockInputColumns} from "../../chain/blocks/blockInput/blockInput.js";
|
|
6
6
|
import {IBlockInput} from "../../chain/blocks/blockInput/types.js";
|
|
7
7
|
import {isDaOutOfRange} from "../../chain/blocks/blockInput/utils.js";
|
|
8
|
+
import {PayloadEnvelopeInput} from "../../chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js";
|
|
8
9
|
import {BlockError, BlockErrorCode} from "../../chain/errors/index.js";
|
|
10
|
+
import {ZERO_HASH} from "../../constants/constants.js";
|
|
9
11
|
import {PeerSyncMeta} from "../../network/peers/peersData.js";
|
|
10
12
|
import {IClock} from "../../util/clock.js";
|
|
11
13
|
import {CustodyConfig} from "../../util/dataColumns.js";
|
|
12
14
|
import {PeerIdStr} from "../../util/peerId.js";
|
|
13
15
|
import {MAX_BATCH_DOWNLOAD_ATTEMPTS, MAX_BATCH_PROCESSING_ATTEMPTS} from "../constants.js";
|
|
14
|
-
import {DownloadByRangeRequests} from "../utils/downloadByRange.js";
|
|
16
|
+
import {DownloadByRangeRequests, ParentPayloadCommitments} from "../utils/downloadByRange.js";
|
|
15
17
|
import {getBatchSlotRange, hashBlocks} from "./utils/index.js";
|
|
16
18
|
|
|
17
19
|
/**
|
|
@@ -43,28 +45,88 @@ export type Attempt = {
|
|
|
43
45
|
hash: RootHex;
|
|
44
46
|
};
|
|
45
47
|
|
|
48
|
+
type TrackedRequest = {
|
|
49
|
+
/** only happen for the 1st batch in checkpoint sync */
|
|
50
|
+
parentPayload: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* we always issue by_range before parent_payload, so we don't model this as null
|
|
53
|
+
*/
|
|
54
|
+
byRangeColumns: Set<number>;
|
|
55
|
+
};
|
|
56
|
+
|
|
46
57
|
export type AwaitingDownloadState = {
|
|
47
58
|
status: BatchStatus.AwaitingDownload;
|
|
48
59
|
blocks: IBlockInput[];
|
|
60
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
|
|
49
61
|
};
|
|
50
62
|
|
|
51
63
|
export type DownloadSuccessState = {
|
|
52
64
|
status: BatchStatus.AwaitingProcessing;
|
|
53
65
|
blocks: IBlockInput[];
|
|
66
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
|
|
54
67
|
};
|
|
55
68
|
|
|
56
69
|
export type BatchState =
|
|
57
70
|
| AwaitingDownloadState
|
|
58
|
-
| {
|
|
71
|
+
| {
|
|
72
|
+
status: BatchStatus.Downloading;
|
|
73
|
+
peer: PeerIdStr;
|
|
74
|
+
request: TrackedRequest;
|
|
75
|
+
blocks: IBlockInput[];
|
|
76
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
|
|
77
|
+
}
|
|
59
78
|
| DownloadSuccessState
|
|
60
|
-
| {
|
|
61
|
-
|
|
79
|
+
| {
|
|
80
|
+
status: BatchStatus.Processing;
|
|
81
|
+
blocks: IBlockInput[];
|
|
82
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
|
|
83
|
+
attempt: Attempt;
|
|
84
|
+
}
|
|
85
|
+
| {
|
|
86
|
+
status: BatchStatus.AwaitingValidation;
|
|
87
|
+
blocks: IBlockInput[];
|
|
88
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
|
|
89
|
+
attempt: Attempt;
|
|
90
|
+
};
|
|
62
91
|
|
|
63
92
|
export type BatchMetadata = {
|
|
93
|
+
// Batch-level slot window (always present)
|
|
64
94
|
startEpoch: Epoch;
|
|
95
|
+
startSlot: Slot;
|
|
96
|
+
count: number;
|
|
65
97
|
status: BatchStatus;
|
|
98
|
+
|
|
99
|
+
// Per-type outstanding request shapes; only present when that sub-request exists.
|
|
100
|
+
// Format: "startSlot=<n>,count=<n>" (plus ",cols=<indices>" for columns).
|
|
101
|
+
blocksReq?: string;
|
|
102
|
+
blobsReq?: string;
|
|
103
|
+
columnsReq?: string;
|
|
104
|
+
envelopesReq?: string;
|
|
105
|
+
|
|
106
|
+
// Retry counters
|
|
107
|
+
downloadAttempts: number;
|
|
108
|
+
processingAttempts: number;
|
|
109
|
+
|
|
110
|
+
// Cumulative peer attribution for failed attempts (only present when non-empty)
|
|
111
|
+
failedDownloadPeers?: string;
|
|
112
|
+
failedProcessingPeers?: string;
|
|
66
113
|
};
|
|
67
114
|
|
|
115
|
+
function formatRangeReq(req: {startSlot: Slot; count: number}): string {
|
|
116
|
+
return `startSlot=${req.startSlot},count=${req.count}`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function formatColumnsReq(req: {startSlot: Slot; count: number; columns: number[]}): string {
|
|
120
|
+
return `startSlot=${req.startSlot},count=${req.count},cols=${prettyPrintIndices(req.columns)}`;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function getTrackedRequest({parentPayloadRequest, columnsRequest}: DownloadByRangeRequests): TrackedRequest {
|
|
124
|
+
return {
|
|
125
|
+
parentPayload: parentPayloadRequest != null,
|
|
126
|
+
byRangeColumns: new Set(parentPayloadRequest == null ? (columnsRequest?.columns ?? []) : []),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
68
130
|
/**
|
|
69
131
|
* Batches are downloaded at the first block of the epoch.
|
|
70
132
|
*
|
|
@@ -85,9 +147,9 @@ export class Batch {
|
|
|
85
147
|
/** Block, blob and column requests that are used to determine the best peer and are used in downloadByRange */
|
|
86
148
|
requests: DownloadByRangeRequests;
|
|
87
149
|
/** State of the batch. */
|
|
88
|
-
state: BatchState = {status: BatchStatus.AwaitingDownload, blocks: []};
|
|
89
|
-
/** Peers that provided good data */
|
|
90
|
-
|
|
150
|
+
state: BatchState = {status: BatchStatus.AwaitingDownload, blocks: [], payloadEnvelopes: null};
|
|
151
|
+
/** Peers that provided good data, with column coverage for by_range requests */
|
|
152
|
+
private readonly successfulDownloads = new Map<PeerIdStr, TrackedRequest>();
|
|
91
153
|
/** The `Attempts` that have been made and failed to send us this batch. */
|
|
92
154
|
readonly failedProcessingAttempts: Attempt[] = [];
|
|
93
155
|
/** The `Attempts` that have been made and failed because of execution malfunction. */
|
|
@@ -97,8 +159,18 @@ export class Batch {
|
|
|
97
159
|
private readonly config: ChainForkConfig;
|
|
98
160
|
private readonly clock: IClock;
|
|
99
161
|
private readonly custodyConfig: CustodyConfig;
|
|
100
|
-
|
|
101
|
-
|
|
162
|
+
private readonly isFirstBatchInChain: boolean;
|
|
163
|
+
private readonly latestBid: gloas.ExecutionPayloadBid | undefined;
|
|
164
|
+
|
|
165
|
+
constructor(
|
|
166
|
+
startEpoch: Epoch,
|
|
167
|
+
config: ChainForkConfig,
|
|
168
|
+
clock: IClock,
|
|
169
|
+
custodyConfig: CustodyConfig,
|
|
170
|
+
isFirstBatchInChain: boolean,
|
|
171
|
+
latestBid: gloas.ExecutionPayloadBid | undefined,
|
|
172
|
+
targetSlot: Slot
|
|
173
|
+
) {
|
|
102
174
|
this.config = config;
|
|
103
175
|
this.clock = clock;
|
|
104
176
|
this.custodyConfig = custodyConfig;
|
|
@@ -107,10 +179,40 @@ export class Batch {
|
|
|
107
179
|
this.forkName = this.config.getForkName(startSlot);
|
|
108
180
|
this.startEpoch = startEpoch;
|
|
109
181
|
this.startSlot = startSlot;
|
|
110
|
-
this.count = count;
|
|
182
|
+
this.count = Math.min(count, targetSlot - startSlot + 1);
|
|
183
|
+
this.isFirstBatchInChain = isFirstBatchInChain;
|
|
184
|
+
this.latestBid = latestBid;
|
|
111
185
|
this.requests = this.getRequests([]);
|
|
112
186
|
}
|
|
113
187
|
|
|
188
|
+
private shouldDownloadParentEnvelope(firstBlock?: SignedBeaconBlock): boolean {
|
|
189
|
+
if (!this.isFirstBatchInChain) return false;
|
|
190
|
+
|
|
191
|
+
if (this.startSlot === 0 || !isForkPostGloas(this.config.getForkName(this.startSlot - 1))) {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// we only know if we should download parent envelope if firstBlock is downloaded
|
|
196
|
+
if (firstBlock === undefined) return false;
|
|
197
|
+
if (this.latestBid === undefined) return false;
|
|
198
|
+
const firstBlockBidParentHash = (firstBlock.message.body as gloas.BeaconBlockBody).signedExecutionPayloadBid.message
|
|
199
|
+
.parentBlockHash;
|
|
200
|
+
return byteArrayEquals(firstBlockBidParentHash, this.latestBid.blockHash);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
getParentPayloadCommitments(parentBlockRoot: Uint8Array): ParentPayloadCommitments {
|
|
204
|
+
if (this.latestBid === undefined) {
|
|
205
|
+
throw new Error(
|
|
206
|
+
`Coding error: getParentPayloadCommitments called without latestBid for parentBlockRoot=${toRootHex(parentBlockRoot)}`
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
blockRoot: parentBlockRoot,
|
|
211
|
+
blockRootHex: toRootHex(parentBlockRoot),
|
|
212
|
+
kzgCommitments: this.latestBid.blobKzgCommitments,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
114
216
|
/**
|
|
115
217
|
* Builds ByRange requests for block, blobs and columns
|
|
116
218
|
*/
|
|
@@ -129,37 +231,36 @@ export class Batch {
|
|
|
129
231
|
count: this.count,
|
|
130
232
|
step: 1,
|
|
131
233
|
};
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
count: this.count,
|
|
138
|
-
columns: this.custodyConfig.sampledColumns,
|
|
139
|
-
},
|
|
140
|
-
};
|
|
234
|
+
const requests: DownloadByRangeRequests = {blocksRequest};
|
|
235
|
+
|
|
236
|
+
// Post-Gloas envelopes are required for block processing, independent of DA retention window.
|
|
237
|
+
if (isForkPostGloas(this.forkName)) {
|
|
238
|
+
requests.envelopesRequest = {startSlot: this.startSlot, count: this.count};
|
|
141
239
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
},
|
|
240
|
+
|
|
241
|
+
if (isForkPostFulu(this.forkName) && withinValidRequestWindow) {
|
|
242
|
+
requests.columnsRequest = {
|
|
243
|
+
startSlot: this.startSlot,
|
|
244
|
+
count: this.count,
|
|
245
|
+
columns: this.custodyConfig.sampledColumns,
|
|
149
246
|
};
|
|
247
|
+
} else if (isForkPostDeneb(this.forkName) && withinValidRequestWindow) {
|
|
248
|
+
requests.blobsRequest = {startSlot: this.startSlot, count: this.count};
|
|
150
249
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
};
|
|
250
|
+
|
|
251
|
+
return requests;
|
|
154
252
|
}
|
|
155
253
|
|
|
156
254
|
// subsequent request where part of the epoch has already been downloaded. Need to figure out what is the beginning
|
|
157
255
|
// of the range where download needs to resume
|
|
158
256
|
let blockStartSlot = this.startSlot;
|
|
159
257
|
let dataStartSlot = this.startSlot;
|
|
258
|
+
let envelopeStartSlot = this.startSlot;
|
|
160
259
|
const neededColumns = new Set<number>();
|
|
260
|
+
const envelopesBySlot = this.state.payloadEnvelopes ?? new Map<Slot, PayloadEnvelopeInput>();
|
|
161
261
|
|
|
162
262
|
// ensure blocks are in slot-wise order
|
|
263
|
+
const isPostGloas = isForkPostGloas(this.forkName);
|
|
163
264
|
for (const blockInput of blocks) {
|
|
164
265
|
const blockSlot = blockInput.slot;
|
|
165
266
|
// check if block/data is present (hasBlock/hasAllData). If present then check if startSlot is the same as
|
|
@@ -175,14 +276,36 @@ export class Batch {
|
|
|
175
276
|
if (blockInput.hasBlock() && blockStartSlot === blockSlot) {
|
|
176
277
|
blockStartSlot = blockSlot + 1;
|
|
177
278
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
279
|
+
|
|
280
|
+
// Range sync uses hasComputedAllData (all sampled columns physically present), not hasAllData
|
|
281
|
+
// which flips at the reconstruction threshold. Sync never triggers reconstruction, so accepting
|
|
282
|
+
// a half-downloaded block here makes writeBlockInputToDb later block on waitForComputedAllData.
|
|
283
|
+
if (isPostGloas) {
|
|
284
|
+
// Post-Gloas: column data lives on PayloadEnvelopeInput, not on BlockInputNoData.
|
|
285
|
+
const payloadInput = envelopesBySlot.get(blockSlot);
|
|
286
|
+
if (blockInput.hasBlock() && envelopeStartSlot === blockSlot && payloadInput?.hasPayloadEnvelope()) {
|
|
287
|
+
envelopeStartSlot = blockSlot + 1;
|
|
288
|
+
}
|
|
289
|
+
if (payloadInput && !payloadInput.hasComputedAllData()) {
|
|
290
|
+
for (const index of payloadInput.getMissingSampledColumnMeta().missing) {
|
|
181
291
|
neededColumns.add(index);
|
|
182
292
|
}
|
|
293
|
+
} else if (payloadInput?.hasComputedAllData() && dataStartSlot === blockSlot) {
|
|
294
|
+
// Only advance dataStartSlot when we know columns for this slot are complete. If
|
|
295
|
+
// payloadInput is missing entirely we cannot tell, so stop here so the next round
|
|
296
|
+
// re-requests columns (and envelopes) starting at this slot.
|
|
297
|
+
dataStartSlot = blockSlot + 1;
|
|
298
|
+
}
|
|
299
|
+
} else {
|
|
300
|
+
if (isBlockInputColumns(blockInput) ? !blockInput.hasComputedAllData() : !blockInput.hasAllData()) {
|
|
301
|
+
if (isBlockInputColumns(blockInput)) {
|
|
302
|
+
for (const index of blockInput.getMissingSampledColumnMeta().missing) {
|
|
303
|
+
neededColumns.add(index);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
} else if (dataStartSlot === blockSlot) {
|
|
307
|
+
dataStartSlot = blockSlot + 1;
|
|
183
308
|
}
|
|
184
|
-
} else if (dataStartSlot === blockSlot) {
|
|
185
|
-
dataStartSlot = blockSlot + 1;
|
|
186
309
|
}
|
|
187
310
|
}
|
|
188
311
|
|
|
@@ -202,11 +325,15 @@ export class Batch {
|
|
|
202
325
|
// range of 40 - 63, startSlot will be inclusive but subtraction will exclusive so need to + 1
|
|
203
326
|
const count = endSlot - dataStartSlot + 1;
|
|
204
327
|
if (isForkPostFulu(this.forkName) && withinValidRequestWindow) {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
328
|
+
// Skip the column re-request when we have no specific column indices outstanding.
|
|
329
|
+
// Peer rejects an empty `columns` list
|
|
330
|
+
if (neededColumns.size > 0) {
|
|
331
|
+
requests.columnsRequest = {
|
|
332
|
+
count,
|
|
333
|
+
startSlot: dataStartSlot,
|
|
334
|
+
columns: Array.from(neededColumns),
|
|
335
|
+
};
|
|
336
|
+
}
|
|
210
337
|
} else if (isForkPostDeneb(this.forkName) && withinValidRequestWindow) {
|
|
211
338
|
requests.blobsRequest = {
|
|
212
339
|
count,
|
|
@@ -216,6 +343,43 @@ export class Batch {
|
|
|
216
343
|
// dataSlot will still have a value but do not create a request for preDeneb forks
|
|
217
344
|
}
|
|
218
345
|
|
|
346
|
+
if (isForkPostGloas(this.forkName) && envelopeStartSlot <= endSlot) {
|
|
347
|
+
requests.envelopesRequest = {
|
|
348
|
+
startSlot: envelopeStartSlot,
|
|
349
|
+
count: endSlot - envelopeStartSlot + 1,
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Only the first batch of a SyncChain may need the dangling-parent payload by-root.
|
|
354
|
+
if (blocks.length > 0 && this.shouldDownloadParentEnvelope(blocks[0].getBlock())) {
|
|
355
|
+
// shouldDownloadParentEnvelope() = true means there are at least 1 block
|
|
356
|
+
const parentRoot = blocks[0].getBlock().message.parentRoot;
|
|
357
|
+
if (!byteArrayEquals(parentRoot, ZERO_HASH)) {
|
|
358
|
+
const parentRootHex = toRootHex(parentRoot);
|
|
359
|
+
let parentPayloadInput: PayloadEnvelopeInput | undefined;
|
|
360
|
+
if (this.state.payloadEnvelopes) {
|
|
361
|
+
for (const pi of this.state.payloadEnvelopes.values()) {
|
|
362
|
+
if (pi.blockRootHex === parentRootHex) {
|
|
363
|
+
parentPayloadInput = pi;
|
|
364
|
+
break;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const needsEnvelope = !parentPayloadInput?.hasPayloadEnvelope();
|
|
370
|
+
const missingColumns = parentPayloadInput
|
|
371
|
+
? parentPayloadInput.getMissingSampledColumnMeta().missing
|
|
372
|
+
: this.custodyConfig.sampledColumns;
|
|
373
|
+
|
|
374
|
+
if (needsEnvelope || missingColumns.length > 0) {
|
|
375
|
+
requests.parentPayloadRequest = {
|
|
376
|
+
...(needsEnvelope ? {envelopeBlockRoot: parentRoot} : {}),
|
|
377
|
+
...(missingColumns.length > 0 ? {blockRoot: parentRoot, columns: missingColumns} : {}),
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
219
383
|
return requests;
|
|
220
384
|
}
|
|
221
385
|
|
|
@@ -227,24 +391,28 @@ export class Batch {
|
|
|
227
391
|
return this.requests;
|
|
228
392
|
}
|
|
229
393
|
|
|
230
|
-
// post-fulu we need to ensure that we only request columns that the peer has advertised
|
|
231
|
-
const {columnsRequest} = this.requests;
|
|
232
|
-
if (columnsRequest == null) {
|
|
233
|
-
return this.requests;
|
|
234
|
-
}
|
|
394
|
+
// post-fulu we need to ensure that we only request columns that the peer has advertised.
|
|
395
|
+
const {columnsRequest, parentPayloadRequest} = this.requests;
|
|
235
396
|
|
|
236
397
|
const peerColumns = new Set(peer.custodyColumns ?? []);
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
398
|
+
const filteredColumnsRequest =
|
|
399
|
+
columnsRequest != null ? columnsRequest.columns.filter((c) => peerColumns.has(c)) : null;
|
|
400
|
+
const parentColumns = parentPayloadRequest?.columns;
|
|
401
|
+
const filteredParentColumns = parentColumns != null ? parentColumns.filter((c) => peerColumns.has(c)) : null;
|
|
402
|
+
|
|
403
|
+
const updatedColumnRequest =
|
|
404
|
+
columnsRequest != null && filteredColumnsRequest != null
|
|
405
|
+
? {columnsRequest: {...columnsRequest, columns: filteredColumnsRequest}}
|
|
406
|
+
: {};
|
|
407
|
+
const updatedParentPayloadRequest =
|
|
408
|
+
parentPayloadRequest != null && filteredParentColumns != null
|
|
409
|
+
? {parentPayloadRequest: {...parentPayloadRequest, columns: filteredParentColumns}}
|
|
410
|
+
: {};
|
|
241
411
|
|
|
242
412
|
return {
|
|
243
413
|
...this.requests,
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
columns: requestedColumns,
|
|
247
|
-
},
|
|
414
|
+
...updatedColumnRequest,
|
|
415
|
+
...updatedParentPayloadRequest,
|
|
248
416
|
};
|
|
249
417
|
}
|
|
250
418
|
|
|
@@ -255,29 +423,93 @@ export class Batch {
|
|
|
255
423
|
return [...this.failedDownloadAttempts, ...this.failedProcessingAttempts.flatMap((a) => a.peers)];
|
|
256
424
|
}
|
|
257
425
|
|
|
426
|
+
/**
|
|
427
|
+
* True only if the peer has already returned a successful response for the current request.
|
|
428
|
+
* A by_range success may update `this.requests` to parent_payload, and the same peer is then
|
|
429
|
+
* still eligible for the newly discovered parent payload data.
|
|
430
|
+
* For by_range, a peer that previously succeeded with a superset of requested columns is skipped.
|
|
431
|
+
*/
|
|
432
|
+
hasPeerSucceededCurrentRequest(peer: PeerSyncMeta): boolean {
|
|
433
|
+
const successfulDownload = this.successfulDownloads.get(peer.peerId);
|
|
434
|
+
if (successfulDownload == null) return false;
|
|
435
|
+
|
|
436
|
+
const request = getTrackedRequest(this.getRequestsForPeer(peer));
|
|
437
|
+
if (request.parentPayload) return successfulDownload.parentPayload;
|
|
438
|
+
|
|
439
|
+
const requestByRangeColumns = request.byRangeColumns;
|
|
440
|
+
|
|
441
|
+
if (requestByRangeColumns.size === 0) {
|
|
442
|
+
// this means a download blocks/envelops by_range only
|
|
443
|
+
// don't do that again if we already did it
|
|
444
|
+
// see https://github.com/ChainSafe/lodestar/issues/9357
|
|
445
|
+
return true;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
return [...requestByRangeColumns].every((column) => successfulDownload.byRangeColumns.has(column));
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
private getSuccessfulPeers(): PeerIdStr[] {
|
|
452
|
+
return Array.from(this.successfulDownloads.keys());
|
|
453
|
+
}
|
|
454
|
+
|
|
258
455
|
getMetadata(): BatchMetadata {
|
|
259
|
-
|
|
456
|
+
const {blocksRequest, blobsRequest, columnsRequest, envelopesRequest} = this.requests;
|
|
457
|
+
const failedProcessingPeerList = this.failedProcessingAttempts.flatMap((a) => a.peers);
|
|
458
|
+
return {
|
|
459
|
+
startEpoch: this.startEpoch,
|
|
460
|
+
startSlot: this.startSlot,
|
|
461
|
+
count: this.count,
|
|
462
|
+
status: this.state.status,
|
|
463
|
+
...(blocksRequest && {blocksReq: formatRangeReq(blocksRequest)}),
|
|
464
|
+
...(blobsRequest && {blobsReq: formatRangeReq(blobsRequest)}),
|
|
465
|
+
...(columnsRequest && {columnsReq: formatColumnsReq(columnsRequest)}),
|
|
466
|
+
...(envelopesRequest && {envelopesReq: formatRangeReq(envelopesRequest)}),
|
|
467
|
+
downloadAttempts: this.failedDownloadAttempts.length,
|
|
468
|
+
processingAttempts: this.failedProcessingAttempts.length,
|
|
469
|
+
...(this.failedDownloadAttempts.length > 0 && {
|
|
470
|
+
failedDownloadPeers: this.failedDownloadAttempts.join(","),
|
|
471
|
+
}),
|
|
472
|
+
...(failedProcessingPeerList.length > 0 && {
|
|
473
|
+
failedProcessingPeers: failedProcessingPeerList.join(","),
|
|
474
|
+
}),
|
|
475
|
+
};
|
|
260
476
|
}
|
|
261
477
|
|
|
262
478
|
getBlocks(): IBlockInput[] {
|
|
263
479
|
return this.state.blocks;
|
|
264
480
|
}
|
|
265
481
|
|
|
482
|
+
getPayloadEnvelopes(): Map<Slot, PayloadEnvelopeInput> | null {
|
|
483
|
+
return this.state.payloadEnvelopes;
|
|
484
|
+
}
|
|
485
|
+
|
|
266
486
|
/**
|
|
267
487
|
* AwaitingDownload -> Downloading
|
|
268
488
|
*/
|
|
269
|
-
startDownloading(peer:
|
|
489
|
+
startDownloading(peer: PeerSyncMeta): void {
|
|
270
490
|
if (this.state.status !== BatchStatus.AwaitingDownload) {
|
|
271
491
|
throw new BatchError(this.wrongStatusErrorType(BatchStatus.AwaitingDownload));
|
|
272
492
|
}
|
|
273
493
|
|
|
274
|
-
|
|
494
|
+
const request = getTrackedRequest(this.getRequestsForPeer(peer));
|
|
495
|
+
|
|
496
|
+
this.state = {
|
|
497
|
+
status: BatchStatus.Downloading,
|
|
498
|
+
peer: peer.peerId,
|
|
499
|
+
request,
|
|
500
|
+
blocks: this.state.blocks,
|
|
501
|
+
payloadEnvelopes: this.state.payloadEnvelopes,
|
|
502
|
+
};
|
|
275
503
|
}
|
|
276
504
|
|
|
277
505
|
/**
|
|
278
506
|
* Downloading -> AwaitingProcessing
|
|
279
507
|
*/
|
|
280
|
-
downloadingSuccess(
|
|
508
|
+
downloadingSuccess(
|
|
509
|
+
peer: PeerIdStr,
|
|
510
|
+
blocks: IBlockInput[],
|
|
511
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null
|
|
512
|
+
): DownloadSuccessState {
|
|
281
513
|
if (this.state.status !== BatchStatus.Downloading) {
|
|
282
514
|
throw new BatchError(this.wrongStatusErrorType(BatchStatus.Downloading));
|
|
283
515
|
}
|
|
@@ -285,13 +517,27 @@ export class Batch {
|
|
|
285
517
|
// ensure that blocks are always sorted before getting stored on the batch.state or being used to getRequests
|
|
286
518
|
blocks.sort((a, b) => a.slot - b.slot);
|
|
287
519
|
|
|
288
|
-
this.
|
|
520
|
+
const successfulDownload = this.successfulDownloads.get(peer) ?? {
|
|
521
|
+
parentPayload: false,
|
|
522
|
+
byRangeColumns: new Set<number>(),
|
|
523
|
+
};
|
|
524
|
+
successfulDownload.parentPayload ||= this.state.request.parentPayload;
|
|
525
|
+
if (!this.state.request.parentPayload) {
|
|
526
|
+
for (const column of this.state.request.byRangeColumns) {
|
|
527
|
+
successfulDownload.byRangeColumns.add(column);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
this.successfulDownloads.set(peer, successfulDownload);
|
|
289
531
|
|
|
290
532
|
let allComplete = true;
|
|
291
533
|
const slots = new Set<number>();
|
|
292
534
|
for (const block of blocks) {
|
|
293
535
|
slots.add(block.slot);
|
|
294
|
-
|
|
536
|
+
const dataComplete = isBlockInputColumns(block)
|
|
537
|
+
? // by_range needs to download all columns
|
|
538
|
+
block.hasBlock() && block.hasComputedAllData()
|
|
539
|
+
: block.hasBlockAndAllData();
|
|
540
|
+
if (!dataComplete) {
|
|
295
541
|
allComplete = false;
|
|
296
542
|
}
|
|
297
543
|
}
|
|
@@ -305,11 +551,48 @@ export class Batch {
|
|
|
305
551
|
status: this.state.status,
|
|
306
552
|
});
|
|
307
553
|
}
|
|
554
|
+
const newPayloadEnvelopes = payloadEnvelopes ?? this.state.payloadEnvelopes;
|
|
555
|
+
|
|
556
|
+
if (allComplete && isForkPostGloas(this.forkName)) {
|
|
557
|
+
for (const block of blocks) {
|
|
558
|
+
const payloadInput = newPayloadEnvelopes?.get(block.slot);
|
|
559
|
+
// only need to make sure envelope has all columns, not all blocks have payload
|
|
560
|
+
// assertLinearChainSegment() was called before reaching this
|
|
561
|
+
if (payloadInput?.hasPayloadEnvelope() && !payloadInput.hasComputedAllData()) {
|
|
562
|
+
allComplete = false;
|
|
563
|
+
break;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// First batch of a sync chain must additionally have the dangling-parent payload fully
|
|
569
|
+
// present, otherwise `processBlocks` will throw PARENT_PAYLOAD_UNKNOWN. The parent's
|
|
570
|
+
// `PayloadEnvelopeInput` is identified by `blockRootHex` matching `blocks[0].parentRoot`.
|
|
571
|
+
if (allComplete && blocks.length > 0 && this.shouldDownloadParentEnvelope(blocks[0].getBlock())) {
|
|
572
|
+
const parentRoot = blocks[0].getBlock().message.parentRoot;
|
|
573
|
+
// Genesis has no parent payload — nothing to wait for.
|
|
574
|
+
if (!byteArrayEquals(parentRoot, ZERO_HASH)) {
|
|
575
|
+
const parentRootHex = toRootHex(parentRoot);
|
|
576
|
+
let parentPayloadComplete = false;
|
|
577
|
+
if (newPayloadEnvelopes) {
|
|
578
|
+
for (const payloadInput of newPayloadEnvelopes.values()) {
|
|
579
|
+
if (payloadInput.blockRootHex === parentRootHex) {
|
|
580
|
+
parentPayloadComplete = payloadInput.hasPayloadEnvelope() && payloadInput.hasComputedAllData();
|
|
581
|
+
break;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
if (!parentPayloadComplete) {
|
|
586
|
+
allComplete = false;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
308
591
|
if (allComplete) {
|
|
309
|
-
this.state = {status: BatchStatus.AwaitingProcessing, blocks};
|
|
592
|
+
this.state = {status: BatchStatus.AwaitingProcessing, blocks, payloadEnvelopes: newPayloadEnvelopes};
|
|
310
593
|
} else {
|
|
594
|
+
this.state = {status: BatchStatus.AwaitingDownload, blocks, payloadEnvelopes: newPayloadEnvelopes};
|
|
311
595
|
this.requests = this.getRequests(blocks);
|
|
312
|
-
this.state = {status: BatchStatus.AwaitingDownload, blocks};
|
|
313
596
|
}
|
|
314
597
|
|
|
315
598
|
return this.state as DownloadSuccessState;
|
|
@@ -328,25 +611,50 @@ export class Batch {
|
|
|
328
611
|
throw new BatchError(this.errorType({code: BatchErrorCode.MAX_DOWNLOAD_ATTEMPTS}));
|
|
329
612
|
}
|
|
330
613
|
|
|
331
|
-
this.state = {
|
|
614
|
+
this.state = {
|
|
615
|
+
status: BatchStatus.AwaitingDownload,
|
|
616
|
+
blocks: this.state.blocks,
|
|
617
|
+
payloadEnvelopes: this.state.payloadEnvelopes,
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Downloading -> AwaitingDownload (without counting as a failed attempt).
|
|
623
|
+
* Used when the peer rate-limited us — the request was never actually served.
|
|
624
|
+
*/
|
|
625
|
+
downloadingRateLimited(): void {
|
|
626
|
+
if (this.state.status !== BatchStatus.Downloading) {
|
|
627
|
+
throw new BatchError(this.wrongStatusErrorType(BatchStatus.Downloading));
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
this.state = {
|
|
631
|
+
status: BatchStatus.AwaitingDownload,
|
|
632
|
+
blocks: this.state.blocks,
|
|
633
|
+
payloadEnvelopes: this.state.payloadEnvelopes,
|
|
634
|
+
};
|
|
332
635
|
}
|
|
333
636
|
|
|
334
637
|
/**
|
|
335
638
|
* AwaitingProcessing -> Processing
|
|
336
639
|
*/
|
|
337
|
-
startProcessing():
|
|
640
|
+
startProcessing(): {
|
|
641
|
+
blocks: IBlockInput[];
|
|
642
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
|
|
643
|
+
peers: PeerIdStr[];
|
|
644
|
+
} {
|
|
338
645
|
if (this.state.status !== BatchStatus.AwaitingProcessing) {
|
|
339
646
|
throw new BatchError(this.wrongStatusErrorType(BatchStatus.AwaitingProcessing));
|
|
340
647
|
}
|
|
341
648
|
|
|
342
649
|
const blocks = this.state.blocks;
|
|
650
|
+
const payloadEnvelopes = this.state.payloadEnvelopes;
|
|
343
651
|
const hash = hashBlocks(blocks, this.config); // tracks blocks to report peer on processing error
|
|
344
|
-
// Reset
|
|
345
|
-
// that the data came from will be handled by the Attempt that goes for processing
|
|
346
|
-
const peers = this.
|
|
347
|
-
this.
|
|
348
|
-
this.state = {status: BatchStatus.Processing, blocks, attempt: {peers, hash}};
|
|
349
|
-
return blocks;
|
|
652
|
+
// Reset successfulDownloads in case another download attempt needs to be made. When Attempt is successful or not
|
|
653
|
+
// the peers that the data came from will be handled by the Attempt that goes for processing.
|
|
654
|
+
const peers = this.getSuccessfulPeers();
|
|
655
|
+
this.successfulDownloads.clear();
|
|
656
|
+
this.state = {status: BatchStatus.Processing, blocks, payloadEnvelopes, attempt: {peers, hash}};
|
|
657
|
+
return {blocks, payloadEnvelopes, peers};
|
|
350
658
|
}
|
|
351
659
|
|
|
352
660
|
/**
|
|
@@ -357,7 +665,12 @@ export class Batch {
|
|
|
357
665
|
throw new BatchError(this.wrongStatusErrorType(BatchStatus.Processing));
|
|
358
666
|
}
|
|
359
667
|
|
|
360
|
-
this.state = {
|
|
668
|
+
this.state = {
|
|
669
|
+
status: BatchStatus.AwaitingValidation,
|
|
670
|
+
blocks: this.state.blocks,
|
|
671
|
+
payloadEnvelopes: this.state.payloadEnvelopes,
|
|
672
|
+
attempt: this.state.attempt,
|
|
673
|
+
};
|
|
361
674
|
}
|
|
362
675
|
|
|
363
676
|
/**
|
|
@@ -408,7 +721,7 @@ export class Batch {
|
|
|
408
721
|
|
|
409
722
|
// remove any downloaded blocks and re-attempt
|
|
410
723
|
// TODO(fulu): need to remove the bad blocks from the SeenBlockInputCache
|
|
411
|
-
this.state = {status: BatchStatus.AwaitingDownload, blocks: []};
|
|
724
|
+
this.state = {status: BatchStatus.AwaitingDownload, blocks: [], payloadEnvelopes: null};
|
|
412
725
|
}
|
|
413
726
|
|
|
414
727
|
private onProcessingError(attempt: Attempt): void {
|
|
@@ -419,12 +732,12 @@ export class Batch {
|
|
|
419
732
|
|
|
420
733
|
// remove any downloaded blocks and re-attempt
|
|
421
734
|
// TODO(fulu): need to remove the bad blocks from the SeenBlockInputCache
|
|
422
|
-
this.state = {status: BatchStatus.AwaitingDownload, blocks: []};
|
|
735
|
+
this.state = {status: BatchStatus.AwaitingDownload, blocks: [], payloadEnvelopes: null};
|
|
423
736
|
}
|
|
424
737
|
|
|
425
738
|
/** Helper to construct typed BatchError. Stack traces are correct as the error is thrown above */
|
|
426
739
|
private errorType(type: BatchErrorType): BatchErrorType & BatchErrorMetadata {
|
|
427
|
-
return {...type,
|
|
740
|
+
return {...type, startEpoch: this.startEpoch, status: this.state.status};
|
|
428
741
|
}
|
|
429
742
|
|
|
430
743
|
private wrongStatusErrorType(expectedStatus: BatchStatus): BatchErrorType & BatchErrorMetadata {
|