@lodestar/fork-choice 1.43.0-dev.e341cdc614 → 1.43.0-dev.e3c96e7a79

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,
@@ -11,7 +11,6 @@ import {
11
11
  getAttesterSlashableIndices,
12
12
  isExecutionBlockBodyType,
13
13
  isStatePostBellatrix,
14
- isStatePostGloas,
15
14
  } from "@lodestar/state-transition";
16
15
  import {
17
16
  AttesterSlashing,
@@ -53,7 +52,7 @@ import {
53
52
  NotReorgedReason,
54
53
  ShouldOverrideForkChoiceUpdateResult,
55
54
  } from "./interface.js";
56
- import {CheckpointWithPayloadStatus, IForkChoiceStore, JustifiedBalances, toCheckpointWithPayload} from "./store.js";
55
+ import {CheckpointWithHex, IForkChoiceStore, JustifiedBalances, toCheckpointWithHex} from "./store.js";
57
56
 
58
57
  export type ForkChoiceOpts = {
59
58
  proposerBoost?: boolean;
@@ -311,6 +310,14 @@ export class ForkChoice implements IForkChoice {
311
310
  return this.proposerBoostRoot ?? HEX_ZERO_HASH;
312
311
  }
313
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
+
314
321
  /**
315
322
  * To predict the proposer head of the next slot. That is, to predict if proposer-boost-reorg could happen.
316
323
  * Reason why we can't be certain is because information of the head block is not fully available yet
@@ -556,11 +563,11 @@ export class ForkChoice implements IForkChoice {
556
563
  return this.protoArray.nodes;
557
564
  }
558
565
 
559
- getFinalizedCheckpoint(): CheckpointWithPayloadStatus {
566
+ getFinalizedCheckpoint(): CheckpointWithHex {
560
567
  return this.fcStore.finalizedCheckpoint;
561
568
  }
562
569
 
563
- getJustifiedCheckpoint(): CheckpointWithPayloadStatus {
570
+ getJustifiedCheckpoint(): CheckpointWithHex {
564
571
  return this.fcStore.justified.checkpoint;
565
572
  }
566
573
 
@@ -667,18 +674,10 @@ export class ForkChoice implements IForkChoice {
667
674
  this.proposerBoostRoot = blockRootHex;
668
675
  }
669
676
 
670
- // Get justified checkpoint with payload status for Gloas
671
- const justifiedPayloadStatus = getCheckpointPayloadStatus(
672
- this.config,
673
- state,
674
- state.currentJustifiedCheckpoint.epoch
675
- );
676
- const justifiedCheckpoint = toCheckpointWithPayload(state.currentJustifiedCheckpoint, justifiedPayloadStatus);
677
+ const justifiedCheckpoint = toCheckpointWithHex(state.currentJustifiedCheckpoint);
677
678
  const stateJustifiedEpoch = justifiedCheckpoint.epoch;
678
679
 
679
- // Get finalized checkpoint with payload status for Gloas
680
- const finalizedPayloadStatus = getCheckpointPayloadStatus(this.config, state, state.finalizedCheckpoint.epoch);
681
- const finalizedCheckpoint = toCheckpointWithPayload(state.finalizedCheckpoint, finalizedPayloadStatus);
680
+ const finalizedCheckpoint = toCheckpointWithHex(state.finalizedCheckpoint);
682
681
 
683
682
  // Justified balances for `justifiedCheckpoint` are new to the fork-choice. Compute them on demand only if
684
683
  // the justified checkpoint changes
@@ -700,61 +699,29 @@ export class ForkChoice implements IForkChoice {
700
699
  // This is an optimization. It should reduce the amount of times we run
701
700
  // `process_justification_and_finalization` by approximately 1/3rd when the chain is
702
701
  // performing optimally.
703
- let unrealizedJustifiedCheckpoint: CheckpointWithPayloadStatus;
704
- let unrealizedFinalizedCheckpoint: CheckpointWithPayloadStatus;
702
+ let unrealizedJustifiedCheckpoint: CheckpointWithHex;
703
+ let unrealizedFinalizedCheckpoint: CheckpointWithHex;
705
704
  if (this.opts?.computeUnrealized) {
706
705
  if (
707
706
  parentBlock.unrealizedJustifiedEpoch === blockEpoch &&
708
707
  parentBlock.unrealizedFinalizedEpoch + 1 >= blockEpoch
709
708
  ) {
710
709
  // reuse from parent, happens at 1/3 last blocks of epoch as monitored in mainnet
711
- // Get payload status for unrealized justified checkpoint
712
- const unrealizedJustifiedPayloadStatus = getCheckpointPayloadStatus(
713
- this.config,
714
- state,
715
- parentBlock.unrealizedJustifiedEpoch
716
- );
717
710
  unrealizedJustifiedCheckpoint = {
718
711
  epoch: parentBlock.unrealizedJustifiedEpoch,
719
712
  root: fromHex(parentBlock.unrealizedJustifiedRoot),
720
713
  rootHex: parentBlock.unrealizedJustifiedRoot,
721
- payloadStatus: unrealizedJustifiedPayloadStatus,
722
714
  };
723
- // Get payload status for unrealized finalized checkpoint
724
- const unrealizedFinalizedPayloadStatus = getCheckpointPayloadStatus(
725
- this.config,
726
- state,
727
- parentBlock.unrealizedFinalizedEpoch
728
- );
729
715
  unrealizedFinalizedCheckpoint = {
730
716
  epoch: parentBlock.unrealizedFinalizedEpoch,
731
717
  root: fromHex(parentBlock.unrealizedFinalizedRoot),
732
718
  rootHex: parentBlock.unrealizedFinalizedRoot,
733
- payloadStatus: unrealizedFinalizedPayloadStatus,
734
719
  };
735
720
  } else {
736
721
  // compute new, happens 2/3 first blocks of epoch as monitored in mainnet
737
722
  const unrealized = state.computeUnrealizedCheckpoints();
738
- // Get payload status for unrealized justified checkpoint
739
- const unrealizedJustifiedPayloadStatus = getCheckpointPayloadStatus(
740
- this.config,
741
- state,
742
- unrealized.justifiedCheckpoint.epoch
743
- );
744
- unrealizedJustifiedCheckpoint = toCheckpointWithPayload(
745
- unrealized.justifiedCheckpoint,
746
- unrealizedJustifiedPayloadStatus
747
- );
748
- // Get payload status for unrealized finalized checkpoint
749
- const unrealizedFinalizedPayloadStatus = getCheckpointPayloadStatus(
750
- this.config,
751
- state,
752
- unrealized.finalizedCheckpoint.epoch
753
- );
754
- unrealizedFinalizedCheckpoint = toCheckpointWithPayload(
755
- unrealized.finalizedCheckpoint,
756
- unrealizedFinalizedPayloadStatus
757
- );
723
+ unrealizedJustifiedCheckpoint = toCheckpointWithHex(unrealized.justifiedCheckpoint);
724
+ unrealizedFinalizedCheckpoint = toCheckpointWithHex(unrealized.finalizedCheckpoint);
758
725
  }
759
726
  } else {
760
727
  unrealizedJustifiedCheckpoint = justifiedCheckpoint;
@@ -821,7 +788,7 @@ export class ForkChoice implements IForkChoice {
821
788
  // Fallback to parent block's number (we know it's post-merge from check above)
822
789
  return parentBlock.executionPayloadNumber;
823
790
  })(),
824
- executionStatus: this.getPostGloasExecStatus(executionStatus),
791
+ executionStatus: this.getPostMergeExecStatus(executionStatus),
825
792
  dataAvailabilityStatus,
826
793
  }
827
794
  : isExecutionBlockBodyType(block.body) &&
@@ -831,7 +798,7 @@ export class ForkChoice implements IForkChoice {
831
798
  ? {
832
799
  executionPayloadBlockHash: toRootHex(block.body.executionPayload.blockHash),
833
800
  executionPayloadNumber: block.body.executionPayload.blockNumber,
834
- executionStatus: this.getPreGloasExecStatus(executionStatus),
801
+ executionStatus: this.getPostMergeExecStatus(executionStatus),
835
802
  dataAvailabilityStatus,
836
803
  }
837
804
  : {
@@ -980,17 +947,17 @@ export class ForkChoice implements IForkChoice {
980
947
  blockRoot: RootHex,
981
948
  executionPayloadBlockHash: RootHex,
982
949
  executionPayloadNumber: number,
983
- executionPayloadStateRoot: RootHex,
984
- executionStatus: PayloadExecutionStatus
950
+ executionStatus: PayloadExecutionStatus,
951
+ dataAvailabilityStatus: DataAvailabilityStatus
985
952
  ): void {
986
953
  this.protoArray.onExecutionPayload(
987
954
  blockRoot,
988
955
  this.fcStore.currentSlot,
989
956
  executionPayloadBlockHash,
990
957
  executionPayloadNumber,
991
- executionPayloadStateRoot,
992
958
  this.proposerBoostRoot,
993
- executionStatus
959
+ executionStatus,
960
+ dataAvailabilityStatus
994
961
  );
995
962
  }
996
963
 
@@ -1076,6 +1043,12 @@ export class ForkChoice implements IForkChoice {
1076
1043
  return this.protoArray.hasPayload(blockRoot);
1077
1044
  }
1078
1045
 
1046
+ getPTCVotes(blockRootHex: RootHex): (boolean | null)[] | null {
1047
+ const votes = this.protoArray.getPTCVotes(blockRootHex);
1048
+ if (votes === null) return null;
1049
+ return votes.toBoolArray().map((v) => v ?? null);
1050
+ }
1051
+
1079
1052
  /**
1080
1053
  * Returns a MUTABLE `ProtoBlock` if the block is known **and** a descendant of the finalized root.
1081
1054
  */
@@ -1119,8 +1092,8 @@ export class ForkChoice implements IForkChoice {
1119
1092
  }
1120
1093
 
1121
1094
  getJustifiedBlock(): ProtoBlock {
1122
- const {rootHex, payloadStatus} = this.fcStore.justified.checkpoint;
1123
- const block = this.getBlockHex(rootHex, payloadStatus);
1095
+ const {rootHex} = this.fcStore.justified.checkpoint;
1096
+ const block = this.getBlockHexDefaultStatus(rootHex);
1124
1097
  if (!block) {
1125
1098
  throw new ForkChoiceError({
1126
1099
  code: ForkChoiceErrorCode.MISSING_PROTO_ARRAY_BLOCK,
@@ -1131,8 +1104,8 @@ export class ForkChoice implements IForkChoice {
1131
1104
  }
1132
1105
 
1133
1106
  getFinalizedBlock(): ProtoBlock {
1134
- const {rootHex, payloadStatus} = this.fcStore.finalizedCheckpoint;
1135
- const block = this.getBlockHex(rootHex, payloadStatus);
1107
+ const {rootHex} = this.fcStore.finalizedCheckpoint;
1108
+ const block = this.getBlockHexDefaultStatus(rootHex);
1136
1109
  if (!block) {
1137
1110
  throw new ForkChoiceError({
1138
1111
  code: ForkChoiceErrorCode.MISSING_PROTO_ARRAY_BLOCK,
@@ -1207,13 +1180,12 @@ export class ForkChoice implements IForkChoice {
1207
1180
  }
1208
1181
 
1209
1182
  /**
1210
- * Returns all blocks backwards starting from a block root.
1211
- * Return only the non-finalized blocks.
1183
+ * Raw ancestor walk from `blockRoot` back toward the previous finalized block. Includes both
1184
+ * `blockRoot` and the previous-finalized boundary as last element. Mirrors the semantics of
1185
+ * `getAllAncestorAndNonAncestorBlocks.ancestors`
1212
1186
  */
1213
1187
  getAllAncestorBlocks(blockRoot: RootHex, payloadStatus: PayloadStatus): ProtoBlock[] {
1214
- const blocks = this.protoArray.getAllAncestorNodes(blockRoot, payloadStatus);
1215
- // the last node is the previous finalized one, it's there to check onBlock finalized checkpoint only.
1216
- return blocks.slice(0, blocks.length - 1);
1188
+ return this.protoArray.getAllAncestorNodes(blockRoot, payloadStatus);
1217
1189
  }
1218
1190
 
1219
1191
  /**
@@ -1225,18 +1197,33 @@ export class ForkChoice implements IForkChoice {
1225
1197
 
1226
1198
  /**
1227
1199
  * Returns both ancestor and non-ancestor blocks in a single traversal.
1200
+ *
1201
+ * `ancestors` is the raw walk and includes the previous finalized block as its last element —
1202
+ * callers that don't want the boundary should slice it off themselves.
1203
+ * Post-gloas for each block root, it returns exactly one variant of it.
1228
1204
  */
1229
1205
  getAllAncestorAndNonAncestorBlocks(
1230
1206
  blockRoot: RootHex,
1231
1207
  payloadStatus: PayloadStatus
1232
1208
  ): {ancestors: ProtoBlock[]; nonAncestors: ProtoBlock[]} {
1233
- const {ancestors, nonAncestors} = this.protoArray.getAllAncestorAndNonAncestorNodes(blockRoot, payloadStatus);
1209
+ return this.protoArray.getAllAncestorAndNonAncestorNodes(blockRoot, payloadStatus);
1210
+ }
1234
1211
 
1235
- return {
1236
- // the last node is the previous finalized one, it's there to check onBlock finalized checkpoint only.
1237
- ancestors: ancestors.slice(0, ancestors.length - 1),
1238
- nonAncestors,
1239
- };
1212
+ /**
1213
+ * Same to getAllAncestorAndNonAncestorBlocks with default variant of ${blockRoot} to start with
1214
+ */
1215
+ getAllAncestorAndNonAncestorBlocksDefaultStatus(blockRoot: RootHex): {
1216
+ ancestors: ProtoBlock[];
1217
+ nonAncestors: ProtoBlock[];
1218
+ } {
1219
+ const defaultStatus = this.protoArray.getDefaultVariant(blockRoot);
1220
+ if (defaultStatus === undefined) {
1221
+ throw new ForkChoiceError({
1222
+ code: ForkChoiceErrorCode.MISSING_PROTO_ARRAY_BLOCK,
1223
+ root: blockRoot,
1224
+ });
1225
+ }
1226
+ return this.getAllAncestorAndNonAncestorBlocks(blockRoot, defaultStatus);
1240
1227
  }
1241
1228
 
1242
1229
  getCanonicalBlockByRoot(blockRoot: Root): ProtoBlock | null {
@@ -1308,6 +1295,17 @@ export class ForkChoice implements IForkChoice {
1308
1295
  }
1309
1296
  }
1310
1297
 
1298
+ forwardIterateDescendantsDefaultStatus(blockRoot: RootHex): IterableIterator<ProtoBlock> {
1299
+ const defaultStatus = this.protoArray.getDefaultVariant(blockRoot);
1300
+ if (defaultStatus === undefined) {
1301
+ throw new ForkChoiceError({
1302
+ code: ForkChoiceErrorCode.MISSING_PROTO_ARRAY_BLOCK,
1303
+ root: blockRoot,
1304
+ });
1305
+ }
1306
+ return this.forwardIterateDescendants(blockRoot, defaultStatus);
1307
+ }
1308
+
1311
1309
  /** Very expensive function, iterates the entire ProtoArray. TODO: Is this function even necessary? */
1312
1310
  getBlockSummariesByParentRoot(parentRoot: RootHex): ProtoBlock[] {
1313
1311
  return this.protoArray.nodes.filter((node) => node.parentRoot === parentRoot);
@@ -1459,24 +1457,16 @@ export class ForkChoice implements IForkChoice {
1459
1457
  return dataAvailabilityStatus;
1460
1458
  }
1461
1459
 
1462
- private getPreGloasExecStatus(
1460
+ private getPostMergeExecStatus(
1463
1461
  executionStatus: BlockExecutionStatus
1464
1462
  ): ExecutionStatus.Valid | ExecutionStatus.Syncing {
1465
- if (executionStatus === ExecutionStatus.PreMerge || executionStatus === ExecutionStatus.PayloadSeparated)
1463
+ if (executionStatus === ExecutionStatus.PreMerge)
1466
1464
  throw Error(
1467
1465
  `Invalid post-merge execution status: expected: ${ExecutionStatus.Syncing} or ${ExecutionStatus.Valid}, got ${executionStatus}`
1468
1466
  );
1469
1467
  return executionStatus;
1470
1468
  }
1471
1469
 
1472
- private getPostGloasExecStatus(executionStatus: BlockExecutionStatus): ExecutionStatus.PayloadSeparated {
1473
- if (executionStatus !== ExecutionStatus.PayloadSeparated)
1474
- throw Error(
1475
- `Invalid post-gloas execution status: expected: ${ExecutionStatus.PayloadSeparated}, got ${executionStatus}`
1476
- );
1477
- return executionStatus;
1478
- }
1479
-
1480
1470
  /**
1481
1471
  * Why `getJustifiedBalances` getter?
1482
1472
  * - updateCheckpoints() is called in both on_block and on_tick.
@@ -1494,12 +1484,12 @@ export class ForkChoice implements IForkChoice {
1494
1484
  *
1495
1485
  * **`on_tick`**
1496
1486
  * May need the justified balances of:
1497
- * - unrealizedJustified: Already available in `CheckpointWithPayloadAndBalance`
1487
+ * - unrealizedJustified: Already available in `CheckpointWithBalance`
1498
1488
  * Since this balances are already available the getter is just `() => balances`, without cache interaction
1499
1489
  */
1500
1490
  private updateCheckpoints(
1501
- justifiedCheckpoint: CheckpointWithPayloadStatus,
1502
- finalizedCheckpoint: CheckpointWithPayloadStatus,
1491
+ justifiedCheckpoint: CheckpointWithHex,
1492
+ finalizedCheckpoint: CheckpointWithHex,
1503
1493
  getJustifiedBalances: () => JustifiedBalances
1504
1494
  ): void {
1505
1495
  // Update justified checkpoint.
@@ -1519,8 +1509,8 @@ export class ForkChoice implements IForkChoice {
1519
1509
  * Update unrealized checkpoints in store if necessary
1520
1510
  */
1521
1511
  private updateUnrealizedCheckpoints(
1522
- unrealizedJustifiedCheckpoint: CheckpointWithPayloadStatus,
1523
- unrealizedFinalizedCheckpoint: CheckpointWithPayloadStatus,
1512
+ unrealizedJustifiedCheckpoint: CheckpointWithHex,
1513
+ unrealizedFinalizedCheckpoint: CheckpointWithHex,
1524
1514
  getJustifiedBalances: () => JustifiedBalances
1525
1515
  ): void {
1526
1516
  if (unrealizedJustifiedCheckpoint.epoch > this.fcStore.unrealizedJustified.checkpoint.epoch) {
@@ -1895,38 +1885,3 @@ export function getCommitteeFraction(
1895
1885
  const committeeWeight = Math.floor(justifiedTotalActiveBalanceByIncrement / config.slotsPerEpoch);
1896
1886
  return Math.floor((committeeWeight * config.committeePercent) / 100);
1897
1887
  }
1898
-
1899
- /**
1900
- * Get the payload status for a checkpoint.
1901
- *
1902
- * Pre-Gloas: always FULL (payload embedded in block)
1903
- * Gloas: determined by state.execution_payload_availability
1904
- *
1905
- * @param config - The chain fork config to determine fork at checkpoint slot
1906
- * @param state - The state to check execution_payload_availability
1907
- * @param checkpointEpoch - The epoch of the checkpoint
1908
- */
1909
- export function getCheckpointPayloadStatus(
1910
- config: ChainForkConfig,
1911
- state: IBeaconStateView,
1912
- checkpointEpoch: number
1913
- ): PayloadStatus {
1914
- // Compute checkpoint slot first to determine the correct fork
1915
- const checkpointSlot = computeStartSlotAtEpoch(checkpointEpoch);
1916
- const fork = config.getForkSeq(checkpointSlot);
1917
-
1918
- // Pre-Gloas: always FULL
1919
- if (fork < ForkSeq.gloas) {
1920
- return PayloadStatus.FULL;
1921
- }
1922
- if (!isStatePostGloas(state)) {
1923
- throw new Error(`Expected gloas+ state for checkpoint payload status, got fork=${state.forkName}`);
1924
- }
1925
-
1926
- // For Gloas, check state.execution_payload_availability
1927
- // - For non-skipped slots at checkpoint: returns false (EMPTY) since payload hasn't arrived yet
1928
- // - For skipped slots at checkpoint: returns the actual availability status from state
1929
- const payloadAvailable = state.executionPayloadAvailability.get(checkpointSlot % SLOTS_PER_HISTORICAL_ROOT);
1930
-
1931
- return payloadAvailable ? PayloadStatus.FULL : PayloadStatus.EMPTY;
1932
- }
@@ -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,14 +198,13 @@ 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
- executionStatus: PayloadExecutionStatus
206
+ executionStatus: PayloadExecutionStatus,
207
+ dataAvailabilityStatus: DataAvailabilityStatus
209
208
  ): void;
210
209
  /**
211
210
  * Call `onTick` for all slots between `fcStore.getCurrentSlot()` and the provided `currentSlot`.
@@ -233,6 +232,7 @@ export interface IForkChoice {
233
232
  hasPayloadUnsafe(blockRoot: Root): boolean;
234
233
  hasPayloadHexUnsafe(blockRoot: RootHex): boolean;
235
234
  getSlotsPresent(windowStart: number): number;
235
+ getPTCVotes(blockRootHex: RootHex): (boolean | null)[] | null;
236
236
  /**
237
237
  * Returns a `ProtoBlock` if the block is known **and** a descendant of the finalized root.
238
238
  */
@@ -241,6 +241,7 @@ export interface IForkChoice {
241
241
  getBlockDefaultStatus(blockRoot: Root): ProtoBlock | null;
242
242
  getBlockHexDefaultStatus(blockRoot: RootHex): ProtoBlock | null;
243
243
  getBlockHexAndBlockHash(blockRoot: RootHex, blockHash: RootHex): ProtoBlock | null;
244
+ shouldExtendPayload(blockRoot: RootHex): boolean;
244
245
  getFinalizedBlock(): ProtoBlock;
245
246
  getJustifiedBlock(): ProtoBlock;
246
247
  getFinalizedCheckpointSlot(): Slot;
@@ -272,11 +273,23 @@ export interface IForkChoice {
272
273
  getAllNonAncestorBlocks(blockRoot: RootHex, payloadStatus: PayloadStatus): ProtoBlock[];
273
274
  /**
274
275
  * Returns both ancestor and non-ancestor blocks in a single traversal.
276
+ *
277
+ * `ancestors` is the raw walk and includes the previous finalized block as its last element —
278
+ * callers that don't want the boundary should slice it off themselves.
275
279
  */
276
280
  getAllAncestorAndNonAncestorBlocks(
277
281
  blockRoot: RootHex,
278
282
  payloadStatus: PayloadStatus
279
283
  ): {ancestors: ProtoBlock[]; nonAncestors: ProtoBlock[]};
284
+ /**
285
+ * Same as `getAllAncestorAndNonAncestorBlocks` but resolves the default payload-status variant
286
+ * (FULL pre-Gloas, PENDING for Gloas) for the given root. Use when the caller holds a
287
+ * `CheckpointWithHex` / finalized root without a specific payload-status variant in mind.
288
+ */
289
+ getAllAncestorAndNonAncestorBlocksDefaultStatus(blockRoot: RootHex): {
290
+ ancestors: ProtoBlock[];
291
+ nonAncestors: ProtoBlock[];
292
+ };
280
293
  getCanonicalBlockByRoot(blockRoot: Root): ProtoBlock | null;
281
294
  getCanonicalBlockAtSlot(slot: Slot): ProtoBlock | null;
282
295
  getCanonicalBlockClosestLteSlot(slot: Slot): ProtoBlock | null;
@@ -288,6 +301,12 @@ export interface IForkChoice {
288
301
  * Iterates forward descendants of blockRoot. Does not yield blockRoot itself
289
302
  */
290
303
  forwardIterateDescendants(blockRoot: RootHex, payloadStatus: PayloadStatus): IterableIterator<ProtoBlock>;
304
+ /**
305
+ * Same as `forwardIterateDescendants` but resolves the default payload-status variant
306
+ * (FULL pre-Gloas, PENDING for Gloas) for the given root. Use when the caller holds a
307
+ * `CheckpointWithHex` / finalized root without a specific payload-status variant in mind.
308
+ */
309
+ forwardIterateDescendantsDefaultStatus(blockRoot: RootHex): IterableIterator<ProtoBlock>;
291
310
  getBlockSummariesByParentRoot(parentRoot: RootHex): ProtoBlock[];
292
311
  getBlockSummariesAtSlot(slot: Slot): ProtoBlock[];
293
312
  /** 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,