@lodestar/fork-choice 1.42.0 → 1.43.0-dev.07875b3e0c

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.
@@ -1,5 +1,5 @@
1
1
  import {ChainForkConfig} from "@lodestar/config";
2
- import {ForkSeq, SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params";
2
+ import {SLOTS_PER_EPOCH} from "@lodestar/params";
3
3
  import {
4
4
  DataAvailabilityStatus,
5
5
  EffectiveBalanceIncrements,
@@ -10,6 +10,7 @@ import {
10
10
  computeStartSlotAtEpoch,
11
11
  getAttesterSlashableIndices,
12
12
  isExecutionBlockBodyType,
13
+ isStatePostBellatrix,
13
14
  } from "@lodestar/state-transition";
14
15
  import {
15
16
  AttesterSlashing,
@@ -51,7 +52,7 @@ import {
51
52
  NotReorgedReason,
52
53
  ShouldOverrideForkChoiceUpdateResult,
53
54
  } from "./interface.js";
54
- import {CheckpointWithPayloadStatus, IForkChoiceStore, JustifiedBalances, toCheckpointWithPayload} from "./store.js";
55
+ import {CheckpointWithHex, IForkChoiceStore, JustifiedBalances, toCheckpointWithHex} from "./store.js";
55
56
 
56
57
  export type ForkChoiceOpts = {
57
58
  proposerBoost?: boolean;
@@ -309,6 +310,14 @@ export class ForkChoice implements IForkChoice {
309
310
  return this.proposerBoostRoot ?? HEX_ZERO_HASH;
310
311
  }
311
312
 
313
+ /**
314
+ * Decides whether to extend an available payload from the previous slot,
315
+ * corresponding to the beacon block `blockRoot`.
316
+ */
317
+ shouldExtendPayload(blockRoot: RootHex): boolean {
318
+ return this.protoArray.shouldExtendPayload(blockRoot, this.proposerBoostRoot);
319
+ }
320
+
312
321
  /**
313
322
  * To predict the proposer head of the next slot. That is, to predict if proposer-boost-reorg could happen.
314
323
  * Reason why we can't be certain is because information of the head block is not fully available yet
@@ -554,11 +563,11 @@ export class ForkChoice implements IForkChoice {
554
563
  return this.protoArray.nodes;
555
564
  }
556
565
 
557
- getFinalizedCheckpoint(): CheckpointWithPayloadStatus {
566
+ getFinalizedCheckpoint(): CheckpointWithHex {
558
567
  return this.fcStore.finalizedCheckpoint;
559
568
  }
560
569
 
561
- getJustifiedCheckpoint(): CheckpointWithPayloadStatus {
570
+ getJustifiedCheckpoint(): CheckpointWithHex {
562
571
  return this.fcStore.justified.checkpoint;
563
572
  }
564
573
 
@@ -639,10 +648,7 @@ export class ForkChoice implements IForkChoice {
639
648
  // Check block is a descendant of the finalized block at the checkpoint finalized slot.
640
649
  const blockAncestorNode = this.getAncestor(parentRootHex, finalizedSlot);
641
650
  const fcStoreFinalized = this.fcStore.finalizedCheckpoint;
642
- if (
643
- blockAncestorNode.blockRoot !== fcStoreFinalized.rootHex ||
644
- blockAncestorNode.payloadStatus !== fcStoreFinalized.payloadStatus
645
- ) {
651
+ if (blockAncestorNode.blockRoot !== fcStoreFinalized.rootHex) {
646
652
  throw new ForkChoiceError({
647
653
  code: ForkChoiceErrorCode.INVALID_BLOCK,
648
654
  err: {
@@ -668,18 +674,10 @@ export class ForkChoice implements IForkChoice {
668
674
  this.proposerBoostRoot = blockRootHex;
669
675
  }
670
676
 
671
- // Get justified checkpoint with payload status for Gloas
672
- const justifiedPayloadStatus = getCheckpointPayloadStatus(
673
- this.config,
674
- state,
675
- state.currentJustifiedCheckpoint.epoch
676
- );
677
- const justifiedCheckpoint = toCheckpointWithPayload(state.currentJustifiedCheckpoint, justifiedPayloadStatus);
677
+ const justifiedCheckpoint = toCheckpointWithHex(state.currentJustifiedCheckpoint);
678
678
  const stateJustifiedEpoch = justifiedCheckpoint.epoch;
679
679
 
680
- // Get finalized checkpoint with payload status for Gloas
681
- const finalizedPayloadStatus = getCheckpointPayloadStatus(this.config, state, state.finalizedCheckpoint.epoch);
682
- const finalizedCheckpoint = toCheckpointWithPayload(state.finalizedCheckpoint, finalizedPayloadStatus);
680
+ const finalizedCheckpoint = toCheckpointWithHex(state.finalizedCheckpoint);
683
681
 
684
682
  // Justified balances for `justifiedCheckpoint` are new to the fork-choice. Compute them on demand only if
685
683
  // the justified checkpoint changes
@@ -701,61 +699,29 @@ export class ForkChoice implements IForkChoice {
701
699
  // This is an optimization. It should reduce the amount of times we run
702
700
  // `process_justification_and_finalization` by approximately 1/3rd when the chain is
703
701
  // performing optimally.
704
- let unrealizedJustifiedCheckpoint: CheckpointWithPayloadStatus;
705
- let unrealizedFinalizedCheckpoint: CheckpointWithPayloadStatus;
702
+ let unrealizedJustifiedCheckpoint: CheckpointWithHex;
703
+ let unrealizedFinalizedCheckpoint: CheckpointWithHex;
706
704
  if (this.opts?.computeUnrealized) {
707
705
  if (
708
706
  parentBlock.unrealizedJustifiedEpoch === blockEpoch &&
709
707
  parentBlock.unrealizedFinalizedEpoch + 1 >= blockEpoch
710
708
  ) {
711
709
  // reuse from parent, happens at 1/3 last blocks of epoch as monitored in mainnet
712
- // Get payload status for unrealized justified checkpoint
713
- const unrealizedJustifiedPayloadStatus = getCheckpointPayloadStatus(
714
- this.config,
715
- state,
716
- parentBlock.unrealizedJustifiedEpoch
717
- );
718
710
  unrealizedJustifiedCheckpoint = {
719
711
  epoch: parentBlock.unrealizedJustifiedEpoch,
720
712
  root: fromHex(parentBlock.unrealizedJustifiedRoot),
721
713
  rootHex: parentBlock.unrealizedJustifiedRoot,
722
- payloadStatus: unrealizedJustifiedPayloadStatus,
723
714
  };
724
- // Get payload status for unrealized finalized checkpoint
725
- const unrealizedFinalizedPayloadStatus = getCheckpointPayloadStatus(
726
- this.config,
727
- state,
728
- parentBlock.unrealizedFinalizedEpoch
729
- );
730
715
  unrealizedFinalizedCheckpoint = {
731
716
  epoch: parentBlock.unrealizedFinalizedEpoch,
732
717
  root: fromHex(parentBlock.unrealizedFinalizedRoot),
733
718
  rootHex: parentBlock.unrealizedFinalizedRoot,
734
- payloadStatus: unrealizedFinalizedPayloadStatus,
735
719
  };
736
720
  } else {
737
721
  // compute new, happens 2/3 first blocks of epoch as monitored in mainnet
738
722
  const unrealized = state.computeUnrealizedCheckpoints();
739
- // Get payload status for unrealized justified checkpoint
740
- const unrealizedJustifiedPayloadStatus = getCheckpointPayloadStatus(
741
- this.config,
742
- state,
743
- unrealized.justifiedCheckpoint.epoch
744
- );
745
- unrealizedJustifiedCheckpoint = toCheckpointWithPayload(
746
- unrealized.justifiedCheckpoint,
747
- unrealizedJustifiedPayloadStatus
748
- );
749
- // Get payload status for unrealized finalized checkpoint
750
- const unrealizedFinalizedPayloadStatus = getCheckpointPayloadStatus(
751
- this.config,
752
- state,
753
- unrealized.finalizedCheckpoint.epoch
754
- );
755
- unrealizedFinalizedCheckpoint = toCheckpointWithPayload(
756
- unrealized.finalizedCheckpoint,
757
- unrealizedFinalizedPayloadStatus
758
- );
723
+ unrealizedJustifiedCheckpoint = toCheckpointWithHex(unrealized.justifiedCheckpoint);
724
+ unrealizedFinalizedCheckpoint = toCheckpointWithHex(unrealized.finalizedCheckpoint);
759
725
  }
760
726
  } else {
761
727
  unrealizedJustifiedCheckpoint = justifiedCheckpoint;
@@ -825,7 +791,10 @@ export class ForkChoice implements IForkChoice {
825
791
  executionStatus: this.getPostGloasExecStatus(executionStatus),
826
792
  dataAvailabilityStatus,
827
793
  }
828
- : isExecutionBlockBodyType(block.body) && state.isExecutionStateType && state.isExecutionEnabled(block)
794
+ : isExecutionBlockBodyType(block.body) &&
795
+ isStatePostBellatrix(state) &&
796
+ state.isExecutionStateType &&
797
+ state.isExecutionEnabled(block)
829
798
  ? {
830
799
  executionPayloadBlockHash: toRootHex(block.body.executionPayload.blockHash),
831
800
  executionPayloadNumber: block.body.executionPayload.blockNumber,
@@ -978,7 +947,6 @@ export class ForkChoice implements IForkChoice {
978
947
  blockRoot: RootHex,
979
948
  executionPayloadBlockHash: RootHex,
980
949
  executionPayloadNumber: number,
981
- executionPayloadStateRoot: RootHex,
982
950
  executionStatus: PayloadExecutionStatus
983
951
  ): void {
984
952
  this.protoArray.onExecutionPayload(
@@ -986,7 +954,6 @@ export class ForkChoice implements IForkChoice {
986
954
  this.fcStore.currentSlot,
987
955
  executionPayloadBlockHash,
988
956
  executionPayloadNumber,
989
- executionPayloadStateRoot,
990
957
  this.proposerBoostRoot,
991
958
  executionStatus
992
959
  );
@@ -1117,8 +1084,8 @@ export class ForkChoice implements IForkChoice {
1117
1084
  }
1118
1085
 
1119
1086
  getJustifiedBlock(): ProtoBlock {
1120
- const {rootHex, payloadStatus} = this.fcStore.justified.checkpoint;
1121
- const block = this.getBlockHex(rootHex, payloadStatus);
1087
+ const {rootHex} = this.fcStore.justified.checkpoint;
1088
+ const block = this.getBlockHexDefaultStatus(rootHex);
1122
1089
  if (!block) {
1123
1090
  throw new ForkChoiceError({
1124
1091
  code: ForkChoiceErrorCode.MISSING_PROTO_ARRAY_BLOCK,
@@ -1129,8 +1096,8 @@ export class ForkChoice implements IForkChoice {
1129
1096
  }
1130
1097
 
1131
1098
  getFinalizedBlock(): ProtoBlock {
1132
- const {rootHex, payloadStatus} = this.fcStore.finalizedCheckpoint;
1133
- const block = this.getBlockHex(rootHex, payloadStatus);
1099
+ const {rootHex} = this.fcStore.finalizedCheckpoint;
1100
+ const block = this.getBlockHexDefaultStatus(rootHex);
1134
1101
  if (!block) {
1135
1102
  throw new ForkChoiceError({
1136
1103
  code: ForkChoiceErrorCode.MISSING_PROTO_ARRAY_BLOCK,
@@ -1223,18 +1190,33 @@ export class ForkChoice implements IForkChoice {
1223
1190
 
1224
1191
  /**
1225
1192
  * Returns both ancestor and non-ancestor blocks in a single traversal.
1193
+ *
1194
+ * `ancestors` is the raw walk and includes the previous finalized block as its last element —
1195
+ * callers that don't want the boundary should slice it off themselves.
1196
+ * Post-gloas for each block root, it returns exactly one variant of it.
1226
1197
  */
1227
1198
  getAllAncestorAndNonAncestorBlocks(
1228
1199
  blockRoot: RootHex,
1229
1200
  payloadStatus: PayloadStatus
1230
1201
  ): {ancestors: ProtoBlock[]; nonAncestors: ProtoBlock[]} {
1231
- const {ancestors, nonAncestors} = this.protoArray.getAllAncestorAndNonAncestorNodes(blockRoot, payloadStatus);
1202
+ return this.protoArray.getAllAncestorAndNonAncestorNodes(blockRoot, payloadStatus);
1203
+ }
1232
1204
 
1233
- return {
1234
- // the last node is the previous finalized one, it's there to check onBlock finalized checkpoint only.
1235
- ancestors: ancestors.slice(0, ancestors.length - 1),
1236
- nonAncestors,
1237
- };
1205
+ /**
1206
+ * Same to getAllAncestorAndNonAncestorBlocks with default variant of ${blockRoot} to start with
1207
+ */
1208
+ getAllAncestorAndNonAncestorBlocksDefaultStatus(blockRoot: RootHex): {
1209
+ ancestors: ProtoBlock[];
1210
+ nonAncestors: ProtoBlock[];
1211
+ } {
1212
+ const defaultStatus = this.protoArray.getDefaultVariant(blockRoot);
1213
+ if (defaultStatus === undefined) {
1214
+ throw new ForkChoiceError({
1215
+ code: ForkChoiceErrorCode.MISSING_PROTO_ARRAY_BLOCK,
1216
+ root: blockRoot,
1217
+ });
1218
+ }
1219
+ return this.getAllAncestorAndNonAncestorBlocks(blockRoot, defaultStatus);
1238
1220
  }
1239
1221
 
1240
1222
  getCanonicalBlockByRoot(blockRoot: Root): ProtoBlock | null {
@@ -1306,6 +1288,17 @@ export class ForkChoice implements IForkChoice {
1306
1288
  }
1307
1289
  }
1308
1290
 
1291
+ forwardIterateDescendantsDefaultStatus(blockRoot: RootHex): IterableIterator<ProtoBlock> {
1292
+ const defaultStatus = this.protoArray.getDefaultVariant(blockRoot);
1293
+ if (defaultStatus === undefined) {
1294
+ throw new ForkChoiceError({
1295
+ code: ForkChoiceErrorCode.MISSING_PROTO_ARRAY_BLOCK,
1296
+ root: blockRoot,
1297
+ });
1298
+ }
1299
+ return this.forwardIterateDescendants(blockRoot, defaultStatus);
1300
+ }
1301
+
1309
1302
  /** Very expensive function, iterates the entire ProtoArray. TODO: Is this function even necessary? */
1310
1303
  getBlockSummariesByParentRoot(parentRoot: RootHex): ProtoBlock[] {
1311
1304
  return this.protoArray.nodes.filter((node) => node.parentRoot === parentRoot);
@@ -1492,12 +1485,12 @@ export class ForkChoice implements IForkChoice {
1492
1485
  *
1493
1486
  * **`on_tick`**
1494
1487
  * May need the justified balances of:
1495
- * - unrealizedJustified: Already available in `CheckpointWithPayloadAndBalance`
1488
+ * - unrealizedJustified: Already available in `CheckpointWithBalance`
1496
1489
  * Since this balances are already available the getter is just `() => balances`, without cache interaction
1497
1490
  */
1498
1491
  private updateCheckpoints(
1499
- justifiedCheckpoint: CheckpointWithPayloadStatus,
1500
- finalizedCheckpoint: CheckpointWithPayloadStatus,
1492
+ justifiedCheckpoint: CheckpointWithHex,
1493
+ finalizedCheckpoint: CheckpointWithHex,
1501
1494
  getJustifiedBalances: () => JustifiedBalances
1502
1495
  ): void {
1503
1496
  // Update justified checkpoint.
@@ -1517,8 +1510,8 @@ export class ForkChoice implements IForkChoice {
1517
1510
  * Update unrealized checkpoints in store if necessary
1518
1511
  */
1519
1512
  private updateUnrealizedCheckpoints(
1520
- unrealizedJustifiedCheckpoint: CheckpointWithPayloadStatus,
1521
- unrealizedFinalizedCheckpoint: CheckpointWithPayloadStatus,
1513
+ unrealizedJustifiedCheckpoint: CheckpointWithHex,
1514
+ unrealizedFinalizedCheckpoint: CheckpointWithHex,
1522
1515
  getJustifiedBalances: () => JustifiedBalances
1523
1516
  ): void {
1524
1517
  if (unrealizedJustifiedCheckpoint.epoch > this.fcStore.unrealizedJustified.checkpoint.epoch) {
@@ -1680,15 +1673,42 @@ export class ForkChoice implements IForkChoice {
1680
1673
  });
1681
1674
  }
1682
1675
 
1683
- // For Gloas blocks, attestation index must be 0 or 1
1684
- if (isGloasBlock(block) && attestationData.index !== 0 && attestationData.index !== 1) {
1685
- throw new ForkChoiceError({
1686
- code: ForkChoiceErrorCode.INVALID_ATTESTATION,
1687
- err: {
1688
- code: InvalidAttestationCode.INVALID_DATA_INDEX,
1689
- index: attestationData.index,
1690
- },
1691
- });
1676
+ if (isGloasBlock(block)) {
1677
+ // For Gloas blocks, attestation index must be 0 or 1
1678
+ if (attestationData.index !== 0 && attestationData.index !== 1) {
1679
+ throw new ForkChoiceError({
1680
+ code: ForkChoiceErrorCode.INVALID_ATTESTATION,
1681
+ err: {
1682
+ code: InvalidAttestationCode.INVALID_DATA_INDEX,
1683
+ index: attestationData.index,
1684
+ },
1685
+ });
1686
+ }
1687
+
1688
+ // Same-slot attestations can only vote for the PENDING variant
1689
+ if (block.slot === slot && attestationData.index !== 0) {
1690
+ throw new ForkChoiceError({
1691
+ code: ForkChoiceErrorCode.INVALID_ATTESTATION,
1692
+ err: {
1693
+ code: InvalidAttestationCode.INVALID_DATA_INDEX,
1694
+ index: attestationData.index,
1695
+ },
1696
+ });
1697
+ }
1698
+
1699
+ // If attesting for a full node, the payload must be known
1700
+ if (attestationData.index === 1) {
1701
+ const fullNodeIndex = this.protoArray.getNodeIndexByRootAndStatus(beaconBlockRootHex, PayloadStatus.FULL);
1702
+ if (fullNodeIndex === undefined) {
1703
+ throw new ForkChoiceError({
1704
+ code: ForkChoiceErrorCode.INVALID_ATTESTATION,
1705
+ err: {
1706
+ code: InvalidAttestationCode.UNKNOWN_PAYLOAD_STATUS,
1707
+ beaconBlockRoot: beaconBlockRootHex,
1708
+ },
1709
+ });
1710
+ }
1711
+ }
1692
1712
  }
1693
1713
 
1694
1714
  this.validatedAttestationDatas.add(attDataRoot);
@@ -1866,35 +1886,3 @@ export function getCommitteeFraction(
1866
1886
  const committeeWeight = Math.floor(justifiedTotalActiveBalanceByIncrement / config.slotsPerEpoch);
1867
1887
  return Math.floor((committeeWeight * config.committeePercent) / 100);
1868
1888
  }
1869
-
1870
- /**
1871
- * Get the payload status for a checkpoint.
1872
- *
1873
- * Pre-Gloas: always FULL (payload embedded in block)
1874
- * Gloas: determined by state.execution_payload_availability
1875
- *
1876
- * @param config - The chain fork config to determine fork at checkpoint slot
1877
- * @param state - The state to check execution_payload_availability
1878
- * @param checkpointEpoch - The epoch of the checkpoint
1879
- */
1880
- export function getCheckpointPayloadStatus(
1881
- config: ChainForkConfig,
1882
- state: IBeaconStateView,
1883
- checkpointEpoch: number
1884
- ): PayloadStatus {
1885
- // Compute checkpoint slot first to determine the correct fork
1886
- const checkpointSlot = computeStartSlotAtEpoch(checkpointEpoch);
1887
- const fork = config.getForkSeq(checkpointSlot);
1888
-
1889
- // Pre-Gloas: always FULL
1890
- if (fork < ForkSeq.gloas) {
1891
- return PayloadStatus.FULL;
1892
- }
1893
-
1894
- // For Gloas, check state.execution_payload_availability
1895
- // - For non-skipped slots at checkpoint: returns false (EMPTY) since payload hasn't arrived yet
1896
- // - For skipped slots at checkpoint: returns the actual availability status from state
1897
- const payloadAvailable = state.executionPayloadAvailability.get(checkpointSlot % SLOTS_PER_HISTORICAL_ROOT);
1898
-
1899
- return payloadAvailable ? PayloadStatus.FULL : PayloadStatus.EMPTY;
1900
- }
@@ -9,7 +9,7 @@ import {
9
9
  ProtoNode,
10
10
  } from "../protoArray/interface.js";
11
11
  import {UpdateAndGetHeadOpt} from "./forkChoice.js";
12
- import {CheckpointWithHex, CheckpointWithPayloadStatus} from "./store.js";
12
+ import {CheckpointWithHex} from "./store.js";
13
13
 
14
14
  export type CheckpointHex = {
15
15
  epoch: Epoch;
@@ -21,12 +21,12 @@ export type CheckpointsWithHex = {
21
21
  finalizedCheckpoint: CheckpointWithHex;
22
22
  };
23
23
 
24
- export type CheckpointWithPayloadAndBalance = {
25
- checkpoint: CheckpointWithPayloadStatus;
24
+ export type CheckpointWithBalance = {
25
+ checkpoint: CheckpointWithHex;
26
26
  balances: EffectiveBalanceIncrements;
27
27
  };
28
28
 
29
- export type CheckpointWithPayloadAndTotalBalance = CheckpointWithPayloadAndBalance & {
29
+ export type CheckpointWithTotalBalance = CheckpointWithBalance & {
30
30
  totalBalance: number;
31
31
  };
32
32
 
@@ -121,8 +121,8 @@ export interface IForkChoice {
121
121
  * Retrieve all nodes for the debug API.
122
122
  */
123
123
  getAllNodes(): ProtoNode[];
124
- getFinalizedCheckpoint(): CheckpointWithPayloadStatus;
125
- getJustifiedCheckpoint(): CheckpointWithPayloadStatus;
124
+ getFinalizedCheckpoint(): CheckpointWithHex;
125
+ getJustifiedCheckpoint(): CheckpointWithHex;
126
126
  /**
127
127
  * Add `block` to the fork choice DAG.
128
128
  *
@@ -198,13 +198,11 @@ export interface IForkChoice {
198
198
  * @param blockRoot - The beacon block root for which the payload arrived
199
199
  * @param executionPayloadBlockHash - The block hash of the execution payload
200
200
  * @param executionPayloadNumber - The block number of the execution payload
201
- * @param executionPayloadStateRoot - The execution payload state root ie. the root of post-state after processExecutionPayloadEnvelope()
202
201
  */
203
202
  onExecutionPayload(
204
203
  blockRoot: RootHex,
205
204
  executionPayloadBlockHash: RootHex,
206
205
  executionPayloadNumber: number,
207
- executionPayloadStateRoot: RootHex,
208
206
  executionStatus: PayloadExecutionStatus
209
207
  ): void;
210
208
  /**
@@ -241,6 +239,7 @@ export interface IForkChoice {
241
239
  getBlockDefaultStatus(blockRoot: Root): ProtoBlock | null;
242
240
  getBlockHexDefaultStatus(blockRoot: RootHex): ProtoBlock | null;
243
241
  getBlockHexAndBlockHash(blockRoot: RootHex, blockHash: RootHex): ProtoBlock | null;
242
+ shouldExtendPayload(blockRoot: RootHex): boolean;
244
243
  getFinalizedBlock(): ProtoBlock;
245
244
  getJustifiedBlock(): ProtoBlock;
246
245
  getFinalizedCheckpointSlot(): Slot;
@@ -272,11 +271,23 @@ export interface IForkChoice {
272
271
  getAllNonAncestorBlocks(blockRoot: RootHex, payloadStatus: PayloadStatus): ProtoBlock[];
273
272
  /**
274
273
  * Returns both ancestor and non-ancestor blocks in a single traversal.
274
+ *
275
+ * `ancestors` is the raw walk and includes the previous finalized block as its last element —
276
+ * callers that don't want the boundary should slice it off themselves.
275
277
  */
276
278
  getAllAncestorAndNonAncestorBlocks(
277
279
  blockRoot: RootHex,
278
280
  payloadStatus: PayloadStatus
279
281
  ): {ancestors: ProtoBlock[]; nonAncestors: ProtoBlock[]};
282
+ /**
283
+ * Same as `getAllAncestorAndNonAncestorBlocks` but resolves the default payload-status variant
284
+ * (FULL pre-Gloas, PENDING for Gloas) for the given root. Use when the caller holds a
285
+ * `CheckpointWithHex` / finalized root without a specific payload-status variant in mind.
286
+ */
287
+ getAllAncestorAndNonAncestorBlocksDefaultStatus(blockRoot: RootHex): {
288
+ ancestors: ProtoBlock[];
289
+ nonAncestors: ProtoBlock[];
290
+ };
280
291
  getCanonicalBlockByRoot(blockRoot: Root): ProtoBlock | null;
281
292
  getCanonicalBlockAtSlot(slot: Slot): ProtoBlock | null;
282
293
  getCanonicalBlockClosestLteSlot(slot: Slot): ProtoBlock | null;
@@ -288,6 +299,12 @@ export interface IForkChoice {
288
299
  * Iterates forward descendants of blockRoot. Does not yield blockRoot itself
289
300
  */
290
301
  forwardIterateDescendants(blockRoot: RootHex, payloadStatus: PayloadStatus): IterableIterator<ProtoBlock>;
302
+ /**
303
+ * Same as `forwardIterateDescendants` but resolves the default payload-status variant
304
+ * (FULL pre-Gloas, PENDING for Gloas) for the given root. Use when the caller holds a
305
+ * `CheckpointWithHex` / finalized root without a specific payload-status variant in mind.
306
+ */
307
+ forwardIterateDescendantsDefaultStatus(blockRoot: RootHex): IterableIterator<ProtoBlock>;
291
308
  getBlockSummariesByParentRoot(parentRoot: RootHex): ProtoBlock[];
292
309
  getBlockSummariesAtSlot(slot: Slot): ProtoBlock[];
293
310
  /** Returns the distance of common ancestor of nodes to the max of the newNode and the prevNode. */
@@ -1,8 +1,7 @@
1
1
  import {EffectiveBalanceIncrements, IBeaconStateView} from "@lodestar/state-transition";
2
2
  import {RootHex, Slot, ValidatorIndex, phase0} from "@lodestar/types";
3
3
  import {toRootHex} from "@lodestar/utils";
4
- import {PayloadStatus} from "../protoArray/interface.js";
5
- import {CheckpointWithPayloadAndBalance, CheckpointWithPayloadAndTotalBalance} from "./interface.js";
4
+ import {CheckpointWithBalance, CheckpointWithTotalBalance} from "./interface.js";
6
5
 
7
6
  /**
8
7
  * Stores checkpoints in a hybrid format:
@@ -11,15 +10,6 @@ import {CheckpointWithPayloadAndBalance, CheckpointWithPayloadAndTotalBalance} f
11
10
  */
12
11
  export type CheckpointWithHex = phase0.Checkpoint & {rootHex: RootHex};
13
12
 
14
- /**
15
- * Checkpoint with payload status for Gloas fork choice.
16
- * Used to track which variant (EMPTY or FULL) of the finalized/justified block to use.
17
- *
18
- * Pre-Gloas: payloadStatus is always FULL (payload embedded in block)
19
- * Gloas: determined by state.execution_payload_availability
20
- */
21
- export type CheckpointWithPayloadStatus = CheckpointWithHex & {payloadStatus: PayloadStatus};
22
-
23
13
  export type JustifiedBalances = EffectiveBalanceIncrements;
24
14
 
25
15
  /**
@@ -29,7 +19,7 @@ export type JustifiedBalances = EffectiveBalanceIncrements;
29
19
  * @param blockState state that declares justified checkpoint `checkpoint`
30
20
  */
31
21
  export type JustifiedBalancesGetter = (
32
- checkpoint: CheckpointWithPayloadStatus,
22
+ checkpoint: CheckpointWithHex,
33
23
  blockState: IBeaconStateView
34
24
  ) => JustifiedBalances;
35
25
 
@@ -47,11 +37,11 @@ export type JustifiedBalancesGetter = (
47
37
  */
48
38
  export interface IForkChoiceStore {
49
39
  currentSlot: Slot;
50
- get justified(): CheckpointWithPayloadAndTotalBalance;
51
- set justified(justified: CheckpointWithPayloadAndBalance);
52
- unrealizedJustified: CheckpointWithPayloadAndBalance;
53
- finalizedCheckpoint: CheckpointWithPayloadStatus;
54
- unrealizedFinalizedCheckpoint: CheckpointWithPayloadStatus;
40
+ get justified(): CheckpointWithTotalBalance;
41
+ set justified(justified: CheckpointWithBalance);
42
+ unrealizedJustified: CheckpointWithBalance;
43
+ finalizedCheckpoint: CheckpointWithHex;
44
+ unrealizedFinalizedCheckpoint: CheckpointWithHex;
55
45
  justifiedBalancesGetter: JustifiedBalancesGetter;
56
46
  equivocatingIndices: Set<ValidatorIndex>;
57
47
  }
@@ -60,10 +50,10 @@ export interface IForkChoiceStore {
60
50
  * IForkChoiceStore implementer which emits forkChoice events on updated justified and finalized checkpoints.
61
51
  */
62
52
  export class ForkChoiceStore implements IForkChoiceStore {
63
- private _justified: CheckpointWithPayloadAndTotalBalance;
64
- unrealizedJustified: CheckpointWithPayloadAndBalance;
65
- private _finalizedCheckpoint: CheckpointWithPayloadStatus;
66
- unrealizedFinalizedCheckpoint: CheckpointWithPayloadStatus;
53
+ private _justified: CheckpointWithTotalBalance;
54
+ unrealizedJustified: CheckpointWithBalance;
55
+ private _finalizedCheckpoint: CheckpointWithHex;
56
+ unrealizedFinalizedCheckpoint: CheckpointWithHex;
67
57
  equivocatingIndices = new Set<ValidatorIndex>();
68
58
  justifiedBalancesGetter: JustifiedBalancesGetter;
69
59
  currentSlot: Slot;
@@ -74,49 +64,37 @@ export class ForkChoiceStore implements IForkChoiceStore {
74
64
  finalizedCheckpoint: phase0.Checkpoint,
75
65
  justifiedBalances: EffectiveBalanceIncrements,
76
66
  justifiedBalancesGetter: JustifiedBalancesGetter,
77
- /**
78
- * Payload status for justified checkpoint.
79
- * Pre-Gloas: always FULL
80
- * Gloas: determined by state.execution_payload_availability
81
- */
82
- justifiedPayloadStatus: PayloadStatus,
83
- /**
84
- * Payload status for finalized checkpoint.
85
- * Pre-Gloas: always FULL
86
- * Gloas: determined by state.execution_payload_availability
87
- */
88
- finalizedPayloadStatus: PayloadStatus,
89
67
  private readonly events?: {
90
- onJustified: (cp: CheckpointWithPayloadStatus) => void;
91
- onFinalized: (cp: CheckpointWithPayloadStatus) => void;
68
+ onJustified: (cp: CheckpointWithHex) => void;
69
+ onFinalized: (cp: CheckpointWithHex) => void;
92
70
  }
93
71
  ) {
94
72
  this.justifiedBalancesGetter = justifiedBalancesGetter;
95
73
  this.currentSlot = currentSlot;
96
74
  const justified = {
97
- checkpoint: toCheckpointWithPayload(justifiedCheckpoint, justifiedPayloadStatus),
75
+ checkpoint: toCheckpointWithHex(justifiedCheckpoint),
98
76
  balances: justifiedBalances,
99
77
  totalBalance: computeTotalBalance(justifiedBalances),
100
78
  };
101
79
  this._justified = justified;
102
80
  this.unrealizedJustified = justified;
103
- this._finalizedCheckpoint = toCheckpointWithPayload(finalizedCheckpoint, finalizedPayloadStatus);
81
+ this._finalizedCheckpoint = toCheckpointWithHex(finalizedCheckpoint);
104
82
  this.unrealizedFinalizedCheckpoint = this._finalizedCheckpoint;
105
83
  }
106
84
 
107
- get justified(): CheckpointWithPayloadAndTotalBalance {
85
+ get justified(): CheckpointWithTotalBalance {
108
86
  return this._justified;
109
87
  }
110
- set justified(justified: CheckpointWithPayloadAndBalance) {
88
+ set justified(justified: CheckpointWithBalance) {
111
89
  this._justified = {...justified, totalBalance: computeTotalBalance(justified.balances)};
112
90
  this.events?.onJustified(justified.checkpoint);
113
91
  }
114
92
 
115
- get finalizedCheckpoint(): CheckpointWithPayloadStatus {
93
+ get finalizedCheckpoint(): CheckpointWithHex {
116
94
  return this._finalizedCheckpoint;
117
95
  }
118
- set finalizedCheckpoint(checkpoint: CheckpointWithPayloadStatus) {
119
- const cp = toCheckpointWithPayload(checkpoint, checkpoint.payloadStatus);
96
+ set finalizedCheckpoint(checkpoint: CheckpointWithHex) {
97
+ const cp = toCheckpointWithHex(checkpoint);
120
98
  this._finalizedCheckpoint = cp;
121
99
  this.events?.onFinalized(cp);
122
100
  }
@@ -133,16 +111,6 @@ export function toCheckpointWithHex(checkpoint: phase0.Checkpoint): CheckpointWi
133
111
  };
134
112
  }
135
113
 
136
- export function toCheckpointWithPayload(
137
- checkpoint: phase0.Checkpoint,
138
- payloadStatus: PayloadStatus
139
- ): CheckpointWithPayloadStatus {
140
- return {
141
- ...toCheckpointWithHex(checkpoint),
142
- payloadStatus,
143
- };
144
- }
145
-
146
114
  export function equalCheckpointWithHex(a: CheckpointWithHex, b: CheckpointWithHex): boolean {
147
115
  return a.epoch === b.epoch && a.rootHex === b.rootHex;
148
116
  }
package/src/index.ts CHANGED
@@ -6,17 +6,12 @@ export {
6
6
  type InvalidBlock,
7
7
  InvalidBlockCode,
8
8
  } from "./forkChoice/errors.js";
9
- export {
10
- ForkChoice,
11
- type ForkChoiceOpts,
12
- UpdateHeadOpt,
13
- getCheckpointPayloadStatus,
14
- } from "./forkChoice/forkChoice.js";
9
+ export {ForkChoice, type ForkChoiceOpts, UpdateHeadOpt} from "./forkChoice/forkChoice.js";
15
10
  export {
16
11
  type AncestorResult,
17
12
  AncestorStatus,
18
- type CheckpointWithPayloadAndBalance,
19
- type CheckpointWithPayloadAndTotalBalance,
13
+ type CheckpointWithBalance,
14
+ type CheckpointWithTotalBalance,
20
15
  EpochDifference,
21
16
  type IForkChoice,
22
17
  NotReorgedReason,
@@ -24,7 +19,6 @@ export {
24
19
  export * from "./forkChoice/safeBlocks.js";
25
20
  export {
26
21
  type CheckpointWithHex,
27
- type CheckpointWithPayloadStatus,
28
22
  ForkChoiceStore,
29
23
  type IForkChoiceStore,
30
24
  type JustifiedBalancesGetter,