@lodestar/beacon-node 1.43.0-dev.6b7eebbf6d → 1.43.0-dev.6f485b1b61
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 +23 -2
- package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.js +89 -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/blocks/writePayloadEnvelopeInputToDb.d.ts.map +1 -1
- package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js +1 -10
- package/lib/chain/blocks/writePayloadEnvelopeInputToDb.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 +42 -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/executionPayloadBid.d.ts +5 -0
- package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadBid.js +1 -0
- package/lib/chain/errors/executionPayloadBid.js.map +1 -1
- package/lib/chain/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/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 +31 -13
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +11 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +47 -15
- 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 +24 -7
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +69 -17
- 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 +24 -9
- 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 +10 -0
- 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 +1 -0
- package/lib/network/interface.d.ts.map +1 -1
- package/lib/network/network.d.ts +1 -0
- package/lib/network/network.d.ts.map +1 -1
- package/lib/network/network.js +5 -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/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/node/nodejs.js +2 -2
- package/lib/node/nodejs.js.map +1 -1
- package/lib/sync/constants.d.ts +3 -1
- package/lib/sync/constants.d.ts.map +1 -1
- package/lib/sync/constants.js +3 -4
- package/lib/sync/constants.js.map +1 -1
- package/lib/sync/range/batch.d.ts +35 -5
- package/lib/sync/range/batch.d.ts.map +1 -1
- package/lib/sync/range/batch.js +240 -59
- package/lib/sync/range/batch.js.map +1 -1
- package/lib/sync/range/chain.d.ts +19 -4
- package/lib/sync/range/chain.d.ts.map +1 -1
- package/lib/sync/range/chain.js +64 -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 +31 -9
- package/lib/sync/range/range.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 +738 -61
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/sync/utils/downloadByRange.d.ts +67 -10
- package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRange.js +211 -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/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 -15
- 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 +114 -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/blocks/writePayloadEnvelopeInputToDb.ts +8 -17
- package/src/chain/chain.ts +55 -10
- package/src/chain/emitter.ts +0 -11
- package/src/chain/errors/blockError.ts +4 -1
- package/src/chain/errors/executionPayloadBid.ts +6 -0
- 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/opPools/payloadAttestationPool.ts +29 -8
- package/src/chain/prepareNextSlot.ts +36 -14
- package/src/chain/produceBlock/produceBlockBody.ts +57 -14
- 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 +89 -21
- package/src/chain/seenCache/seenProposerPreferences.ts +32 -0
- package/src/chain/validation/block.ts +1 -0
- package/src/chain/validation/executionPayloadBid.ts +25 -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 +1 -0
- package/src/network/network.ts +11 -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/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/node/nodejs.ts +2 -2
- package/src/sync/constants.ts +4 -4
- package/src/sync/range/batch.ts +320 -67
- package/src/sync/range/chain.ts +89 -14
- package/src/sync/range/range.ts +34 -9
- package/src/sync/sync.ts +13 -1
- package/src/sync/types.ts +72 -0
- package/src/sync/unknownBlock.ts +928 -65
- package/src/sync/utils/downloadByRange.ts +378 -39
- package/src/sync/utils/downloadByRoot.ts +24 -2
- package/src/sync/utils/pendingBlocksTree.ts +0 -15
- package/src/util/sszBytes.ts +8 -6
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
ForkPostDeneb,
|
|
4
|
+
ForkPostFulu,
|
|
5
|
+
ForkPostGloas,
|
|
6
|
+
ForkPreFulu,
|
|
7
|
+
isForkPostFulu,
|
|
8
|
+
isForkPostGloas,
|
|
9
|
+
} from "@lodestar/params";
|
|
10
|
+
import {
|
|
11
|
+
ColumnIndex,
|
|
12
|
+
DataColumnSidecar,
|
|
13
|
+
RootHex,
|
|
14
|
+
SignedBeaconBlock,
|
|
15
|
+
Slot,
|
|
16
|
+
deneb,
|
|
17
|
+
fulu,
|
|
18
|
+
gloas,
|
|
19
|
+
isGloasDataColumnSidecar,
|
|
20
|
+
phase0,
|
|
21
|
+
} from "@lodestar/types";
|
|
4
22
|
import {LodestarError, Logger, byteArrayEquals, fromHex, prettyPrintIndices, toRootHex} from "@lodestar/utils";
|
|
5
23
|
import {
|
|
6
24
|
BlockInputSource,
|
|
@@ -9,12 +27,18 @@ import {
|
|
|
9
27
|
isBlockInputBlobs,
|
|
10
28
|
isBlockInputColumns,
|
|
11
29
|
} from "../../chain/blocks/blockInput/index.js";
|
|
30
|
+
import {PayloadEnvelopeInput} from "../../chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js";
|
|
31
|
+
import {PayloadEnvelopeInputSource} from "../../chain/blocks/payloadEnvelopeInput/types.js";
|
|
12
32
|
import {SeenBlockInput} from "../../chain/seenCache/seenGossipBlockInput.js";
|
|
33
|
+
import {SeenPayloadEnvelopeInput} from "../../chain/seenCache/seenPayloadEnvelopeInput.js";
|
|
13
34
|
import {validateBlockBlobSidecars} from "../../chain/validation/blobSidecar.js";
|
|
14
|
-
import {
|
|
35
|
+
import {
|
|
36
|
+
validateFuluBlockDataColumnSidecars,
|
|
37
|
+
validateGloasBlockDataColumnSidecars,
|
|
38
|
+
} from "../../chain/validation/dataColumnSidecar.js";
|
|
15
39
|
import {BeaconMetrics} from "../../metrics/metrics/beacon.js";
|
|
16
40
|
import {INetwork} from "../../network/index.js";
|
|
17
|
-
import {getBlobKzgCommitments} from "../../util/dataColumns.js";
|
|
41
|
+
import {CustodyConfig, getBlobKzgCommitments} from "../../util/dataColumns.js";
|
|
18
42
|
import {PeerIdStr} from "../../util/peerId.js";
|
|
19
43
|
import {WarnResult} from "../../util/wrapError.js";
|
|
20
44
|
|
|
@@ -22,12 +46,30 @@ export type DownloadByRangeRequests = {
|
|
|
22
46
|
blocksRequest?: phase0.BeaconBlocksByRangeRequest;
|
|
23
47
|
blobsRequest?: deneb.BlobSidecarsByRangeRequest;
|
|
24
48
|
columnsRequest?: fulu.DataColumnSidecarsByRangeRequest;
|
|
49
|
+
envelopesRequest?: gloas.ExecutionPayloadEnvelopesByRangeRequest;
|
|
50
|
+
/**
|
|
51
|
+
* Post-Gloas only. Fetches the dangling-parent's payload envelope and/or its missing sampled
|
|
52
|
+
* data columns by-root. Set by `Batch` for the first batch of a `SyncChain` after the first
|
|
53
|
+
* block's parentRoot is known.
|
|
54
|
+
*/
|
|
55
|
+
parentPayloadRequest?: {
|
|
56
|
+
blockRoot?: Uint8Array;
|
|
57
|
+
columns?: ColumnIndex[];
|
|
58
|
+
envelopeBlockRoot?: Uint8Array;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export type ParentPayloadCommitments = {
|
|
63
|
+
blockRoot: Uint8Array;
|
|
64
|
+
blockRootHex: RootHex;
|
|
65
|
+
kzgCommitments: deneb.BlobKzgCommitments;
|
|
25
66
|
};
|
|
26
67
|
|
|
27
68
|
export type DownloadByRangeResponses = {
|
|
28
69
|
blocks?: SignedBeaconBlock[];
|
|
29
70
|
blobSidecars?: deneb.BlobSidecars;
|
|
30
|
-
columnSidecars?:
|
|
71
|
+
columnSidecars?: DataColumnSidecar[];
|
|
72
|
+
payloadEnvelopes?: gloas.SignedExecutionPayloadEnvelope[];
|
|
31
73
|
};
|
|
32
74
|
|
|
33
75
|
export type DownloadAndCacheByRangeProps = DownloadByRangeRequests & {
|
|
@@ -36,14 +78,24 @@ export type DownloadAndCacheByRangeProps = DownloadByRangeRequests & {
|
|
|
36
78
|
logger: Logger;
|
|
37
79
|
peerIdStr: string;
|
|
38
80
|
batchBlocks?: IBlockInput[];
|
|
81
|
+
/** Required when `parentPayloadRequest` is set; supplies the data needed to validate the parent's columns. */
|
|
82
|
+
parentPayloadCommitments?: ParentPayloadCommitments;
|
|
39
83
|
peerDasMetrics?: BeaconMetrics["peerDas"] | null;
|
|
40
84
|
};
|
|
41
85
|
|
|
42
86
|
export type CacheByRangeResponsesProps = {
|
|
43
87
|
cache: SeenBlockInput;
|
|
88
|
+
seenPayloadEnvelopeInputCache: SeenPayloadEnvelopeInput;
|
|
44
89
|
peerIdStr: string;
|
|
45
90
|
responses: ValidatedResponses;
|
|
46
91
|
batchBlocks: IBlockInput[];
|
|
92
|
+
/** Raw envelopes downloaded in this batch, keyed by slot (from downloadByRange return) */
|
|
93
|
+
downloadedPayloadEnvelopes: Map<Slot, gloas.SignedExecutionPayloadEnvelope> | null;
|
|
94
|
+
/** Envelopes already wrapped from previous partial downloads on this batch */
|
|
95
|
+
existingPayloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
|
|
96
|
+
/** Sampled/custody column indices for building PayloadEnvelopeInputs */
|
|
97
|
+
custodyConfig: Pick<CustodyConfig, "sampledColumns" | "custodyColumns">;
|
|
98
|
+
seenTimestampSec: number;
|
|
47
99
|
};
|
|
48
100
|
|
|
49
101
|
export type ValidatedBlock = {
|
|
@@ -58,7 +110,7 @@ export type ValidatedBlobSidecars = {
|
|
|
58
110
|
|
|
59
111
|
export type ValidatedColumnSidecars = {
|
|
60
112
|
blockRoot: Uint8Array;
|
|
61
|
-
columnSidecars:
|
|
113
|
+
columnSidecars: DataColumnSidecar[];
|
|
62
114
|
};
|
|
63
115
|
|
|
64
116
|
export type ValidatedResponses = {
|
|
@@ -72,12 +124,16 @@ export type ValidatedResponses = {
|
|
|
72
124
|
*/
|
|
73
125
|
export function cacheByRangeResponses({
|
|
74
126
|
cache,
|
|
127
|
+
seenPayloadEnvelopeInputCache,
|
|
75
128
|
peerIdStr,
|
|
76
129
|
responses,
|
|
77
130
|
batchBlocks,
|
|
78
|
-
|
|
131
|
+
downloadedPayloadEnvelopes,
|
|
132
|
+
existingPayloadEnvelopes,
|
|
133
|
+
custodyConfig,
|
|
134
|
+
seenTimestampSec,
|
|
135
|
+
}: CacheByRangeResponsesProps): {blocks: IBlockInput[]; payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null} {
|
|
79
136
|
const source = BlockInputSource.byRange;
|
|
80
|
-
const seenTimestampSec = Date.now() / 1000;
|
|
81
137
|
const updatedBatchBlocks = new Map<Slot, IBlockInput>(batchBlocks.map((block) => [block.slot, block]));
|
|
82
138
|
|
|
83
139
|
const blocks = responses.validatedBlocks ?? [];
|
|
@@ -149,16 +205,82 @@ export function cacheByRangeResponses({
|
|
|
149
205
|
}
|
|
150
206
|
}
|
|
151
207
|
|
|
208
|
+
// Seed seenPayloadEnvelopeInputCache for every gloas block in the batch, regardless of whether
|
|
209
|
+
// the peer returned its envelope. Without this, a block returned without its envelope would be
|
|
210
|
+
// imported with no cache entry, and later payload-by-root sync would throw
|
|
211
|
+
// "Missing PayloadEnvelopeInput for known block" (see issue #9306).
|
|
212
|
+
for (const blockInput of updatedBatchBlocks.values()) {
|
|
213
|
+
if (!blockInput.hasBlock() || !isForkPostGloas(blockInput.forkName)) continue;
|
|
214
|
+
seenPayloadEnvelopeInputCache.add({
|
|
215
|
+
blockRootHex: blockInput.blockRootHex,
|
|
216
|
+
block: blockInput.getBlock() as SignedBeaconBlock<ForkPostGloas>,
|
|
217
|
+
forkName: blockInput.forkName,
|
|
218
|
+
sampledColumns: custodyConfig.sampledColumns,
|
|
219
|
+
custodyColumns: custodyConfig.custodyColumns,
|
|
220
|
+
timeCreatedSec: seenTimestampSec,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
let payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null =
|
|
225
|
+
existingPayloadEnvelopes !== null ? new Map(existingPayloadEnvelopes) : null;
|
|
226
|
+
if (downloadedPayloadEnvelopes !== null) {
|
|
227
|
+
payloadEnvelopes ??= new Map();
|
|
228
|
+
for (const [slot, envelope] of downloadedPayloadEnvelopes) {
|
|
229
|
+
const envelopeBlockRootHex = toRootHex(envelope.message.beaconBlockRoot);
|
|
230
|
+
const payloadInput = seenPayloadEnvelopeInputCache.get(envelopeBlockRootHex);
|
|
231
|
+
if (payloadInput === undefined) {
|
|
232
|
+
// Unreachable given the loop above seeded an entry for every gloas block in the batch.
|
|
233
|
+
// for the parent block, it's populated at BeaconChain init
|
|
234
|
+
throw new Error(`Missing PayloadEnvelopeInput for block ${envelopeBlockRootHex}`);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (!payloadInput.hasPayloadEnvelope()) {
|
|
238
|
+
payloadInput.addPayloadEnvelope({
|
|
239
|
+
envelope,
|
|
240
|
+
source: PayloadEnvelopeInputSource.byRange,
|
|
241
|
+
seenTimestampSec,
|
|
242
|
+
peerIdStr,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
payloadEnvelopes.set(slot, payloadInput);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
152
250
|
for (const {blockRoot, columnSidecars} of responses.validatedColumnSidecars ?? []) {
|
|
153
|
-
const
|
|
154
|
-
if (
|
|
251
|
+
const firstColumn = columnSidecars[0];
|
|
252
|
+
if (!firstColumn) {
|
|
155
253
|
throw new Error(
|
|
156
254
|
`Coding Error: empty columnSidecars returned for blockRoot=${toRootHex(blockRoot)} from validation functions`
|
|
157
255
|
);
|
|
158
256
|
}
|
|
159
|
-
|
|
257
|
+
|
|
160
258
|
const blockRootHex = toRootHex(blockRoot);
|
|
161
259
|
|
|
260
|
+
if (isGloasDataColumnSidecar(firstColumn)) {
|
|
261
|
+
// Gloas columns are attached to the matching PayloadEnvelopeInput, NOT to IBlockInput.
|
|
262
|
+
// Gloas DataColumnSidecar has `slot` directly (no signedBlockHeader).
|
|
263
|
+
const dataSlot = firstColumn.slot;
|
|
264
|
+
const payloadInput = payloadEnvelopes?.get(dataSlot);
|
|
265
|
+
if (!payloadInput) {
|
|
266
|
+
// Should not happen: we built payloadInputs for all gloas blocks above
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
for (const columnSidecar of columnSidecars as gloas.DataColumnSidecar[]) {
|
|
270
|
+
payloadInput.addColumn({
|
|
271
|
+
columnSidecar,
|
|
272
|
+
seenTimestampSec,
|
|
273
|
+
peerIdStr,
|
|
274
|
+
source: PayloadEnvelopeInputSource.byRange,
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const fuluColumns = columnSidecars as fulu.DataColumnSidecar[];
|
|
281
|
+
const dataSlot = fuluColumns[0].signedBlockHeader.message.slot;
|
|
282
|
+
const existing = updatedBatchBlocks.get(dataSlot);
|
|
283
|
+
|
|
162
284
|
if (!existing) {
|
|
163
285
|
throw new Error("Coding error: blockInput must exist when adding columns");
|
|
164
286
|
}
|
|
@@ -172,7 +294,7 @@ export function cacheByRangeResponses({
|
|
|
172
294
|
actual: existing.type,
|
|
173
295
|
});
|
|
174
296
|
}
|
|
175
|
-
for (const columnSidecar of
|
|
297
|
+
for (const columnSidecar of fuluColumns) {
|
|
176
298
|
// will throw if root hex does not match (meaning we are following the wrong chain)
|
|
177
299
|
existing.addColumn(
|
|
178
300
|
{
|
|
@@ -187,7 +309,7 @@ export function cacheByRangeResponses({
|
|
|
187
309
|
}
|
|
188
310
|
}
|
|
189
311
|
|
|
190
|
-
return Array.from(updatedBatchBlocks.values());
|
|
312
|
+
return {blocks: Array.from(updatedBatchBlocks.values()), payloadEnvelopes};
|
|
191
313
|
}
|
|
192
314
|
|
|
193
315
|
export async function downloadByRange({
|
|
@@ -198,8 +320,16 @@ export async function downloadByRange({
|
|
|
198
320
|
blocksRequest,
|
|
199
321
|
blobsRequest,
|
|
200
322
|
columnsRequest,
|
|
323
|
+
envelopesRequest,
|
|
324
|
+
parentPayloadRequest,
|
|
325
|
+
parentPayloadCommitments,
|
|
201
326
|
peerDasMetrics,
|
|
202
|
-
}: DownloadAndCacheByRangeProps): Promise<
|
|
327
|
+
}: DownloadAndCacheByRangeProps): Promise<
|
|
328
|
+
WarnResult<
|
|
329
|
+
{responses: ValidatedResponses; payloadEnvelopes: Map<Slot, gloas.SignedExecutionPayloadEnvelope> | null},
|
|
330
|
+
DownloadByRangeError
|
|
331
|
+
>
|
|
332
|
+
> {
|
|
203
333
|
let response: DownloadByRangeResponses;
|
|
204
334
|
try {
|
|
205
335
|
response = await requestByRange({
|
|
@@ -208,6 +338,8 @@ export async function downloadByRange({
|
|
|
208
338
|
blocksRequest,
|
|
209
339
|
blobsRequest,
|
|
210
340
|
columnsRequest,
|
|
341
|
+
envelopesRequest,
|
|
342
|
+
parentPayloadRequest,
|
|
211
343
|
});
|
|
212
344
|
} catch (err) {
|
|
213
345
|
throw new DownloadByRangeError({
|
|
@@ -217,17 +349,18 @@ export async function downloadByRange({
|
|
|
217
349
|
});
|
|
218
350
|
}
|
|
219
351
|
|
|
220
|
-
|
|
352
|
+
return validateResponses({
|
|
221
353
|
config,
|
|
222
354
|
batchBlocks,
|
|
223
355
|
blocksRequest,
|
|
224
356
|
blobsRequest,
|
|
225
357
|
columnsRequest,
|
|
358
|
+
envelopesRequest,
|
|
359
|
+
parentPayloadRequest,
|
|
360
|
+
parentPayloadCommitments,
|
|
226
361
|
peerDasMetrics,
|
|
227
362
|
...response,
|
|
228
363
|
});
|
|
229
|
-
|
|
230
|
-
return validated;
|
|
231
364
|
}
|
|
232
365
|
|
|
233
366
|
/**
|
|
@@ -239,13 +372,16 @@ export async function requestByRange({
|
|
|
239
372
|
blocksRequest,
|
|
240
373
|
blobsRequest,
|
|
241
374
|
columnsRequest,
|
|
375
|
+
envelopesRequest,
|
|
376
|
+
parentPayloadRequest,
|
|
242
377
|
}: DownloadByRangeRequests & {
|
|
243
378
|
network: INetwork;
|
|
244
379
|
peerIdStr: PeerIdStr;
|
|
245
380
|
}): Promise<DownloadByRangeResponses> {
|
|
246
381
|
let blocks: undefined | SignedBeaconBlock[];
|
|
247
382
|
let blobSidecars: undefined | deneb.BlobSidecars;
|
|
248
|
-
|
|
383
|
+
const columnSidecars: DataColumnSidecar[] = [];
|
|
384
|
+
const payloadEnvelopes: gloas.SignedExecutionPayloadEnvelope[] = [];
|
|
249
385
|
|
|
250
386
|
const requests: Promise<unknown>[] = [];
|
|
251
387
|
|
|
@@ -268,17 +404,49 @@ export async function requestByRange({
|
|
|
268
404
|
if (columnsRequest) {
|
|
269
405
|
requests.push(
|
|
270
406
|
network.sendDataColumnSidecarsByRange(peerIdStr, columnsRequest).then((columnResponse) => {
|
|
271
|
-
columnSidecars
|
|
407
|
+
columnSidecars.push(...columnResponse);
|
|
408
|
+
})
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (envelopesRequest) {
|
|
413
|
+
requests.push(
|
|
414
|
+
network.sendExecutionPayloadEnvelopesByRange(peerIdStr, envelopesRequest).then((envelopeResponse) => {
|
|
415
|
+
payloadEnvelopes.push(...envelopeResponse);
|
|
272
416
|
})
|
|
273
417
|
);
|
|
274
418
|
}
|
|
275
419
|
|
|
420
|
+
// Only happens on the 1st batch of a SyncChain — fetches whichever pieces of the
|
|
421
|
+
// dangling-parent's payload are still missing from the seen-cache entry.
|
|
422
|
+
if (parentPayloadRequest?.envelopeBlockRoot) {
|
|
423
|
+
requests.push(
|
|
424
|
+
network
|
|
425
|
+
.sendExecutionPayloadEnvelopesByRoot(peerIdStr, [parentPayloadRequest.envelopeBlockRoot])
|
|
426
|
+
.then((envelopeResponse) => {
|
|
427
|
+
payloadEnvelopes.push(...envelopeResponse);
|
|
428
|
+
})
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
if (parentPayloadRequest?.blockRoot && parentPayloadRequest.columns && parentPayloadRequest.columns.length > 0) {
|
|
432
|
+
requests.push(
|
|
433
|
+
network
|
|
434
|
+
.sendDataColumnSidecarsByRoot(peerIdStr, [
|
|
435
|
+
{blockRoot: parentPayloadRequest.blockRoot, columns: parentPayloadRequest.columns},
|
|
436
|
+
])
|
|
437
|
+
.then((columnResponse) => {
|
|
438
|
+
columnSidecars.push(...columnResponse);
|
|
439
|
+
})
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
|
|
276
443
|
await Promise.all(requests);
|
|
277
444
|
|
|
278
445
|
return {
|
|
279
446
|
blocks,
|
|
280
447
|
blobSidecars,
|
|
281
448
|
columnSidecars,
|
|
449
|
+
payloadEnvelopes,
|
|
282
450
|
};
|
|
283
451
|
}
|
|
284
452
|
|
|
@@ -291,16 +459,26 @@ export async function validateResponses({
|
|
|
291
459
|
blocksRequest,
|
|
292
460
|
blobsRequest,
|
|
293
461
|
columnsRequest,
|
|
462
|
+
envelopesRequest,
|
|
463
|
+
parentPayloadRequest,
|
|
464
|
+
parentPayloadCommitments,
|
|
294
465
|
blocks,
|
|
295
466
|
blobSidecars,
|
|
296
467
|
columnSidecars,
|
|
468
|
+
payloadEnvelopes,
|
|
297
469
|
peerDasMetrics,
|
|
298
470
|
}: DownloadByRangeRequests &
|
|
299
471
|
DownloadByRangeResponses & {
|
|
300
472
|
config: ChainForkConfig;
|
|
301
473
|
batchBlocks?: IBlockInput[];
|
|
474
|
+
parentPayloadCommitments?: ParentPayloadCommitments;
|
|
302
475
|
peerDasMetrics?: BeaconMetrics["peerDas"] | null;
|
|
303
|
-
}): Promise<
|
|
476
|
+
}): Promise<
|
|
477
|
+
WarnResult<
|
|
478
|
+
{responses: ValidatedResponses; payloadEnvelopes: Map<Slot, gloas.SignedExecutionPayloadEnvelope> | null},
|
|
479
|
+
DownloadByRangeError
|
|
480
|
+
>
|
|
481
|
+
> {
|
|
304
482
|
// Blocks are always required for blob/column validation
|
|
305
483
|
// If a blocksRequest is provided, blocks have just been downloaded
|
|
306
484
|
// If no blocksRequest is provided, batchBlocks must have been provided from cache
|
|
@@ -314,6 +492,11 @@ export async function validateResponses({
|
|
|
314
492
|
);
|
|
315
493
|
}
|
|
316
494
|
|
|
495
|
+
// `parentPayloadRequest` and `parentPayloadCommitments` must be supplied together
|
|
496
|
+
if ((parentPayloadRequest === undefined) !== (parentPayloadCommitments === undefined)) {
|
|
497
|
+
throw new Error("Coding error: parentPayloadRequest and parentPayloadCommitments must be both set or both unset");
|
|
498
|
+
}
|
|
499
|
+
|
|
317
500
|
const validatedResponses: ValidatedResponses = {};
|
|
318
501
|
let warnings: DownloadByRangeError[] | null = null;
|
|
319
502
|
|
|
@@ -325,9 +508,31 @@ export async function validateResponses({
|
|
|
325
508
|
validatedResponses.validatedBlocks = result.result;
|
|
326
509
|
}
|
|
327
510
|
|
|
511
|
+
const needsEnvelopeValidation = !!envelopesRequest || parentPayloadCommitments !== undefined;
|
|
328
512
|
const dataRequest = blobsRequest ?? columnsRequest;
|
|
513
|
+
if (!dataRequest && !needsEnvelopeValidation) {
|
|
514
|
+
return {result: {responses: validatedResponses, payloadEnvelopes: null}, warnings};
|
|
515
|
+
}
|
|
516
|
+
|
|
329
517
|
if (!dataRequest) {
|
|
330
|
-
|
|
518
|
+
// Only envelope and/or parent-by-root validation needed
|
|
519
|
+
if (parentPayloadCommitments !== undefined) {
|
|
520
|
+
const parentValidated = await validateParentPayloadColumns(
|
|
521
|
+
parentPayloadCommitments,
|
|
522
|
+
columnSidecars ?? [],
|
|
523
|
+
peerDasMetrics
|
|
524
|
+
);
|
|
525
|
+
if (parentValidated) {
|
|
526
|
+
validatedResponses.validatedColumnSidecars = [parentValidated];
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
const validatedPayloadEnvelopes = validateEnvelopesByRangeResponse(
|
|
530
|
+
validatedResponses.validatedBlocks ?? [],
|
|
531
|
+
batchBlocks,
|
|
532
|
+
payloadEnvelopes ?? [],
|
|
533
|
+
parentPayloadCommitments
|
|
534
|
+
);
|
|
535
|
+
return {result: {responses: validatedResponses, payloadEnvelopes: validatedPayloadEnvelopes}, warnings};
|
|
331
536
|
}
|
|
332
537
|
|
|
333
538
|
const blocksForDataValidation = getBlocksForDataValidation(
|
|
@@ -385,7 +590,62 @@ export async function validateResponses({
|
|
|
385
590
|
warnings = validatedColumnSidecarsResult.warnings;
|
|
386
591
|
}
|
|
387
592
|
|
|
388
|
-
|
|
593
|
+
// Parent columns (by-root): KZG-validate against parent's bid commitments and append.
|
|
594
|
+
if (parentPayloadCommitments !== undefined) {
|
|
595
|
+
const parentValidated = await validateParentPayloadColumns(
|
|
596
|
+
parentPayloadCommitments,
|
|
597
|
+
columnSidecars ?? [],
|
|
598
|
+
peerDasMetrics
|
|
599
|
+
);
|
|
600
|
+
if (parentValidated) {
|
|
601
|
+
validatedResponses.validatedColumnSidecars = [
|
|
602
|
+
...(validatedResponses.validatedColumnSidecars ?? []),
|
|
603
|
+
parentValidated,
|
|
604
|
+
];
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
let validatedPayloadEnvelopes: Map<Slot, gloas.SignedExecutionPayloadEnvelope> | null = null;
|
|
609
|
+
if (needsEnvelopeValidation) {
|
|
610
|
+
validatedPayloadEnvelopes = validateEnvelopesByRangeResponse(
|
|
611
|
+
validatedResponses.validatedBlocks ?? [],
|
|
612
|
+
batchBlocks,
|
|
613
|
+
payloadEnvelopes ?? [],
|
|
614
|
+
parentPayloadCommitments
|
|
615
|
+
);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
return {result: {responses: validatedResponses, payloadEnvelopes: validatedPayloadEnvelopes}, warnings};
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
async function validateParentPayloadColumns(
|
|
622
|
+
parentPayloadCommitments: ParentPayloadCommitments,
|
|
623
|
+
columnSidecars: DataColumnSidecar[],
|
|
624
|
+
peerDasMetrics?: BeaconMetrics["peerDas"] | null
|
|
625
|
+
): Promise<ValidatedColumnSidecars | null> {
|
|
626
|
+
const parentColumns: gloas.DataColumnSidecar[] = [];
|
|
627
|
+
for (const cs of columnSidecars) {
|
|
628
|
+
if (isGloasDataColumnSidecar(cs) && byteArrayEquals(cs.beaconBlockRoot, parentPayloadCommitments.blockRoot)) {
|
|
629
|
+
parentColumns.push(cs);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
if (parentColumns.length === 0) {
|
|
634
|
+
return null;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
parentColumns.sort((a, b) => a.index - b.index);
|
|
638
|
+
const parentSlot = parentColumns[0].slot;
|
|
639
|
+
|
|
640
|
+
await validateGloasBlockDataColumnSidecars(
|
|
641
|
+
parentSlot,
|
|
642
|
+
parentPayloadCommitments.blockRoot,
|
|
643
|
+
parentPayloadCommitments.kzgCommitments,
|
|
644
|
+
parentColumns,
|
|
645
|
+
peerDasMetrics
|
|
646
|
+
);
|
|
647
|
+
|
|
648
|
+
return {blockRoot: parentPayloadCommitments.blockRoot, columnSidecars: parentColumns};
|
|
389
649
|
}
|
|
390
650
|
|
|
391
651
|
/**
|
|
@@ -615,19 +875,19 @@ export async function validateColumnsByRangeResponse(
|
|
|
615
875
|
config: ChainForkConfig,
|
|
616
876
|
request: fulu.DataColumnSidecarsByRangeRequest,
|
|
617
877
|
blocks: ValidatedBlock[],
|
|
618
|
-
columnSidecars:
|
|
878
|
+
columnSidecars: DataColumnSidecar[],
|
|
619
879
|
peerDasMetrics?: BeaconMetrics["peerDas"] | null
|
|
620
880
|
): Promise<WarnResult<ValidatedColumnSidecars[], DownloadByRangeError>> {
|
|
621
881
|
const warnings: DownloadByRangeError[] = [];
|
|
622
882
|
|
|
623
|
-
|
|
624
|
-
// validate against the block bid commitments instead of the fulu signed header shape
|
|
625
|
-
const seenColumns = new Map<Slot, Map<number, fulu.DataColumnSidecar>>();
|
|
883
|
+
const seenColumns = new Map<Slot, Map<number, DataColumnSidecar>>();
|
|
626
884
|
let currentSlot = -1;
|
|
627
885
|
let currentIndex = -1;
|
|
628
886
|
// Check for duplicates and order
|
|
629
887
|
for (const columnSidecar of columnSidecars) {
|
|
630
|
-
const slot = columnSidecar
|
|
888
|
+
const slot = isGloasDataColumnSidecar(columnSidecar)
|
|
889
|
+
? columnSidecar.slot
|
|
890
|
+
: columnSidecar.signedBlockHeader.message.slot;
|
|
631
891
|
let seenSlotColumns = seenColumns.get(slot);
|
|
632
892
|
if (!seenSlotColumns) {
|
|
633
893
|
seenSlotColumns = new Map();
|
|
@@ -686,20 +946,20 @@ export async function validateColumnsByRangeResponse(
|
|
|
686
946
|
const slot = block.message.slot;
|
|
687
947
|
const rootHex = toRootHex(blockRoot);
|
|
688
948
|
const forkName = config.getForkName(slot);
|
|
689
|
-
const columnSidecarsMap: Map<number,
|
|
949
|
+
const columnSidecarsMap: Map<number, DataColumnSidecar> = seenColumns.get(slot) ?? new Map();
|
|
690
950
|
const columnSidecars = Array.from(columnSidecarsMap.values()).sort((a, b) => a.index - b.index);
|
|
691
951
|
|
|
692
952
|
let blobCount: number;
|
|
693
953
|
if (!isForkPostFulu(forkName)) {
|
|
694
|
-
const dataSlot = columnSidecars.at(0)?.signedBlockHeader.message.slot;
|
|
695
954
|
throw new DownloadByRangeError({
|
|
696
955
|
code: DownloadByRangeErrorCode.MISMATCH_BLOCK_FORK,
|
|
697
956
|
slot,
|
|
698
957
|
blockFork: forkName,
|
|
699
|
-
dataFork:
|
|
958
|
+
dataFork: "unknown",
|
|
700
959
|
});
|
|
701
960
|
}
|
|
702
|
-
|
|
961
|
+
const kzgCommitments = getBlobKzgCommitments(forkName, block as SignedBeaconBlock<ForkPostFulu>);
|
|
962
|
+
blobCount = kzgCommitments.length;
|
|
703
963
|
|
|
704
964
|
if (columnSidecars.length === 0) {
|
|
705
965
|
if (!blobCount) {
|
|
@@ -768,15 +1028,25 @@ export async function validateColumnsByRangeResponse(
|
|
|
768
1028
|
);
|
|
769
1029
|
}
|
|
770
1030
|
|
|
1031
|
+
const validatePromise = isForkPostGloas(forkName)
|
|
1032
|
+
? validateGloasBlockDataColumnSidecars(
|
|
1033
|
+
slot,
|
|
1034
|
+
blockRoot,
|
|
1035
|
+
kzgCommitments,
|
|
1036
|
+
columnSidecars as gloas.DataColumnSidecar[],
|
|
1037
|
+
peerDasMetrics
|
|
1038
|
+
)
|
|
1039
|
+
: validateFuluBlockDataColumnSidecars(
|
|
1040
|
+
null, // do not pass chain here so we do not validate header signature
|
|
1041
|
+
slot,
|
|
1042
|
+
blockRoot,
|
|
1043
|
+
blobCount,
|
|
1044
|
+
columnSidecars as fulu.DataColumnSidecar[],
|
|
1045
|
+
peerDasMetrics
|
|
1046
|
+
);
|
|
1047
|
+
|
|
771
1048
|
validationPromises.push(
|
|
772
|
-
|
|
773
|
-
null, // do not pass chain here so we do not validate header signature
|
|
774
|
-
slot,
|
|
775
|
-
blockRoot,
|
|
776
|
-
blobCount,
|
|
777
|
-
columnSidecars,
|
|
778
|
-
peerDasMetrics
|
|
779
|
-
).then(() => ({
|
|
1049
|
+
validatePromise.then(() => ({
|
|
780
1050
|
blockRoot,
|
|
781
1051
|
columnSidecars,
|
|
782
1052
|
}))
|
|
@@ -882,6 +1152,9 @@ export enum DownloadByRangeErrorCode {
|
|
|
882
1152
|
/** Cached block input type mismatches new data */
|
|
883
1153
|
MISMATCH_BLOCK_FORK = "DOWNLOAD_BY_RANGE_ERROR_MISMATCH_BLOCK_FORK",
|
|
884
1154
|
MISMATCH_BLOCK_INPUT_TYPE = "DOWNLOAD_BY_RANGE_ERROR_MISMATCH_BLOCK_INPUT_TYPE",
|
|
1155
|
+
|
|
1156
|
+
/** Envelope beaconBlockRoot does not match the block's root */
|
|
1157
|
+
INVALID_ENVELOPE_BEACON_BLOCK_ROOT = "DOWNLOAD_BY_RANGE_ERROR_INVALID_ENVELOPE_BEACON_BLOCK_ROOT",
|
|
885
1158
|
}
|
|
886
1159
|
|
|
887
1160
|
export type DownloadByRangeErrorType =
|
|
@@ -973,6 +1246,72 @@ export type DownloadByRangeErrorType =
|
|
|
973
1246
|
blockRoot: string;
|
|
974
1247
|
expected: DAType;
|
|
975
1248
|
actual: DAType;
|
|
1249
|
+
}
|
|
1250
|
+
| {
|
|
1251
|
+
code: DownloadByRangeErrorCode.INVALID_ENVELOPE_BEACON_BLOCK_ROOT;
|
|
1252
|
+
slot: Slot;
|
|
1253
|
+
expected: string;
|
|
1254
|
+
actual: string;
|
|
976
1255
|
};
|
|
977
1256
|
|
|
978
1257
|
export class DownloadByRangeError extends LodestarError<DownloadByRangeErrorType> {}
|
|
1258
|
+
|
|
1259
|
+
/**
|
|
1260
|
+
* Validates SignedExecutionPayloadEnvelopes received for a range request.
|
|
1261
|
+
*
|
|
1262
|
+
* Three categories of envelope slots:
|
|
1263
|
+
* - In-batch slot whose block we have: verify envelope.beaconBlockRoot matches.
|
|
1264
|
+
* - Dangling-parent envelope (only when `parentPayloadCommitments` is set, i.e. the first
|
|
1265
|
+
* batch of a `SyncChain`): keep if `envelope.beaconBlockRoot === parentPayloadCommitments.blockRoot`.
|
|
1266
|
+
* - Other "orphan" envelopes (e.g. unrelated slots): ignored.
|
|
1267
|
+
*/
|
|
1268
|
+
export function validateEnvelopesByRangeResponse(
|
|
1269
|
+
validatedBlocks: ValidatedBlock[],
|
|
1270
|
+
batchBlocks: IBlockInput[] | undefined,
|
|
1271
|
+
payloadEnvelopes: gloas.SignedExecutionPayloadEnvelope[],
|
|
1272
|
+
parentPayloadCommitments?: ParentPayloadCommitments
|
|
1273
|
+
): Map<Slot, gloas.SignedExecutionPayloadEnvelope> {
|
|
1274
|
+
// Build a map of slot -> blockRoot for all blocks in the batch
|
|
1275
|
+
const batchBlockRoots = new Map<Slot, Uint8Array>();
|
|
1276
|
+
if (batchBlocks) {
|
|
1277
|
+
for (const blockInput of batchBlocks) {
|
|
1278
|
+
batchBlockRoots.set(blockInput.slot, fromHex(blockInput.blockRootHex));
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
for (const {block, blockRoot} of validatedBlocks) {
|
|
1282
|
+
batchBlockRoots.set(block.message.slot, blockRoot);
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
const payloadEnvelopeMap = new Map<Slot, gloas.SignedExecutionPayloadEnvelope>();
|
|
1286
|
+
|
|
1287
|
+
for (const payloadEnvelope of payloadEnvelopes) {
|
|
1288
|
+
const slot = payloadEnvelope.message.payload.slotNumber;
|
|
1289
|
+
const batchBlockRoot = batchBlockRoots.get(slot);
|
|
1290
|
+
|
|
1291
|
+
if (batchBlockRoot === undefined) {
|
|
1292
|
+
// Keep the requested dangling-parent envelope only when its beaconBlockRoot matches
|
|
1293
|
+
// exactly. All other unrelated envelopes are dropped.
|
|
1294
|
+
if (
|
|
1295
|
+
parentPayloadCommitments !== undefined &&
|
|
1296
|
+
byteArrayEquals(payloadEnvelope.message.beaconBlockRoot, parentPayloadCommitments.blockRoot)
|
|
1297
|
+
) {
|
|
1298
|
+
payloadEnvelopeMap.set(slot, payloadEnvelope);
|
|
1299
|
+
}
|
|
1300
|
+
continue;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
// Verify beaconBlockRoot matches the block's root
|
|
1304
|
+
if (!byteArrayEquals(payloadEnvelope.message.beaconBlockRoot, batchBlockRoot)) {
|
|
1305
|
+
throw new DownloadByRangeError({
|
|
1306
|
+
code: DownloadByRangeErrorCode.INVALID_ENVELOPE_BEACON_BLOCK_ROOT,
|
|
1307
|
+
slot,
|
|
1308
|
+
expected: toRootHex(batchBlockRoot),
|
|
1309
|
+
actual: toRootHex(payloadEnvelope.message.beaconBlockRoot),
|
|
1310
|
+
});
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
payloadEnvelopeMap.set(slot, payloadEnvelope);
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
return payloadEnvelopeMap;
|
|
1317
|
+
}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
ForkPostDeneb,
|
|
5
|
+
ForkPostFulu,
|
|
6
|
+
ForkPostGloas,
|
|
7
|
+
ForkPreFulu,
|
|
8
|
+
isForkPostDeneb,
|
|
9
|
+
isForkPostFulu,
|
|
10
|
+
isForkPostGloas,
|
|
11
|
+
} from "@lodestar/params";
|
|
4
12
|
import {BlobIndex, ColumnIndex, SignedBeaconBlock, Slot, deneb, fulu} from "@lodestar/types";
|
|
5
13
|
import {LodestarError, byteArrayEquals, fromHex, prettyPrintIndices, toHex, toRootHex} from "@lodestar/utils";
|
|
6
14
|
import {isBlockInputBlobs, isBlockInputColumns} from "../../chain/blocks/blockInput/blockInput.js";
|
|
@@ -107,6 +115,17 @@ export async function downloadByRoot({
|
|
|
107
115
|
});
|
|
108
116
|
}
|
|
109
117
|
|
|
118
|
+
if (isForkPostGloas(blockInput.forkName)) {
|
|
119
|
+
chain.seenPayloadEnvelopeInputCache.add({
|
|
120
|
+
blockRootHex: rootHex,
|
|
121
|
+
block: blockInput.getBlock() as SignedBeaconBlock<ForkPostGloas>,
|
|
122
|
+
forkName: blockInput.forkName,
|
|
123
|
+
sampledColumns: chain.custodyConfig.sampledColumns,
|
|
124
|
+
custodyColumns: chain.custodyConfig.custodyColumns,
|
|
125
|
+
timeCreatedSec: Date.now() / 1000,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
110
129
|
const hasAllDataPreDownload = blockInput.hasBlockAndAllData();
|
|
111
130
|
|
|
112
131
|
if (isBlockInputBlobs(blockInput) && !hasAllDataPreDownload) {
|
|
@@ -263,7 +282,10 @@ export async function fetchByRoot({
|
|
|
263
282
|
blockRoot,
|
|
264
283
|
});
|
|
265
284
|
const forkName = config.getForkName(block.message.slot);
|
|
266
|
-
if (
|
|
285
|
+
if (isForkPostGloas(forkName)) {
|
|
286
|
+
// Post-gloas block sync only needs the block body. Payload columns stay on the
|
|
287
|
+
// payload/envelope path and are queued independently in the network processor.
|
|
288
|
+
} else if (isForkPostFulu(forkName)) {
|
|
267
289
|
columnSidecarResult = await fetchAndValidateColumns({
|
|
268
290
|
config,
|
|
269
291
|
chain,
|