@lodestar/beacon-node 1.42.0-dev.efc1ab8e31 → 1.42.0-dev.f866249fa3

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 (247) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +11 -11
  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 +4 -0
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/beacon/state/index.d.ts.map +1 -1
  8. package/lib/api/impl/beacon/state/index.js +13 -10
  9. package/lib/api/impl/beacon/state/index.js.map +1 -1
  10. package/lib/api/impl/debug/index.js.map +1 -1
  11. package/lib/api/impl/lodestar/index.d.ts.map +1 -1
  12. package/lib/api/impl/lodestar/index.js +4 -0
  13. package/lib/api/impl/lodestar/index.js.map +1 -1
  14. package/lib/api/impl/validator/index.d.ts.map +1 -1
  15. package/lib/api/impl/validator/index.js +7 -1
  16. package/lib/api/impl/validator/index.js.map +1 -1
  17. package/lib/chain/ColumnReconstructionTracker.d.ts +2 -1
  18. package/lib/chain/ColumnReconstructionTracker.d.ts.map +1 -1
  19. package/lib/chain/ColumnReconstructionTracker.js +5 -5
  20. package/lib/chain/ColumnReconstructionTracker.js.map +1 -1
  21. package/lib/chain/GetBlobsTracker.d.ts +2 -1
  22. package/lib/chain/GetBlobsTracker.d.ts.map +1 -1
  23. package/lib/chain/GetBlobsTracker.js +14 -12
  24. package/lib/chain/GetBlobsTracker.js.map +1 -1
  25. package/lib/chain/blocks/blockInput/blockInput.d.ts +5 -5
  26. package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
  27. package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
  28. package/lib/chain/blocks/blockInput/types.d.ts +4 -4
  29. package/lib/chain/blocks/blockInput/types.d.ts.map +1 -1
  30. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  31. package/lib/chain/blocks/importBlock.js +19 -5
  32. package/lib/chain/blocks/importBlock.js.map +1 -1
  33. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  34. package/lib/chain/blocks/importExecutionPayload.js +7 -1
  35. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  36. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +14 -6
  37. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  38. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +33 -2
  39. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  40. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +2 -1
  41. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  42. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
  43. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +3 -2
  44. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
  45. package/lib/chain/blocks/verifyBlocksSignatures.d.ts.map +1 -1
  46. package/lib/chain/blocks/verifyBlocksSignatures.js +4 -2
  47. package/lib/chain/blocks/verifyBlocksSignatures.js.map +1 -1
  48. package/lib/chain/chain.d.ts +3 -2
  49. package/lib/chain/chain.d.ts.map +1 -1
  50. package/lib/chain/chain.js +64 -24
  51. package/lib/chain/chain.js.map +1 -1
  52. package/lib/chain/emitter.d.ts +29 -7
  53. package/lib/chain/emitter.d.ts.map +1 -1
  54. package/lib/chain/emitter.js +12 -3
  55. package/lib/chain/emitter.js.map +1 -1
  56. package/lib/chain/errors/dataColumnSidecarError.d.ts +31 -1
  57. package/lib/chain/errors/dataColumnSidecarError.d.ts.map +1 -1
  58. package/lib/chain/errors/dataColumnSidecarError.js +7 -0
  59. package/lib/chain/errors/dataColumnSidecarError.js.map +1 -1
  60. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  61. package/lib/chain/forkChoice/index.js +10 -8
  62. package/lib/chain/forkChoice/index.js.map +1 -1
  63. package/lib/chain/interface.d.ts +4 -2
  64. package/lib/chain/interface.d.ts.map +1 -1
  65. package/lib/chain/lightClient/index.d.ts +2 -2
  66. package/lib/chain/lightClient/index.d.ts.map +1 -1
  67. package/lib/chain/lightClient/index.js.map +1 -1
  68. package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
  69. package/lib/chain/opPools/aggregatedAttestationPool.js +5 -2
  70. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  71. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  72. package/lib/chain/prepareNextSlot.js +7 -1
  73. package/lib/chain/prepareNextSlot.js.map +1 -1
  74. package/lib/chain/produceBlock/computeNewStateRoot.d.ts +2 -2
  75. package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
  76. package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
  77. package/lib/chain/produceBlock/produceBlockBody.d.ts +3 -3
  78. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  79. package/lib/chain/produceBlock/produceBlockBody.js +10 -1
  80. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  81. package/lib/chain/seenCache/seenGossipBlockInput.d.ts +1 -1
  82. package/lib/chain/seenCache/seenGossipBlockInput.d.ts.map +1 -1
  83. package/lib/chain/seenCache/seenGossipBlockInput.js +2 -2
  84. package/lib/chain/seenCache/seenGossipBlockInput.js.map +1 -1
  85. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +1 -1
  86. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  87. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +2 -2
  88. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  89. package/lib/chain/validation/block.d.ts.map +1 -1
  90. package/lib/chain/validation/block.js +2 -2
  91. package/lib/chain/validation/block.js.map +1 -1
  92. package/lib/chain/validation/dataColumnSidecar.d.ts +11 -4
  93. package/lib/chain/validation/dataColumnSidecar.d.ts.map +1 -1
  94. package/lib/chain/validation/dataColumnSidecar.js +184 -5
  95. package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
  96. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  97. package/lib/chain/validation/executionPayloadBid.js +4 -1
  98. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  99. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
  100. package/lib/chain/validation/executionPayloadEnvelope.js +4 -1
  101. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  102. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  103. package/lib/chain/validation/payloadAttestationMessage.js +4 -1
  104. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  105. package/lib/chain/validation/syncCommittee.d.ts.map +1 -1
  106. package/lib/chain/validation/syncCommittee.js +4 -0
  107. package/lib/chain/validation/syncCommittee.js.map +1 -1
  108. package/lib/chain/validation/syncCommitteeContributionAndProof.js +4 -1
  109. package/lib/chain/validation/syncCommitteeContributionAndProof.js.map +1 -1
  110. package/lib/chain/validatorMonitor.d.ts.map +1 -1
  111. package/lib/chain/validatorMonitor.js +3 -3
  112. package/lib/chain/validatorMonitor.js.map +1 -1
  113. package/lib/db/buckets.d.ts +2 -2
  114. package/lib/db/buckets.d.ts.map +1 -1
  115. package/lib/db/buckets.js +2 -2
  116. package/lib/db/buckets.js.map +1 -1
  117. package/lib/db/repositories/blockArchiveIndex.d.ts +2 -2
  118. package/lib/db/repositories/blockArchiveIndex.d.ts.map +1 -1
  119. package/lib/db/repositories/dataColumnSidecar.d.ts.map +1 -1
  120. package/lib/db/repositories/dataColumnSidecar.js +4 -2
  121. package/lib/db/repositories/dataColumnSidecar.js.map +1 -1
  122. package/lib/db/repositories/dataColumnSidecarArchive.d.ts.map +1 -1
  123. package/lib/db/repositories/dataColumnSidecarArchive.js +4 -2
  124. package/lib/db/repositories/dataColumnSidecarArchive.js.map +1 -1
  125. package/lib/metrics/metrics/lodestar.d.ts +20 -0
  126. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  127. package/lib/metrics/metrics/lodestar.js +33 -0
  128. package/lib/metrics/metrics/lodestar.js.map +1 -1
  129. package/lib/network/gossip/topic.d.ts +727 -0
  130. package/lib/network/gossip/topic.d.ts.map +1 -1
  131. package/lib/network/interface.d.ts +3 -2
  132. package/lib/network/interface.d.ts.map +1 -1
  133. package/lib/network/libp2p/index.d.ts.map +1 -1
  134. package/lib/network/libp2p/index.js +19 -13
  135. package/lib/network/libp2p/index.js.map +1 -1
  136. package/lib/network/network.d.ts +3 -2
  137. package/lib/network/network.d.ts.map +1 -1
  138. package/lib/network/network.js +3 -0
  139. package/lib/network/network.js.map +1 -1
  140. package/lib/network/options.d.ts.map +1 -1
  141. package/lib/network/options.js +7 -2
  142. package/lib/network/options.js.map +1 -1
  143. package/lib/network/processor/extractSlotRootFns.d.ts +1 -1
  144. package/lib/network/processor/extractSlotRootFns.d.ts.map +1 -1
  145. package/lib/network/processor/extractSlotRootFns.js +25 -5
  146. package/lib/network/processor/extractSlotRootFns.js.map +1 -1
  147. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  148. package/lib/network/processor/gossipHandlers.js +242 -66
  149. package/lib/network/processor/gossipHandlers.js.map +1 -1
  150. package/lib/network/processor/index.d.ts +11 -1
  151. package/lib/network/processor/index.d.ts.map +1 -1
  152. package/lib/network/processor/index.js +234 -22
  153. package/lib/network/processor/index.js.map +1 -1
  154. package/lib/network/reqresp/types.d.ts +3 -3
  155. package/lib/network/reqresp/types.d.ts.map +1 -1
  156. package/lib/network/reqresp/types.js +9 -3
  157. package/lib/network/reqresp/types.js.map +1 -1
  158. package/lib/node/nodejs.d.ts.map +1 -1
  159. package/lib/node/nodejs.js +4 -1
  160. package/lib/node/nodejs.js.map +1 -1
  161. package/lib/node/notifier.d.ts.map +1 -1
  162. package/lib/node/notifier.js +2 -2
  163. package/lib/node/notifier.js.map +1 -1
  164. package/lib/sync/unknownBlock.js +2 -2
  165. package/lib/sync/unknownBlock.js.map +1 -1
  166. package/lib/sync/utils/downloadByRange.d.ts +3 -3
  167. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  168. package/lib/sync/utils/downloadByRange.js +4 -2
  169. package/lib/sync/utils/downloadByRange.js.map +1 -1
  170. package/lib/sync/utils/downloadByRoot.d.ts +3 -3
  171. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  172. package/lib/sync/utils/downloadByRoot.js +10 -5
  173. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  174. package/lib/util/blobs.d.ts +3 -3
  175. package/lib/util/blobs.d.ts.map +1 -1
  176. package/lib/util/blobs.js +21 -10
  177. package/lib/util/blobs.js.map +1 -1
  178. package/lib/util/dataColumns.d.ts +18 -11
  179. package/lib/util/dataColumns.d.ts.map +1 -1
  180. package/lib/util/dataColumns.js +51 -17
  181. package/lib/util/dataColumns.js.map +1 -1
  182. package/lib/util/execution.d.ts +6 -2
  183. package/lib/util/execution.d.ts.map +1 -1
  184. package/lib/util/execution.js +49 -25
  185. package/lib/util/execution.js.map +1 -1
  186. package/lib/util/sszBytes.d.ts +25 -1
  187. package/lib/util/sszBytes.d.ts.map +1 -1
  188. package/lib/util/sszBytes.js +189 -2
  189. package/lib/util/sszBytes.js.map +1 -1
  190. package/package.json +15 -15
  191. package/src/api/impl/beacon/blocks/index.ts +17 -14
  192. package/src/api/impl/beacon/pool/index.ts +4 -0
  193. package/src/api/impl/beacon/state/index.ts +15 -15
  194. package/src/api/impl/debug/index.ts +2 -2
  195. package/src/api/impl/lodestar/index.ts +4 -0
  196. package/src/api/impl/validator/index.ts +7 -0
  197. package/src/chain/ColumnReconstructionTracker.ts +6 -5
  198. package/src/chain/GetBlobsTracker.ts +14 -12
  199. package/src/chain/blocks/blockInput/blockInput.ts +8 -8
  200. package/src/chain/blocks/blockInput/types.ts +4 -4
  201. package/src/chain/blocks/importBlock.ts +29 -8
  202. package/src/chain/blocks/importExecutionPayload.ts +7 -1
  203. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +53 -12
  204. package/src/chain/blocks/payloadEnvelopeInput/types.ts +2 -1
  205. package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +2 -1
  206. package/src/chain/blocks/verifyBlocksSignatures.ts +9 -2
  207. package/src/chain/chain.ts +73 -28
  208. package/src/chain/emitter.ts +25 -7
  209. package/src/chain/errors/dataColumnSidecarError.ts +32 -1
  210. package/src/chain/forkChoice/index.ts +11 -8
  211. package/src/chain/interface.ts +4 -2
  212. package/src/chain/lightClient/index.ts +7 -3
  213. package/src/chain/opPools/aggregatedAttestationPool.ts +6 -1
  214. package/src/chain/prepareNextSlot.ts +8 -0
  215. package/src/chain/produceBlock/computeNewStateRoot.ts +2 -1
  216. package/src/chain/produceBlock/produceBlockBody.ts +25 -5
  217. package/src/chain/seenCache/seenGossipBlockInput.ts +2 -2
  218. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +2 -2
  219. package/src/chain/validation/block.ts +2 -1
  220. package/src/chain/validation/dataColumnSidecar.ts +230 -7
  221. package/src/chain/validation/executionPayloadBid.ts +4 -0
  222. package/src/chain/validation/executionPayloadEnvelope.ts +8 -1
  223. package/src/chain/validation/payloadAttestationMessage.ts +4 -0
  224. package/src/chain/validation/syncCommittee.ts +5 -1
  225. package/src/chain/validation/syncCommitteeContributionAndProof.ts +5 -1
  226. package/src/chain/validatorMonitor.ts +3 -2
  227. package/src/db/buckets.ts +2 -2
  228. package/src/db/repositories/dataColumnSidecar.ts +4 -2
  229. package/src/db/repositories/dataColumnSidecarArchive.ts +4 -2
  230. package/src/metrics/metrics/lodestar.ts +34 -0
  231. package/src/network/interface.ts +3 -2
  232. package/src/network/libp2p/index.ts +21 -15
  233. package/src/network/network.ts +7 -4
  234. package/src/network/options.ts +7 -2
  235. package/src/network/processor/extractSlotRootFns.ts +32 -6
  236. package/src/network/processor/gossipHandlers.ts +305 -79
  237. package/src/network/processor/index.ts +304 -22
  238. package/src/network/reqresp/types.ts +13 -5
  239. package/src/node/nodejs.ts +5 -2
  240. package/src/node/notifier.ts +7 -2
  241. package/src/sync/unknownBlock.ts +3 -3
  242. package/src/sync/utils/downloadByRange.ts +9 -7
  243. package/src/sync/utils/downloadByRoot.ts +16 -12
  244. package/src/util/blobs.ts +35 -15
  245. package/src/util/dataColumns.ts +69 -25
  246. package/src/util/execution.ts +49 -30
  247. package/src/util/sszBytes.ts +245 -3
