@lodestar/beacon-node 1.41.0-dev.3b98c59c64 → 1.41.0-dev.477bc362ce

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 (210) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +3 -2
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/debug/index.d.ts.map +1 -1
  5. package/lib/api/impl/debug/index.js +1 -0
  6. package/lib/api/impl/debug/index.js.map +1 -1
  7. package/lib/api/impl/node/utils.d.ts +1 -1
  8. package/lib/api/impl/node/utils.d.ts.map +1 -1
  9. package/lib/api/impl/node/utils.js.map +1 -1
  10. package/lib/api/impl/validator/index.js +2 -2
  11. package/lib/api/impl/validator/index.js.map +1 -1
  12. package/lib/chain/archiveStore/utils/updateBackfillRange.js +1 -1
  13. package/lib/chain/archiveStore/utils/updateBackfillRange.js.map +1 -1
  14. package/lib/chain/blocks/blockInput/blockInput.d.ts +20 -2
  15. package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
  16. package/lib/chain/blocks/blockInput/blockInput.js +47 -0
  17. package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
  18. package/lib/chain/blocks/blockInput/types.d.ts +2 -1
  19. package/lib/chain/blocks/blockInput/types.d.ts.map +1 -1
  20. package/lib/chain/blocks/blockInput/types.js +1 -0
  21. package/lib/chain/blocks/blockInput/types.js.map +1 -1
  22. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  23. package/lib/chain/blocks/importBlock.js +26 -3
  24. package/lib/chain/blocks/importBlock.js.map +1 -1
  25. package/lib/chain/blocks/verifyBlocksDataAvailability.d.ts.map +1 -1
  26. package/lib/chain/blocks/verifyBlocksDataAvailability.js +3 -0
  27. package/lib/chain/blocks/verifyBlocksDataAvailability.js.map +1 -1
  28. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts +4 -0
  29. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
  30. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +5 -1
  31. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
  32. package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts.map +1 -1
  33. package/lib/chain/blocks/verifyBlocksSanityChecks.js +4 -1
  34. package/lib/chain/blocks/verifyBlocksSanityChecks.js.map +1 -1
  35. package/lib/chain/chain.js +6 -6
  36. package/lib/chain/chain.js.map +1 -1
  37. package/lib/chain/emitter.d.ts +3 -3
  38. package/lib/chain/emitter.d.ts.map +1 -1
  39. package/lib/chain/errors/executionPayloadEnvelope.d.ts +2 -2
  40. package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
  41. package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
  42. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  43. package/lib/chain/forkChoice/index.js +30 -24
  44. package/lib/chain/forkChoice/index.js.map +1 -1
  45. package/lib/chain/opPools/aggregatedAttestationPool.js +1 -1
  46. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  47. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  48. package/lib/chain/produceBlock/produceBlockBody.js +1 -2
  49. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  50. package/lib/chain/regen/queued.d.ts.map +1 -1
  51. package/lib/chain/regen/queued.js +4 -1
  52. package/lib/chain/regen/queued.js.map +1 -1
  53. package/lib/chain/regen/regen.d.ts.map +1 -1
  54. package/lib/chain/regen/regen.js +5 -1
  55. package/lib/chain/regen/regen.js.map +1 -1
  56. package/lib/chain/seenCache/seenGossipBlockInput.d.ts.map +1 -1
  57. package/lib/chain/seenCache/seenGossipBlockInput.js +15 -7
  58. package/lib/chain/seenCache/seenGossipBlockInput.js.map +1 -1
  59. package/lib/chain/validation/aggregateAndProof.js +1 -1
  60. package/lib/chain/validation/aggregateAndProof.js.map +1 -1
  61. package/lib/chain/validation/attestation.js +3 -3
  62. package/lib/chain/validation/attestation.js.map +1 -1
  63. package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
  64. package/lib/chain/validation/attesterSlashing.js +8 -1
  65. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  66. package/lib/chain/validation/blobSidecar.js +2 -2
  67. package/lib/chain/validation/blobSidecar.js.map +1 -1
  68. package/lib/chain/validation/block.d.ts.map +1 -1
  69. package/lib/chain/validation/block.js +6 -3
  70. package/lib/chain/validation/block.js.map +1 -1
  71. package/lib/chain/validation/dataColumnSidecar.js +1 -1
  72. package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
  73. package/lib/chain/validation/executionPayloadBid.js +1 -2
  74. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  75. package/lib/chain/validation/executionPayloadEnvelope.js +4 -4
  76. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  77. package/lib/chain/validation/payloadAttestationMessage.js +1 -2
  78. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  79. package/lib/db/repositories/blockArchive.d.ts.map +1 -1
  80. package/lib/db/repositories/blockArchive.js +1 -2
  81. package/lib/db/repositories/blockArchive.js.map +1 -1
  82. package/lib/execution/engine/http.d.ts +1 -0
  83. package/lib/execution/engine/http.d.ts.map +1 -1
  84. package/lib/execution/engine/http.js +3 -0
  85. package/lib/execution/engine/http.js.map +1 -1
  86. package/lib/metrics/metrics/lodestar.d.ts +3 -0
  87. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  88. package/lib/metrics/metrics/lodestar.js +5 -0
  89. package/lib/metrics/metrics/lodestar.js.map +1 -1
  90. package/lib/network/core/networkCore.d.ts +3 -3
  91. package/lib/network/core/networkCore.d.ts.map +1 -1
  92. package/lib/network/core/networkCore.js.map +1 -1
  93. package/lib/network/core/networkCoreWorkerHandler.d.ts +3 -3
  94. package/lib/network/core/networkCoreWorkerHandler.d.ts.map +1 -1
  95. package/lib/network/core/types.d.ts +2 -2
  96. package/lib/network/core/types.d.ts.map +1 -1
  97. package/lib/network/events.d.ts +2 -1
  98. package/lib/network/events.d.ts.map +1 -1
  99. package/lib/network/events.js.map +1 -1
  100. package/lib/network/gossip/encoding.d.ts +3 -3
  101. package/lib/network/gossip/encoding.d.ts.map +1 -1
  102. package/lib/network/gossip/encoding.js.map +1 -1
  103. package/lib/network/gossip/gossipsub.d.ts +13 -4
  104. package/lib/network/gossip/gossipsub.d.ts.map +1 -1
  105. package/lib/network/gossip/gossipsub.js +47 -20
  106. package/lib/network/gossip/gossipsub.js.map +1 -1
  107. package/lib/network/gossip/interface.d.ts +3 -3
  108. package/lib/network/gossip/interface.d.ts.map +1 -1
  109. package/lib/network/gossip/scoringParameters.d.ts +1 -1
  110. package/lib/network/gossip/scoringParameters.d.ts.map +1 -1
  111. package/lib/network/gossip/scoringParameters.js +1 -1
  112. package/lib/network/gossip/scoringParameters.js.map +1 -1
  113. package/lib/network/interface.d.ts +3 -3
  114. package/lib/network/interface.d.ts.map +1 -1
  115. package/lib/network/libp2p/index.d.ts +1 -1
  116. package/lib/network/libp2p/index.d.ts.map +1 -1
  117. package/lib/network/libp2p/index.js +7 -2
  118. package/lib/network/libp2p/index.js.map +1 -1
  119. package/lib/network/network.d.ts +2 -2
  120. package/lib/network/network.d.ts.map +1 -1
  121. package/lib/network/network.js.map +1 -1
  122. package/lib/network/options.d.ts.map +1 -1
  123. package/lib/network/options.js +3 -0
  124. package/lib/network/options.js.map +1 -1
  125. package/lib/network/peers/datastore.d.ts +7 -5
  126. package/lib/network/peers/datastore.d.ts.map +1 -1
  127. package/lib/network/peers/datastore.js +10 -10
  128. package/lib/network/peers/datastore.js.map +1 -1
  129. package/lib/network/peers/peerManager.d.ts +1 -0
  130. package/lib/network/peers/peerManager.d.ts.map +1 -1
  131. package/lib/network/peers/peerManager.js +51 -29
  132. package/lib/network/peers/peerManager.js.map +1 -1
  133. package/lib/network/peers/utils/prioritizePeers.d.ts +3 -3
  134. package/lib/network/peers/utils/prioritizePeers.d.ts.map +1 -1
  135. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  136. package/lib/network/processor/gossipHandlers.js +4 -1
  137. package/lib/network/processor/gossipHandlers.js.map +1 -1
  138. package/lib/network/processor/gossipValidatorFn.js +1 -1
  139. package/lib/network/processor/types.d.ts +1 -1
  140. package/lib/network/processor/types.d.ts.map +1 -1
  141. package/lib/network/reqresp/handlers/blobSidecarsByRoot.js +1 -1
  142. package/lib/network/reqresp/handlers/blobSidecarsByRoot.js.map +1 -1
  143. package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js +1 -1
  144. package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js.map +1 -1
  145. package/lib/network/reqresp/score.d.ts.map +1 -1
  146. package/lib/network/reqresp/score.js +0 -1
  147. package/lib/network/reqresp/score.js.map +1 -1
  148. package/lib/network/util.js +2 -2
  149. package/lib/network/util.js.map +1 -1
  150. package/lib/util/clock.d.ts +6 -0
  151. package/lib/util/clock.d.ts.map +1 -1
  152. package/lib/util/clock.js +9 -3
  153. package/lib/util/clock.js.map +1 -1
  154. package/package.json +38 -41
  155. package/src/api/impl/beacon/blocks/index.ts +3 -2
  156. package/src/api/impl/debug/index.ts +1 -0
  157. package/src/api/impl/node/utils.ts +3 -3
  158. package/src/api/impl/validator/index.ts +2 -2
  159. package/src/chain/archiveStore/utils/updateBackfillRange.ts +1 -1
  160. package/src/chain/blocks/blockInput/blockInput.ts +68 -3
  161. package/src/chain/blocks/blockInput/types.ts +1 -0
  162. package/src/chain/blocks/importBlock.ts +34 -3
  163. package/src/chain/blocks/verifyBlocksDataAvailability.ts +3 -0
  164. package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +9 -2
  165. package/src/chain/blocks/verifyBlocksSanityChecks.ts +7 -2
  166. package/src/chain/chain.ts +6 -6
  167. package/src/chain/emitter.ts +3 -3
  168. package/src/chain/errors/executionPayloadEnvelope.ts +6 -2
  169. package/src/chain/forkChoice/index.ts +39 -21
  170. package/src/chain/opPools/aggregatedAttestationPool.ts +1 -1
  171. package/src/chain/produceBlock/produceBlockBody.ts +1 -2
  172. package/src/chain/regen/queued.ts +7 -2
  173. package/src/chain/regen/regen.ts +8 -2
  174. package/src/chain/seenCache/seenGossipBlockInput.ts +16 -7
  175. package/src/chain/validation/aggregateAndProof.ts +1 -1
  176. package/src/chain/validation/attestation.ts +3 -3
  177. package/src/chain/validation/attesterSlashing.ts +9 -0
  178. package/src/chain/validation/blobSidecar.ts +2 -2
  179. package/src/chain/validation/block.ts +9 -4
  180. package/src/chain/validation/dataColumnSidecar.ts +1 -1
  181. package/src/chain/validation/executionPayloadBid.ts +1 -2
  182. package/src/chain/validation/executionPayloadEnvelope.ts +4 -4
  183. package/src/chain/validation/payloadAttestationMessage.ts +1 -2
  184. package/src/db/repositories/blockArchive.ts +1 -2
  185. package/src/execution/engine/http.ts +3 -0
  186. package/src/metrics/metrics/lodestar.ts +5 -0
  187. package/src/network/core/networkCore.ts +3 -3
  188. package/src/network/core/networkCoreWorkerHandler.ts +3 -3
  189. package/src/network/core/types.ts +2 -2
  190. package/src/network/events.ts +2 -1
  191. package/src/network/gossip/encoding.ts +3 -3
  192. package/src/network/gossip/gossipsub.ts +86 -25
  193. package/src/network/gossip/interface.ts +3 -3
  194. package/src/network/gossip/scoringParameters.ts +4 -4
  195. package/src/network/interface.ts +3 -3
  196. package/src/network/libp2p/index.ts +8 -3
  197. package/src/network/network.ts +3 -3
  198. package/src/network/options.ts +3 -0
  199. package/src/network/peers/datastore.ts +13 -10
  200. package/src/network/peers/peerManager.ts +56 -30
  201. package/src/network/peers/utils/prioritizePeers.ts +3 -3
  202. package/src/network/processor/gossipHandlers.ts +12 -3
  203. package/src/network/processor/gossipValidatorFn.ts +1 -1
  204. package/src/network/processor/types.ts +1 -1
  205. package/src/network/reqresp/handlers/blobSidecarsByRoot.ts +1 -1
  206. package/src/network/reqresp/handlers/dataColumnSidecarsByRoot.ts +1 -1
  207. package/src/network/reqresp/score.ts +0 -1
  208. package/src/network/util.ts +2 -2
  209. package/src/util/clock.ts +9 -4
  210. package/src/util/workerEvents.ts +1 -1
