@lodestar/beacon-node 1.43.0-dev.180030f946 → 1.43.0-dev.1d4e5f45ec

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 (248) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +15 -4
  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/validator/index.d.ts.map +1 -1
  11. package/lib/api/impl/validator/index.js +68 -2
  12. package/lib/api/impl/validator/index.js.map +1 -1
  13. package/lib/chain/blocks/blockInput/blockInput.d.ts +3 -0
  14. package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
  15. package/lib/chain/blocks/blockInput/blockInput.js +4 -1
  16. package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
  17. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  18. package/lib/chain/blocks/importBlock.js +16 -31
  19. package/lib/chain/blocks/importBlock.js.map +1 -1
  20. package/lib/chain/blocks/importExecutionPayload.d.ts +9 -3
  21. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  22. package/lib/chain/blocks/importExecutionPayload.js +37 -15
  23. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  24. package/lib/chain/blocks/index.d.ts.map +1 -1
  25. package/lib/chain/blocks/index.js +35 -21
  26. package/lib/chain/blocks/index.js.map +1 -1
  27. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +12 -1
  28. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  29. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +28 -2
  30. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  31. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +17 -0
  32. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  33. package/lib/chain/blocks/types.d.ts +2 -1
  34. package/lib/chain/blocks/types.d.ts.map +1 -1
  35. package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
  36. package/lib/chain/blocks/utils/chainSegment.js +8 -0
  37. package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
  38. package/lib/chain/blocks/verifyBlock.d.ts +2 -1
  39. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  40. package/lib/chain/blocks/verifyBlock.js +30 -12
  41. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  42. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts +0 -4
  43. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
  44. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +5 -2
  45. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
  46. package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts +2 -1
  47. package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts.map +1 -1
  48. package/lib/chain/blocks/verifyBlocksSanityChecks.js +25 -5
  49. package/lib/chain/blocks/verifyBlocksSanityChecks.js.map +1 -1
  50. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +2 -2
  51. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
  52. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +12 -8
  53. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
  54. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -1
  55. package/lib/chain/blocks/verifyPayloadsDataAvailability.js +8 -3
  56. package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -1
  57. package/lib/chain/chain.d.ts +2 -1
  58. package/lib/chain/chain.d.ts.map +1 -1
  59. package/lib/chain/chain.js +28 -9
  60. package/lib/chain/chain.js.map +1 -1
  61. package/lib/chain/emitter.d.ts +0 -11
  62. package/lib/chain/emitter.d.ts.map +1 -1
  63. package/lib/chain/emitter.js +0 -4
  64. package/lib/chain/emitter.js.map +1 -1
  65. package/lib/chain/errors/index.d.ts +1 -0
  66. package/lib/chain/errors/index.d.ts.map +1 -1
  67. package/lib/chain/errors/index.js +1 -0
  68. package/lib/chain/errors/index.js.map +1 -1
  69. package/lib/chain/errors/proposerPreferences.d.ts +40 -0
  70. package/lib/chain/errors/proposerPreferences.d.ts.map +1 -0
  71. package/lib/chain/errors/proposerPreferences.js +14 -0
  72. package/lib/chain/errors/proposerPreferences.js.map +1 -0
  73. package/lib/chain/initState.d.ts.map +1 -1
  74. package/lib/chain/initState.js +6 -1
  75. package/lib/chain/initState.js.map +1 -1
  76. package/lib/chain/interface.d.ts +2 -1
  77. package/lib/chain/interface.d.ts.map +1 -1
  78. package/lib/chain/interface.js.map +1 -1
  79. package/lib/chain/opPools/payloadAttestationPool.d.ts +3 -2
  80. package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
  81. package/lib/chain/opPools/payloadAttestationPool.js +26 -4
  82. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  83. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  84. package/lib/chain/prepareNextSlot.js +16 -18
  85. package/lib/chain/prepareNextSlot.js.map +1 -1
  86. package/lib/chain/produceBlock/produceBlockBody.d.ts +12 -3
  87. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  88. package/lib/chain/produceBlock/produceBlockBody.js +35 -17
  89. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  90. package/lib/chain/regen/interface.d.ts +1 -0
  91. package/lib/chain/regen/interface.d.ts.map +1 -1
  92. package/lib/chain/regen/interface.js +1 -0
  93. package/lib/chain/regen/interface.js.map +1 -1
  94. package/lib/chain/regen/queued.d.ts.map +1 -1
  95. package/lib/chain/regen/queued.js +1 -4
  96. package/lib/chain/regen/queued.js.map +1 -1
  97. package/lib/chain/regen/regen.d.ts.map +1 -1
  98. package/lib/chain/regen/regen.js +1 -4
  99. package/lib/chain/regen/regen.js.map +1 -1
  100. package/lib/chain/seenCache/index.d.ts +1 -0
  101. package/lib/chain/seenCache/index.d.ts.map +1 -1
  102. package/lib/chain/seenCache/index.js +1 -0
  103. package/lib/chain/seenCache/index.js.map +1 -1
  104. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +21 -11
  105. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  106. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +70 -20
  107. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  108. package/lib/chain/seenCache/seenProposerPreferences.d.ts +16 -0
  109. package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +1 -0
  110. package/lib/chain/seenCache/seenProposerPreferences.js +26 -0
  111. package/lib/chain/seenCache/seenProposerPreferences.js.map +1 -0
  112. package/lib/chain/validation/executionPayloadBid.js +11 -8
  113. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  114. package/lib/chain/validation/proposerPreferences.d.ts +8 -0
  115. package/lib/chain/validation/proposerPreferences.d.ts.map +1 -0
  116. package/lib/chain/validation/proposerPreferences.js +91 -0
  117. package/lib/chain/validation/proposerPreferences.js.map +1 -0
  118. package/lib/metrics/metrics/lodestar.d.ts +1 -0
  119. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  120. package/lib/metrics/metrics/lodestar.js +4 -0
  121. package/lib/metrics/metrics/lodestar.js.map +1 -1
  122. package/lib/network/gossip/interface.d.ts +7 -1
  123. package/lib/network/gossip/interface.d.ts.map +1 -1
  124. package/lib/network/gossip/interface.js +1 -0
  125. package/lib/network/gossip/interface.js.map +1 -1
  126. package/lib/network/gossip/scoringParameters.d.ts.map +1 -1
  127. package/lib/network/gossip/scoringParameters.js +12 -1
  128. package/lib/network/gossip/scoringParameters.js.map +1 -1
  129. package/lib/network/gossip/topic.d.ts +29 -766
  130. package/lib/network/gossip/topic.d.ts.map +1 -1
  131. package/lib/network/gossip/topic.js +6 -0
  132. package/lib/network/gossip/topic.js.map +1 -1
  133. package/lib/network/interface.d.ts +1 -0
  134. package/lib/network/interface.d.ts.map +1 -1
  135. package/lib/network/network.d.ts +1 -0
  136. package/lib/network/network.d.ts.map +1 -1
  137. package/lib/network/network.js +5 -0
  138. package/lib/network/network.js.map +1 -1
  139. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  140. package/lib/network/processor/gossipHandlers.js +38 -16
  141. package/lib/network/processor/gossipHandlers.js.map +1 -1
  142. package/lib/network/processor/gossipQueues/index.d.ts.map +1 -1
  143. package/lib/network/processor/gossipQueues/index.js +5 -0
  144. package/lib/network/processor/gossipQueues/index.js.map +1 -1
  145. package/lib/network/processor/index.d.ts.map +1 -1
  146. package/lib/network/processor/index.js +6 -5
  147. package/lib/network/processor/index.js.map +1 -1
  148. package/lib/node/nodejs.js +2 -2
  149. package/lib/node/nodejs.js.map +1 -1
  150. package/lib/node/notifier.js +1 -7
  151. package/lib/node/notifier.js.map +1 -1
  152. package/lib/sync/constants.d.ts +3 -1
  153. package/lib/sync/constants.d.ts.map +1 -1
  154. package/lib/sync/constants.js +3 -4
  155. package/lib/sync/constants.js.map +1 -1
  156. package/lib/sync/range/batch.d.ts +23 -3
  157. package/lib/sync/range/batch.d.ts.map +1 -1
  158. package/lib/sync/range/batch.js +191 -36
  159. package/lib/sync/range/batch.js.map +1 -1
  160. package/lib/sync/range/chain.d.ts +13 -2
  161. package/lib/sync/range/chain.d.ts.map +1 -1
  162. package/lib/sync/range/chain.js +61 -9
  163. package/lib/sync/range/chain.js.map +1 -1
  164. package/lib/sync/range/range.d.ts.map +1 -1
  165. package/lib/sync/range/range.js +14 -3
  166. package/lib/sync/range/range.js.map +1 -1
  167. package/lib/sync/sync.d.ts.map +1 -1
  168. package/lib/sync/sync.js +13 -0
  169. package/lib/sync/sync.js.map +1 -1
  170. package/lib/sync/types.d.ts +34 -0
  171. package/lib/sync/types.d.ts.map +1 -1
  172. package/lib/sync/types.js +34 -0
  173. package/lib/sync/types.js.map +1 -1
  174. package/lib/sync/unknownBlock.d.ts +29 -1
  175. package/lib/sync/unknownBlock.d.ts.map +1 -1
  176. package/lib/sync/unknownBlock.js +738 -61
  177. package/lib/sync/unknownBlock.js.map +1 -1
  178. package/lib/sync/utils/downloadByRange.d.ts +29 -8
  179. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  180. package/lib/sync/utils/downloadByRange.js +104 -42
  181. package/lib/sync/utils/downloadByRange.js.map +1 -1
  182. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  183. package/lib/sync/utils/downloadByRoot.js +16 -2
  184. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  185. package/lib/sync/utils/pendingBlocksTree.d.ts +0 -1
  186. package/lib/sync/utils/pendingBlocksTree.d.ts.map +1 -1
  187. package/lib/sync/utils/pendingBlocksTree.js +0 -9
  188. package/lib/sync/utils/pendingBlocksTree.js.map +1 -1
  189. package/lib/util/sszBytes.d.ts.map +1 -1
  190. package/lib/util/sszBytes.js +8 -6
  191. package/lib/util/sszBytes.js.map +1 -1
  192. package/package.json +16 -16
  193. package/src/api/impl/beacon/blocks/index.ts +20 -4
  194. package/src/api/impl/beacon/pool/index.ts +83 -1
  195. package/src/api/impl/debug/index.ts +0 -1
  196. package/src/api/impl/validator/index.ts +82 -1
  197. package/src/chain/blocks/blockInput/blockInput.ts +4 -1
  198. package/src/chain/blocks/importBlock.ts +16 -50
  199. package/src/chain/blocks/importExecutionPayload.ts +51 -20
  200. package/src/chain/blocks/index.ts +32 -15
  201. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +37 -3
  202. package/src/chain/blocks/payloadEnvelopeInput/types.ts +18 -0
  203. package/src/chain/blocks/types.ts +2 -1
  204. package/src/chain/blocks/utils/chainSegment.ts +8 -0
  205. package/src/chain/blocks/verifyBlock.ts +45 -13
  206. package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +6 -4
  207. package/src/chain/blocks/verifyBlocksSanityChecks.ts +26 -7
  208. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +16 -8
  209. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +7 -4
  210. package/src/chain/chain.ts +32 -7
  211. package/src/chain/emitter.ts +0 -11
  212. package/src/chain/errors/index.ts +1 -0
  213. package/src/chain/errors/proposerPreferences.ts +47 -0
  214. package/src/chain/initState.ts +9 -1
  215. package/src/chain/interface.ts +2 -0
  216. package/src/chain/opPools/payloadAttestationPool.ts +29 -8
  217. package/src/chain/prepareNextSlot.ts +21 -29
  218. package/src/chain/produceBlock/produceBlockBody.ts +46 -22
  219. package/src/chain/regen/interface.ts +1 -0
  220. package/src/chain/regen/queued.ts +2 -7
  221. package/src/chain/regen/regen.ts +2 -7
  222. package/src/chain/seenCache/index.ts +1 -0
  223. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +90 -24
  224. package/src/chain/seenCache/seenProposerPreferences.ts +32 -0
  225. package/src/chain/validation/executionPayloadBid.ts +11 -8
  226. package/src/chain/validation/proposerPreferences.ts +110 -0
  227. package/src/metrics/metrics/lodestar.ts +4 -0
  228. package/src/network/gossip/interface.ts +6 -0
  229. package/src/network/gossip/scoringParameters.ts +14 -1
  230. package/src/network/gossip/topic.ts +6 -0
  231. package/src/network/interface.ts +1 -0
  232. package/src/network/network.ts +11 -0
  233. package/src/network/processor/gossipHandlers.ts +53 -17
  234. package/src/network/processor/gossipQueues/index.ts +5 -0
  235. package/src/network/processor/index.ts +6 -5
  236. package/src/node/nodejs.ts +2 -2
  237. package/src/node/notifier.ts +1 -8
  238. package/src/sync/constants.ts +4 -4
  239. package/src/sync/range/batch.ts +240 -42
  240. package/src/sync/range/chain.ts +77 -10
  241. package/src/sync/range/range.ts +16 -3
  242. package/src/sync/sync.ts +13 -1
  243. package/src/sync/types.ts +72 -0
  244. package/src/sync/unknownBlock.ts +928 -65
  245. package/src/sync/utils/downloadByRange.ts +166 -44
  246. package/src/sync/utils/downloadByRoot.ts +24 -2
  247. package/src/sync/utils/pendingBlocksTree.ts +0 -15
  248. package/src/util/sszBytes.ts +8 -6
@@ -4,7 +4,13 @@ import {toRootHex, withTimeout} from "@lodestar/utils";
4
4
  import {VersionedHashes} from "../../../execution/index.js";
5
5
  import {kzgCommitmentToVersionedHash} from "../../../util/blobs.js";
6
6
  import {MissingColumnMeta} from "../blockInput/types.js";
7
- import {AddPayloadEnvelopeProps, ColumnWithSource, CreateFromBlockProps, SourceMeta} from "./types.js";
7
+ import {
8
+ AddPayloadEnvelopeProps,
9
+ ColumnWithSource,
10
+ CreateFromBidProps,
11
+ CreateFromBlockProps,
12
+ SourceMeta,
13
+ } from "./types.js";
8
14
 
9
15
  export type PayloadEnvelopeInputState =
10
16
  | {
@@ -64,6 +70,7 @@ export class PayloadEnvelopeInput {
64
70
  readonly proposerIndex: ValidatorIndex;
65
71
  readonly bid: gloas.ExecutionPayloadBid;
66
72
  readonly versionedHashes: VersionedHashes;
73
+ readonly daOutOfRange: boolean;
67
74
 
68
75
  private columnsCache = new Map<ColumnIndex, ColumnWithSource>();
69
76
 
@@ -87,6 +94,7 @@ export class PayloadEnvelopeInput {
87
94
  sampledColumns: ColumnIndex[];
88
95
  custodyColumns: ColumnIndex[];
89
96
  timeCreatedSec: number;
97
+ daOutOfRange: boolean;
90
98
  }) {
91
99
  this.blockRootHex = props.blockRootHex;
92
100
  this.slot = props.slot;
@@ -97,13 +105,14 @@ export class PayloadEnvelopeInput {
97
105
  this.sampledColumns = props.sampledColumns;
98
106
  this.custodyColumns = props.custodyColumns;
99
107
  this.timeCreatedSec = props.timeCreatedSec;
108
+ this.daOutOfRange = props.daOutOfRange;
100
109
  this.payloadEnvelopeDataPromise = createPromise();
101
110
  this.allDataPromise = createPromise();
102
111
  this.columnsDataPromise = createPromise();
103
112
 
104
113
  const noBlobs = props.bid.blobKzgCommitments.length === 0;
105
114
  const noSampledColumns = props.sampledColumns.length === 0;
106
- const hasAllData = noBlobs || noSampledColumns;
115
+ const hasAllData = props.daOutOfRange || noBlobs || noSampledColumns;
107
116
 
108
117
  if (hasAllData) {
109
118
  this.state = {hasPayload: false, hasAllData: true, hasComputedAllData: true};
@@ -125,6 +134,27 @@ export class PayloadEnvelopeInput {
125
134
  sampledColumns: props.sampledColumns,
126
135
  custodyColumns: props.custodyColumns,
127
136
  timeCreatedSec: props.timeCreatedSec,
137
+ daOutOfRange: props.daOutOfRange,
138
+ });
139
+ }
140
+
141
+ /**
142
+ * Create a `PayloadEnvelopeInput` from a state's `latestExecutionPayloadBid` (the bid
143
+ * recorded in beacon state for the latest imported block). Used when seeding the cache
144
+ * for a checkpoint anchor block — we have the bid via state but not the full
145
+ * SignedBeaconBlock body.
146
+ */
147
+ static createFromBid(props: CreateFromBidProps): PayloadEnvelopeInput {
148
+ return new PayloadEnvelopeInput({
149
+ blockRootHex: props.blockRootHex,
150
+ slot: props.slot,
151
+ forkName: props.forkName,
152
+ proposerIndex: props.proposerIndex,
153
+ bid: props.bid,
154
+ sampledColumns: props.sampledColumns,
155
+ custodyColumns: props.custodyColumns,
156
+ timeCreatedSec: props.timeCreatedSec,
157
+ daOutOfRange: props.daOutOfRange,
128
158
  });
129
159
  }
130
160
 
@@ -152,6 +182,7 @@ export class PayloadEnvelopeInput {
152
182
  throw new Error("Payload envelope beacon_block_root mismatch");
153
183
  }
154
184
 
185
+ // TODO GLOAS: track source by metrics, maybe inside the seen cache
155
186
  const source: SourceMeta = {
156
187
  source: props.source,
157
188
  seenTimestampSec: props.seenTimestampSec,
@@ -306,8 +337,11 @@ export class PayloadEnvelopeInput {
306
337
  return this.state.hasAllData;
307
338
  }
308
339
 
340
+ /**
341
+ * Strictly checks missing sampled columns. Does NOT short-circuit on `state.hasAllData`.
342
+ */
309
343
  getMissingSampledColumnMeta(): MissingColumnMeta {
310
- if (this.state.hasAllData) {
344
+ if (this.state.hasComputedAllData) {
311
345
  return {missing: [], versionedHashes: this.versionedHashes};
312
346
  }
313
347
 
@@ -27,6 +27,24 @@ export type CreateFromBlockProps = {
27
27
  sampledColumns: ColumnIndex[];
28
28
  custodyColumns: ColumnIndex[];
29
29
  timeCreatedSec: number;
30
+ daOutOfRange: boolean;
31
+ };
32
+
33
+ /**
34
+ * Used to seed an entry from a state's `latestExecutionPayloadBid` (e.g., when initializing
35
+ * the chain from a checkpoint anchor state — we have the bid via the state but not the
36
+ * full SignedBeaconBlock).
37
+ */
38
+ export type CreateFromBidProps = {
39
+ blockRootHex: RootHex;
40
+ slot: number;
41
+ forkName: ForkName;
42
+ proposerIndex: number;
43
+ bid: gloas.ExecutionPayloadBid;
44
+ sampledColumns: ColumnIndex[];
45
+ custodyColumns: ColumnIndex[];
46
+ timeCreatedSec: number;
47
+ daOutOfRange: boolean;
30
48
  };
31
49
 
32
50
  export type AddPayloadEnvelopeProps = SourceMeta & {
@@ -94,7 +94,8 @@ export type ImportBlockOpts = {
94
94
  *
95
95
  * `executionStatus` reflects the outcome of execution payload verification at block-import time:
96
96
  * - pre-gloas: Valid | Syncing | PreMerge (from EL notifyNewPayload against the in-block payload)
97
- * - post-gloas: PayloadSeparated (payload arrives separately as an envelope and is imported later)
97
+ * - post-gloas: inherited from parent's chain (Valid/Syncing) by importBlock; payload arrives
98
+ * separately as an envelope and creates the FULL variant later via onExecutionPayload
98
99
  */
99
100
  export type FullyVerifiedBlock = {
100
101
  blockInput: IBlockInput;
@@ -41,6 +41,14 @@ export function assertLinearChainSegment(
41
41
  // - EMPTY variant (no envelope for slot): execution hash is unchanged
42
42
  // null only for pre-merge parents, which cannot precede gloas blocks.
43
43
  let currentExecHash: string | null = parentBlock.executionPayloadBlockHash;
44
+ // Checkpoint sync first batch: parent is the anchor PENDING whose executionPayloadBlockHash
45
+ // is the inherited parentBlockHash semantic (= grandparent's payload), not its own payload.
46
+ // If parent's own payload envelope arrives in this batch, advance currentExecHash to that
47
+ // payload's blockHash so the segment validation sees the true EL chain head.
48
+ const parentPayloadInput = payloadEnvelopes?.get(parentBlock.slot);
49
+ if (parentPayloadInput?.hasPayloadEnvelope()) {
50
+ currentExecHash = parentPayloadInput.getBlockHashHex();
51
+ }
44
52
  // Track the execution hash before the last FULL advancement so we can recover
45
53
  // if the next block reveals that envelope was orphaned.
46
54
  let prevExecHash: string | null = currentExecHash;
@@ -41,7 +41,8 @@ export async function verifyBlocksInEpoch(
41
41
  postStates: IBeaconStateView[];
42
42
  proposerBalanceDeltas: number[];
43
43
  segmentExecStatus: SegmentExecStatus;
44
- dataAvailabilityStatuses: DataAvailabilityStatus[];
44
+ blockDAStatuses: DataAvailabilityStatus[];
45
+ payloadDAStatuses: Map<Slot, DataAvailabilityStatus>;
45
46
  indexedAttestationsByBlock: IndexedAttestation[][];
46
47
  }> {
47
48
  const blocks = blockInputs.map((blockInput) => blockInput.getBlock());
@@ -116,28 +117,52 @@ export async function verifyBlocksInEpoch(
116
117
 
117
118
  // Pick the data-availability source by fork:
118
119
  // - Pre-Gloas: blob/Fulu-column data lives in IBlockInput → verifyBlocksDataAvailability.
119
- // - Post-Gloas: verifyPayloadsDataAvailability
120
- const daAvailabilityPromise =
120
+ // - Post-Gloas: verifyPayloadsDataAvailability (payload-level DA, keyed by slot).
121
+ const daAvailabilityPromise: Promise<{
122
+ blockDAStatuses: DataAvailabilityStatus[];
123
+ payloadDAStatuses: Map<Slot, DataAvailabilityStatus>;
124
+ availableTime: number;
125
+ }> =
121
126
  fork >= ForkSeq.gloas
122
127
  ? (async () => {
123
- const payloadInputsForDa: PayloadEnvelopeInput[] = [];
124
- for (const input of blockInputs) {
125
- const pi = payloadEnvelopes?.get(input.slot);
126
- if (pi !== undefined) payloadInputsForDa.push(pi);
128
+ // Validate DA for ALL payloads in the Map, not just those paired with blockInputs.
129
+ // A checkpoint-sync batch may include a payload for a slot whose block was filtered
130
+ // out of relevantBlocks (e.g., the anchor at the finalized slot); that payload still
131
+ // needs DA validation so it can be imported in processBlocks.
132
+ const payloadInputsForDa: PayloadEnvelopeInput[] =
133
+ payloadEnvelopes !== null ? Array.from(payloadEnvelopes.values()) : [];
134
+ const {dataAvailabilityStatuses, availableTime} = await verifyPayloadsDataAvailability(
135
+ payloadInputsForDa,
136
+ abortController.signal
137
+ );
138
+
139
+ const payloadDAStatuses = new Map<Slot, DataAvailabilityStatus>();
140
+ for (let i = 0; i < payloadInputsForDa.length; i++) {
141
+ payloadDAStatuses.set(payloadInputsForDa[i].slot, dataAvailabilityStatuses[i]);
127
142
  }
128
- await verifyPayloadsDataAvailability(payloadInputsForDa, abortController.signal);
129
143
  return {
130
144
  // post-gloas, DataAvailabilityStatus is NotRequired for forkChoice.onBlock() ProtoBlock
131
- dataAvailabilityStatuses: blockInputs.map(() => DataAvailabilityStatus.NotRequired),
132
- availableTime: Date.now(),
145
+ blockDAStatuses: blockInputs.map(() => DataAvailabilityStatus.NotRequired),
146
+ payloadDAStatuses,
147
+ availableTime,
133
148
  };
134
149
  })()
135
- : verifyBlocksDataAvailability(blockInputs, abortController.signal);
150
+ : (async () => {
151
+ const {dataAvailabilityStatuses, availableTime} = await verifyBlocksDataAvailability(
152
+ blockInputs,
153
+ abortController.signal
154
+ );
155
+ return {
156
+ blockDAStatuses: dataAvailabilityStatuses,
157
+ payloadDAStatuses: new Map<Slot, DataAvailabilityStatus>(),
158
+ availableTime,
159
+ };
160
+ })();
136
161
 
137
162
  // batch all I/O operations to reduce overhead
138
163
  const [
139
164
  segmentExecStatus,
140
- {dataAvailabilityStatuses, availableTime},
165
+ {blockDAStatuses, payloadDAStatuses, availableTime},
141
166
  {postStates, proposerBalanceDeltas, verifyStateTime},
142
167
  {verifySignaturesTime},
143
168
  ] = await Promise.all([
@@ -258,7 +283,14 @@ export async function verifyBlocksInEpoch(
258
283
  );
259
284
  }
260
285
 
261
- return {postStates, dataAvailabilityStatuses, proposerBalanceDeltas, segmentExecStatus, indexedAttestationsByBlock};
286
+ return {
287
+ postStates,
288
+ blockDAStatuses,
289
+ payloadDAStatuses,
290
+ proposerBalanceDeltas,
291
+ segmentExecStatus,
292
+ indexedAttestationsByBlock,
293
+ };
262
294
  } finally {
263
295
  abortController.abort();
264
296
  }
@@ -46,8 +46,7 @@ type VerifyBlockExecutionResponse =
46
46
  | VerifyExecutionErrorResponse
47
47
  | {executionStatus: ExecutionStatus.Valid; lvhResponse: LVHValidResponse; execError: null}
48
48
  | {executionStatus: ExecutionStatus.Syncing; lvhResponse?: LVHValidResponse; execError: null}
49
- | {executionStatus: ExecutionStatus.PreMerge; lvhResponse: undefined; execError: null}
50
- | {executionStatus: ExecutionStatus.PayloadSeparated; lvhResponse: undefined; execError: null};
49
+ | {executionStatus: ExecutionStatus.PreMerge; lvhResponse: undefined; execError: null};
51
50
 
52
51
  /**
53
52
  * Verifies 1 or more execution payloads from a linear sequence of blocks.
@@ -145,9 +144,10 @@ export async function verifyBlockExecutionPayload(
145
144
  ): Promise<VerifyBlockExecutionResponse> {
146
145
  const block = blockInput.getBlock();
147
146
 
148
- // Gloas block doesn't have execution payload. Return right away
147
+ // Gloas block doesn't have execution payload. Return Syncing as a placeholder; the actual
148
+ // status for gloas PENDING/EMPTY is derived from parent's chain in importBlock.
149
149
  if (isBlockInputNoData(blockInput)) {
150
- return {executionStatus: ExecutionStatus.PayloadSeparated, lvhResponse: undefined, execError: null};
150
+ return {executionStatus: ExecutionStatus.Syncing, lvhResponse: undefined, execError: null};
151
151
  }
152
152
 
153
153
  /** Not null if execution is enabled */
@@ -198,6 +198,7 @@ export async function verifyBlockExecutionPayload(
198
198
  executionStatus,
199
199
  latestValidExecHash: execResult.latestValidHash,
200
200
  invalidateFromParentBlockRoot: blockInput.parentRootHex,
201
+ invalidateFromParentBlockHash: toRootHex(executionPayloadEnabled.parentHash),
201
202
  };
202
203
  const execError = new BlockError(block, {
203
204
  code: BlockErrorCode.EXECUTION_ENGINE_ERROR,
@@ -281,6 +282,7 @@ function getSegmentErrorResponse(
281
282
  executionStatus: ExecutionStatus.Invalid,
282
283
  latestValidExecHash: lvhResponse.latestValidExecHash,
283
284
  invalidateFromParentBlockRoot: parentBlock.blockRoot,
285
+ invalidateFromParentBlockHash: parentBlock.executionPayloadBlockHash,
284
286
  };
285
287
  }
286
288
  }
@@ -7,6 +7,7 @@ import {IClock} from "../../util/clock.js";
7
7
  import {BlockError, BlockErrorCode} from "../errors/index.js";
8
8
  import {IChainOptions} from "../options.js";
9
9
  import {IBlockInput} from "./blockInput/types.js";
10
+ import {PayloadEnvelopeInput} from "./payloadEnvelopeInput/payloadEnvelopeInput.js";
10
11
  import {ImportBlockOpts} from "./types.js";
11
12
 
12
13
  /**
@@ -30,6 +31,7 @@ export function verifyBlocksSanityChecks(
30
31
  blacklistedBlocks: Map<RootHex, Slot | null>;
31
32
  },
32
33
  blocks: IBlockInput[],
34
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
33
35
  opts: ImportBlockOpts
34
36
  ): {
35
37
  relevantBlocks: IBlockInput[];
@@ -90,15 +92,32 @@ export function verifyBlocksSanityChecks(
90
92
  } else {
91
93
  // When importing a block segment, only the first NON-IGNORED block must be known to the fork-choice.
92
94
  const parentRoot = toRootHex(block.message.parentRoot);
93
- parentBlock = isGloasBeaconBlock(block.message)
94
- ? chain.forkChoice.getBlockHexAndBlockHash(
95
- parentRoot,
96
- toRootHex(block.message.body.signedExecutionPayloadBid.message.parentBlockHash)
97
- )
98
- : chain.forkChoice.getBlockHexDefaultStatus(parentRoot);
99
- if (!parentBlock) {
95
+ const parentBlockDefaultStatus = chain.forkChoice.getBlockHexDefaultStatus(parentRoot);
96
+ if (!parentBlockDefaultStatus) {
100
97
  throw new BlockError(block, {code: BlockErrorCode.PARENT_UNKNOWN, parentRoot});
101
98
  }
99
+
100
+ parentBlock = parentBlockDefaultStatus;
101
+ if (isGloasBeaconBlock(block.message)) {
102
+ const parentBlockHash = toRootHex(block.message.body.signedExecutionPayloadBid.message.parentBlockHash);
103
+ const parentBlockWithPayload = chain.forkChoice.getBlockHexAndBlockHash(parentRoot, parentBlockHash);
104
+ if (!parentBlockWithPayload) {
105
+ // Checkpoint sync: parent's FULL variant may not be in fork-choice yet because the
106
+ // anchor block is initialized with PENDING+EMPTY only. The parent's payload arrives
107
+ // in the same batch via payloadEnvelopes and will be imported by processBlocks. If
108
+ // a matching payload is in the Map, accept the parent as known.
109
+ const parentPayloadInput = payloadEnvelopes?.get(parentBlockDefaultStatus.slot);
110
+ if (parentPayloadInput?.getBlockHashHex() !== parentBlockHash) {
111
+ throw new BlockError(block, {
112
+ code: BlockErrorCode.PARENT_PAYLOAD_UNKNOWN,
113
+ parentRoot,
114
+ parentBlockHash,
115
+ });
116
+ }
117
+ } else {
118
+ parentBlock = parentBlockWithPayload;
119
+ }
120
+ }
102
121
  // Parent is known to the fork-choice
103
122
  parentBlockSlot = parentBlock.slot;
104
123
  }
@@ -20,7 +20,7 @@ export type VerifyExecutionPayloadEnvelopeOpts = {
20
20
  * performed outside this function, see `verifyExecutionPayloadEnvelopeSignature` and
21
21
  * `importExecutionPayload` which run both in parallel with this check.
22
22
  *
23
- * Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.5/specs/gloas/fork-choice.md#new-verify_execution_payload_envelope
23
+ * Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.6/specs/gloas/fork-choice.md#new-verify_execution_payload_envelope
24
24
  */
25
25
  export function verifyExecutionPayloadEnvelope(
26
26
  config: BeaconConfig,
@@ -32,8 +32,8 @@ export function verifyExecutionPayloadEnvelope(
32
32
  const payload = envelope.payload;
33
33
 
34
34
  // Verify consistency with the beacon block.
35
- // Compute header root on a copy of latestBlockHeader to avoid mutating state.
36
- const headerValue = {...state.latestBlockHeader};
35
+ // Compute header root on a clone of latestBlockHeader to avoid mutating state.
36
+ const headerValue = ssz.phase0.BeaconBlockHeader.clone(state.latestBlockHeader);
37
37
  if (byteArrayEquals(headerValue.stateRoot, ssz.Root.defaultValue())) {
38
38
  headerValue.stateRoot = state.hashTreeRoot();
39
39
  }
@@ -43,6 +43,11 @@ export function verifyExecutionPayloadEnvelope(
43
43
  `Envelope's block is not the latest block header envelope=${toRootHex(envelope.beaconBlockRoot)} latestBlockHeader=${toRootHex(headerRoot)}`
44
44
  );
45
45
  }
46
+ if (!byteArrayEquals(envelope.parentBeaconBlockRoot, state.latestBlockHeader.parentRoot)) {
47
+ throw new Error(
48
+ `Envelope's parent_beacon_block_root mismatch envelope=${toRootHex(envelope.parentBeaconBlockRoot)} state=${toRootHex(state.latestBlockHeader.parentRoot)}`
49
+ );
50
+ }
46
51
 
47
52
  // Verify consistency with the committed bid
48
53
  const bid = state.latestExecutionPayloadBid;
@@ -77,16 +82,19 @@ export function verifyExecutionPayloadEnvelope(
77
82
  }
78
83
  }
79
84
 
80
- // Verify the execution payload is valid
81
- if (payload.slotNumber !== state.slot) {
82
- throw new Error(`Slot mismatch between payload and state payload=${payload.slotNumber} state=${state.slot}`);
85
+ // should not use state.slot, it does not work for skipped slot checkpoint sync
86
+ const blockSlot = state.latestBlockHeader.slot;
87
+ if (payload.slotNumber !== blockSlot) {
88
+ throw new Error(
89
+ `Slot mismatch between payload and latest block header payload=${payload.slotNumber} latestBlockHeader=${blockSlot}`
90
+ );
83
91
  }
84
92
  if (!byteArrayEquals(payload.parentHash, state.latestBlockHash)) {
85
93
  throw new Error(
86
94
  `Parent hash mismatch between payload and state payload=${toRootHex(payload.parentHash)} state=${toRootHex(state.latestBlockHash)}`
87
95
  );
88
96
  }
89
- const expectedTimestamp = computeTimeAtSlot(config, state.slot, state.genesisTime);
97
+ const expectedTimestamp = computeTimeAtSlot(config, blockSlot, state.genesisTime);
90
98
  if (payload.timestamp !== expectedTimestamp) {
91
99
  throw new Error(
92
100
  `Timestamp mismatch between payload and state payload=${payload.timestamp} state=${expectedTimestamp}`
@@ -108,7 +116,7 @@ export function verifyExecutionPayloadEnvelope(
108
116
  /**
109
117
  * Verify the BLS signature of an execution payload envelope.
110
118
  *
111
- * Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.5/specs/gloas/fork-choice.md#new-verify_execution_payload_envelope_signature
119
+ * Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.6/specs/gloas/fork-choice.md#new-verify_execution_payload_envelope_signature
112
120
  */
113
121
  export async function verifyExecutionPayloadEnvelopeSignature(
114
122
  config: BeaconConfig,
@@ -28,11 +28,14 @@ export async function verifyPayloadsDataAvailability(
28
28
  await Promise.all(promises);
29
29
 
30
30
  const availableTime = Math.max(0, Math.max(...payloadInputs.map((payloadInput) => payloadInput.getTimeComplete())));
31
- const dataAvailabilityStatuses: DataAvailabilityStatus[] = payloadInputs.map((payloadInput) =>
32
- payloadInput.getBlobKzgCommitments().length === 0
31
+ const dataAvailabilityStatuses: DataAvailabilityStatus[] = payloadInputs.map((payloadInput) => {
32
+ if (payloadInput.daOutOfRange) {
33
+ return DataAvailabilityStatus.OutOfRange;
34
+ }
35
+ return payloadInput.getBlobKzgCommitments().length === 0
33
36
  ? DataAvailabilityStatus.NotRequired
34
- : DataAvailabilityStatus.Available
35
- );
37
+ : DataAvailabilityStatus.Available;
38
+ });
36
39
 
37
40
  return {dataAvailabilityStatuses, availableTime};
38
41
  }
@@ -23,6 +23,7 @@ import {
23
23
  getEffectiveBalancesFromStateBytes,
24
24
  isStatePostAltair,
25
25
  isStatePostElectra,
26
+ isStatePostGloas,
26
27
  } from "@lodestar/state-transition";
27
28
  import {
28
29
  BeaconBlock,
@@ -106,6 +107,7 @@ import {
106
107
  SeenExecutionPayloadBids,
107
108
  SeenPayloadAttesters,
108
109
  SeenPayloadEnvelopeInput,
110
+ SeenProposerPreferences,
109
111
  SeenSyncCommitteeMessages,
110
112
  } from "./seenCache/index.js";
111
113
  import {SeenAggregatedAttestations} from "./seenCache/seenAggregateAndProof.js";
@@ -186,6 +188,7 @@ export class BeaconChain implements IBeaconChain {
186
188
  readonly seenPayloadAttesters = new SeenPayloadAttesters();
187
189
  readonly seenAggregatedAttestations: SeenAggregatedAttestations;
188
190
  readonly seenExecutionPayloadBids = new SeenExecutionPayloadBids();
191
+ readonly seenProposerPreferences = new SeenProposerPreferences();
189
192
  readonly seenBlockProposers = new SeenBlockProposers();
190
193
  readonly seenSyncCommitteeMessages = new SeenSyncCommitteeMessages();
191
194
  readonly seenContributionAndProof: SeenContributionAndProof;
@@ -333,13 +336,6 @@ export class BeaconChain implements IBeaconChain {
333
336
  metrics,
334
337
  logger,
335
338
  });
336
- this.seenPayloadEnvelopeInputCache = new SeenPayloadEnvelopeInput({
337
- chainEvents: emitter,
338
- signal,
339
- serializedCache: this.serializedCache,
340
- metrics,
341
- logger,
342
- });
343
339
 
344
340
  this._earliestAvailableSlot = anchorState.slot;
345
341
 
@@ -395,6 +391,7 @@ export class BeaconChain implements IBeaconChain {
395
391
  metrics,
396
392
  logger
397
393
  );
394
+
398
395
  const regen = new QueuedStateRegenerator({
399
396
  config,
400
397
  forkChoice,
@@ -419,6 +416,33 @@ export class BeaconChain implements IBeaconChain {
419
416
  this.payloadEnvelopeProcessor = new PayloadEnvelopeProcessor(this, metrics, signal);
420
417
 
421
418
  this.forkChoice = forkChoice;
419
+
420
+ this.seenPayloadEnvelopeInputCache = new SeenPayloadEnvelopeInput({
421
+ config,
422
+ clock,
423
+ forkChoice,
424
+ chainEvents: emitter,
425
+ signal,
426
+ serializedCache: this.serializedCache,
427
+ metrics,
428
+ logger,
429
+ });
430
+
431
+ const anchorBlockSlot = anchorState.latestBlockHeader.slot;
432
+ if (isStatePostGloas(anchorState) && anchorBlockSlot > 0) {
433
+ const anchorBid = anchorState.latestExecutionPayloadBid;
434
+ this.seenPayloadEnvelopeInputCache.addFromBid({
435
+ blockRootHex: toRootHex(checkpoint.root),
436
+ slot: anchorBlockSlot,
437
+ forkName: anchorState.forkName,
438
+ proposerIndex: anchorState.latestBlockHeader.proposerIndex,
439
+ bid: anchorBid,
440
+ sampledColumns: this.custodyConfig.sampledColumns,
441
+ custodyColumns: this.custodyConfig.custodyColumns,
442
+ timeCreatedSec: Math.floor(Date.now() / 1000),
443
+ });
444
+ }
445
+
422
446
  this.clock = clock;
423
447
  this.regen = regen;
424
448
  this.bls = bls;
@@ -1437,6 +1461,7 @@ export class BeaconChain implements IBeaconChain {
1437
1461
  this.payloadAttestationPool.prune(slot);
1438
1462
  this.executionPayloadBidPool.prune(slot);
1439
1463
  this.seenExecutionPayloadBids.prune(slot);
1464
+ this.seenProposerPreferences.prune(slot);
1440
1465
  this.seenAttestationDatas.onSlot(slot);
1441
1466
  this.reprocessController.onSlot(slot);
1442
1467
 
@@ -4,7 +4,6 @@ import {routes} from "@lodestar/api";
4
4
  import {CheckpointWithHex} from "@lodestar/fork-choice";
5
5
  import {IBeaconStateView} from "@lodestar/state-transition";
6
6
  import {DataColumnSidecar, RootHex, deneb, phase0} from "@lodestar/types";
7
- import {SignedExecutionPayloadEnvelope} from "@lodestar/types/gloas";
8
7
  import {PeerIdStr} from "../util/peerId.js";
9
8
  import {BlockInputSource, IBlockInput} from "./blocks/blockInput/types.js";
10
9
  import {PayloadEnvelopeInput} from "./blocks/payloadEnvelopeInput/payloadEnvelopeInput.js";
@@ -60,10 +59,6 @@ export enum ChainEvent {
60
59
  * Post-gloas, missing parent could be a SignedBeaconBlock and/or a SignedExecutionPayloadEnvelope
61
60
  */
62
61
  blockUnknownParent = "blockUnknownParent",
63
- /**
64
- * Trigger BlockInputSync to find a SignedBeaconBlock given a SignedExecutionPayloadEnvelop received
65
- */
66
- envelopeUnknownBlock = "envelopeUnknownBlock",
67
62
  /**
68
63
  * Trigger BlockInputSync to find a SignedBeaconBlock with specified block root.
69
64
  */
@@ -92,11 +87,6 @@ type ApiEvents = {[K in routes.events.EventType]: (data: routes.events.EventData
92
87
 
93
88
  export type ChainEventData = {
94
89
  [ChainEvent.blockUnknownParent]: {blockInput: IBlockInput; peer: PeerIdStr; source: BlockInputSource};
95
- [ChainEvent.envelopeUnknownBlock]: {
96
- envelope: SignedExecutionPayloadEnvelope;
97
- peer?: PeerIdStr;
98
- source: BlockInputSource;
99
- };
100
90
  [ChainEvent.unknownBlockRoot]: {rootHex: RootHex; peer?: PeerIdStr; source: BlockInputSource};
101
91
  [ChainEvent.incompleteBlockInput]: {blockInput: IBlockInput; peer: PeerIdStr; source: BlockInputSource};
102
92
  [ChainEvent.incompletePayloadEnvelope]: {
@@ -124,7 +114,6 @@ export type IChainEvents = ApiEvents & {
124
114
  // Sync events that are chain->chain. Initiated from network requests but do not cross the network
125
115
  // barrier so are considered ChainEvent(s).
126
116
  [ChainEvent.blockUnknownParent]: (data: ChainEventData[ChainEvent.blockUnknownParent]) => void;
127
- [ChainEvent.envelopeUnknownBlock]: (data: ChainEventData[ChainEvent.envelopeUnknownBlock]) => void;
128
117
  [ChainEvent.unknownBlockRoot]: (data: ChainEventData[ChainEvent.unknownBlockRoot]) => void;
129
118
  [ChainEvent.incompleteBlockInput]: (data: ChainEventData[ChainEvent.incompleteBlockInput]) => void;
130
119
  [ChainEvent.incompletePayloadEnvelope]: (data: ChainEventData[ChainEvent.incompletePayloadEnvelope]) => void;
@@ -8,6 +8,7 @@ export * from "./executionPayloadBid.js";
8
8
  export * from "./executionPayloadEnvelope.js";
9
9
  export * from "./gossipValidation.js";
10
10
  export * from "./payloadAttestation.js";
11
+ export * from "./proposerPreferences.js";
11
12
  export * from "./proposerSlashingError.js";
12
13
  export * from "./syncCommitteeError.js";
13
14
  export * from "./voluntaryExitError.js";
@@ -0,0 +1,47 @@
1
+ import {RootHex, Slot, ValidatorIndex} from "@lodestar/types";
2
+ import {GossipActionError} from "./gossipValidation.js";
3
+
4
+ export enum ProposerPreferencesErrorCode {
5
+ INVALID_EPOCH = "PROPOSER_PREFERENCES_ERROR_INVALID_EPOCH",
6
+ PROPOSAL_SLOT_PASSED = "PROPOSER_PREFERENCES_ERROR_PROPOSAL_SLOT_PASSED",
7
+ UNKNOWN_DEPENDENT_ROOT = "PROPOSER_PREFERENCES_ERROR_UNKNOWN_DEPENDENT_ROOT",
8
+ INVALID_PROPOSER = "PROPOSER_PREFERENCES_ERROR_INVALID_PROPOSER",
9
+ ALREADY_KNOWN = "PROPOSER_PREFERENCES_ERROR_ALREADY_KNOWN",
10
+ INVALID_SIGNATURE = "PROPOSER_PREFERENCES_ERROR_INVALID_SIGNATURE",
11
+ }
12
+
13
+ export type ProposerPreferencesErrorType =
14
+ | {
15
+ code: ProposerPreferencesErrorCode.INVALID_EPOCH;
16
+ proposalSlot: Slot;
17
+ currentEpoch: number;
18
+ }
19
+ | {
20
+ code: ProposerPreferencesErrorCode.PROPOSAL_SLOT_PASSED;
21
+ proposalSlot: Slot;
22
+ currentSlot: Slot;
23
+ }
24
+ | {
25
+ code: ProposerPreferencesErrorCode.UNKNOWN_DEPENDENT_ROOT;
26
+ proposalSlot: Slot;
27
+ dependentRoot: RootHex;
28
+ }
29
+ | {
30
+ code: ProposerPreferencesErrorCode.INVALID_PROPOSER;
31
+ proposalSlot: Slot;
32
+ validatorIndex: ValidatorIndex;
33
+ dependentRoot: RootHex;
34
+ }
35
+ | {
36
+ code: ProposerPreferencesErrorCode.ALREADY_KNOWN;
37
+ proposalSlot: Slot;
38
+ validatorIndex: ValidatorIndex;
39
+ dependentRoot: RootHex;
40
+ }
41
+ | {
42
+ code: ProposerPreferencesErrorCode.INVALID_SIGNATURE;
43
+ proposalSlot: Slot;
44
+ validatorIndex: ValidatorIndex;
45
+ };
46
+
47
+ export class ProposerPreferencesError extends GossipActionError<ProposerPreferencesErrorType> {}
@@ -1,7 +1,8 @@
1
1
  import {ChainForkConfig} from "@lodestar/config";
2
- import {ZERO_HASH} from "@lodestar/params";
2
+ import {ForkPostGloas, ForkSeq, ZERO_HASH} from "@lodestar/params";
3
3
  import {
4
4
  BeaconStateAllForks,
5
+ BeaconStateGloas,
5
6
  IBeaconStateView,
6
7
  computeEpochAtSlot,
7
8
  computeStartSlotAtEpoch,
@@ -52,6 +53,13 @@ export function createGenesisBlock(config: ChainForkConfig, genesisState: Beacon
52
53
  const genesisBlock = types.SignedBeaconBlock.defaultValue();
53
54
  const stateRoot = genesisState.hashTreeRoot();
54
55
  genesisBlock.message.stateRoot = stateRoot;
56
+
57
+ if (config.getForkSeq(GENESIS_SLOT) >= ForkSeq.gloas) {
58
+ const gloasBlock = genesisBlock as SignedBeaconBlock<ForkPostGloas>;
59
+ const gloasState = genesisState as BeaconStateGloas;
60
+ gloasBlock.message.body.signedExecutionPayloadBid.message = gloasState.latestExecutionPayloadBid.toValue();
61
+ }
62
+
55
63
  return genesisBlock;
56
64
  }
57
65
 
@@ -61,6 +61,7 @@ import {
61
61
  SeenContributionAndProof,
62
62
  SeenExecutionPayloadBids,
63
63
  SeenPayloadAttesters,
64
+ SeenProposerPreferences,
64
65
  SeenSyncCommitteeMessages,
65
66
  } from "./seenCache/index.js";
66
67
  import {SeenAggregatedAttestations} from "./seenCache/seenAggregateAndProof.js";
@@ -131,6 +132,7 @@ export interface IBeaconChain {
131
132
  readonly seenPayloadAttesters: SeenPayloadAttesters;
132
133
  readonly seenAggregatedAttestations: SeenAggregatedAttestations;
133
134
  readonly seenExecutionPayloadBids: SeenExecutionPayloadBids;
135
+ readonly seenProposerPreferences: SeenProposerPreferences;
134
136
  readonly seenBlockProposers: SeenBlockProposers;
135
137
  readonly seenSyncCommitteeMessages: SeenSyncCommitteeMessages;
136
138
  readonly seenContributionAndProof: SeenContributionAndProof;