@@ -12,6 +12,16 @@ import {Metrics} from "../../metrics/metrics.js";
12
12
  import {ClockEvent} from "../../util/clock.js";
13
13
  import {callInNextEventLoop} from "../../util/eventLoop.js";
14
14
  import {PeerIdStr} from "../../util/peerId.js";
15
+ import {
16
+ getBeaconBlockRootFromExecutionPayloadEnvelopeSerialized,
17
+ getDataIndexFromSignedAggregateAndProofSerialized,
18
+ getDataIndexFromSingleAttestationSerialized,
19
+ getParentBlockHashFromGloasSignedBeaconBlockSerialized,
20
+ getParentBlockHashFromSignedExecutionPayloadBidSerialized,
21
+ getParentBlockRootFromSignedExecutionPayloadBidSerialized,
22
+ getParentRootFromSignedBeaconBlockSerialized,
23
+ getPayloadPresentFromPayloadAttestationMessageSerialized,
24
+ } from "../../util/sszBytes.js";
15
25
  import {NetworkEvent, NetworkEventBus} from "../events.js";
16
26
  import {
17
27
  GossipHandlers,
@@ -89,6 +99,8 @@ const MAX_JOBS_SUBMITTED_PER_TICK = 128;
89
99
 
90
100
  // How many gossip messages we keep before new ones get dropped.
91
101
  const MAX_QUEUED_UNKNOWN_BLOCK_GOSSIP_OBJECTS = 16_384;
102
+ // TODO gloas: arbitrary constant, check metrics.
103
+ const MAX_QUEUED_UNKNOWN_PAYLOAD_GOSSIP_OBJECTS = 1024;
92
104
 
93
105
  // We don't want to process too many gossip messages in a single tick
94
106
  // As seen on mainnet, gossip messages concurrency metric ranges from 1000 to 2000
@@ -126,6 +138,20 @@ export enum CannotAcceptWorkReason {
126
138
  regen = "regen_busy",
127
139
  }
128
140
 
141
+ /**
142
+ * No metrics needed here; using a number to keep it lightweight
143
+ */
144
+ enum PreprocessAction {
145
+ AwaitBlock,
146
+ AwaitEnvelope,
147
+ PushToQueue,
148
+ }
149
+
150
+ type PreprocessResult =
151
+ | {action: PreprocessAction.PushToQueue}
152
+ | {action: PreprocessAction.AwaitBlock; root: RootHex}
153
+ | {action: PreprocessAction.AwaitEnvelope; root: RootHex};
154
+
129
155
  /**
130
156
  * Network processor handles the gossip queues and throtles processing to not overload the main thread
131
157
  * - Decides when to process work and what to process
@@ -159,7 +185,11 @@ export class NetworkProcessor {
159
185
  // we may not receive the block for messages like Attestation and SignedAggregateAndProof messages, in that case PendingGossipsubMessage needs
160
186
  // to be stored in this Map and reprocessed once the block comes
161
187
  private readonly awaitingMessagesByBlockRoot: MapDef<RootHex, Set<PendingGossipsubMessage>>;
188
+ // we may not receive the payload for messages that require the FULL payload variant to be processed,
189
+ // in that case PendingGossipsubMessage needs to be stored in this Map and reprocessed once the payload comes
190
+ private readonly awaitingMessagesByPayloadBlockRoot: MapDef<RootHex, Set<PendingGossipsubMessage>>;
162
191
  private unknownBlocksBySlot = new MapDef<Slot, Set<RootHex>>(() => new Set());
192
+ private unknownEnvelopesBySlot = new MapDef<Slot, Set<RootHex>>(() => new Set());
163
193
 
164
194
  constructor(
165
195
  modules: NetworkProcessorModules,
@@ -179,11 +209,13 @@ export class NetworkProcessor {
179
209
  modules
180
210
  );
181
211
 
182
- events.on(NetworkEvent.pendingGossipsubMessage, this.onPendingGossipsubMessage.bind(this));
183
- this.chain.emitter.on(routes.events.EventType.block, this.onBlockProcessed.bind(this));
184
- this.chain.clock.on(ClockEvent.slot, this.onClockSlot.bind(this));
212
+ events.on(NetworkEvent.pendingGossipsubMessage, this.onPendingGossipsubMessage);
213
+ this.chain.emitter.on(routes.events.EventType.block, this.onBlockProcessed);
214
+ this.chain.emitter.on(routes.events.EventType.executionPayload, this.onPayloadEnvelopeProcessed);
215
+ this.chain.clock.on(ClockEvent.slot, this.onClockSlot);
185
216
 
186
217
  this.awaitingMessagesByBlockRoot = new MapDef<RootHex, Set<PendingGossipsubMessage>>(() => new Set());
218
+ this.awaitingMessagesByPayloadBlockRoot = new MapDef<RootHex, Set<PendingGossipsubMessage>>(() => new Set());
187
219
 
188
220
  // TODO: Implement queues and priorization for ReqResp incoming requests
189
221
  // Listens to NetworkEvent.reqRespIncomingRequest event
@@ -196,6 +228,7 @@ export class NetworkProcessor {
196
228
  metrics.gossipValidationQueue.concurrency.set({topic}, this.gossipTopicConcurrency[topic]);
197
229
  }
198
230
  metrics.awaitingBlockGossipMessages.countPerSlot.set(this.unknownBlockGossipsubMessagesCount);
231
+ metrics.awaitingPayloadGossipMessages.countPerSlot.set(this.unknownPayloadGossipsubMessagesCount);
199
232
  // specific metric for beacon_attestation topic
200
233
  metrics.gossipValidationQueue.keyAge.reset();
201
234
  for (const ageMs of this.gossipQueues.beacon_attestation.getDataAgeMs()) {
@@ -212,6 +245,7 @@ export class NetworkProcessor {
212
245
  async stop(): Promise<void> {
213
246
  this.events.off(NetworkEvent.pendingGossipsubMessage, this.onPendingGossipsubMessage);
214
247
  this.chain.emitter.off(routes.events.EventType.block, this.onBlockProcessed);
248
+ this.chain.emitter.off(routes.events.EventType.executionPayload, this.onPayloadEnvelopeProcessed);
215
249
  this.chain.emitter.off(ClockEvent.slot, this.onClockSlot);
216
250
  }
217
251
 
@@ -232,7 +266,7 @@ export class NetworkProcessor {
232
266
 
233
267
  /**
234
268
  * Search block via `ChainEvent.unknownBlockRoot` event
235
- * Note that slot is not necessarily the same to the block's slot but it can be used for a good prune strategy.
269
+ * Slot is the message slot, which is not necessarily the same as the block's slot, but it can be used for a good prune strategy.
236
270
  * In the rare case, if 2 messages on 2 slots search for the same root (for example beacon_attestation) we may emit the same root twice but BlockInputSync should handle it well.
237
271
  */
238
272
  searchUnknownBlock({slot, root}: SlotRootHex, source: BlockInputSource, peer?: PeerIdStr): void {
@@ -248,9 +282,29 @@ export class NetworkProcessor {
248
282
  this.chain.emitter.emit(ChainEvent.unknownBlockRoot, {rootHex: root, peer, source});
249
283
  }
250
284
 
251
- private onPendingGossipsubMessage(message: PendingGossipsubMessage): void {
285
+ /**
286
+ * Search envelope via `ChainEvent.unknownEnvelopeBlockRoot` event
287
+ * Slot is the message slot, which is not necessarily the same as the envelope's slot, but it can be used for a good prune strategy.
288
+ * In the rare case, if 2 messages on 2 slots search for the same root (for example beacon_attestation) we may emit the same root twice but BlockInputSync should handle it well.
289
+ */
290
+ searchUnknownEnvelope({slot, root}: SlotRootHex, source: BlockInputSource, peer?: PeerIdStr): void {
291
+ if (
292
+ this.chain.seenPayloadEnvelope(root) ||
293
+ this.awaitingMessagesByPayloadBlockRoot.has(root) ||
294
+ this.unknownEnvelopesBySlot.getOrDefault(slot).has(root)
295
+ ) {
296
+ return;
297
+ }
298
+ this.unknownEnvelopesBySlot.getOrDefault(slot).add(root);
299
+ this.chain.emitter.emit(ChainEvent.unknownEnvelopeBlockRoot, {rootHex: root, peer, source});
300
+ }
301
+
302
+ private onPendingGossipsubMessage = (message: PendingGossipsubMessage): void => {
252
303
  const topicType = message.topic.type;
253
304
  const extractBlockSlotRootFn = this.extractBlockSlotRootFns[topicType];
305
+
306
+ // 1st extract round: make sure slot is in range and if block root is not available
307
+ // proactively search for it + queue the message
254
308
  const slotRoot = extractBlockSlotRootFn
255
309
  ? extractBlockSlotRootFn(message.msg.data, message.topic.boundary.fork)
256
310
  : null;
@@ -282,27 +336,198 @@ export class NetworkProcessor {
282
336
 
283
337
  message.msgSlot = slot;
284
338
 
339
+ // this determines whether this message needs to wait for a Block or Envelope
340
+ // a message should only wait for what it voted for, hence we don't want to put it on both queues
341
+ let preprocessResult: PreprocessResult = {action: PreprocessAction.PushToQueue};
285
342
  // no need to check if root is a descendant of the current finalized block, it will be checked once we validate the message if needed
286
343
  if (root && !this.chain.forkChoice.hasBlockHexUnsafe(root)) {
344
+ // starting from GLOAS, unknown root from data_column_sidecar also falls into this case
287
345
  this.searchUnknownBlock({slot, root}, BlockInputSource.network_processor, message.propagationSource.toString());
346
+ // for beacon_attestation and beacon_aggregate_and_proof messages, this is only temporary.
347
+ // if "index = 1" we need to await for the Envelope instead
348
+ preprocessResult = {action: PreprocessAction.AwaitBlock, root};
349
+ }
288
350
 
289
- if (this.unknownBlockGossipsubMessagesCount > MAX_QUEUED_UNKNOWN_BLOCK_GOSSIP_OBJECTS) {
290
- // No need to report the dropped job to gossip. It will be eventually pruned from the mcache
291
- this.metrics?.awaitingBlockGossipMessages.reject.inc({
292
- reason: ReprocessRejectReason.reached_limit,
293
- topic: topicType,
294
- });
295
- return;
351
+ // 2nd extract round for some specific topics
352
+ // we separate the search action from the await action
353
+
354
+ // beacon_block: proactively search for parent block/envelope across all forks, but never queue.
355
+ // BlockInputSync handles cascading recovery if the gossip handler throws.
356
+ if (topicType === GossipType.beacon_block) {
357
+ const parentRoot = getParentRootFromSignedBeaconBlockSerialized(message.msg.data);
358
+ if (parentRoot) {
359
+ if (ForkSeq[fork] >= ForkSeq.gloas) {
360
+ // GLOAS: also check parent envelope, same logic as execution_payload_bid
361
+ const parentBlockHash = getParentBlockHashFromGloasSignedBeaconBlockSerialized(message.msg.data);
362
+ if (parentBlockHash && !this.chain.forkChoice.getBlockHexAndBlockHash(parentRoot, parentBlockHash)) {
363
+ const protoBlock = this.chain.forkChoice.getBlockHexDefaultStatus(parentRoot);
364
+ if (protoBlock === null) {
365
+ this.searchUnknownBlock(
366
+ {slot, root: parentRoot},
367
+ BlockInputSource.network_processor,
368
+ message.propagationSource.toString()
369
+ );
370
+ } else if (
371
+ protoBlock.executionPayloadBlockHash &&
372
+ protoBlock.executionPayloadBlockHash !== parentBlockHash
373
+ ) {
374
+ // only search for the envelope by block root if we're sure there is one. Otherwise UnknownBlockSync will penalize the peer.
375
+ this.searchUnknownEnvelope(
376
+ {slot, root: parentRoot},
377
+ BlockInputSource.network_processor,
378
+ message.propagationSource.toString()
379
+ );
380
+ }
381
+ }
382
+ } else if (!this.chain.forkChoice.hasBlockHexUnsafe(parentRoot)) {
383
+ this.searchUnknownBlock(
384
+ {slot, root: parentRoot},
385
+ BlockInputSource.network_processor,
386
+ message.propagationSource.toString()
387
+ );
388
+ }
296
389
  }
390
+ preprocessResult = {action: PreprocessAction.PushToQueue};
391
+ }
297
392
 
298
- this.metrics?.awaitingBlockGossipMessages.queue.inc({topic: topicType});
299
- const awaitingGossipsubMessages = this.awaitingMessagesByBlockRoot.getOrDefault(root);
300
- awaitingGossipsubMessages.add(message);
301
- return;
393
+ if (ForkSeq[fork] >= ForkSeq.gloas) {
394
+ // specific check for each topic
395
+ // note that it's supposed to NOT queue beacon_block (handled above) and execution_payload because it's not a one-off;
396
+ // for those topics, gossip handlers will throw and BlockInputSync will handle a tree of them instead
397
+ switch (topicType) {
398
+ case GossipType.beacon_attestation:
399
+ case GossipType.beacon_aggregate_and_proof: {
400
+ if (root == null) break;
401
+ const attIndex =
402
+ topicType === GossipType.beacon_attestation
403
+ ? getDataIndexFromSingleAttestationSerialized(fork, message.msg.data)
404
+ : getDataIndexFromSignedAggregateAndProofSerialized(message.msg.data);
405
+ if (attIndex === 1 && !this.chain.forkChoice.hasPayloadHexUnsafe(root)) {
406
+ // attestation votes that the payload is available but it is not yet known
407
+ this.searchUnknownEnvelope(
408
+ {slot, root},
409
+ BlockInputSource.network_processor,
410
+ message.propagationSource.toString()
411
+ );
412
+ preprocessResult = {action: PreprocessAction.AwaitEnvelope, root};
413
+ }
414
+ break;
415
+ }
416
+ case GossipType.payload_attestation_message: {
417
+ if (root == null) break;
418
+ const payloadPresent = getPayloadPresentFromPayloadAttestationMessageSerialized(message.msg.data);
419
+ if (payloadPresent && !this.chain.forkChoice.hasPayloadHexUnsafe(root)) {
420
+ // payload attestation votes that the payload is available but it is not yet known
421
+ this.searchUnknownEnvelope(
422
+ {slot, root},
423
+ BlockInputSource.network_processor,
424
+ message.propagationSource.toString()
425
+ );
426
+ // do not await the envelope, payload attestation processing only requires that the block is known
427
+ // also do not reset preprocessResult, we may already await for the block
428
+ }
429
+ break;
430
+ }
431
+ case GossipType.data_column_sidecar: {
432
+ if (root == null) break;
433
+ if (!this.chain.forkChoice.hasPayloadHexUnsafe(root)) {
434
+ this.searchUnknownEnvelope(
435
+ {slot, root},
436
+ BlockInputSource.network_processor,
437
+ message.propagationSource.toString()
438
+ );
439
+ // do not await the envelope, we can do gossip validation
440
+ // also do not reset preprocessResult, we may already await for the block
441
+ }
442
+ break;
443
+ }
444
+ case GossipType.execution_payload: {
445
+ // extractBlockSlotRootFn does not return a root for this topic.
446
+ // Extract beacon_block_root directly and proactively trigger block sync if missing.
447
+ // Do NOT await the block — the handler runs immediately; BlockInputSync handles recovery.
448
+ const blockRoot = getBeaconBlockRootFromExecutionPayloadEnvelopeSerialized(message.msg.data);
449
+ if (blockRoot && !this.chain.forkChoice.hasBlockHexUnsafe(blockRoot)) {
450
+ this.searchUnknownBlock(
451
+ {slot, root: blockRoot},
452
+ BlockInputSource.network_processor,
453
+ message.propagationSource.toString()
454
+ );
455
+ }
456
+ // do not await the block, we want UnknownBlockSync to handle it.
457
+ preprocessResult = {action: PreprocessAction.PushToQueue};
458
+ break;
459
+ }
460
+ case GossipType.execution_payload_bid: {
461
+ // instead of searching for the message root, this searches for the parent root
462
+ const parentBlockRoot = getParentBlockRootFromSignedExecutionPayloadBidSerialized(message.msg.data);
463
+ const parentBlockHash = getParentBlockHashFromSignedExecutionPayloadBidSerialized(message.msg.data);
464
+ if (
465
+ parentBlockRoot &&
466
+ parentBlockHash &&
467
+ !this.chain.forkChoice.getBlockHexAndBlockHash(parentBlockRoot, parentBlockHash)
468
+ ) {
469
+ const protoBlock = this.chain.forkChoice.getBlockHexDefaultStatus(parentBlockRoot);
470
+ if (protoBlock === null) {
471
+ this.searchUnknownBlock(
472
+ {slot, root: parentBlockRoot},
473
+ BlockInputSource.network_processor,
474
+ message.propagationSource.toString()
475
+ );
476
+ preprocessResult = {action: PreprocessAction.AwaitBlock, root: parentBlockRoot};
477
+ } else if (
478
+ protoBlock.executionPayloadBlockHash &&
479
+ protoBlock.executionPayloadBlockHash !== parentBlockHash
480
+ ) {
481
+ this.searchUnknownEnvelope(
482
+ {slot, root: parentBlockRoot},
483
+ BlockInputSource.network_processor,
484
+ message.propagationSource.toString()
485
+ );
486
+ preprocessResult = {action: PreprocessAction.AwaitEnvelope, root: parentBlockRoot};
487
+ }
488
+ }
489
+ break;
490
+ }
491
+ }
302
492
  }
303
493
 
304
- this.pushPendingGossipsubMessageToQueue(message);
305
- }
494
+ switch (preprocessResult.action) {
495
+ case PreprocessAction.PushToQueue:
496
+ this.pushPendingGossipsubMessageToQueue(message);
497
+ break;
498
+ case PreprocessAction.AwaitBlock: {
499
+ if (this.unknownBlockGossipsubMessagesCount > MAX_QUEUED_UNKNOWN_BLOCK_GOSSIP_OBJECTS) {
500
+ // No need to report the dropped job to gossip. It will be eventually pruned from the mcache
501
+ this.metrics?.awaitingBlockGossipMessages.reject.inc({
502
+ reason: ReprocessRejectReason.reached_limit,
503
+ topic: topicType,
504
+ });
505
+ return;
506
+ }
507
+
508
+ this.metrics?.awaitingBlockGossipMessages.queue.inc({topic: topicType});
509
+ const awaitingGossipsubMessages = this.awaitingMessagesByBlockRoot.getOrDefault(preprocessResult.root);
510
+ awaitingGossipsubMessages.add(message);
511
+ break;
512
+ }
513
+ case PreprocessAction.AwaitEnvelope: {
514
+ if (this.unknownPayloadGossipsubMessagesCount > MAX_QUEUED_UNKNOWN_PAYLOAD_GOSSIP_OBJECTS) {
515
+ this.metrics?.awaitingPayloadGossipMessages.reject.inc({
516
+ reason: ReprocessRejectReason.reached_limit,
517
+ topic: topicType,
518
+ });
519
+ return;
520
+ }
521
+
522
+ this.metrics?.awaitingPayloadGossipMessages.queue.inc({topic: topicType});
523
+ const awaitingPayloadGossipsubMessages = this.awaitingMessagesByPayloadBlockRoot.getOrDefault(
524
+ preprocessResult.root
525
+ );
526
+ awaitingPayloadGossipsubMessages.add(message);
527
+ break;
528
+ }
529
+ }
530
+ };
306
531
 
307
532
  private pushPendingGossipsubMessageToQueue(message: PendingGossipsubMessage): void {
308
533
  const topicType = message.topic.type;
@@ -316,7 +541,7 @@ export class NetworkProcessor {
316
541
  this.executeWork();
317
542
  }
318
543
 
319
- private async onBlockProcessed({block: rootHex}: {block: string; executionOptimistic: boolean}): Promise<void> {
544
+ private onBlockProcessed = async ({block: rootHex}: {block: string; executionOptimistic: boolean}): Promise<void> => {
320
545
  const waitingGossipsubMessages = this.awaitingMessagesByBlockRoot.get(rootHex);
321
546
  if (!waitingGossipsubMessages || waitingGossipsubMessages.size === 0) {
322
547
  return;
@@ -343,9 +568,35 @@ export class NetworkProcessor {
343
568
  }
344
569
 
345
570
  this.awaitingMessagesByBlockRoot.delete(rootHex);
346
- }
571
+ };
572
+
573
+ private onPayloadEnvelopeProcessed = async ({blockRoot: rootHex}: {blockRoot: RootHex}): Promise<void> => {
574
+ const waitingGossipsubMessages = this.awaitingMessagesByPayloadBlockRoot.get(rootHex);
575
+ if (!waitingGossipsubMessages || waitingGossipsubMessages.size === 0) {
576
+ return;
577
+ }
578
+
579
+ const nowSec = Date.now() / 1000;
580
+ let count = 0;
581
+ for (const message of waitingGossipsubMessages) {
582
+ const topicType = message.topic.type;
583
+ this.metrics?.awaitingPayloadGossipMessages.waitSecBeforeResolve.set(
584
+ {topic: topicType},
585
+ nowSec - message.seenTimestampSec
586
+ );
587
+ this.metrics?.awaitingPayloadGossipMessages.resolve.inc({topic: topicType});
588
+ this.pushPendingGossipsubMessageToQueue(message);
589
+ count++;
590
+ if (count === MAX_AWAITING_GOSSIP_OBJECTS_PER_TICK) {
591
+ count = 0;
592
+ await sleep(AWAITING_GOSSIP_OBJECTS_YIELD_EVERY_MS);
593
+ }
594
+ }
347
595
 
348
- private onClockSlot(clockSlot: Slot): void {
596
+ this.awaitingMessagesByPayloadBlockRoot.delete(rootHex);
597
+ };
598
+
599
+ private onClockSlot = (clockSlot: Slot): void => {
349
600
  const nowSec = Date.now() / 1000;
350
601
  const minSlot = clockSlot - MAX_UNKNOWN_ROOTS_SLOT_CACHE_SIZE;
351
602
 
@@ -371,7 +622,30 @@ export class NetworkProcessor {
371
622
  }
372
623
  this.unknownBlocksBySlot.delete(slot);
373
624
  }
374
- }
625
+
626
+ for (const [slot, roots] of this.unknownEnvelopesBySlot) {
627
+ if (slot > minSlot) continue;
628
+ for (const rootHex of roots) {
629
+ const gossipMessages = this.awaitingMessagesByPayloadBlockRoot.get(rootHex);
630
+ if (gossipMessages !== undefined) {
631
+ for (const message of gossipMessages) {
632
+ const topicType = message.topic.type;
633
+ this.metrics?.awaitingPayloadGossipMessages.reject.inc({
634
+ topic: topicType,
635
+ reason: ReprocessRejectReason.expired,
636
+ });
637
+ this.metrics?.awaitingPayloadGossipMessages.waitSecBeforeReject.set(
638
+ {topic: topicType, reason: ReprocessRejectReason.expired},
639
+ nowSec - message.seenTimestampSec
640
+ );
641
+ // No need to report the dropped job to gossip. It will be eventually pruned from the mcache
642
+ }
643
+ this.awaitingMessagesByPayloadBlockRoot.delete(rootHex);
644
+ }
645
+ }
646
+ this.unknownEnvelopesBySlot.delete(slot);
647
+ }
648
+ };
375
649
 
376
650
  private executeWork(): void {
377
651
  // TODO: Maybe de-bounce by timing the last time executeWork was run
@@ -517,4 +791,12 @@ export class NetworkProcessor {
517
791
  }
518
792
  return count;
519
793
  }
794
+
795
+ private get unknownPayloadGossipsubMessagesCount(): number {
796
+ let count = 0;
797
+ for (const messages of this.awaitingMessagesByPayloadBlockRoot.values()) {
798
+ count += messages.size;
799
+ }
800
+ return count;
801
+ }
520
802
  }
@@ -1,8 +1,9 @@
1
1
  import {Type} from "@chainsafe/ssz";
2
2
  import {BeaconConfig} from "@lodestar/config";
3
- import {ForkName, ForkPostAltair, isForkPostAltair} from "@lodestar/params";
3
+ import {ForkName, ForkPostAltair, ForkPostFulu, isForkPostAltair, isForkPostFulu} from "@lodestar/params";
4
4
  import {Protocol, ProtocolHandler, ReqRespRequest} from "@lodestar/reqresp";
5
5
  import {
6
+ DataColumnSidecar,
6
7
  LightClientBootstrap,
7
8
  LightClientFinalityUpdate,
8
9
  LightClientOptimisticUpdate,
@@ -83,8 +84,8 @@ type ResponseBodyByMethod = {
83
84
  [ReqRespMethod.BeaconBlocksByRoot]: SignedBeaconBlock;
84
85
  [ReqRespMethod.BlobSidecarsByRange]: deneb.BlobSidecar;
85
86
  [ReqRespMethod.BlobSidecarsByRoot]: deneb.BlobSidecar;
86
- [ReqRespMethod.DataColumnSidecarsByRange]: fulu.DataColumnSidecar;
87
- [ReqRespMethod.DataColumnSidecarsByRoot]: fulu.DataColumnSidecar;
87
+ [ReqRespMethod.DataColumnSidecarsByRange]: DataColumnSidecar;
88
+ [ReqRespMethod.DataColumnSidecarsByRoot]: DataColumnSidecar;
88
89
  [ReqRespMethod.ExecutionPayloadEnvelopesByRoot]: gloas.SignedExecutionPayloadEnvelope;
89
90
  [ReqRespMethod.ExecutionPayloadEnvelopesByRange]: gloas.SignedExecutionPayloadEnvelope;
90
91
 
@@ -146,8 +147,8 @@ export const responseSszTypeByMethod: {[K in ReqRespMethod]: ResponseTypeGetter<
146
147
  [ReqRespMethod.LightClientBootstrap]: (fork) => sszTypesFor(onlyPostAltairFork(fork)).LightClientBootstrap,
147
148
  [ReqRespMethod.LightClientUpdatesByRange]: (fork) => sszTypesFor(onlyPostAltairFork(fork)).LightClientUpdate,
148
149
  [ReqRespMethod.LightClientFinalityUpdate]: (fork) => sszTypesFor(onlyPostAltairFork(fork)).LightClientFinalityUpdate,
149
- [ReqRespMethod.DataColumnSidecarsByRange]: () => ssz.fulu.DataColumnSidecar,
150
- [ReqRespMethod.DataColumnSidecarsByRoot]: () => ssz.fulu.DataColumnSidecar,
150
+ [ReqRespMethod.DataColumnSidecarsByRange]: (fork) => sszTypesFor(onlyPostFuluFork(fork)).DataColumnSidecar,
151
+ [ReqRespMethod.DataColumnSidecarsByRoot]: (fork) => sszTypesFor(onlyPostFuluFork(fork)).DataColumnSidecar,
151
152
  [ReqRespMethod.ExecutionPayloadEnvelopesByRoot]: () => ssz.gloas.SignedExecutionPayloadEnvelope,
152
153
  [ReqRespMethod.ExecutionPayloadEnvelopesByRange]: () => ssz.gloas.SignedExecutionPayloadEnvelope,
153
154
  [ReqRespMethod.LightClientOptimisticUpdate]: (fork) =>
@@ -161,6 +162,13 @@ function onlyPostAltairFork(fork: ForkName): ForkPostAltair {
161
162
  throw Error(`Not a post-altair fork ${fork}`);
162
163
  }
163
164
 
165
+ function onlyPostFuluFork(fork: ForkName): ForkPostFulu {
166
+ if (isForkPostFulu(fork)) {
167
+ return fork;
168
+ }
169
+ throw Error(`Not a post-fulu fork ${fork}`);
170
+ }
171
+
164
172
  export type RequestTypedContainer = {
165
173
  [K in ReqRespMethod]: {method: K; body: RequestBodyByMethod[K]};
166
174
  }[ReqRespMethod];
@@ -6,7 +6,7 @@ import {BeaconApiMethods} from "@lodestar/api/beacon/server";
6
6
  import {BeaconConfig} from "@lodestar/config";
7
7
  import type {LoggerNode} from "@lodestar/logger/node";
8
8
  import {ZERO_HASH_HEX} from "@lodestar/params";
9
- import {IBeaconStateView, PubkeyCache} from "@lodestar/state-transition";
9
+ import {IBeaconStateView, PubkeyCache, isStatePostBellatrix} from "@lodestar/state-transition";
10
10
  import {phase0} from "@lodestar/types";
11
11
  import {sleep, toRootHex} from "@lodestar/utils";
12
12
  import {ProcessShutdownCallback} from "@lodestar/validator";
@@ -221,7 +221,10 @@ export class BeaconNode {
221
221
 
222
222
  let executionEngineOpts = opts.executionEngine;
223
223
  if (opts.executionEngine.mode === "mock") {
224
- const eth1BlockHash = anchorState.isExecutionStateType ? toRootHex(anchorState.latestBlockHash) : undefined;
224
+ const eth1BlockHash =
225
+ isStatePostBellatrix(anchorState) && anchorState.isExecutionStateType
226
+ ? toRootHex(anchorState.latestBlockHash)
227
+ : undefined;
225
228
  executionEngineOpts = {
226
229
  ...opts.executionEngine,
227
230
  genesisBlockHash: ZERO_HASH_HEX,
@@ -1,7 +1,12 @@
1
1
  import {BeaconConfig} from "@lodestar/config";
2
2
  import {ExecutionStatus, ProtoBlock} from "@lodestar/fork-choice";
3
3
  import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH} from "@lodestar/params";
4
- import {IBeaconStateView, computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition";
4
+ import {
5
+ IBeaconStateView,
6
+ computeEpochAtSlot,
7
+ computeStartSlotAtEpoch,
8
+ isStatePostBellatrix,
9
+ } from "@lodestar/state-transition";
5
10
  import {Epoch} from "@lodestar/types";
6
11
  import {ErrorAborted, Logger, prettyBytes, prettyBytesShort, sleep} from "@lodestar/utils";
7
12
  import {IBeaconChain} from "../chain/index.js";
@@ -165,7 +170,7 @@ function getHeadExecutionInfo(
165
170
  const executionStatusStr = headInfo.executionStatus.toLowerCase();
166
171
 
167
172
  // Add execution status to notifier only if head is on/post bellatrix
168
- if (headState.isExecutionStateType) {
173
+ if (isStatePostBellatrix(headState) && headState.isExecutionStateType) {
169
174
  if (headState.isMergeTransitionComplete) {
170
175
  const executionPayloadHashInfo =
171
176
  headInfo.executionStatus !== ExecutionStatus.PreMerge ? headInfo.executionPayloadBlockHash : "empty";
@@ -115,7 +115,7 @@ export class BlockInputSync {
115
115
  this.logger.verbose("BlockInputSync enabled.");
116
116
  this.chain.emitter.on(ChainEvent.unknownBlockRoot, this.onUnknownBlockRoot);
117
117
  this.chain.emitter.on(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
118
- this.chain.emitter.on(ChainEvent.unknownParent, this.onUnknownParent);
118
+ this.chain.emitter.on(ChainEvent.blockUnknownParent, this.onUnknownParent);
119
119
  this.network.events.on(NetworkEvent.peerConnected, this.onPeerConnected);
120
120
  this.network.events.on(NetworkEvent.peerDisconnected, this.onPeerDisconnected);
121
121
  this.subscribedToNetworkEvents = true;
@@ -126,7 +126,7 @@ export class BlockInputSync {
126
126
  this.logger.verbose("BlockInputSync disabled.");
127
127
  this.chain.emitter.off(ChainEvent.unknownBlockRoot, this.onUnknownBlockRoot);
128
128
  this.chain.emitter.off(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
129
- this.chain.emitter.off(ChainEvent.unknownParent, this.onUnknownParent);
129
+ this.chain.emitter.off(ChainEvent.blockUnknownParent, this.onUnknownParent);
130
130
  this.network.events.off(NetworkEvent.peerConnected, this.onPeerConnected);
131
131
  this.network.events.off(NetworkEvent.peerDisconnected, this.onPeerDisconnected);
132
132
  this.subscribedToNetworkEvents = false;
@@ -171,7 +171,7 @@ export class BlockInputSync {
171
171
  /**
172
172
  * Process an unknownBlockParent event and register the block in `pendingBlocks` Map.
173
173
  */
174
- private onUnknownParent = (data: ChainEventData[ChainEvent.unknownParent]): void => {
174
+ private onUnknownParent = (data: ChainEventData[ChainEvent.blockUnknownParent]): void => {
175
175
  try {
176
176
  this.addByRootHex(data.blockInput.parentRootHex, data.peer);
177
177
  this.addByBlockInput(data.blockInput, data.peer);
@@ -11,7 +11,7 @@ import {
11
11
  } from "../../chain/blocks/blockInput/index.js";
12
12
  import {SeenBlockInput} from "../../chain/seenCache/seenGossipBlockInput.js";
13
13
  import {validateBlockBlobSidecars} from "../../chain/validation/blobSidecar.js";
14
- import {validateBlockDataColumnSidecars} from "../../chain/validation/dataColumnSidecar.js";
14
+ import {validateFuluBlockDataColumnSidecars} from "../../chain/validation/dataColumnSidecar.js";
15
15
  import {BeaconMetrics} from "../../metrics/metrics/beacon.js";
16
16
  import {INetwork} from "../../network/index.js";
17
17
  import {getBlobKzgCommitments} from "../../util/dataColumns.js";
@@ -27,7 +27,7 @@ export type DownloadByRangeRequests = {
27
27
  export type DownloadByRangeResponses = {
28
28
  blocks?: SignedBeaconBlock[];
29
29
  blobSidecars?: deneb.BlobSidecars;
30
- columnSidecars?: fulu.DataColumnSidecars;
30
+ columnSidecars?: fulu.DataColumnSidecar[];
31
31
  };
32
32
 
33
33
  export type DownloadAndCacheByRangeProps = DownloadByRangeRequests & {
@@ -58,7 +58,7 @@ export type ValidatedBlobSidecars = {
58
58
 
59
59
  export type ValidatedColumnSidecars = {
60
60
  blockRoot: Uint8Array;
61
- columnSidecars: fulu.DataColumnSidecars;
61
+ columnSidecars: fulu.DataColumnSidecar[];
62
62
  };
63
63
 
64
64
  export type ValidatedResponses = {
@@ -245,7 +245,7 @@ export async function requestByRange({
245
245
  }): Promise<DownloadByRangeResponses> {
246
246
  let blocks: undefined | SignedBeaconBlock[];
247
247
  let blobSidecars: undefined | deneb.BlobSidecars;
248
- let columnSidecars: undefined | fulu.DataColumnSidecars;
248
+ let columnSidecars: undefined | fulu.DataColumnSidecar[];
249
249
 
250
250
  const requests: Promise<unknown>[] = [];
251
251
 
@@ -268,7 +268,7 @@ export async function requestByRange({
268
268
  if (columnsRequest) {
269
269
  requests.push(
270
270
  network.sendDataColumnSidecarsByRange(peerIdStr, columnsRequest).then((columnResponse) => {
271
- columnSidecars = columnResponse;
271
+ columnSidecars = columnResponse as fulu.DataColumnSidecar[];
272
272
  })
273
273
  );
274
274
  }
@@ -615,11 +615,13 @@ export async function validateColumnsByRangeResponse(
615
615
  config: ChainForkConfig,
616
616
  request: fulu.DataColumnSidecarsByRangeRequest,
617
617
  blocks: ValidatedBlock[],
618
- columnSidecars: fulu.DataColumnSidecars,
618
+ columnSidecars: fulu.DataColumnSidecar[],
619
619
  peerDasMetrics?: BeaconMetrics["peerDas"] | null
620
620
  ): Promise<WarnResult<ValidatedColumnSidecars[], DownloadByRangeError>> {
621
621
  const warnings: DownloadByRangeError[] = [];
622
622
 
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
623
625
  const seenColumns = new Map<Slot, Map<number, fulu.DataColumnSidecar>>();
624
626
  let currentSlot = -1;
625
627
  let currentIndex = -1;
@@ -767,7 +769,7 @@ export async function validateColumnsByRangeResponse(
767
769
  }
768
770
 
769
771
  validationPromises.push(
770
- validateBlockDataColumnSidecars(
772
+ validateFuluBlockDataColumnSidecars(
771
773
  null, // do not pass chain here so we do not validate header signature
772
774
  slot,
773
775
  blockRoot,