@@ -1,5 +1,5 @@
1
- import {ForkName, ForkPostFulu, ForkPreDeneb, ForkPreGloas, NUMBER_OF_COLUMNS} from "@lodestar/params";
2
- import {BeaconBlockBody, BlobIndex, ColumnIndex, SignedBeaconBlock, Slot, deneb, fulu} from "@lodestar/types";
1
+ import {ForkName, ForkPostFulu, ForkPostGloas, ForkPreDeneb, ForkPreGloas, NUMBER_OF_COLUMNS} from "@lodestar/params";
2
+ import {BeaconBlockBody, BlobIndex, ColumnIndex, SignedBeaconBlock, Slot, deneb, fulu, gloas} from "@lodestar/types";
3
3
  import {byteArrayEquals, fromHex, prettyBytes, toRootHex, withTimeout} from "@lodestar/utils";
4
4
  import {VersionedHashes} from "../../../execution/index.js";
5
5
  import {kzgCommitmentToVersionedHash} from "../../../util/blobs.js";
@@ -24,7 +24,7 @@ import {
24
24
  SourceMeta,
25
25
  } from "./types.js";
26
26
 
27
- export type BlockInput = BlockInputPreData | BlockInputBlobs | BlockInputColumns;
27
+ export type BlockInput = BlockInputPreData | BlockInputBlobs | BlockInputColumns | BlockInputNoData;
28
28
 
