@lodestar/beacon-node 1.50.0-dev.2201499bbf → 1.50.0-dev.26076bcd3f

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 (181) hide show
  1. package/lib/api/impl/beacon/state/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/state/index.js +6 -4
  3. package/lib/api/impl/beacon/state/index.js.map +1 -1
  4. package/lib/api/impl/validator/index.d.ts.map +1 -1
  5. package/lib/api/impl/validator/index.js +8 -0
  6. package/lib/api/impl/validator/index.js.map +1 -1
  7. package/lib/chain/beaconProposerCache.d.ts +6 -0
  8. package/lib/chain/beaconProposerCache.d.ts.map +1 -1
  9. package/lib/chain/beaconProposerCache.js +16 -0
  10. package/lib/chain/beaconProposerCache.js.map +1 -1
  11. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  12. package/lib/chain/blocks/importBlock.js +7 -5
  13. package/lib/chain/blocks/importBlock.js.map +1 -1
  14. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  15. package/lib/chain/blocks/verifyBlock.js +6 -6
  16. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  17. package/lib/chain/chain.d.ts +1 -0
  18. package/lib/chain/chain.d.ts.map +1 -1
  19. package/lib/chain/chain.js +49 -15
  20. package/lib/chain/chain.js.map +1 -1
  21. package/lib/chain/interface.d.ts +2 -0
  22. package/lib/chain/interface.d.ts.map +1 -1
  23. package/lib/chain/opPools/opPool.d.ts.map +1 -1
  24. package/lib/chain/opPools/opPool.js +1 -23
  25. package/lib/chain/opPools/opPool.js.map +1 -1
  26. package/lib/chain/opPools/proposerPreferencesPool.d.ts +4 -0
  27. package/lib/chain/opPools/proposerPreferencesPool.d.ts.map +1 -1
  28. package/lib/chain/opPools/proposerPreferencesPool.js +13 -1
  29. package/lib/chain/opPools/proposerPreferencesPool.js.map +1 -1
  30. package/lib/chain/opPools/utils.d.ts +11 -0
  31. package/lib/chain/opPools/utils.d.ts.map +1 -1
  32. package/lib/chain/opPools/utils.js +22 -0
  33. package/lib/chain/opPools/utils.js.map +1 -1
  34. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  35. package/lib/chain/prepareNextSlot.js +11 -3
  36. package/lib/chain/prepareNextSlot.js.map +1 -1
  37. package/lib/chain/produceBlock/produceBlockBody.d.ts +8 -0
  38. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  39. package/lib/chain/produceBlock/produceBlockBody.js +40 -28
  40. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  41. package/lib/chain/shufflingCache.d.ts +17 -8
  42. package/lib/chain/shufflingCache.d.ts.map +1 -1
  43. package/lib/chain/shufflingCache.js +68 -18
  44. package/lib/chain/shufflingCache.js.map +1 -1
  45. package/lib/db/beacon.d.ts +2 -1
  46. package/lib/db/beacon.d.ts.map +1 -1
  47. package/lib/db/beacon.js +3 -1
  48. package/lib/db/beacon.js.map +1 -1
  49. package/lib/db/buckets.d.ts +2 -1
  50. package/lib/db/buckets.d.ts.map +1 -1
  51. package/lib/db/buckets.js +1 -0
  52. package/lib/db/buckets.js.map +1 -1
  53. package/lib/db/interface.d.ts +2 -1
  54. package/lib/db/interface.d.ts.map +1 -1
  55. package/lib/db/repositories/blockArchiveIndex.d.ts +2 -2
  56. package/lib/db/repositories/blockArchiveIndex.d.ts.map +1 -1
  57. package/lib/db/repositories/index.d.ts +1 -0
  58. package/lib/db/repositories/index.d.ts.map +1 -1
  59. package/lib/db/repositories/index.js +1 -0
  60. package/lib/db/repositories/index.js.map +1 -1
  61. package/lib/db/repositories/proposerPreferences.d.ts +14 -0
  62. package/lib/db/repositories/proposerPreferences.d.ts.map +1 -0
  63. package/lib/db/repositories/proposerPreferences.js +21 -0
  64. package/lib/db/repositories/proposerPreferences.js.map +1 -0
  65. package/lib/execution/engine/blobVersionedHashes.d.ts +9 -0
  66. package/lib/execution/engine/blobVersionedHashes.d.ts.map +1 -0
  67. package/lib/execution/engine/blobVersionedHashes.js +74 -0
  68. package/lib/execution/engine/blobVersionedHashes.js.map +1 -0
  69. package/lib/execution/engine/http.d.ts +45 -13
  70. package/lib/execution/engine/http.d.ts.map +1 -1
  71. package/lib/execution/engine/http.js +236 -198
  72. package/lib/execution/engine/http.js.map +1 -1
  73. package/lib/execution/engine/index.d.ts +3 -2
  74. package/lib/execution/engine/index.d.ts.map +1 -1
  75. package/lib/execution/engine/index.js +33 -8
  76. package/lib/execution/engine/index.js.map +1 -1
  77. package/lib/execution/engine/interface.d.ts +1 -1
  78. package/lib/execution/engine/interface.d.ts.map +1 -1
  79. package/lib/execution/engine/jsonRpcTransport.d.ts +25 -0
  80. package/lib/execution/engine/jsonRpcTransport.d.ts.map +1 -0
  81. package/lib/execution/engine/jsonRpcTransport.js +158 -0
  82. package/lib/execution/engine/jsonRpcTransport.js.map +1 -0
  83. package/lib/execution/engine/restHttpClient.d.ts +71 -0
  84. package/lib/execution/engine/restHttpClient.d.ts.map +1 -0
  85. package/lib/execution/engine/restHttpClient.js +201 -0
  86. package/lib/execution/engine/restHttpClient.js.map +1 -0
  87. package/lib/execution/engine/restTransport.d.ts +46 -0
  88. package/lib/execution/engine/restTransport.d.ts.map +1 -0
  89. package/lib/execution/engine/restTransport.js +399 -0
  90. package/lib/execution/engine/restTransport.js.map +1 -0
  91. package/lib/execution/engine/sszTypes.d.ts +1261 -0
  92. package/lib/execution/engine/sszTypes.d.ts.map +1 -0
  93. package/lib/execution/engine/sszTypes.js +216 -0
  94. package/lib/execution/engine/sszTypes.js.map +1 -0
  95. package/lib/execution/engine/transport.d.ts +39 -0
  96. package/lib/execution/engine/transport.d.ts.map +1 -0
  97. package/lib/execution/engine/transport.js +2 -0
  98. package/lib/execution/engine/transport.js.map +1 -0
  99. package/lib/execution/engine/types.d.ts +2 -0
  100. package/lib/execution/engine/types.d.ts.map +1 -1
  101. package/lib/execution/engine/types.js +24 -57
  102. package/lib/execution/engine/types.js.map +1 -1
  103. package/lib/execution/engine/utils.d.ts.map +1 -1
  104. package/lib/execution/engine/utils.js +9 -2
  105. package/lib/execution/engine/utils.js.map +1 -1
  106. package/lib/metrics/metrics/lodestar.d.ts +9 -0
  107. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  108. package/lib/metrics/metrics/lodestar.js +18 -0
  109. package/lib/metrics/metrics/lodestar.js.map +1 -1
  110. package/lib/network/core/events.d.ts +5 -1
  111. package/lib/network/core/events.d.ts.map +1 -1
  112. package/lib/network/core/events.js +8 -0
  113. package/lib/network/core/events.js.map +1 -1
  114. package/lib/network/processor/gossipHandlers.js +1 -1
  115. package/lib/network/processor/gossipHandlers.js.map +1 -1
  116. package/lib/node/options.d.ts +3 -2
  117. package/lib/node/options.d.ts.map +1 -1
  118. package/lib/node/options.js +2 -2
  119. package/lib/node/options.js.map +1 -1
  120. package/lib/sync/range/batch.d.ts +5 -5
  121. package/lib/sync/range/batch.d.ts.map +1 -1
  122. package/lib/sync/range/batch.js +11 -17
  123. package/lib/sync/range/batch.js.map +1 -1
  124. package/lib/sync/range/chain.d.ts +4 -4
  125. package/lib/sync/range/chain.d.ts.map +1 -1
  126. package/lib/sync/range/chain.js +7 -5
  127. package/lib/sync/range/chain.js.map +1 -1
  128. package/lib/sync/range/range.d.ts.map +1 -1
  129. package/lib/sync/range/range.js +25 -11
  130. package/lib/sync/range/range.js.map +1 -1
  131. package/lib/sync/utils/downloadByRange.d.ts +38 -14
  132. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  133. package/lib/sync/utils/downloadByRange.js +84 -39
  134. package/lib/sync/utils/downloadByRange.js.map +1 -1
  135. package/lib/util/asyncIterableToEvents.d.ts +10 -2
  136. package/lib/util/asyncIterableToEvents.d.ts.map +1 -1
  137. package/lib/util/asyncIterableToEvents.js +29 -3
  138. package/lib/util/asyncIterableToEvents.js.map +1 -1
  139. package/lib/util/metadata.d.ts.map +1 -1
  140. package/lib/util/metadata.js +2 -1
  141. package/lib/util/metadata.js.map +1 -1
  142. package/package.json +16 -15
  143. package/src/api/impl/beacon/state/index.ts +13 -4
  144. package/src/api/impl/validator/index.ts +11 -0
  145. package/src/chain/beaconProposerCache.ts +19 -1
  146. package/src/chain/blocks/importBlock.ts +8 -4
  147. package/src/chain/blocks/verifyBlock.ts +7 -6
  148. package/src/chain/chain.ts +59 -15
  149. package/src/chain/interface.ts +2 -0
  150. package/src/chain/opPools/opPool.ts +1 -31
  151. package/src/chain/opPools/proposerPreferencesPool.ts +20 -1
  152. package/src/chain/opPools/utils.ts +31 -0
  153. package/src/chain/prepareNextSlot.ts +15 -3
  154. package/src/chain/produceBlock/produceBlockBody.ts +68 -34
  155. package/src/chain/shufflingCache.ts +79 -22
  156. package/src/db/beacon.ts +3 -0
  157. package/src/db/buckets.ts +1 -0
  158. package/src/db/interface.ts +2 -0
  159. package/src/db/repositories/index.ts +1 -0
  160. package/src/db/repositories/proposerPreferences.ts +23 -0
  161. package/src/execution/engine/blobVersionedHashes.ts +72 -0
  162. package/src/execution/engine/http.ts +304 -271
  163. package/src/execution/engine/index.ts +41 -7
  164. package/src/execution/engine/interface.ts +1 -1
  165. package/src/execution/engine/jsonRpcTransport.ts +247 -0
  166. package/src/execution/engine/restHttpClient.ts +269 -0
  167. package/src/execution/engine/restTransport.ts +544 -0
  168. package/src/execution/engine/sszTypes.ts +354 -0
  169. package/src/execution/engine/transport.ts +61 -0
  170. package/src/execution/engine/types.ts +34 -74
  171. package/src/execution/engine/utils.ts +12 -2
  172. package/src/metrics/metrics/lodestar.ts +19 -0
  173. package/src/network/core/events.ts +16 -1
  174. package/src/network/processor/gossipHandlers.ts +1 -1
  175. package/src/node/options.ts +10 -1
  176. package/src/sync/range/batch.ts +14 -19
  177. package/src/sync/range/chain.ts +9 -7
  178. package/src/sync/range/range.ts +26 -12
  179. package/src/sync/utils/downloadByRange.ts +123 -58
  180. package/src/util/asyncIterableToEvents.ts +44 -5
  181. package/src/util/metadata.ts +2 -1
@@ -1,21 +1,30 @@
1
1
  import EventEmitter from "node:events";
2
2
  import {ResponseIncoming, ResponseOutgoing} from "@lodestar/reqresp";
3
- import {AsyncIterableEventBus, IteratorEvent, RequestEvent} from "../../util/asyncIterableToEvents.js";
3
+ import {
4
+ AsyncIterableEventBus,
5
+ IteratorEvent,
6
+ RequestCancelEvent,
7
+ RequestEvent,
8
+ } from "../../util/asyncIterableToEvents.js";
4
9
  import {StrictEventEmitterSingleArg} from "../../util/strictEvents.js";
5
10
  import {EventDirection} from "../events.js";
6
11
  import {IncomingRequestArgs, OutgoingRequestArgs} from "../reqresp/types.js";
7
12
 
8
13
  export enum ReqRespBridgeEvent {
9
14
  outgoingRequest = "reqresp.outgoingRequest",
15
+ outgoingRequestCancel = "reqresp.outgoingRequestCancel",
10
16
  outgoingResponse = "reqresp.outgoingResponse",
11
17
  incomingRequest = "reqresp.incomingRequest",
18
+ incomingRequestCancel = "reqresp.incomingRequestCancel",
12
19
  incomingResponse = "reqresp.incomingResponse",
13
20
  }
