@lodestar/beacon-node 1.43.0-dev.78c66bac71 → 1.43.0-dev.87cbe69c66

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.
Files changed (260) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +16 -5
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
  5. package/lib/api/impl/beacon/pool/index.js +45 -2
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/debug/index.d.ts.map +1 -1
  8. package/lib/api/impl/debug/index.js +0 -1
  9. package/lib/api/impl/debug/index.js.map +1 -1
  10. package/lib/api/impl/lodestar/index.js +1 -1
  11. package/lib/api/impl/lodestar/index.js.map +1 -1
  12. package/lib/api/impl/validator/index.d.ts.map +1 -1
  13. package/lib/api/impl/validator/index.js +68 -2
  14. package/lib/api/impl/validator/index.js.map +1 -1
  15. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  16. package/lib/chain/blocks/importBlock.js +24 -20
  17. package/lib/chain/blocks/importBlock.js.map +1 -1
  18. package/lib/chain/blocks/importExecutionPayload.d.ts +19 -6
  19. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  20. package/lib/chain/blocks/importExecutionPayload.js +45 -23
  21. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  22. package/lib/chain/blocks/index.d.ts +5 -3
  23. package/lib/chain/blocks/index.d.ts.map +1 -1
  24. package/lib/chain/blocks/index.js +59 -25
  25. package/lib/chain/blocks/index.js.map +1 -1
  26. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +1 -0
  27. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  28. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +5 -1
  29. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  30. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +1 -0
  31. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  32. package/lib/chain/blocks/payloadEnvelopeProcessor.js +2 -2
  33. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
  34. package/lib/chain/blocks/types.d.ts +4 -3
  35. package/lib/chain/blocks/types.d.ts.map +1 -1
  36. package/lib/chain/blocks/utils/chainSegment.d.ts +23 -2
  37. package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
  38. package/lib/chain/blocks/utils/chainSegment.js +89 -12
  39. package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
  40. package/lib/chain/blocks/verifyBlock.d.ts +5 -3
  41. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  42. package/lib/chain/blocks/verifyBlock.js +50 -7
  43. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  44. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts +0 -4
  45. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
  46. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +5 -2
  47. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
  48. package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts +2 -1
  49. package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts.map +1 -1
  50. package/lib/chain/blocks/verifyBlocksSanityChecks.js +25 -5
  51. package/lib/chain/blocks/verifyBlocksSanityChecks.js.map +1 -1
  52. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +2 -2
  53. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
  54. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +7 -4
  55. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
  56. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -1
  57. package/lib/chain/blocks/verifyPayloadsDataAvailability.js +8 -3
  58. package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -1
  59. package/lib/chain/chain.d.ts +3 -2
  60. package/lib/chain/chain.d.ts.map +1 -1
  61. package/lib/chain/chain.js +12 -4
  62. package/lib/chain/chain.js.map +1 -1
  63. package/lib/chain/emitter.d.ts +0 -11
  64. package/lib/chain/emitter.d.ts.map +1 -1
  65. package/lib/chain/emitter.js +0 -4
  66. package/lib/chain/emitter.js.map +1 -1
  67. package/lib/chain/errors/blockError.d.ts +8 -1
  68. package/lib/chain/errors/blockError.d.ts.map +1 -1
  69. package/lib/chain/errors/blockError.js +2 -0
  70. package/lib/chain/errors/blockError.js.map +1 -1
  71. package/lib/chain/errors/index.d.ts +1 -0
  72. package/lib/chain/errors/index.d.ts.map +1 -1
  73. package/lib/chain/errors/index.js +1 -0
  74. package/lib/chain/errors/index.js.map +1 -1
  75. package/lib/chain/errors/proposerPreferences.d.ts +40 -0
  76. package/lib/chain/errors/proposerPreferences.d.ts.map +1 -0
  77. package/lib/chain/errors/proposerPreferences.js +14 -0
  78. package/lib/chain/errors/proposerPreferences.js.map +1 -0
  79. package/lib/chain/interface.d.ts +3 -2
  80. package/lib/chain/interface.d.ts.map +1 -1
  81. package/lib/chain/interface.js.map +1 -1
  82. package/lib/chain/opPools/payloadAttestationPool.d.ts +3 -2
  83. package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
  84. package/lib/chain/opPools/payloadAttestationPool.js +26 -4
  85. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  86. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  87. package/lib/chain/prepareNextSlot.js +15 -17
  88. package/lib/chain/prepareNextSlot.js.map +1 -1
  89. package/lib/chain/produceBlock/produceBlockBody.d.ts +12 -3
  90. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  91. package/lib/chain/produceBlock/produceBlockBody.js +35 -17
  92. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  93. package/lib/chain/regen/interface.d.ts +1 -0
  94. package/lib/chain/regen/interface.d.ts.map +1 -1
  95. package/lib/chain/regen/interface.js +1 -0
  96. package/lib/chain/regen/interface.js.map +1 -1
  97. package/lib/chain/regen/queued.d.ts.map +1 -1
  98. package/lib/chain/regen/queued.js +1 -4
  99. package/lib/chain/regen/queued.js.map +1 -1
  100. package/lib/chain/regen/regen.d.ts.map +1 -1
  101. package/lib/chain/regen/regen.js +1 -4
  102. package/lib/chain/regen/regen.js.map +1 -1
  103. package/lib/chain/seenCache/index.d.ts +1 -0
  104. package/lib/chain/seenCache/index.d.ts.map +1 -1
  105. package/lib/chain/seenCache/index.js +1 -0
  106. package/lib/chain/seenCache/index.js.map +1 -1
  107. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +8 -2
  108. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  109. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +20 -4
  110. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  111. package/lib/chain/seenCache/seenProposerPreferences.d.ts +16 -0
  112. package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +1 -0
  113. package/lib/chain/seenCache/seenProposerPreferences.js +31 -0
  114. package/lib/chain/seenCache/seenProposerPreferences.js.map +1 -0
  115. package/lib/chain/validation/block.d.ts.map +1 -1
  116. package/lib/chain/validation/block.js +1 -0
  117. package/lib/chain/validation/block.js.map +1 -1
  118. package/lib/chain/validation/executionPayloadBid.js +11 -8
  119. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  120. package/lib/chain/validation/proposerPreferences.d.ts +8 -0
  121. package/lib/chain/validation/proposerPreferences.d.ts.map +1 -0
  122. package/lib/chain/validation/proposerPreferences.js +91 -0
  123. package/lib/chain/validation/proposerPreferences.js.map +1 -0
  124. package/lib/metrics/metrics/lodestar.d.ts +1 -0
  125. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  126. package/lib/metrics/metrics/lodestar.js +4 -0
  127. package/lib/metrics/metrics/lodestar.js.map +1 -1
  128. package/lib/network/gossip/interface.d.ts +7 -1
  129. package/lib/network/gossip/interface.d.ts.map +1 -1
  130. package/lib/network/gossip/interface.js +1 -0
  131. package/lib/network/gossip/interface.js.map +1 -1
  132. package/lib/network/gossip/scoringParameters.d.ts.map +1 -1
  133. package/lib/network/gossip/scoringParameters.js +12 -1
  134. package/lib/network/gossip/scoringParameters.js.map +1 -1
  135. package/lib/network/gossip/topic.d.ts +10 -0
  136. package/lib/network/gossip/topic.d.ts.map +1 -1
  137. package/lib/network/gossip/topic.js +6 -0
  138. package/lib/network/gossip/topic.js.map +1 -1
  139. package/lib/network/interface.d.ts +1 -0
  140. package/lib/network/interface.d.ts.map +1 -1
  141. package/lib/network/network.d.ts +1 -0
  142. package/lib/network/network.d.ts.map +1 -1
  143. package/lib/network/network.js +5 -0
  144. package/lib/network/network.js.map +1 -1
  145. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  146. package/lib/network/processor/gossipHandlers.js +24 -16
  147. package/lib/network/processor/gossipHandlers.js.map +1 -1
  148. package/lib/network/processor/gossipQueues/index.d.ts.map +1 -1
  149. package/lib/network/processor/gossipQueues/index.js +5 -0
  150. package/lib/network/processor/gossipQueues/index.js.map +1 -1
  151. package/lib/network/processor/index.d.ts.map +1 -1
  152. package/lib/network/processor/index.js +6 -5
  153. package/lib/network/processor/index.js.map +1 -1
  154. package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
  155. package/lib/network/reqresp/handlers/beaconBlocksByRange.js +14 -6
  156. package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
  157. package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts.map +1 -1
  158. package/lib/network/reqresp/handlers/blobSidecarsByRange.js +11 -5
  159. package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
  160. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
  161. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +17 -5
  162. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
  163. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
  164. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +7 -4
  165. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
  166. package/lib/node/nodejs.js +2 -2
  167. package/lib/node/nodejs.js.map +1 -1
  168. package/lib/sync/range/batch.d.ts +23 -2
  169. package/lib/sync/range/batch.d.ts.map +1 -1
  170. package/lib/sync/range/batch.js +84 -33
  171. package/lib/sync/range/batch.js.map +1 -1
  172. package/lib/sync/range/chain.d.ts +6 -2
  173. package/lib/sync/range/chain.d.ts.map +1 -1
  174. package/lib/sync/range/chain.js +26 -7
  175. package/lib/sync/range/chain.js.map +1 -1
  176. package/lib/sync/range/range.d.ts.map +1 -1
  177. package/lib/sync/range/range.js +17 -6
  178. package/lib/sync/range/range.js.map +1 -1
  179. package/lib/sync/types.d.ts +34 -0
  180. package/lib/sync/types.d.ts.map +1 -1
  181. package/lib/sync/types.js +34 -0
  182. package/lib/sync/types.js.map +1 -1
  183. package/lib/sync/unknownBlock.d.ts +22 -1
  184. package/lib/sync/unknownBlock.d.ts.map +1 -1
  185. package/lib/sync/unknownBlock.js +602 -53
  186. package/lib/sync/unknownBlock.js.map +1 -1
  187. package/lib/sync/utils/downloadByRange.d.ts +46 -10
  188. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  189. package/lib/sync/utils/downloadByRange.js +164 -24
  190. package/lib/sync/utils/downloadByRange.js.map +1 -1
  191. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  192. package/lib/sync/utils/downloadByRoot.js +16 -2
  193. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  194. package/lib/sync/utils/pendingBlocksTree.d.ts +0 -1
  195. package/lib/sync/utils/pendingBlocksTree.d.ts.map +1 -1
  196. package/lib/sync/utils/pendingBlocksTree.js +0 -9
  197. package/lib/sync/utils/pendingBlocksTree.js.map +1 -1
  198. package/lib/util/sszBytes.d.ts.map +1 -1
  199. package/lib/util/sszBytes.js +8 -6
  200. package/lib/util/sszBytes.js.map +1 -1
  201. package/package.json +16 -15
  202. package/src/api/impl/beacon/blocks/index.ts +21 -5
  203. package/src/api/impl/beacon/pool/index.ts +83 -1
  204. package/src/api/impl/debug/index.ts +0 -1
  205. package/src/api/impl/lodestar/index.ts +1 -1
  206. package/src/api/impl/validator/index.ts +82 -1
  207. package/src/chain/blocks/importBlock.ts +24 -38
  208. package/src/chain/blocks/importExecutionPayload.ts +59 -25
  209. package/src/chain/blocks/index.ts +73 -22
  210. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +6 -1
  211. package/src/chain/blocks/payloadEnvelopeInput/types.ts +1 -0
  212. package/src/chain/blocks/payloadEnvelopeProcessor.ts +2 -2
  213. package/src/chain/blocks/types.ts +4 -3
  214. package/src/chain/blocks/utils/chainSegment.ts +114 -17
  215. package/src/chain/blocks/verifyBlock.ts +70 -9
  216. package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +6 -4
  217. package/src/chain/blocks/verifyBlocksSanityChecks.ts +26 -7
  218. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +9 -4
  219. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +7 -4
  220. package/src/chain/chain.ts +16 -3
  221. package/src/chain/emitter.ts +0 -11
  222. package/src/chain/errors/blockError.ts +4 -1
  223. package/src/chain/errors/index.ts +1 -0
  224. package/src/chain/errors/proposerPreferences.ts +47 -0
  225. package/src/chain/interface.ts +7 -1
  226. package/src/chain/opPools/payloadAttestationPool.ts +29 -8
  227. package/src/chain/prepareNextSlot.ts +20 -28
  228. package/src/chain/produceBlock/produceBlockBody.ts +46 -22
  229. package/src/chain/regen/interface.ts +1 -0
  230. package/src/chain/regen/queued.ts +2 -7
  231. package/src/chain/regen/regen.ts +2 -7
  232. package/src/chain/seenCache/index.ts +1 -0
  233. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +25 -5
  234. package/src/chain/seenCache/seenProposerPreferences.ts +37 -0
  235. package/src/chain/validation/block.ts +1 -0
  236. package/src/chain/validation/executionPayloadBid.ts +11 -8
  237. package/src/chain/validation/proposerPreferences.ts +110 -0
  238. package/src/metrics/metrics/lodestar.ts +4 -0
  239. package/src/network/gossip/interface.ts +6 -0
  240. package/src/network/gossip/scoringParameters.ts +14 -1
  241. package/src/network/gossip/topic.ts +6 -0
  242. package/src/network/interface.ts +1 -0
  243. package/src/network/network.ts +11 -0
  244. package/src/network/processor/gossipHandlers.ts +35 -17
  245. package/src/network/processor/gossipQueues/index.ts +5 -0
  246. package/src/network/processor/index.ts +6 -5
  247. package/src/network/reqresp/handlers/beaconBlocksByRange.ts +14 -6
  248. package/src/network/reqresp/handlers/blobSidecarsByRange.ts +11 -5
  249. package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -5
  250. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +7 -4
  251. package/src/node/nodejs.ts +2 -2
  252. package/src/sync/range/batch.ts +142 -38
  253. package/src/sync/range/chain.ts +37 -9
  254. package/src/sync/range/range.ts +18 -6
  255. package/src/sync/types.ts +72 -0
  256. package/src/sync/unknownBlock.ts +760 -57
  257. package/src/sync/utils/downloadByRange.ts +274 -39
  258. package/src/sync/utils/downloadByRoot.ts +24 -2
  259. package/src/sync/utils/pendingBlocksTree.ts +0 -15
  260. package/src/util/sszBytes.ts +8 -6