29
29
  export function isBlockInputPreDeneb(blockInput: IBlockInput): blockInput is BlockInputPreData {
30
30
  return blockInput.type === DAType.PreData;
@@ -37,6 +37,10 @@ export function isBlockInputColumns(blockInput: IBlockInput): blockInput is Bloc
37
37
  return blockInput.type === DAType.Columns;
38
38
  }
39
39
 
40
+ export function isBlockInputNoData(blockInput: IBlockInput): blockInput is BlockInputNoData {
41
+ return blockInput.type === DAType.NoData;
42
+ }
43
+
40
44
  function createPromise<T>(): PromiseParts<T> {
41
45
  let resolve!: (value: T) => void;
42
46
  let reject!: (e: Error) => void;
@@ -903,3 +907,64 @@ export class BlockInputColumns extends AbstractBlockInput<ForkColumnsDA, fulu.Da
903
907
  return Promise.resolve(this.getSampledColumns());
904
908
  }
905
909
  }
910
+
911
+ type BlockInputNoDataState = {
912
+ hasBlock: true;
913
+ hasAllData: true;
914
+ block: SignedBeaconBlock<ForkPostGloas>;
915
+ source: SourceMeta;
916
+ timeCompleteSec: number;
917
+ };
918
+
919
+ export class BlockInputNoData extends AbstractBlockInput<ForkPostGloas, null> {
920
+ type = DAType.NoData as const;
921
+
922
+ state: BlockInputNoDataState;
923
+
924
+ private constructor(init: BlockInputInit, state: BlockInputNoDataState) {
925
+ super(init);
926
+ this.state = state;
927
+ this.dataPromise.resolve(null);
928
+ this.blockPromise.resolve(state.block);
929
+ }
930
+
931
+ static createFromBlock(props: AddBlock<ForkPostGloas> & CreateBlockInputMeta): BlockInputNoData {
932
+ const init: BlockInputInit = {
933
+ daOutOfRange: props.daOutOfRange,
934
+ timeCreated: props.seenTimestampSec,
935
+ forkName: props.forkName,
936
+ slot: props.block.message.slot,
937
+ blockRootHex: props.blockRootHex,
938
+ parentRootHex: toRootHex(props.block.message.parentRoot),
939
+ };
940
+ const state: BlockInputNoDataState = {
941
+ hasBlock: true,
942
+ hasAllData: true,
943
+ block: props.block,
944
+ source: {
945
+ source: props.source,
946
+ seenTimestampSec: props.seenTimestampSec,
947
+ peerIdStr: props.peerIdStr,
948
+ },
949
+ timeCompleteSec: props.seenTimestampSec,
950
+ };
951
+ return new BlockInputNoData(init, state);
952
+ }
953
+
954
+ addBlock(_: AddBlock<ForkPostGloas>, opts = {throwOnDuplicateAdd: true}): void {
955
+ if (opts.throwOnDuplicateAdd) {
956
+ throw new BlockInputError(
957
+ {
958
+ code: BlockInputErrorCode.INVALID_CONSTRUCTION,
959
+ blockRoot: this.blockRootHex,
960
+ },
961
+ "Cannot addBlock to BlockInputNoData - block already exists"
962
+ );
963
+ }
964
+ }
965
+
966
+ getBlobKzgCommitments(): deneb.BlobKzgCommitments {
967
+ return (this.state.block.message.body as gloas.BeaconBlockBody).signedExecutionPayloadBid.message
968
+ .blobKzgCommitments;
969
+ }
970
+ }
@@ -6,6 +6,7 @@ export enum DAType {
6
6
  PreData = "pre-data",
7
7
  Blobs = "blobs",
8
8
  Columns = "columns",
9
+ NoData = "no-data",
9
10
  }
10
11
 
11
12
  export type DAData = null | deneb.BlobSidecars | fulu.DataColumnSidecars;
@@ -20,7 +20,7 @@ import {
20
20
  isStartSlotOfEpoch,
21
21
  isStateValidatorsNodesPopulated,
22
22
  } from "@lodestar/state-transition";
23
- import {Attestation, BeaconBlock, altair, capella, electra, phase0, ssz} from "@lodestar/types";
23
+ import {Attestation, BeaconBlock, altair, capella, electra, isGloasBeaconBlock, phase0, ssz} from "@lodestar/types";
24
24
  import {isErrorAborted, toRootHex} from "@lodestar/utils";
25
25
  import {ZERO_HASH_HEX} from "../../constants/index.js";
26
26
  import {callInNextEventLoop} from "../../util/eventLoop.js";
@@ -230,6 +230,32 @@ export async function importBlock(
230
230
  }
231
231
  }
232
232
 