14
21
 
15
22
  export type ReqRespBridgeEventData = {
16
23
  [ReqRespBridgeEvent.outgoingRequest]: RequestEvent<OutgoingRequestArgs>;
24
+ [ReqRespBridgeEvent.outgoingRequestCancel]: RequestCancelEvent;
17
25
  [ReqRespBridgeEvent.outgoingResponse]: IteratorEvent<ResponseOutgoing>;
18
26
  [ReqRespBridgeEvent.incomingRequest]: RequestEvent<IncomingRequestArgs>;
27
+ [ReqRespBridgeEvent.incomingRequestCancel]: RequestCancelEvent;
19
28
  [ReqRespBridgeEvent.incomingResponse]: IteratorEvent<ResponseIncoming>;
20
29
  };
21
30
 
@@ -26,8 +35,10 @@ export class ReqRespBridgeEventBus extends (EventEmitter as {new (): IReqRespBri
26
35
  // NOTE: If the same event is on this two arrays it can create an infinite cycle
27
36
  export const reqRespBridgeEventDirection: Record<ReqRespBridgeEvent, EventDirection> = {
28
37
  [ReqRespBridgeEvent.outgoingRequest]: EventDirection.mainToWorker,
38
+ [ReqRespBridgeEvent.outgoingRequestCancel]: EventDirection.mainToWorker,
29
39
  [ReqRespBridgeEvent.outgoingResponse]: EventDirection.mainToWorker,
30
40
  [ReqRespBridgeEvent.incomingRequest]: EventDirection.workerToMain,
41
+ [ReqRespBridgeEvent.incomingRequestCancel]: EventDirection.workerToMain,
31
42
  [ReqRespBridgeEvent.incomingResponse]: EventDirection.workerToMain,
32
43
  };
33
44
 
@@ -36,8 +47,10 @@ export function getReqRespBridgeReqEvents(
36
47
  ): AsyncIterableEventBus<OutgoingRequestArgs, ResponseIncoming> {
37
48
  return {
38
49
  emitRequest: (data) => events.emit(ReqRespBridgeEvent.outgoingRequest, data),
50
+ emitRequestCancel: (data) => events.emit(ReqRespBridgeEvent.outgoingRequestCancel, data),
39
51
  emitResponse: (data) => events.emit(ReqRespBridgeEvent.incomingResponse, data),
40
52
  onRequest: (cb) => events.on(ReqRespBridgeEvent.outgoingRequest, cb),
53
+ onRequestCancel: (cb) => events.on(ReqRespBridgeEvent.outgoingRequestCancel, cb),
41
54
  onResponse: (cb) => events.on(ReqRespBridgeEvent.incomingResponse, cb),
42
55
  };
43
56
  }
@@ -47,8 +60,10 @@ export function getReqRespBridgeRespEvents(
47
60
  ): AsyncIterableEventBus<IncomingRequestArgs, ResponseOutgoing> {
48
61
  return {
49
62
  emitRequest: (data) => events.emit(ReqRespBridgeEvent.incomingRequest, data),
63
+ emitRequestCancel: (data) => events.emit(ReqRespBridgeEvent.incomingRequestCancel, data),
50
64
  emitResponse: (data) => events.emit(ReqRespBridgeEvent.outgoingResponse, data),
51
65
  onRequest: (cb) => events.on(ReqRespBridgeEvent.incomingRequest, cb),
66
+ onRequestCancel: (cb) => events.on(ReqRespBridgeEvent.incomingRequestCancel, cb),
52
67
  onResponse: (cb) => events.on(ReqRespBridgeEvent.outgoingResponse, cb),
53
68
  };
54
69
  }
@@ -1395,7 +1395,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
1395
1395
  const delaySec = chain.clock.secFromSlot(payloadAttestationMessage.data.slot, seenTimestampSec);
1396
1396
  metrics?.gossipPayloadAttestationMessage.elapsedTimeTillReceived.observe({source: OpSource.gossip}, delaySec);
1397
1397
  const nextSlotProposer = chain.getHeadState().getBeaconProposer(payloadAttestationMessage.data.slot + 1);
1398
- const isNextSlotProposer = chain.beaconProposerCache.get(nextSlotProposer) !== undefined;
1398
+ const isNextSlotProposer = chain.beaconProposerCache.has(nextSlotProposer);
1399
1399
 
1400
1400
  if (isNextSlotProposer) {
1401
1401
  try {
@@ -3,12 +3,14 @@ import {ArchiveMode, DEFAULT_ARCHIVE_MODE, IChainOptions, defaultChainOptions} f
3
3
  import {ValidatorMonitorOpts, defaultValidatorMonitorOpts} from "../chain/validatorMonitor.js";
4
4
  import {DatabaseOptions, defaultDbOptions} from "../db/options.js";
5
5
  import {
6
+ EngineApiMode,
6
7
  ExecutionBuilderOpts,
7
8
  ExecutionEngineOpts,
8
9
  defaultExecutionBuilderHttpOpts,
9
10
  defaultExecutionBuilderOpts,
10
11
  defaultExecutionEngineHttpOpts,
11
12
  defaultExecutionEngineOpts,
13
+ engineApiModes,
12
14
  } from "../execution/index.js";
13
15
  import {MetricsOptions, defaultMetricsOptions} from "../metrics/options.js";
14
16
  import {MonitoringOptions, defaultMonitoringOptions} from "../monitoring/options.js";
@@ -19,7 +21,14 @@ import {SyncOptions, defaultSyncOptions} from "../sync/options.js";
19
21
  export {allNamespaces} from "../api/rest/index.js";
20
22
 
21
23
  // Re-export to use as default values in CLI args
22
- export {defaultExecutionEngineHttpOpts, defaultExecutionBuilderHttpOpts, ArchiveMode, DEFAULT_ARCHIVE_MODE};
24
+ export {
25
+ defaultExecutionEngineHttpOpts,
26
+ defaultExecutionBuilderHttpOpts,
27
+ engineApiModes,
28
+ ArchiveMode,
29
+ DEFAULT_ARCHIVE_MODE,
30
+ };
31
+ export type {EngineApiMode};
23
32
 
24
33
  export interface IBeaconNodeOptions {
25
34
  api: ApiOptions;
@@ -14,7 +14,7 @@ import {IClock} from "../../util/clock.js";
14
14
  import {CustodyConfig} from "../../util/dataColumns.js";
15
15
  import {PeerIdStr} from "../../util/peerId.js";
16
16
  import {MAX_BATCH_DOWNLOAD_ATTEMPTS, MAX_BATCH_PROCESSING_ATTEMPTS} from "../constants.js";
17
- import {DownloadByRangeRequests, ParentPayloadCommitments} from "../utils/downloadByRange.js";
17
+ import {DownloadByRangeRequests, ParentPayload} from "../utils/downloadByRange.js";
18
18
  import {getBatchSlotRange, hashBlocks} from "./utils/index.js";
19
19
 
20
20
  /**
@@ -175,7 +175,7 @@ export class Batch {
175
175
  private readonly clock: IClock;
176
176
  private readonly custodyConfig: CustodyConfig;
177
177
  private readonly isFirstBatchInChain: boolean;
178
- private readonly latestBid: gloas.ExecutionPayloadBid | undefined;
178
+ private readonly parentPayload: ParentPayload | undefined;
179
179
 
180
180
  constructor(
181
181
  startEpoch: Epoch,
@@ -183,7 +183,7 @@ export class Batch {
183
183
  clock: IClock,
184
184
  custodyConfig: CustodyConfig,
185
185
  isFirstBatchInChain: boolean,
186
- latestBid: gloas.ExecutionPayloadBid | undefined,
186
+ parentPayload: ParentPayload | undefined,
187
187
  targetSlot: Slot
188
188
  ) {
189
189
  this.config = config;
@@ -196,7 +196,7 @@ export class Batch {
196
196
  this.startSlot = startSlot;
197
197
  this.count = Math.min(count, targetSlot - startSlot + 1);
198
198
  this.isFirstBatchInChain = isFirstBatchInChain;
199
- this.latestBid = latestBid;
199
+ this.parentPayload = parentPayload;
200
200
  this.requests = this.getRequests([]);
201
201
  }
202
202
 
@@ -208,24 +208,19 @@ export class Batch {
208
208
  }
209
209
 
210
210
  // we only know if we should download parent envelope if firstBlock is downloaded
211
- if (firstBlock === undefined) return false;
212
- if (this.latestBid === undefined) return false;
213
- const firstBlockBidParentHash = (firstBlock.message.body as gloas.BeaconBlockBody).signedExecutionPayloadBid.message
214
- .parentBlockHash;
215
- return byteArrayEquals(firstBlockBidParentHash, this.latestBid.blockHash);
211
+ if (firstBlock === undefined || this.parentPayload === undefined) return false;
212
+ const firstBlockBid = (firstBlock.message.body as gloas.BeaconBlockBody).signedExecutionPayloadBid.message;
213
+ return (
214
+ byteArrayEquals(firstBlock.message.parentRoot, this.parentPayload.blockRoot) &&
215
+ byteArrayEquals(firstBlockBid.parentBlockHash, this.parentPayload.bid.blockHash)
216
+ );
216
217
  }
217
218
 
218
- getParentPayloadCommitments(parentBlockRoot: Uint8Array): ParentPayloadCommitments {
219
- if (this.latestBid === undefined) {
220
- throw new Error(
221
- `Coding error: getParentPayloadCommitments called without latestBid for parentBlockRoot=${toRootHex(parentBlockRoot)}`
222
- );
219
+ getParentPayload(): ParentPayload {
220
+ if (this.parentPayload === undefined) {
221
+ throw new Error("Coding error: getParentPayload called without parentPayload");
223
222
  }
224
- return {
225
- blockRoot: parentBlockRoot,
226
- blockRootHex: toRootHex(parentBlockRoot),
227
- kzgCommitments: this.latestBid.blobKzgCommitments,
228
- };
223
+ return this.parentPayload;
229
224
  }
230
225
 
231
226
  /**
@@ -1,5 +1,5 @@
1
1
  import {ChainForkConfig} from "@lodestar/config";
2
- import {Epoch, Root, Slot, gloas} from "@lodestar/types";
2
+ import {Epoch, Root, Slot} from "@lodestar/types";
3
3
  import {ErrorAborted, LodestarError, Logger, prettyPrintIndices, toRootHex} from "@lodestar/utils";
4
4
  import {isBlockInputBlobs, isBlockInputColumns} from "../../chain/blocks/blockInput/blockInput.js";
5
5
  import {BlockInputErrorCode} from "../../chain/blocks/blockInput/errors.js";
@@ -16,7 +16,7 @@ import {ItTrigger} from "../../util/itTrigger.js";
16
16
  import {PeerIdStr} from "../../util/peerId.js";
17
17
  import {WarnResult, wrapError} from "../../util/wrapError.js";
18
18
  import {BATCH_BUFFER_SIZE, EPOCHS_PER_BATCH, MAX_LOOK_AHEAD_EPOCHS} from "../constants.js";
19
- import {DownloadByRangeError, DownloadByRangeErrorCode} from "../utils/downloadByRange.js";
19
+ import {DownloadByRangeError, DownloadByRangeErrorCode, ParentPayload} from "../utils/downloadByRange.js";
20
20
  import {getRateLimitedUntilMs} from "../utils/rateLimit.js";
21
21
  import {RangeSyncType} from "../utils/remoteSyncType.js";
22
22
  import {Batch, BatchError, BatchErrorCode, BatchMetadata, BatchStatus} from "./batch.js";
@@ -160,7 +160,7 @@ export class SyncChain {
160
160
  private readonly clock: IClock;
161
161
  private readonly metrics: Metrics | null;
162
162
  private readonly custodyConfig: CustodyConfig;
163
- private readonly latestBid: gloas.ExecutionPayloadBid | undefined;
163
+ private readonly parentPayload: ParentPayload | undefined;
164
164
 
165
165
  constructor(
166
166
  initialBatchEpoch: Epoch,
@@ -168,7 +168,7 @@ export class SyncChain {
168
168
  syncType: RangeSyncType,
169
169
  fns: SyncChainFns,
170
170
  modules: SyncChainModules,
171
- latestBid: gloas.ExecutionPayloadBid | undefined
171
+ parentPayload: ParentPayload | undefined
172
172
  ) {
173
173
  const {config, clock, custodyConfig, logger, metrics} = modules;
174
174
  this.firstBatchEpoch = initialBatchEpoch;
@@ -184,7 +184,7 @@ export class SyncChain {
184
184
  this.clock = clock;
185
185
  this.metrics = metrics;
186
186
  this.custodyConfig = custodyConfig;
187
- this.latestBid = latestBid;
187
+ this.parentPayload = parentPayload;
188
188
  this.logger = logger;
189
189
  this.logId = `${syncType}-${nextChainId++}`;
190
190
 
@@ -536,8 +536,8 @@ export class SyncChain {
536
536
  this.clock,
537
537
  this.custodyConfig,
538
538
  this.isFirstBatch,
539
- // `latestBid` is only meaningful for the first batch's parent-payload check
540
- this.isFirstBatch ? this.latestBid : undefined,
539
+ // `parentPayload` is only meaningful for the first batch
540
+ this.isFirstBatch ? this.parentPayload : undefined,
541
541
  this.target.slot
542
542
  );
543
543
  this.isFirstBatch = false;
@@ -586,6 +586,8 @@ export class SyncChain {
586
586
  case DownloadByRangeErrorCode.OUT_OF_RANGE_BLOCKS:
587
587
  case DownloadByRangeErrorCode.PARENT_ROOT_MISMATCH:
588
588
  case DownloadByRangeErrorCode.INVALID_ENVELOPE_BEACON_BLOCK_ROOT:
589
+ case DownloadByRangeErrorCode.INVALID_ENVELOPE_BLOCK_HASH:
590
+ case DownloadByRangeErrorCode.INVALID_ENVELOPE_SLOT:
589
591
  case DownloadByRangeErrorCode.INVALID_CHAIN_SEGMENT:
590
592
  case BlobSidecarErrorCode.INCLUSION_PROOF_INVALID:
591
593
  case BlobSidecarErrorCode.INVALID_KZG_PROOF_BATCH:
@@ -2,8 +2,8 @@ import {EventEmitter} from "node:events";
2
2
  import {StrictEventEmitter} from "strict-event-emitter-types";
3
3
  import {BeaconConfig} from "@lodestar/config";
4
4
  import {IBeaconStateViewGloas, computeStartSlotAtEpoch, isStatePostGloas} from "@lodestar/state-transition";
5
- import {Epoch, Status, fulu} from "@lodestar/types";
6
- import {Logger, prettyPrintIndices, toRootHex} from "@lodestar/utils";
5
+ import {Epoch, Status, fulu, ssz} from "@lodestar/types";
6
+ import {Logger, byteArrayEquals, prettyPrintIndices, toRootHex} from "@lodestar/utils";
7
7
  import {IBlockInput} from "../../chain/blocks/blockInput/types.js";
8
8
  import {PayloadError, PayloadErrorCode} from "../../chain/blocks/importExecutionPayload.js";
9
9
  import {AttestationImportOpt, ImportBlockOpts} from "../../chain/blocks/index.js";
@@ -16,6 +16,7 @@ import {PeerIdStr} from "../../util/peerId.js";
16
16
  import {
17
17
  DownloadByRangeError,
18
18
  DownloadByRangeErrorCode,
19
+ ParentPayload,
19
20
  cacheByRangeResponses,
20
21
  downloadByRange,
21
22
  } from "../utils/downloadByRange.js";
@@ -278,15 +279,14 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
278
279
  private downloadByRange: SyncChainFns["downloadByRange"] = async (peer, batch) => {
279
280
  const batchBlocks = batch.getBlocks();
280
281
  const requests = batch.getRequestsForPeer(peer);
281
- const parentRoot = requests.parentPayloadRequest?.envelopeBlockRoot ?? requests.parentPayloadRequest?.blockRoot;
282
- const parentPayloadCommitments = parentRoot ? batch.getParentPayloadCommitments(parentRoot) : undefined;
282
+ const parentPayload = requests.parentPayloadRequest ? batch.getParentPayload() : undefined;
283
283
  const {result, warnings} = await downloadByRange({
284
284
  config: this.config,
285
285
  network: this.network,
286
286
  logger: this.logger,
287
287
  peerIdStr: peer.peerId,
288
288
  batchBlocks,
289
- parentPayloadCommitments,
289
+ parentPayload,
290
290
  peerDasMetrics: this.chain.metrics?.peerDas,
291
291
  ...requests,
292
292
  });
@@ -299,6 +299,7 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
299
299
  batchBlocks,
300
300
  downloadedPayloadEnvelopes,
301
301
  existingPayloadEnvelopes: batch.getPayloadEnvelopes(),
302
+ parentPayload,
302
303
  custodyConfig: this.chain.custodyConfig,
303
304
  seenTimestampSec: Date.now() / 1000,
304
305
  });
@@ -376,13 +377,26 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
376
377
  private addPeerOrCreateChain(startEpoch: Epoch, target: ChainTarget, peer: PeerIdStr, syncType: RangeSyncType): void {
377
378
  let syncChain = this.chains.get(syncType);
378
379
  if (!syncChain) {
379
- // The first batch of a new sync chain may need to detect whether the parent block was an
380
- // gloas "empty" block (no envelope produced). It does so by comparing the first
381
- // downloaded block's `bid.parentBlockHash` against the head state's `latestExecutionPayloadBid.blockHash`.
380
+ // The first block of the first batch may build on the head's FULL variant before its payload is imported,
381
+ // the batch then downloads the head's payload as dangling parent and validates it against the bid
382
382
  const headState = this.chain.getHeadState();
383
- const latestBid = isStatePostGloas(headState)
384
- ? (headState as IBeaconStateViewGloas).latestExecutionPayloadBid
385
- : undefined;
383
+ let parentPayload: ParentPayload | undefined;
384
+ if (isStatePostGloas(headState) && headState.latestBlockHeader.slot > 0) {
385
+ const header = ssz.phase0.BeaconBlockHeader.clone(headState.latestBlockHeader);
386
+ if (byteArrayEquals(header.stateRoot, ssz.Root.defaultValue())) {
387
+ header.stateRoot = headState.hashTreeRoot();
388
+ }
389
+ const headRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(header);
390
+ const headSlot = headState.latestBlockHeader.slot;
391
+ parentPayload = {
392
+ blockRoot: headRoot,
393
+ blockRootHex: toRootHex(headRoot),
394
+ slot: headSlot,
395
+ proposerIndex: headState.latestBlockHeader.proposerIndex,
396
+ forkName: this.config.getForkName(headSlot),
397
+ bid: (headState as IBeaconStateViewGloas).latestExecutionPayloadBid,
398
+ };
399
+ }
386
400
 
387
401
  syncChain = new SyncChain(
388
402
  startEpoch,
@@ -403,7 +417,7 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
403
417
  custodyConfig: this.chain.custodyConfig,
404
418
  metrics: this.metrics,
405
419
  },
406
- latestBid
420
+ parentPayload
407
421
  );
408
422
  this.chains.set(syncType, syncChain);
409
423