@@ -1,6 +1,23 @@
1
1
  import {ChainForkConfig} from "@lodestar/config";
2
- import {ForkPostDeneb, ForkPostFulu, ForkPreFulu, isForkPostFulu} from "@lodestar/params";
3
- import {SignedBeaconBlock, Slot, deneb, fulu, phase0} from "@lodestar/types";
2
+ import {
3
+ ForkPostDeneb,
4
+ ForkPostFulu,
5
+ ForkPostGloas,
6
+ ForkPreFulu,
7
+ isForkPostFulu,
8
+ isForkPostGloas,
9
+ } from "@lodestar/params";
10
+ import {
11
+ DataColumnSidecar,
12
+ SignedBeaconBlock,
13
+ Slot,
14
+ deneb,
15
+ fulu,
16
+ gloas,
17
+ isGloasBeaconBlock,
18
+ isGloasDataColumnSidecar,
19
+ phase0,
20
+ } from "@lodestar/types";
4
21
  import {LodestarError, Logger, byteArrayEquals, fromHex, prettyPrintIndices, toRootHex} from "@lodestar/utils";
5
22
  import {
6
23
  BlockInputSource,
@@ -9,12 +26,18 @@ import {
9
26
  isBlockInputBlobs,
10
27
  isBlockInputColumns,
11
28
  } from "../../chain/blocks/blockInput/index.js";
29
+ import {PayloadEnvelopeInput} from "../../chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js";
30
+ import {PayloadEnvelopeInputSource} from "../../chain/blocks/payloadEnvelopeInput/types.js";
12
31
  import {SeenBlockInput} from "../../chain/seenCache/seenGossipBlockInput.js";
32
+ import {SeenPayloadEnvelopeInput} from "../../chain/seenCache/seenPayloadEnvelopeInput.js";
13
33
  import {validateBlockBlobSidecars} from "../../chain/validation/blobSidecar.js";
14
- import {validateFuluBlockDataColumnSidecars} from "../../chain/validation/dataColumnSidecar.js";
34
+ import {
35
+ validateFuluBlockDataColumnSidecars,
36
+ validateGloasBlockDataColumnSidecars,
37
+ } from "../../chain/validation/dataColumnSidecar.js";
15
38
  import {BeaconMetrics} from "../../metrics/metrics/beacon.js";
16
39
  import {INetwork} from "../../network/index.js";
17
- import {getBlobKzgCommitments} from "../../util/dataColumns.js";
40
+ import {CustodyConfig, getBlobKzgCommitments} from "../../util/dataColumns.js";
18
41
  import {PeerIdStr} from "../../util/peerId.js";
19
42
  import {WarnResult} from "../../util/wrapError.js";
20
43
 
@@ -22,12 +45,14 @@ export type DownloadByRangeRequests = {
22
45
  blocksRequest?: phase0.BeaconBlocksByRangeRequest;
23
46
  blobsRequest?: deneb.BlobSidecarsByRangeRequest;
24
47
  columnsRequest?: fulu.DataColumnSidecarsByRangeRequest;
48
+ envelopesRequest?: gloas.ExecutionPayloadEnvelopesByRangeRequest;
25
49
  };
26
50
 
27
51
  export type DownloadByRangeResponses = {
28
52
  blocks?: SignedBeaconBlock[];
29
53
  blobSidecars?: deneb.BlobSidecars;
30
- columnSidecars?: fulu.DataColumnSidecar[];
54
+ columnSidecars?: DataColumnSidecar[];
55
+ payloadEnvelopes?: gloas.SignedExecutionPayloadEnvelope[];
31
56
  };
32
57
 
33
58
  export type DownloadAndCacheByRangeProps = DownloadByRangeRequests & {
@@ -41,9 +66,17 @@ export type DownloadAndCacheByRangeProps = DownloadByRangeRequests & {
41
66
 
42
67
  export type CacheByRangeResponsesProps = {
43
68
  cache: SeenBlockInput;
69
+ seenPayloadEnvelopeInputCache: SeenPayloadEnvelopeInput;
44
70
  peerIdStr: string;
45
71
  responses: ValidatedResponses;
46
72
  batchBlocks: IBlockInput[];
73
+ /** Raw envelopes downloaded in this batch, keyed by slot (from downloadByRange return) */
74
+ downloadedPayloadEnvelopes: Map<Slot, gloas.SignedExecutionPayloadEnvelope> | null;
75
+ /** Envelopes already wrapped from previous partial downloads on this batch */
76
+ existingPayloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
77
+ /** Sampled/custody column indices for building PayloadEnvelopeInputs */
78
+ custodyConfig: Pick<CustodyConfig, "sampledColumns" | "custodyColumns">;
79
+ seenTimestampSec: number;
47
80
  };
48
81
 
49
82
  export type ValidatedBlock = {
@@ -58,7 +91,7 @@ export type ValidatedBlobSidecars = {
58
91
 
59
92
  export type ValidatedColumnSidecars = {
60
93
  blockRoot: Uint8Array;
61
- columnSidecars: fulu.DataColumnSidecar[];
94
+ columnSidecars: DataColumnSidecar[];
62
95
  };
63
96
 
64
97
  export type ValidatedResponses = {
@@ -72,12 +105,16 @@ export type ValidatedResponses = {
72
105
  */
73
106
  export function cacheByRangeResponses({
74
107
  cache,
108
+ seenPayloadEnvelopeInputCache,
75
109
  peerIdStr,
76
110
  responses,
77
111
  batchBlocks,
78
- }: CacheByRangeResponsesProps): IBlockInput[] {
112
+ downloadedPayloadEnvelopes,
113
+ existingPayloadEnvelopes,
114
+ custodyConfig,
115
+ seenTimestampSec,
116
+ }: CacheByRangeResponsesProps): {blocks: IBlockInput[]; payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null} {
79
117
  const source = BlockInputSource.byRange;
80
- const seenTimestampSec = Date.now() / 1000;
81
118
  const updatedBatchBlocks = new Map<Slot, IBlockInput>(batchBlocks.map((block) => [block.slot, block]));
82
119
 
83
120
  const blocks = responses.validatedBlocks ?? [];
@@ -149,16 +186,88 @@ export function cacheByRangeResponses({
149
186
  }
150
187
  }
151
188
 
189
+ // Seed seenPayloadEnvelopeInputCache for every gloas block in the batch, regardless of whether
190
+ // the peer returned its envelope. Without this, a block returned without its envelope would be
191
+ // imported with no cache entry, and later payload-by-root sync would throw
192
+ // "Missing PayloadEnvelopeInput for known block" (see issue #9306).
193
+ for (const blockInput of updatedBatchBlocks.values()) {
194
+ if (!blockInput.hasBlock() || !isForkPostGloas(blockInput.forkName)) continue;
195
+ seenPayloadEnvelopeInputCache.add({
196
+ blockRootHex: blockInput.blockRootHex,
197
+ block: blockInput.getBlock() as SignedBeaconBlock<ForkPostGloas>,
198
+ forkName: blockInput.forkName,
199
+ sampledColumns: custodyConfig.sampledColumns,
200
+ custodyColumns: custodyConfig.custodyColumns,
201
+ timeCreatedSec: seenTimestampSec,
202
+ });
203
+ }
204
+
205
+ // Attach envelopes to entries whose envelope was returned by the peer. The returned
206
+ // payloadEnvelopes map only contains entries with envelopes ready for importExecutionPayload.
207
+ let payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null = null;
208
+ if (downloadedPayloadEnvelopes !== null) {
209
+ payloadEnvelopes = new Map(existingPayloadEnvelopes ?? []);
210
+
211
+ for (const [slot, envelope] of downloadedPayloadEnvelopes) {
212
+ const blockInput = updatedBatchBlocks.get(slot);
213
+ if (!blockInput?.hasBlock() || !isForkPostGloas(blockInput.forkName)) {
214
+ // No block to pair this envelope with; drop silently
215
+ continue;
216
+ }
217
+
218
+ const payloadInput = seenPayloadEnvelopeInputCache.get(blockInput.blockRootHex);
219
+ if (payloadInput === undefined) {
220
+ // Unreachable given the loop above seeded an entry for every gloas block in the batch.
221
+ continue;
222
+ }
223
+
224
+ if (!payloadInput.hasPayloadEnvelope()) {
225
+ payloadInput.addPayloadEnvelope({
226
+ envelope,
227
+ source: PayloadEnvelopeInputSource.byRange,
228
+ seenTimestampSec,
229
+ peerIdStr,
230
+ });
231
+ }
232
+
233
+ payloadEnvelopes.set(slot, payloadInput);
234
+ }
235
+ }
236
+
152
237
  for (const {blockRoot, columnSidecars} of responses.validatedColumnSidecars ?? []) {
153
- const dataSlot = columnSidecars.at(0)?.signedBlockHeader.message.slot;
154
- if (dataSlot === undefined) {
238
+ const firstColumn = columnSidecars[0];
239
+ if (!firstColumn) {
155
240
  throw new Error(
156
241
  `Coding Error: empty columnSidecars returned for blockRoot=${toRootHex(blockRoot)} from validation functions`
157
242
  );
158
243
  }
159
- const existing = updatedBatchBlocks.get(dataSlot);
244
+
160
245
  const blockRootHex = toRootHex(blockRoot);
161
246
 
247
+ if (isGloasDataColumnSidecar(firstColumn)) {
248
+ // Gloas columns are attached to the matching PayloadEnvelopeInput, NOT to IBlockInput.
249
+ // Gloas DataColumnSidecar has `slot` directly (no signedBlockHeader).
250
+ const dataSlot = firstColumn.slot;
251
+ const payloadInput = payloadEnvelopes?.get(dataSlot);
252
+ if (!payloadInput) {
253
+ // Should not happen: we built payloadInputs for all gloas blocks above
254
+ continue;
255
+ }
256
+ for (const columnSidecar of columnSidecars as gloas.DataColumnSidecar[]) {
257
+ payloadInput.addColumn({
258
+ columnSidecar,
259
+ seenTimestampSec,
260
+ peerIdStr,
261
+ source: PayloadEnvelopeInputSource.byRange,
262
+ });
263
+ }
264
+ continue;
265
+ }
266
+
267
+ const fuluColumns = columnSidecars as fulu.DataColumnSidecar[];
268
+ const dataSlot = fuluColumns[0].signedBlockHeader.message.slot;
269
+ const existing = updatedBatchBlocks.get(dataSlot);
270
+
162
271
  if (!existing) {
163
272
  throw new Error("Coding error: blockInput must exist when adding columns");
164
273
  }
@@ -172,7 +281,7 @@ export function cacheByRangeResponses({
172
281
  actual: existing.type,
173
282
  });
174
283
  }
175
- for (const columnSidecar of columnSidecars) {
284
+ for (const columnSidecar of fuluColumns) {
176
285
  // will throw if root hex does not match (meaning we are following the wrong chain)
177
286
  existing.addColumn(
178
287
  {
@@ -187,7 +296,7 @@ export function cacheByRangeResponses({
187
296
  }
188
297
  }
189
298
 
190
- return Array.from(updatedBatchBlocks.values());
299
+ return {blocks: Array.from(updatedBatchBlocks.values()), payloadEnvelopes};
191
300
  }
192
301
 
193
302
  export async function downloadByRange({
@@ -198,8 +307,14 @@ export async function downloadByRange({
198
307
  blocksRequest,
199
308
  blobsRequest,
200
309
  columnsRequest,
310
+ envelopesRequest,
201
311
  peerDasMetrics,
202
- }: DownloadAndCacheByRangeProps): Promise<WarnResult<ValidatedResponses, DownloadByRangeError>> {
312
+ }: DownloadAndCacheByRangeProps): Promise<
313
+ WarnResult<
314
+ {responses: ValidatedResponses; payloadEnvelopes: Map<Slot, gloas.SignedExecutionPayloadEnvelope> | null},
315
+ DownloadByRangeError
316
+ >
317
+ > {
203
318
  let response: DownloadByRangeResponses;
204
319
  try {
205
320
  response = await requestByRange({
@@ -208,6 +323,7 @@ export async function downloadByRange({
208
323
  blocksRequest,
209
324
  blobsRequest,
210
325
  columnsRequest,
326
+ envelopesRequest,
211
327
  });
212
328
  } catch (err) {
213
329
  throw new DownloadByRangeError({
@@ -217,17 +333,16 @@ export async function downloadByRange({
217
333
  });
218
334
  }
219
335
 
220
- const validated = await validateResponses({
336
+ return validateResponses({
221
337
  config,
222
338
  batchBlocks,
223
339
  blocksRequest,
224
340
  blobsRequest,
225
341
  columnsRequest,
342
+ envelopesRequest,
226
343
  peerDasMetrics,
227
344
  ...response,
228
345
  });
229
-
230
- return validated;
231
346
  }
232
347
 
233
348
  /**
@@ -239,13 +354,15 @@ export async function requestByRange({
239
354
  blocksRequest,
240
355
  blobsRequest,
241
356
  columnsRequest,
357
+ envelopesRequest,
242
358
  }: DownloadByRangeRequests & {
243
359
  network: INetwork;
244
360
  peerIdStr: PeerIdStr;
245
361
  }): Promise<DownloadByRangeResponses> {
246
362
  let blocks: undefined | SignedBeaconBlock[];
247
363
  let blobSidecars: undefined | deneb.BlobSidecars;
248
- let columnSidecars: undefined | fulu.DataColumnSidecar[];
364
+ let columnSidecars: undefined | DataColumnSidecar[];
365
+ const payloadEnvelopes: gloas.SignedExecutionPayloadEnvelope[] = [];
249
366
 
250
367
  const requests: Promise<unknown>[] = [];
251
368
 
@@ -253,6 +370,17 @@ export async function requestByRange({
253
370
  requests.push(
254
371
  network.sendBeaconBlocksByRange(peerIdStr, blocksRequest).then((blockResponse) => {
255
372
  blocks = blockResponse;
373
+ const firstBlock = blockResponse.at(0);
374
+ if (firstBlock && isGloasBeaconBlock(firstBlock.message)) {
375
+ return network
376
+ .sendExecutionPayloadEnvelopesByRoot(peerIdStr, [
377
+ firstBlock.message.body.signedExecutionPayloadBid.message.parentBlockRoot,
378
+ ])
379
+ .then((envelopeResponse) => {
380
+ payloadEnvelopes?.unshift(...envelopeResponse);
381
+ });
382
+ }
383
+ return undefined;
256
384
  })
257
385
  );
258
386
  }
@@ -268,7 +396,15 @@ export async function requestByRange({
268
396
  if (columnsRequest) {
269
397
  requests.push(
270
398
  network.sendDataColumnSidecarsByRange(peerIdStr, columnsRequest).then((columnResponse) => {
271
- columnSidecars = columnResponse as fulu.DataColumnSidecar[];
399
+ columnSidecars = columnResponse;
400
+ })
401
+ );
402
+ }
403
+
404
+ if (envelopesRequest) {
405
+ requests.push(
406
+ network.sendExecutionPayloadEnvelopesByRange(peerIdStr, envelopesRequest).then((envelopeResponse) => {
407
+ payloadEnvelopes?.push(...envelopeResponse);
272
408
  })
273
409
  );
274
410
  }
@@ -279,6 +415,7 @@ export async function requestByRange({
279
415
  blocks,
280
416
  blobSidecars,
281
417
  columnSidecars,
418
+ payloadEnvelopes,
282
419
  };
283
420
  }
284
421
 
@@ -291,16 +428,23 @@ export async function validateResponses({
291
428
  blocksRequest,
292
429
  blobsRequest,
293
430
  columnsRequest,
431
+ envelopesRequest,
294
432
  blocks,
295
433
  blobSidecars,
296
434
  columnSidecars,
435
+ payloadEnvelopes,
297
436
  peerDasMetrics,
298
437
  }: DownloadByRangeRequests &
299
438
  DownloadByRangeResponses & {
300
439
  config: ChainForkConfig;
301
440
  batchBlocks?: IBlockInput[];
302
441
  peerDasMetrics?: BeaconMetrics["peerDas"] | null;
303
- }): Promise<WarnResult<ValidatedResponses, DownloadByRangeError>> {
442
+ }): Promise<
443
+ WarnResult<
444
+ {responses: ValidatedResponses; payloadEnvelopes: Map<Slot, gloas.SignedExecutionPayloadEnvelope> | null},
445
+ DownloadByRangeError
446
+ >
447
+ > {
304
448
  // Blocks are always required for blob/column validation
305
449
  // If a blocksRequest is provided, blocks have just been downloaded
306
450
  // If no blocksRequest is provided, batchBlocks must have been provided from cache
@@ -326,8 +470,21 @@ export async function validateResponses({
326
470
  }
327
471
 
328
472
  const dataRequest = blobsRequest ?? columnsRequest;
473
+ if (!dataRequest && !envelopesRequest) {
474
+ return {result: {responses: validatedResponses, payloadEnvelopes: null}, warnings};
475
+ }
476
+
329
477
  if (!dataRequest) {
330
- return {result: validatedResponses, warnings};
478
+ // Only envelope validation needed
479
+ let validatedPayloadEnvelopes: Map<Slot, gloas.SignedExecutionPayloadEnvelope> | null = null;
480
+ if (envelopesRequest) {
481
+ validatedPayloadEnvelopes = validateEnvelopesByRangeResponse(
482
+ validatedResponses.validatedBlocks ?? [],
483
+ batchBlocks,
484
+ payloadEnvelopes ?? []
485
+ );
486
+ }
487
+ return {result: {responses: validatedResponses, payloadEnvelopes: validatedPayloadEnvelopes}, warnings};
331
488
  }
332
489
 
333
490
  const blocksForDataValidation = getBlocksForDataValidation(
@@ -385,7 +542,17 @@ export async function validateResponses({
385
542
  warnings = validatedColumnSidecarsResult.warnings;
386
543
  }
387
544
 
388
- return {result: validatedResponses, warnings};
545
+ // Validate envelopes if an envelopes request was made
546
+ let validatedPayloadEnvelopes: Map<Slot, gloas.SignedExecutionPayloadEnvelope> | null = null;
547
+ if (envelopesRequest) {
548
+ validatedPayloadEnvelopes = validateEnvelopesByRangeResponse(
549
+ validatedResponses.validatedBlocks ?? [],
550
+ batchBlocks,
551
+ payloadEnvelopes ?? []
552
+ );
553
+ }
554
+
555
+ return {result: {responses: validatedResponses, payloadEnvelopes: validatedPayloadEnvelopes}, warnings};
389
556
  }
390
557
 
391
558
  /**
@@ -615,19 +782,19 @@ export async function validateColumnsByRangeResponse(
615
782
  config: ChainForkConfig,
616
783
  request: fulu.DataColumnSidecarsByRangeRequest,
617
784
  blocks: ValidatedBlock[],
618
- columnSidecars: fulu.DataColumnSidecar[],
785
+ columnSidecars: DataColumnSidecar[],
619
786
  peerDasMetrics?: BeaconMetrics["peerDas"] | null
620
787
  ): Promise<WarnResult<ValidatedColumnSidecars[], DownloadByRangeError>> {
621
788
  const warnings: DownloadByRangeError[] = [];
622
789
 
623
- // TODO GLOAS: Extend by range column sync to support gloas.DataColumnSidecar and
624
- // validate against the block bid commitments instead of the fulu signed header shape
625
- const seenColumns = new Map<Slot, Map<number, fulu.DataColumnSidecar>>();
790
+ const seenColumns = new Map<Slot, Map<number, DataColumnSidecar>>();
626
791
  let currentSlot = -1;
627
792
  let currentIndex = -1;
628
793
  // Check for duplicates and order
629
794
  for (const columnSidecar of columnSidecars) {
630
- const slot = columnSidecar.signedBlockHeader.message.slot;
795
+ const slot = isGloasDataColumnSidecar(columnSidecar)
796
+ ? columnSidecar.slot
797
+ : columnSidecar.signedBlockHeader.message.slot;
631
798
  let seenSlotColumns = seenColumns.get(slot);
632
799
  if (!seenSlotColumns) {
633
800
  seenSlotColumns = new Map();
@@ -686,20 +853,20 @@ export async function validateColumnsByRangeResponse(
686
853
  const slot = block.message.slot;
687
854
  const rootHex = toRootHex(blockRoot);
688
855
  const forkName = config.getForkName(slot);
689
- const columnSidecarsMap: Map<number, fulu.DataColumnSidecar> = seenColumns.get(slot) ?? new Map();
856
+ const columnSidecarsMap: Map<number, DataColumnSidecar> = seenColumns.get(slot) ?? new Map();
690
857
  const columnSidecars = Array.from(columnSidecarsMap.values()).sort((a, b) => a.index - b.index);
691
858
 
692
859
  let blobCount: number;
693
860
  if (!isForkPostFulu(forkName)) {
694
- const dataSlot = columnSidecars.at(0)?.signedBlockHeader.message.slot;
695
861
  throw new DownloadByRangeError({
696
862
  code: DownloadByRangeErrorCode.MISMATCH_BLOCK_FORK,
697
863
  slot,
698
864
  blockFork: forkName,
699
- dataFork: dataSlot ? config.getForkName(dataSlot) : "unknown",
865
+ dataFork: "unknown",
700
866
  });
701
867
  }
702
- blobCount = getBlobKzgCommitments(forkName, block as SignedBeaconBlock<ForkPostFulu>).length;
868
+ const kzgCommitments = getBlobKzgCommitments(forkName, block as SignedBeaconBlock<ForkPostFulu>);
869
+ blobCount = kzgCommitments.length;
703
870
 
704
871
  if (columnSidecars.length === 0) {
705
872
  if (!blobCount) {
@@ -768,15 +935,25 @@ export async function validateColumnsByRangeResponse(
768
935
  );
769
936
  }
770
937
 
938
+ const validatePromise = isForkPostGloas(forkName)
939
+ ? validateGloasBlockDataColumnSidecars(
940
+ slot,
941
+ blockRoot,
942
+ kzgCommitments,
943
+ columnSidecars as gloas.DataColumnSidecar[],
944
+ peerDasMetrics
945
+ )
946
+ : validateFuluBlockDataColumnSidecars(
947
+ null, // do not pass chain here so we do not validate header signature
948
+ slot,
949
+ blockRoot,
950
+ blobCount,
951
+ columnSidecars as fulu.DataColumnSidecar[],
952
+ peerDasMetrics
953
+ );
954
+
771
955
  validationPromises.push(
772
- validateFuluBlockDataColumnSidecars(
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(() => ({
956
+ validatePromise.then(() => ({
780
957
  blockRoot,
781
958
  columnSidecars,
782
959
  }))
@@ -882,6 +1059,9 @@ export enum DownloadByRangeErrorCode {
882
1059
  /** Cached block input type mismatches new data */
883
1060
  MISMATCH_BLOCK_FORK = "DOWNLOAD_BY_RANGE_ERROR_MISMATCH_BLOCK_FORK",
884
1061
  MISMATCH_BLOCK_INPUT_TYPE = "DOWNLOAD_BY_RANGE_ERROR_MISMATCH_BLOCK_INPUT_TYPE",
1062
+
1063
+ /** Envelope beaconBlockRoot does not match the block's root */
1064
+ INVALID_ENVELOPE_BEACON_BLOCK_ROOT = "DOWNLOAD_BY_RANGE_ERROR_INVALID_ENVELOPE_BEACON_BLOCK_ROOT",
885
1065
  }
886
1066
 
887
1067
  export type DownloadByRangeErrorType =
@@ -973,6 +1153,61 @@ export type DownloadByRangeErrorType =
973
1153
  blockRoot: string;
974
1154
  expected: DAType;
975
1155
  actual: DAType;
1156
+ }
1157
+ | {
1158
+ code: DownloadByRangeErrorCode.INVALID_ENVELOPE_BEACON_BLOCK_ROOT;
1159
+ slot: Slot;
1160
+ expected: string;
1161
+ actual: string;
976
1162
  };
977
1163
 
978
1164
  export class DownloadByRangeError extends LodestarError<DownloadByRangeErrorType> {}
1165
+
1166
+ /**
1167
+ * Validates SignedExecutionPayloadEnvelopes received for a range request.
1168
+ * For each envelope whose slot appears in the downloaded blocks, verifies that
1169
+ * envelope.message.beaconBlockRoot matches the corresponding block's root.
1170
+ * Envelopes for slots not in the batch (orphaned payloads) are silently ignored.
1171
+ */
1172
+ export function validateEnvelopesByRangeResponse(
1173
+ validatedBlocks: ValidatedBlock[],
1174
+ batchBlocks: IBlockInput[] | undefined,
1175
+ payloadEnvelopes: gloas.SignedExecutionPayloadEnvelope[]
1176
+ ): Map<Slot, gloas.SignedExecutionPayloadEnvelope> {
1177
+ // Build a map of slot -> blockRoot for all blocks in the batch
1178
+ const batchBlockRoots = new Map<Slot, Uint8Array>();
1179
+ if (batchBlocks) {
1180
+ for (const blockInput of batchBlocks) {
1181
+ batchBlockRoots.set(blockInput.slot, fromHex(blockInput.blockRootHex));
1182
+ }
1183
+ }
1184
+ for (const {block, blockRoot} of validatedBlocks) {
1185
+ batchBlockRoots.set(block.message.slot, blockRoot);
1186
+ }
1187
+
1188
+ const payloadEnvelopeMap = new Map<Slot, gloas.SignedExecutionPayloadEnvelope>();
1189
+
1190
+ for (const payloadEnvelope of payloadEnvelopes) {
1191
+ const slot = payloadEnvelope.message.payload.slotNumber;
1192
+ const batchBlockRoot = batchBlockRoots.get(slot);
1193
+
1194
+ // Envelopes for slots not in the batch are silently ignored (orphaned payloads or a parent payload)
1195
+ if (batchBlockRoot === undefined) {
1196
+ continue;
1197
+ }
1198
+
1199
+ // Verify beaconBlockRoot matches the block's root
1200
+ if (!byteArrayEquals(payloadEnvelope.message.beaconBlockRoot, batchBlockRoot)) {
1201
+ throw new DownloadByRangeError({
1202
+ code: DownloadByRangeErrorCode.INVALID_ENVELOPE_BEACON_BLOCK_ROOT,
1203
+ slot,
1204
+ expected: toRootHex(batchBlockRoot),
1205
+ actual: toRootHex(payloadEnvelope.message.beaconBlockRoot),
1206
+ });
1207
+ }
1208
+
1209
+ payloadEnvelopeMap.set(slot, payloadEnvelope);
1210
+ }
1211
+
1212
+ return payloadEnvelopeMap;
1213
+ }
@@ -1,6 +1,14 @@
1
1
  import {routes} from "@lodestar/api";
2
2
  import {ChainForkConfig} from "@lodestar/config";
3
- import {ForkPostDeneb, ForkPostFulu, ForkPreFulu, isForkPostDeneb, isForkPostFulu} from "@lodestar/params";
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 (isForkPostFulu(forkName)) {
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,
@@ -40,21 +40,6 @@ function addToDescendantBlocks(
40
40
  return descendantBlocks;
41
41
  }
42
42
 
43
- export function getDescendantBlocks(
44
- blockRootHex: RootHex,
45
- blocks: Map<RootHex, BlockInputSyncCacheItem>
46
- ): BlockInputSyncCacheItem[] {
47
- const descendantBlocks: BlockInputSyncCacheItem[] = [];
48
-
49
- for (const block of blocks.values()) {
50
- if ((isPendingBlockInput(block) ? block.blockInput.parentRootHex : undefined) === blockRootHex) {
51
- descendantBlocks.push(block);
52
- }
53
- }
54
-
55
- return descendantBlocks;
56
- }
57
-
58
43
  export type UnknownAndAncestorBlocks = {
59
44
  unknowns: BlockInputSyncCacheItem[];
60
45
  ancestors: PendingBlockInput[];
@@ -558,9 +558,10 @@ export function getBeaconBlockRootFromDataColumnSidecarSerialized(data: Uint8Arr
558
558
  * └─ ExecutionPayloadEnvelope (starts at byte 100):
559
559
  * ├─ 4 bytes: payload offset
560
560
  * ├─ 4 bytes: executionRequests offset
561
- * ├─ 8 bytes: builderIndex (offset 108-115)
562
- * ├─ 32 bytes: beaconBlockRoot (offset 116-147)
563
- * └─ variable: payload data (starts at envelope + 48)
561
+ * ├─ 8 bytes: builderIndex (offset 108-115)
562
+ * ├─ 32 bytes: beaconBlockRoot (offset 116-147)
563
+ * ├─ 32 bytes: parentBeaconBlockRoot (offset 148-179) new in Gloas alpha.6 (consensus-specs#5152)
564
+ * └─ variable: payload data (starts at envelope + 80)
564
565
  * └─ ExecutionPayload fixed portion includes slotNumber at offset 532
565
566
  */
566
567
  const SIGNED_EXECUTION_PAYLOAD_ENVELOPE_MESSAGE_OFFSET = 4;
@@ -576,12 +577,13 @@ const BEACON_BLOCK_ROOT_OFFSET_IN_SIGNED_EXECUTION_PAYLOAD_ENVELOPE =
576
577
  EXECUTION_PAYLOAD_ENVELOPE_REQUESTS_OFFSET +
577
578
  EXECUTION_PAYLOAD_ENVELOPE_BUILDER_INDEX_SIZE; // 116
578
579
 
579
- // Envelope fixed portion (without slot): payload_offset(4) + requests_offset(4) + builderIndex(8) + beaconBlockRoot(32) = 48
580
+ // Envelope fixed portion: payload_offset(4) + requests_offset(4) + builderIndex(8) + beaconBlockRoot(32) + parentBeaconBlockRoot(32) = 80
580
581
  const EXECUTION_PAYLOAD_ENVELOPE_FIXED_SIZE =
581
582
  EXECUTION_PAYLOAD_ENVELOPE_PAYLOAD_OFFSET +
582
583
  EXECUTION_PAYLOAD_ENVELOPE_REQUESTS_OFFSET +
583
584
  EXECUTION_PAYLOAD_ENVELOPE_BUILDER_INDEX_SIZE +
584
- ROOT_SIZE; // 48
585
+ ROOT_SIZE +
586
+ ROOT_SIZE; // 80
585
587
 
586
588
  // slotNumber offset within ExecutionPayload fixed portion:
587
589
  // parentHash(32) + feeRecipient(20) + stateRoot(32) + receiptsRoot(32) + logsBloom(256) +
@@ -595,7 +597,7 @@ const ENVELOPE_START_IN_SIGNED =
595
597
  SIGNED_EXECUTION_PAYLOAD_ENVELOPE_MESSAGE_OFFSET + SIGNED_EXECUTION_PAYLOAD_ENVELOPE_SIGNATURE_SIZE; // 100
596
598
 
597
599
  const SLOT_OFFSET_IN_SIGNED_EXECUTION_PAYLOAD_ENVELOPE =
598
- ENVELOPE_START_IN_SIGNED + EXECUTION_PAYLOAD_ENVELOPE_FIXED_SIZE + SLOT_NUMBER_OFFSET_IN_EXECUTION_PAYLOAD; // 100 + 48 + 532 = 680
600
+ ENVELOPE_START_IN_SIGNED + EXECUTION_PAYLOAD_ENVELOPE_FIXED_SIZE + SLOT_NUMBER_OFFSET_IN_EXECUTION_PAYLOAD; // 100 + 80 + 532 = 712
599
601
 
600
602
  export function getSlotFromExecutionPayloadEnvelopeSerialized(data: Uint8Array): Slot | null {
601
603
  if (data.length < SLOT_OFFSET_IN_SIGNED_EXECUTION_PAYLOAD_ENVELOPE + SLOT_SIZE) {