233
+ // 4.5. Import payload attestations to fork choice (Gloas)
234
+ //
235
+ if (isGloasBeaconBlock(block.message)) {
236
+ for (const payloadAttestation of block.message.body.payloadAttestations) {
237
+ try {
238
+ // Extract PTC indices from aggregation bits
239
+ const ptcIndices: number[] = [];
240
+ for (let i = 0; i < payloadAttestation.aggregationBits.bitLen; i++) {
241
+ if (payloadAttestation.aggregationBits.get(i)) {
242
+ ptcIndices.push(i);
243
+ }
244
+ }
245
+
246
+ if (ptcIndices.length > 0) {
247
+ this.forkChoice.notifyPtcMessages(
248
+ toRootHex(payloadAttestation.data.beaconBlockRoot),
249
+ ptcIndices,
250
+ payloadAttestation.data.payloadPresent
251
+ );
252
+ }
253
+ } catch (e) {
254
+ this.logger.warn("Error processing PayloadAttestation from block", {slot: blockSlot}, e as Error);
255
+ }
256
+ }
257
+ }
258
+
233
259
  // 5. Compute head. If new head, immediately stateCache.setHeadState()
234
260
 
235
261
  const oldHead = this.forkChoice.getHead();
@@ -345,7 +371,7 @@ export async function importBlock(
345
371
  // 3) Proposer boost reorg related flag is turned on (this is checked inside the function)
346
372
  // 4) Block meets the criteria of being re-orged out (this is also checked inside the function)
347
373
  const result = this.forkChoice.shouldOverrideForkChoiceUpdate(
348
- blockSummary.blockRoot,
374
+ blockSummary,
349
375
  this.clock.secFromSlot(currentSlot),
350
376
  currentSlot
351
377
  );
@@ -441,7 +467,12 @@ export async function importBlock(
441
467
  this.metrics?.currentActiveValidators.set(activeValidatorsCount);
442
468
  this.metrics?.currentValidators.set({status: "active"}, activeValidatorsCount);
443
469
 
444
- const parentBlockSummary = this.forkChoice.getBlock(checkpointState.latestBlockHeader.parentRoot);
470
+ const parentBlockSummary = isGloasBeaconBlock(block.message)
471
+ ? this.forkChoice.getBlockHexAndBlockHash(
472
+ toRootHex(checkpointState.latestBlockHeader.parentRoot),
473
+ toRootHex(block.message.body.signedExecutionPayloadBid.message.parentBlockHash)
474
+ )
475
+ : this.forkChoice.getBlockDefaultStatus(checkpointState.latestBlockHeader.parentRoot);
445
476
 
446
477
  if (parentBlockSummary) {
447
478
  const justifiedCheckpoint = checkpointState.currentJustifiedCheckpoint;
@@ -29,6 +29,9 @@ export async function verifyBlocksDataAvailability(
29
29
 
30
30
  const availableTime = Math.max(0, Math.max(...blocks.map((blockInput) => blockInput.getTimeComplete())));
31
31
  const dataAvailabilityStatuses: DataAvailabilityStatus[] = blocks.map((blockInput) => {
32
+ if (blockInput.type === DAType.NoData) {
33
+ return DataAvailabilityStatus.NotRequired;
34
+ }
32
35
  if (blockInput.type === DAType.PreData) {
33
36
  return DataAvailabilityStatus.PreData;
34
37
  }
@@ -21,7 +21,7 @@ import {Metrics} from "../../metrics/metrics.js";
21
21
  import {IClock} from "../../util/clock.js";
22
22
  import {BlockError, BlockErrorCode} from "../errors/index.js";
23
23
  import {BlockProcessOpts} from "../options.js";
24
- import {isBlockInputBlobs, isBlockInputColumns} from "./blockInput/blockInput.js";
24
+ import {isBlockInputBlobs, isBlockInputColumns, isBlockInputNoData} from "./blockInput/blockInput.js";
25
25
  import {IBlockInput} from "./blockInput/types.js";
26
26
  import {ImportBlockOpts} from "./types.js";
27
27
 
@@ -51,7 +51,8 @@ type VerifyBlockExecutionResponse =
51
51
  | VerifyExecutionErrorResponse
52
52
  | {executionStatus: ExecutionStatus.Valid; lvhResponse: LVHValidResponse; execError: null}
53
53
  | {executionStatus: ExecutionStatus.Syncing; lvhResponse?: LVHValidResponse; execError: null}
54
- | {executionStatus: ExecutionStatus.PreMerge; lvhResponse: undefined; execError: null};
54
+ | {executionStatus: ExecutionStatus.PreMerge; lvhResponse: undefined; execError: null}
55
+ | {executionStatus: ExecutionStatus.PayloadSeparated; lvhResponse: undefined; execError: null};
55
56
 
56
57
  /**
57
58
  * Verifies 1 or more execution payloads from a linear sequence of blocks.
@@ -148,6 +149,12 @@ export async function verifyBlockExecutionPayload(
148
149
  preState0: CachedBeaconStateAllForks
149
150
  ): Promise<VerifyBlockExecutionResponse> {
150
151
  const block = blockInput.getBlock();
152
+
153
+ // Gloas block doesn't have execution payload. Return right away
154
+ if (isBlockInputNoData(blockInput)) {
155
+ return {executionStatus: ExecutionStatus.PayloadSeparated, lvhResponse: undefined, execError: null};
156
+ }
157
+
151
158
  /** Not null if execution is enabled */
152
159
  const executionPayloadEnabled =
153
160
  isExecutionStateType(preState0) &&
@@ -1,7 +1,7 @@
1
1
  import {ChainForkConfig} from "@lodestar/config";
2
2
  import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
3
3
  import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
4
- import {RootHex, Slot} from "@lodestar/types";
4
+ import {RootHex, Slot, isGloasBeaconBlock} from "@lodestar/types";
5
5
  import {toRootHex} from "@lodestar/utils";
6
6
  import {IClock} from "../../util/clock.js";
7
7
  import {BlockError, BlockErrorCode} from "../errors/index.js";
@@ -90,7 +90,12 @@ export function verifyBlocksSanityChecks(
90
90
  } else {
91
91
  // When importing a block segment, only the first NON-IGNORED block must be known to the fork-choice.
92
92
  const parentRoot = toRootHex(block.message.parentRoot);
93
- parentBlock = chain.forkChoice.getBlockHex(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);
94
99
  if (!parentBlock) {
95
100
  throw new BlockError(block, {code: BlockErrorCode.PARENT_UNKNOWN, parentRoot});
96
101
  }
@@ -600,7 +600,7 @@ export class BeaconChain implements IBeaconChain {
600
600
  ): Promise<{state: CachedBeaconStateAllForks | Uint8Array; executionOptimistic: boolean; finalized: boolean} | null> {
601
601
  if (opts?.allowRegen) {
602
602
  const state = await this.regen.getState(stateRoot, RegenCaller.restApi);
603
- const block = this.forkChoice.getBlock(state.latestBlockHeader.hashTreeRoot());
603
+ const block = this.forkChoice.getBlockDefaultStatus(state.latestBlockHeader.hashTreeRoot());
604
604
  const finalizedEpoch = this.forkChoice.getFinalizedCheckpoint().epoch;
605
605
  return {
606
606
  state,
@@ -616,7 +616,7 @@ export class BeaconChain implements IBeaconChain {
616
616
  // TODO: This is very inneficient for debug requests of serialized content, since it deserializes to serialize again
617
617
  const cachedStateCtx = this.regen.getStateSync(stateRoot);
618
618
  if (cachedStateCtx) {
619
- const block = this.forkChoice.getBlock(cachedStateCtx.latestBlockHeader.hashTreeRoot());
619
+ const block = this.forkChoice.getBlockDefaultStatus(cachedStateCtx.latestBlockHeader.hashTreeRoot());
620
620
  const finalizedEpoch = this.forkChoice.getFinalizedCheckpoint().epoch;
621
621
  return {
622
622
  state: cachedStateCtx,
@@ -650,7 +650,7 @@ export class BeaconChain implements IBeaconChain {
650
650
  // finalized or justified checkpoint states maynot be available with PersistentCheckpointStateCache, use getCheckpointStateOrBytes() api to get Uint8Array
651
651
  const cachedStateCtx = this.regen.getCheckpointStateSync(checkpoint);
652
652
  if (cachedStateCtx) {
653
- const block = this.forkChoice.getBlock(cachedStateCtx.latestBlockHeader.hashTreeRoot());
653
+ const block = this.forkChoice.getBlockDefaultStatus(cachedStateCtx.latestBlockHeader.hashTreeRoot());
654
654
  const finalizedEpoch = this.forkChoice.getFinalizedCheckpoint().epoch;
655
655
  return {
656
656
  state: cachedStateCtx,
@@ -667,7 +667,7 @@ export class BeaconChain implements IBeaconChain {
667
667
  ): Promise<{state: CachedBeaconStateAllForks | Uint8Array; executionOptimistic: boolean; finalized: boolean} | null> {
668
668
  const cachedStateCtx = await this.regen.getCheckpointStateOrBytes(checkpoint);
669
669
  if (cachedStateCtx) {
670
- const block = this.forkChoice.getBlock(checkpoint.root);
670
+ const block = this.forkChoice.getBlockDefaultStatus(checkpoint.root);
671
671
  const finalizedEpoch = this.forkChoice.getFinalizedCheckpoint().epoch;
672
672
  return {
673
673
  state: cachedStateCtx,
@@ -711,7 +711,7 @@ export class BeaconChain implements IBeaconChain {
711
711
  async getBlockByRoot(
712
712
  root: string
713
713
  ): Promise<{block: SignedBeaconBlock; executionOptimistic: boolean; finalized: boolean} | null> {
714
- const block = this.forkChoice.getBlockHex(root);
714
+ const block = this.forkChoice.getBlockHexDefaultStatus(root);
715
715
  if (block) {
716
716
  // Block found in fork-choice.
717
717
  // It may be in the block input cache, awaiting full DA reconstruction, check there first
@@ -735,7 +735,7 @@ export class BeaconChain implements IBeaconChain {
735
735
  async getSerializedBlockByRoot(
736
736
  root: string
737
737
  ): Promise<{block: Uint8Array; executionOptimistic: boolean; finalized: boolean; slot: Slot} | null> {
738
- const block = this.forkChoice.getBlockHex(root);
738
+ const block = this.forkChoice.getBlockHexDefaultStatus(root);
739
739
  if (block) {
740
740
  // Block found in fork-choice.
741
741
  // It may be in the block input cache, awaiting full DA reconstruction, check there first
@@ -1,7 +1,7 @@
1
1
  import {EventEmitter} from "node:events";
2
2
  import {StrictEventEmitter} from "strict-event-emitter-types";
3
3
  import {routes} from "@lodestar/api";
4
- import {CheckpointWithHex} from "@lodestar/fork-choice";
4
+ import {CheckpointWithPayload} from "@lodestar/fork-choice";
5
5
  import {CachedBeaconStateAllForks} from "@lodestar/state-transition";
6
6
  import {DataColumnSidecars, RootHex, deneb, phase0} from "@lodestar/types";
7
7
  import {PeerIdStr} from "../util/peerId.js";
@@ -83,8 +83,8 @@ export type ChainEventData = {
83
83
  export type IChainEvents = ApiEvents & {
84
84
  [ChainEvent.checkpoint]: (checkpoint: phase0.Checkpoint, state: CachedBeaconStateAllForks) => void;
85
85
 
86
- [ChainEvent.forkChoiceJustified]: (checkpoint: CheckpointWithHex) => void;
87
- [ChainEvent.forkChoiceFinalized]: (checkpoint: CheckpointWithHex) => void;
86
+ [ChainEvent.forkChoiceJustified]: (checkpoint: CheckpointWithPayload) => void;
87
+ [ChainEvent.forkChoiceFinalized]: (checkpoint: CheckpointWithPayload) => void;
88
88
 
89
89
  [ChainEvent.updateTargetCustodyGroupCount]: (targetGroupCount: number) => void;
90
90
 
@@ -25,9 +25,13 @@ export type ExecutionPayloadEnvelopeErrorType =
25
25
  | {
26
26
  code: ExecutionPayloadEnvelopeErrorCode.BUILDER_INDEX_MISMATCH;
27
27
  envelopeBuilderIndex: BuilderIndex;
28
- bidBuilderIndex: BuilderIndex;
28
+ bidBuilderIndex: BuilderIndex | null;
29
+ }
30
+ | {
31
+ code: ExecutionPayloadEnvelopeErrorCode.BLOCK_HASH_MISMATCH;
32
+ envelopeBlockHash: RootHex;
33
+ bidBlockHash: RootHex | null;
29
34
  }
30
- | {code: ExecutionPayloadEnvelopeErrorCode.BLOCK_HASH_MISMATCH; envelopeBlockHash: RootHex; bidBlockHash: RootHex}
31
35
  | {code: ExecutionPayloadEnvelopeErrorCode.INVALID_SIGNATURE}
32
36
  | {code: ExecutionPayloadEnvelopeErrorCode.CACHE_FAIL; blockRoot: RootHex};
33
37
 
@@ -4,9 +4,11 @@ import {
4
4
  ForkChoice,
5
5
  ForkChoiceStore,
6
6
  JustifiedBalancesGetter,
7
+ PayloadStatus,
7
8
  ProtoArray,
8
9
  ProtoBlock,
9
10
  ForkChoiceOpts as RawForkChoiceOpts,
11
+ getCheckpointPayloadStatus,
10
12
  } from "@lodestar/fork-choice";
11
13
  import {ZERO_HASH_HEX} from "@lodestar/params";
12
14
  import {
@@ -104,6 +106,14 @@ export function initializeForkChoiceFromFinalizedState(
104
106
  // production code use ForkChoice constructor directly
105
107
  const forkchoiceConstructor = opts.forkchoiceConstructor ?? ForkChoice;
106
108
 
109
+ const isForkPostGloas = (state as CachedBeaconStateGloas).latestBlockHash !== undefined;
110
+
111
+ // Determine justified checkpoint payload status
112
+ const justifiedPayloadStatus = getCheckpointPayloadStatus(state, justifiedCheckpoint.epoch);
113
+
114
+ // Determine finalized checkpoint payload status
115
+ const finalizedPayloadStatus = getCheckpointPayloadStatus(state, finalizedCheckpoint.epoch);
116
+
107
117
  return new forkchoiceConstructor(
108
118
  config,
109
119
 
@@ -113,6 +123,8 @@ export function initializeForkChoiceFromFinalizedState(
113
123
  finalizedCheckpoint,
114
124
  justifiedBalances,
115
125
  justifiedBalancesGetter,
126
+ justifiedPayloadStatus,
127
+ finalizedPayloadStatus,
116
128
  {
117
129
  onJustified: (cp) => emitter.emit(ChainEvent.forkChoiceJustified, cp),
118
130
  onFinalized: (cp) => emitter.emit(ChainEvent.forkChoiceFinalized, cp),
@@ -145,15 +157,12 @@ export function initializeForkChoiceFromFinalizedState(
145
157
  : {executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}),
146
158
 
147
159
  dataAvailabilityStatus: DataAvailabilityStatus.PreData,
148
- ...(computeEpochAtSlot(blockHeader.slot) < state.config.GLOAS_FORK_EPOCH
149
- ? {
150
- builderIndex: undefined,
151
- blockHashHex: undefined,
152
- }
153
- : {
154
- builderIndex: (state as CachedBeaconStateGloas).latestExecutionPayloadBid.builderIndex,
155
- blockHashHex: toRootHex((state as CachedBeaconStateGloas).latestExecutionPayloadBid.blockHash),
156
- }),
160
+ payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL, // TODO GLOAS: Post-gloas how do we know if the checkpoint payload is FULL or EMPTY?
161
+ builderIndex: isForkPostGloas ? (state as CachedBeaconStateGloas).latestExecutionPayloadBid.builderIndex : null,
162
+ blockHashFromBid: isForkPostGloas
163
+ ? toRootHex((state as CachedBeaconStateGloas).latestExecutionPayloadBid.blockHash)
164
+ : null,
165
+ parentBlockHash: isForkPostGloas ? toRootHex((state as CachedBeaconStateGloas).latestBlockHash) : null,
157
166
  },
158
167
  currentSlot
159
168
  ),
@@ -196,12 +205,22 @@ export function initializeForkChoiceFromUnfinalizedState(
196
205
 
197
206
  // this is not the justified state, but there is no other ways to get justified balances
198
207
  const justifiedBalances = getEffectiveBalanceIncrementsZeroInactive(unfinalizedState);
208
+
209
+ const isForkPostGloas = (unfinalizedState as CachedBeaconStateGloas).latestBlockHash !== undefined;
210
+
211
+ // For unfinalized state, use getCheckpointPayloadStatus to determine the correct status.
212
+ // It checks state.execution_payload_availability to determine EMPTY vs FULL.
213
+ const justifiedPayloadStatus = getCheckpointPayloadStatus(unfinalizedState, justifiedCheckpoint.epoch);
214
+ const finalizedPayloadStatus = getCheckpointPayloadStatus(unfinalizedState, finalizedCheckpoint.epoch);
215
+
199
216
  const store = new ForkChoiceStore(
200
217
  currentSlot,
201
218
  justifiedCheckpoint,
202
219
  finalizedCheckpoint,
203
220
  justifiedBalances,
204
221
  justifiedBalancesGetter,
222
+ justifiedPayloadStatus,
223
+ finalizedPayloadStatus,
205
224
  {
206
225
  onJustified: (cp) => emitter.emit(ChainEvent.forkChoiceJustified, cp),
207
226
  onFinalized: (cp) => emitter.emit(ChainEvent.forkChoiceFinalized, cp),
@@ -235,15 +254,14 @@ export function initializeForkChoiceFromUnfinalizedState(
235
254
  : {executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}),
236
255
 
237
256
  dataAvailabilityStatus: DataAvailabilityStatus.PreData,
238
- ...(computeEpochAtSlot(blockHeader.slot) < unfinalizedState.config.GLOAS_FORK_EPOCH
239
- ? {
240
- builderIndex: undefined,
241
- blockHashHex: undefined,
242
- }
243
- : {
244
- builderIndex: (unfinalizedState as CachedBeaconStateGloas).latestExecutionPayloadBid.builderIndex,
245
- blockHashHex: toRootHex((unfinalizedState as CachedBeaconStateGloas).latestExecutionPayloadBid.blockHash),
246
- }),
257
+ payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL, // TODO GLOAS: Post-gloas how do we know if the checkpoint payload is FULL or EMPTY?
258
+ builderIndex: isForkPostGloas
259
+ ? (unfinalizedState as CachedBeaconStateGloas).latestExecutionPayloadBid.builderIndex
260
+ : null,
261
+ blockHashFromBid: isForkPostGloas
262
+ ? toRootHex((unfinalizedState as CachedBeaconStateGloas).latestExecutionPayloadBid.blockHash)
263
+ : null,
264
+ parentBlockHash: isForkPostGloas ? toRootHex((unfinalizedState as CachedBeaconStateGloas).latestBlockHash) : null,
247
265
  };
248
266
 
249
267
  const parentSlot = blockHeader.slot - 1;
@@ -285,9 +303,9 @@ export function initializeForkChoiceFromUnfinalizedState(
285
303
  };
286
304
 
287
305
  const protoArray = ProtoArray.initialize(finalizedBlock, currentSlot);
288
- protoArray.onBlock(justifiedBlock, currentSlot);
289
- protoArray.onBlock(parentBlock, currentSlot);
290
- protoArray.onBlock(headBlock, currentSlot);
306
+ protoArray.onBlock(justifiedBlock, currentSlot, null);
307
+ protoArray.onBlock(parentBlock, currentSlot, null);
308
+ protoArray.onBlock(headBlock, currentSlot, null);
291
309
 
292
310
  logger?.verbose("Initialized protoArray successfully", {...logCtx, length: protoArray.length()});
293
311
 
@@ -864,7 +864,7 @@ function isValidShuffling(
864
864
  // attestation's shuffling is the same as the current state's.
865
865
  // To account for skipped slots, find the first block at *or before* the pivot slot.
866
866
  const beaconBlockRootHex = blockRootHex;
867
- const beaconBlock = forkChoice.getBlockHex(beaconBlockRootHex);
867
+ const beaconBlock = forkChoice.getBlockHexDefaultStatus(beaconBlockRootHex);
868
868
  if (!beaconBlock) {
869
869
  return InvalidAttestationData.BlockNotInForkChoice;
870
870
  }
@@ -723,8 +723,7 @@ export function getPayloadAttributesForSSE(
723
723
 
724
724
  let parentBlockNumber: number;
725
725
  if (isForkPostGloas(fork)) {
726
- // TODO GLOAS: revisit this after fork choice changes are merged
727
- const parentBlock = chain.forkChoice.getBlock(parentBlockRoot);
726
+ const parentBlock = chain.forkChoice.getBlockHexAndBlockHash(toRootHex(parentBlockRoot), toRootHex(parentHash));
728
727
  if (parentBlock?.executionPayloadBlockHash == null) {
729
728
  throw Error(`Parent block not found in fork choice root=${toRootHex(parentBlockRoot)}`);
730
729
  }
@@ -1,7 +1,7 @@
1
1
  import {routes} from "@lodestar/api";
2
2
  import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
3
3
  import {CachedBeaconStateAllForks, computeEpochAtSlot} from "@lodestar/state-transition";
4
- import {BeaconBlock, Epoch, RootHex, Slot, phase0} from "@lodestar/types";
4
+ import {BeaconBlock, Epoch, RootHex, Slot, isGloasBeaconBlock, phase0} from "@lodestar/types";
5
5
  import {Logger, toRootHex} from "@lodestar/utils";
6
6
  import {Metrics} from "../../metrics/index.js";
7
7
  import {JobItemQueue} from "../../util/queue/index.js";
@@ -88,7 +88,12 @@ export class QueuedStateRegenerator implements IStateRegenerator {
88
88
  */
89
89
  getPreStateSync(block: BeaconBlock): CachedBeaconStateAllForks | null {
90
90
  const parentRoot = toRootHex(block.parentRoot);
91
- const parentBlock = this.forkChoice.getBlockHex(parentRoot);
91
+ const parentBlock = isGloasBeaconBlock(block)
92
+ ? this.forkChoice.getBlockHexAndBlockHash(
93
+ parentRoot,
94
+ toRootHex(block.body.signedExecutionPayloadBid.message.parentBlockHash)
95
+ )
96
+ : this.forkChoice.getBlockHexDefaultStatus(parentRoot);
92
97
  if (!parentBlock) {
93
98
  throw new RegenError({
94
99
  code: RegenErrorCode.BLOCK_NOT_IN_FORKCHOICE,
@@ -11,7 +11,7 @@ import {
11
11
  processSlots,
12
12
  stateTransition,
13
13
  } from "@lodestar/state-transition";
14
- import {BeaconBlock, RootHex, SignedBeaconBlock, Slot} from "@lodestar/types";
14
+ import {BeaconBlock, RootHex, SignedBeaconBlock, Slot, isGloasBeaconBlock} from "@lodestar/types";
15
15
  import {Logger, fromHex, toRootHex} from "@lodestar/utils";
16
16
  import {IBeaconDb} from "../../db/index.js";
17
17
  import {Metrics} from "../../metrics/index.js";
@@ -58,7 +58,13 @@ export class StateRegenerator implements IStateRegeneratorInternal {
58
58
  opts: StateRegenerationOpts,
59
59
  regenCaller: RegenCaller
60
60
  ): Promise<CachedBeaconStateAllForks> {
61
- const parentBlock = this.modules.forkChoice.getBlock(block.parentRoot);
61
+ const parentRoot = toRootHex(block.parentRoot);
62
+ const parentBlock = isGloasBeaconBlock(block)
63
+ ? this.modules.forkChoice.getBlockHexAndBlockHash(
64
+ parentRoot,
65
+ toRootHex(block.body.signedExecutionPayloadBid.message.parentBlockHash)
66
+ )
67
+ : this.modules.forkChoice.getBlockHexDefaultStatus(parentRoot);
62
68
  if (!parentBlock) {
63
69
  throw new RegenError({
64
70
  code: RegenErrorCode.BLOCK_NOT_IN_FORKCHOICE,
@@ -3,6 +3,7 @@ import {CheckpointWithHex} from "@lodestar/fork-choice";
3
3
  import {
4
4
  ForkName,
5
5
  ForkPostFulu,
6
+ ForkPostGloas,
6
7
  ForkPreGloas,
7
8
  SLOTS_PER_EPOCH,
8
9
  isForkPostDeneb,
@@ -20,6 +21,7 @@ import {
20
21
  BlockInput,
21
22
  BlockInputBlobs,
22
23
  BlockInputColumns,
24
+ BlockInputNoData,
23
25
  BlockInputPreData,
24
26
  BlockWithSource,
25
27
  DAType,
@@ -179,12 +181,19 @@ export class SeenBlockInput {
179
181
  if (!blockInput) {
180
182
  const {forkName, daOutOfRange} = this.buildCommonProps(block.message.slot);
181
183
 
182
- // TODO GLOAS: Implement
183
184
  if (isForkPostGloas(forkName)) {
184
- throw Error("Not implemented");
185
- }
186
- // Pre-deneb
187
- if (!isForkPostDeneb(forkName)) {
185
+ // Post-gloas
186
+ blockInput = BlockInputNoData.createFromBlock({
187
+ block: block as SignedBeaconBlock<ForkPostGloas>,
188
+ blockRootHex,
189
+ daOutOfRange,
190
+ forkName,
191
+ source,
192
+ seenTimestampSec,
193
+ peerIdStr,
194
+ });
195
+ } else if (!isForkPostDeneb(forkName)) {
196
+ // Pre-deneb
188
197
  blockInput = BlockInputPreData.createFromBlock({
189
198
  block,
190
199
  blockRootHex,
@@ -194,8 +203,8 @@ export class SeenBlockInput {
194
203
  seenTimestampSec,
195
204
  peerIdStr,
196
205
  });
197
- // Fulu Only
198
206
  } else if (isForkPostFulu(forkName)) {
207
+ // Fulu Only
199
208
  blockInput = BlockInputColumns.createFromBlock({
200
209
  block: block as SignedBeaconBlock<ForkPostFulu & ForkPreGloas>,
201
210
  blockRootHex,
@@ -207,8 +216,8 @@ export class SeenBlockInput {
207
216
  seenTimestampSec,
208
217
  peerIdStr,
209
218
  });
210
- // Deneb and Electra
211
219
  } else {
220
+ // Deneb and Electra
212
221
  blockInput = BlockInputBlobs.createFromBlock({
213
222
  block: block as SignedBeaconBlock<ForkBlobsDA>,
214
223
  blockRootHex,
@@ -81,7 +81,7 @@ async function validateAggregateAndProof(
81
81
  });
82
82
  }
83
83
  // [REJECT] `aggregate.data.index == 0` if `block.slot == aggregate.data.slot`.
84
- const block = chain.forkChoice.getBlock(attData.beaconBlockRoot);
84
+ const block = chain.forkChoice.getBlockDefaultStatus(attData.beaconBlockRoot);
85
85
 
86
86
  // If block is unknown, we don't handle it here. It will throw error later on at `verifyHeadBlockAndTargetRoot()`
87
87
  if (block !== null && block.slot === attData.slot && attData.index !== 0) {
@@ -186,7 +186,7 @@ export async function validateGossipAttestationsSameAttData(
186
186
  chain.seenAttesters.add(targetEpoch, validatorIndex);
187
187
  } else {
188
188
  step0ResultOrErrors[oldIndex] = {
189
- err: new AttestationError(GossipAction.IGNORE, {
189
+ err: new AttestationError(GossipAction.REJECT, {
190
190
  code: AttestationErrorCode.INVALID_SIGNATURE,
191
191
  }),
192
192
  };
@@ -307,7 +307,7 @@ async function validateAttestationNoSignatureCheck(
307
307
  }
308
308
 
309
309
  // [REJECT] `attestation.data.index == 0` if `block.slot == attestation.data.slot`.
310
- const block = chain.forkChoice.getBlock(attData.beaconBlockRoot);
310
+ const block = chain.forkChoice.getBlockDefaultStatus(attData.beaconBlockRoot);
311
311
 
312
312
  // block being null will be handled by `verifyHeadBlockAndTargetRoot`
313
313
  if (block !== null && block.slot === attSlot && attData.index !== 0) {
@@ -756,7 +756,7 @@ export function getAttestationDataSigningRoot(config: BeaconConfig, data: phase0
756
756
  function verifyHeadBlockIsKnown(chain: IBeaconChain, beaconBlockRoot: Root): ProtoBlock {
757
757
  // TODO (LH): Enforce a maximum skip distance for unaggregated attestations.
758
758
 
759
- const headBlock = chain.forkChoice.getBlock(beaconBlockRoot);
759
+ const headBlock = chain.forkChoice.getBlockDefaultStatus(beaconBlockRoot);
760
760
  if (headBlock === null) {
761
761
  throw new AttestationError(GossipAction.IGNORE, {
762
762
  code: AttestationErrorCode.UNKNOWN_OR_PREFINALIZED_BEACON_BLOCK_ROOT,
@@ -2,6 +2,7 @@ import {
2
2
  assertValidAttesterSlashing,
3
3
  getAttesterSlashableIndices,
4
4
  getAttesterSlashingSignatureSets,
5
+ isSlashableValidator,
5
6
  } from "@lodestar/state-transition";
6
7
  import {AttesterSlashing} from "@lodestar/types";
7
8
  import {AttesterSlashingError, AttesterSlashingErrorCode, GossipAction} from "../errors/index.js";
@@ -58,6 +59,14 @@ export async function validateAttesterSlashing(
58
59
  });
59
60
  }
60
61
 
62
+ const currentEpoch = state.epochCtx.epoch;
63
+ if (!intersectingIndices.some((index) => isSlashableValidator(state.validators.getReadonly(index), currentEpoch))) {
64
+ throw new AttesterSlashingError(GossipAction.REJECT, {
65
+ code: AttesterSlashingErrorCode.INVALID,
66
+ error: Error("AttesterSlashing has no slashable validators"),
67
+ });
68
+ }
69
+
61
70
  const signatureSets = getAttesterSlashingSignatureSets(chain.config, state.slot, attesterSlashing);
62
71
  if (!(await chain.bls.verifySignatureSets(signatureSets, {batchable: true, priority: prioritizeBls}))) {
63
72
  throw new AttesterSlashingError(GossipAction.REJECT, {
@@ -78,7 +78,7 @@ export async function validateGossipBlobSidecar(
78
78
  // already know this block.
79
79
  const blockRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(blobSidecar.signedBlockHeader.message);
80
80
  const blockHex = toRootHex(blockRoot);
81
- if (chain.forkChoice.getBlockHex(blockHex) !== null) {
81
+ if (chain.forkChoice.getBlockHexDefaultStatus(blockHex) !== null) {
82
82
  throw new BlobSidecarGossipError(GossipAction.IGNORE, {code: BlobSidecarErrorCode.ALREADY_KNOWN, root: blockHex});
83
83
  }
84
84
 
@@ -89,7 +89,7 @@ export async function validateGossipBlobSidecar(
89
89
  // gossip and non-gossip sources) (a client MAY queue blocks for processing once the parent block is
90
90
  // retrieved).
91
91
  const parentRoot = toRootHex(blobSidecar.signedBlockHeader.message.parentRoot);
92
- const parentBlock = chain.forkChoice.getBlockHex(parentRoot);
92
+ const parentBlock = chain.forkChoice.getBlockHexDefaultStatus(parentRoot);
93
93
  if (parentBlock === null) {
94
94
  // If fork choice does *not* consider the parent to be a descendant of the finalized block,
95
95
  // then there are two more cases: