@lodestar/fork-choice 1.41.0-dev.09945f6589 → 1.41.0-dev.0df187678b

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.
@@ -12,7 +12,7 @@ import {
12
12
  ProtoNode,
13
13
  } from "../protoArray/interface.js";
14
14
  import {UpdateAndGetHeadOpt} from "./forkChoice.js";
15
- import {CheckpointWithHex, CheckpointWithPayload} from "./store.js";
15
+ import {CheckpointWithHex, CheckpointWithPayloadStatus} from "./store.js";
16
16
 
17
17
  export type CheckpointHex = {
18
18
  epoch: Epoch;
@@ -25,7 +25,7 @@ export type CheckpointsWithHex = {
25
25
  };
26
26
 
27
27
  export type CheckpointWithPayloadAndBalance = {
28
- checkpoint: CheckpointWithPayload;
28
+ checkpoint: CheckpointWithPayloadStatus;
29
29
  balances: EffectiveBalanceIncrements;
30
30
  };
31
31
 
@@ -124,8 +124,8 @@ export interface IForkChoice {
124
124
  * Retrieve all nodes for the debug API.
125
125
  */
126
126
  getAllNodes(): ProtoNode[];
127
- getFinalizedCheckpoint(): CheckpointWithPayload;
128
- getJustifiedCheckpoint(): CheckpointWithPayload;
127
+ getFinalizedCheckpoint(): CheckpointWithPayloadStatus;
128
+ getJustifiedCheckpoint(): CheckpointWithPayloadStatus;
129
129
  /**
130
130
  * Add `block` to the fork choice DAG.
131
131
  *
@@ -246,7 +246,12 @@ export interface IForkChoice {
246
246
  * Always returns `false` if either input roots are unknown.
247
247
  * Still returns `true` if `ancestorRoot===descendantRoot` (and the roots are known)
248
248
  */
249
- isDescendant(ancestorRoot: RootHex, descendantRoot: RootHex): boolean;
249
+ isDescendant(
250
+ ancestorRoot: RootHex,
251
+ ancestorPayloadStatus: PayloadStatus,
252
+ descendantRoot: RootHex,
253
+ descendantPayloadStatus: PayloadStatus
254
+ ): boolean;
250
255
  /**
251
256
  * Prune items up to a finalized root.
252
257
  */
@@ -255,16 +260,20 @@ export interface IForkChoice {
255
260
  /**
256
261
  * Iterates backwards through ancestor block summaries, starting from a block root
257
262
  */
258
- iterateAncestorBlocks(blockRoot: RootHex): IterableIterator<ProtoBlock>;
259
- getAllAncestorBlocks(blockRoot: RootHex): ProtoBlock[];
263
+ iterateAncestorBlocks(blockRoot: RootHex, payloadStatus: PayloadStatus): IterableIterator<ProtoBlock>;
264
+ getAllAncestorBlocks(blockRoot: RootHex, payloadStatus: PayloadStatus): ProtoBlock[];
260
265
  /**
261
266
  * The same to iterateAncestorBlocks but this gets non-ancestor nodes instead of ancestor nodes.
262
267
  */
263
- getAllNonAncestorBlocks(blockRoot: RootHex): ProtoBlock[];
268
+ getAllNonAncestorBlocks(blockRoot: RootHex, payloadStatus: PayloadStatus): ProtoBlock[];
264
269
  /**
265
270
  * Returns both ancestor and non-ancestor blocks in a single traversal.
266
271
  */
267
- getAllAncestorAndNonAncestorBlocks(blockRoot: RootHex): {ancestors: ProtoBlock[]; nonAncestors: ProtoBlock[]};
272
+ getAllAncestorAndNonAncestorBlocks(
273
+ blockRoot: RootHex,
274
+ payloadStatus: PayloadStatus
275
+ ): {ancestors: ProtoBlock[]; nonAncestors: ProtoBlock[]};
276
+ getCanonicalBlockByRoot(blockRoot: Root): ProtoBlock | null;
268
277
  getCanonicalBlockAtSlot(slot: Slot): ProtoBlock | null;
269
278
  getCanonicalBlockClosestLteSlot(slot: Slot): ProtoBlock | null;
270
279
  /**
@@ -274,7 +283,7 @@ export interface IForkChoice {
274
283
  /**
275
284
  * Iterates forward descendants of blockRoot. Does not yield blockRoot itself
276
285
  */
277
- forwardIterateDescendants(blockRoot: RootHex): IterableIterator<ProtoBlock>;
286
+ forwardIterateDescendants(blockRoot: RootHex, payloadStatus: PayloadStatus): IterableIterator<ProtoBlock>;
278
287
  getBlockSummariesByParentRoot(parentRoot: RootHex): ProtoBlock[];
279
288
  getBlockSummariesAtSlot(slot: Slot): ProtoBlock[];
280
289
  /** Returns the distance of common ancestor of nodes to the max of the newNode and the prevNode. */
@@ -18,7 +18,7 @@ export type CheckpointWithHex = phase0.Checkpoint & {rootHex: RootHex};
18
18
  * Pre-Gloas: payloadStatus is always FULL (payload embedded in block)
19
19
  * Gloas: determined by state.execution_payload_availability
20
20
  */
21
- export type CheckpointWithPayload = CheckpointWithHex & {payloadStatus: PayloadStatus};
21
+ export type CheckpointWithPayloadStatus = CheckpointWithHex & {payloadStatus: PayloadStatus};
22
22
 
23
23
  export type JustifiedBalances = EffectiveBalanceIncrements;
24
24
 
@@ -29,7 +29,7 @@ export type JustifiedBalances = EffectiveBalanceIncrements;
29
29
  * @param blockState state that declares justified checkpoint `checkpoint`
30
30
  */
31
31
  export type JustifiedBalancesGetter = (
32
- checkpoint: CheckpointWithPayload,
32
+ checkpoint: CheckpointWithPayloadStatus,
33
33
  blockState: CachedBeaconStateAllForks
34
34
  ) => JustifiedBalances;
35
35
 
@@ -50,8 +50,8 @@ export interface IForkChoiceStore {
50
50
  get justified(): CheckpointWithPayloadAndTotalBalance;
51
51
  set justified(justified: CheckpointWithPayloadAndBalance);
52
52
  unrealizedJustified: CheckpointWithPayloadAndBalance;
53
- finalizedCheckpoint: CheckpointWithPayload;
54
- unrealizedFinalizedCheckpoint: CheckpointWithPayload;
53
+ finalizedCheckpoint: CheckpointWithPayloadStatus;
54
+ unrealizedFinalizedCheckpoint: CheckpointWithPayloadStatus;
55
55
  justifiedBalancesGetter: JustifiedBalancesGetter;
56
56
  equivocatingIndices: Set<ValidatorIndex>;
57
57
  }
@@ -62,8 +62,8 @@ export interface IForkChoiceStore {
62
62
  export class ForkChoiceStore implements IForkChoiceStore {
63
63
  private _justified: CheckpointWithPayloadAndTotalBalance;
64
64
  unrealizedJustified: CheckpointWithPayloadAndBalance;
65
- private _finalizedCheckpoint: CheckpointWithPayload;
66
- unrealizedFinalizedCheckpoint: CheckpointWithPayload;
65
+ private _finalizedCheckpoint: CheckpointWithPayloadStatus;
66
+ unrealizedFinalizedCheckpoint: CheckpointWithPayloadStatus;
67
67
  equivocatingIndices = new Set<ValidatorIndex>();
68
68
  justifiedBalancesGetter: JustifiedBalancesGetter;
69
69
  currentSlot: Slot;
@@ -87,8 +87,8 @@ export class ForkChoiceStore implements IForkChoiceStore {
87
87
  */
88
88
  finalizedPayloadStatus: PayloadStatus,
89
89
  private readonly events?: {
90
- onJustified: (cp: CheckpointWithPayload) => void;
91
- onFinalized: (cp: CheckpointWithPayload) => void;
90
+ onJustified: (cp: CheckpointWithPayloadStatus) => void;
91
+ onFinalized: (cp: CheckpointWithPayloadStatus) => void;
92
92
  }
93
93
  ) {
94
94
  this.justifiedBalancesGetter = justifiedBalancesGetter;
@@ -112,10 +112,10 @@ export class ForkChoiceStore implements IForkChoiceStore {
112
112
  this.events?.onJustified(justified.checkpoint);
113
113
  }
114
114
 
115
- get finalizedCheckpoint(): CheckpointWithPayload {
115
+ get finalizedCheckpoint(): CheckpointWithPayloadStatus {
116
116
  return this._finalizedCheckpoint;
117
117
  }
118
- set finalizedCheckpoint(checkpoint: CheckpointWithPayload) {
118
+ set finalizedCheckpoint(checkpoint: CheckpointWithPayloadStatus) {
119
119
  const cp = toCheckpointWithPayload(checkpoint, checkpoint.payloadStatus);
120
120
  this._finalizedCheckpoint = cp;
121
121
  this.events?.onFinalized(cp);
@@ -136,7 +136,7 @@ export function toCheckpointWithHex(checkpoint: phase0.Checkpoint): CheckpointWi
136
136
  export function toCheckpointWithPayload(
137
137
  checkpoint: phase0.Checkpoint,
138
138
  payloadStatus: PayloadStatus
139
- ): CheckpointWithPayload {
139
+ ): CheckpointWithPayloadStatus {
140
140
  return {
141
141
  ...toCheckpointWithHex(checkpoint),
142
142
  payloadStatus,
package/src/index.ts CHANGED
@@ -24,7 +24,7 @@ export {
24
24
  export * from "./forkChoice/safeBlocks.js";
25
25
  export {
26
26
  type CheckpointWithHex,
27
- type CheckpointWithPayload,
27
+ type CheckpointWithPayloadStatus,
28
28
  ForkChoiceStore,
29
29
  type IForkChoiceStore,
30
30
  type JustifiedBalancesGetter,
@@ -1477,11 +1477,8 @@ export class ProtoArray {
1477
1477
  * For Gloas blocks: returns EMPTY/FULL variants (not PENDING) based on parent payload status
1478
1478
  * For pre-Gloas blocks: returns FULL variants
1479
1479
  */
1480
- *iterateAncestorNodes(blockRoot: RootHex): IterableIterator<ProtoNode> {
1481
- // Get canonical node: FULL for pre-Gloas, PENDING for Gloas
1482
- const defaultStatus = this.getDefaultVariant(blockRoot);
1483
- const startIndex =
1484
- defaultStatus !== undefined ? this.getNodeIndexByRootAndStatus(blockRoot, defaultStatus) : undefined;
1480
+ *iterateAncestorNodes(blockRoot: RootHex, payloadStatus: PayloadStatus): IterableIterator<ProtoNode> {
1481
+ const startIndex = this.getNodeIndexByRootAndStatus(blockRoot, payloadStatus);
1485
1482
  if (startIndex === undefined) {
1486
1483
  return;
1487
1484
  }
@@ -1520,11 +1517,8 @@ export class ProtoArray {
1520
1517
  * For Gloas blocks: returns EMPTY/FULL variants (not PENDING) based on parent payload status
1521
1518
  * For pre-Gloas blocks: returns FULL variants
1522
1519
  */
1523
- getAllAncestorNodes(blockRoot: RootHex): ProtoNode[] {
1524
- // Get canonical node: FULL for pre-Gloas, PENDING for Gloas
1525
- const defaultStatus = this.getDefaultVariant(blockRoot);
1526
- const startIndex =
1527
- defaultStatus !== undefined ? this.getNodeIndexByRootAndStatus(blockRoot, defaultStatus) : undefined;
1520
+ getAllAncestorNodes(blockRoot: RootHex, payloadStatus: PayloadStatus): ProtoNode[] {
1521
+ const startIndex = this.getNodeIndexByRootAndStatus(blockRoot, payloadStatus);
1528
1522
  if (startIndex === undefined) {
1529
1523
  return [];
1530
1524
  }
@@ -1537,12 +1531,10 @@ export class ProtoArray {
1537
1531
  });
1538
1532
  }
1539
1533
 
1540
- // Include starting node if node is pre-gloas
1541
- // Reason why we exclude post-gloas is because node is always default variant (PENDING)
1542
- // which we want to exclude.
1534
+ // Exclude PENDING variant from returned ancestors.
1543
1535
  const nodes: ProtoNode[] = [];
1544
1536
 
1545
- if (!isGloasBlock(node)) {
1537
+ if (node.payloadStatus !== PayloadStatus.PENDING) {
1546
1538
  nodes.push(node);
1547
1539
  }
1548
1540
 
@@ -1567,13 +1559,8 @@ export class ProtoArray {
1567
1559
  * For Gloas blocks: returns EMPTY/FULL variants (not PENDING) based on parent payload status
1568
1560
  * For pre-Gloas blocks: returns FULL variants
1569
1561
  */
1570
- getAllNonAncestorNodes(blockRoot: RootHex): ProtoNode[] {
1571
- // Get canonical node: FULL for pre-Gloas, PENDING for Gloas
1572
- const defaultStatus = this.getDefaultVariant(blockRoot);
1573
- if (defaultStatus === undefined) {
1574
- return [];
1575
- }
1576
- const startIndex = this.getNodeIndexByRootAndStatus(blockRoot, defaultStatus);
1562
+ getAllNonAncestorNodes(blockRoot: RootHex, payloadStatus: PayloadStatus): ProtoNode[] {
1563
+ const startIndex = this.getNodeIndexByRootAndStatus(blockRoot, payloadStatus);
1577
1564
  if (startIndex === undefined) {
1578
1565
  return [];
1579
1566
  }
@@ -1613,11 +1600,11 @@ export class ProtoArray {
1613
1600
  * For Gloas blocks: returns EMPTY/FULL variants (not PENDING) based on parent payload status
1614
1601
  * For pre-Gloas blocks: returns FULL variants
1615
1602
  */
1616
- getAllAncestorAndNonAncestorNodes(blockRoot: RootHex): {ancestors: ProtoNode[]; nonAncestors: ProtoNode[]} {
1617
- // Get canonical node: FULL for pre-Gloas, PENDING for Gloas
1618
- const defaultStatus = this.getDefaultVariant(blockRoot);
1619
- const startIndex =
1620
- defaultStatus !== undefined ? this.getNodeIndexByRootAndStatus(blockRoot, defaultStatus) : undefined;
1603
+ getAllAncestorAndNonAncestorNodes(
1604
+ blockRoot: RootHex,
1605
+ payloadStatus: PayloadStatus
1606
+ ): {ancestors: ProtoNode[]; nonAncestors: ProtoNode[]} {
1607
+ const startIndex = this.getNodeIndexByRootAndStatus(blockRoot, payloadStatus);
1621
1608
  if (startIndex === undefined) {
1622
1609
  return {ancestors: [], nonAncestors: []};
1623
1610
  }
@@ -1735,26 +1722,28 @@ export class ProtoArray {
1735
1722
  /**
1736
1723
  * Returns `true` if the `descendantRoot` has an ancestor with `ancestorRoot`.
1737
1724
  * Always returns `false` if either input roots are unknown.
1738
- * Still returns `true` if `ancestorRoot` === `descendantRoot` (and the roots are known)
1725
+ * Still returns `true` if `ancestorRoot` === `descendantRoot` and payload statuses match.
1739
1726
  */
1740
- isDescendant(ancestorRoot: RootHex, descendantRoot: RootHex): boolean {
1741
- // We use the default variant (PENDING for Gloas, FULL for pre-Gloas)
1742
- // We cannot use FULL/EMPTY variants for Gloas because they may not be canonical
1743
- const defaultStatus = this.getDefaultVariant(ancestorRoot);
1744
- const ancestorNode = defaultStatus !== undefined ? this.getNode(ancestorRoot, defaultStatus) : undefined;
1727
+ isDescendant(
1728
+ ancestorRoot: RootHex,
1729
+ ancestorPayloadStatus: PayloadStatus,
1730
+ descendantRoot: RootHex,
1731
+ descendantPayloadStatus: PayloadStatus
1732
+ ): boolean {
1733
+ const ancestorNode = this.getNode(ancestorRoot, ancestorPayloadStatus);
1745
1734
  if (!ancestorNode) {
1746
1735
  return false;
1747
1736
  }
1748
1737
 
1749
- if (ancestorRoot === descendantRoot) {
1738
+ if (ancestorRoot === descendantRoot && ancestorPayloadStatus === descendantPayloadStatus) {
1750
1739
  return true;
1751
1740
  }
1752
1741
 
1753
- for (const node of this.iterateAncestorNodes(descendantRoot)) {
1742
+ for (const node of this.iterateAncestorNodes(descendantRoot, descendantPayloadStatus)) {
1754
1743
  if (node.slot < ancestorNode.slot) {
1755
1744
  return false;
1756
1745
  }
1757
- if (node.blockRoot === ancestorNode.blockRoot) {
1746
+ if (node.blockRoot === ancestorNode.blockRoot && node.payloadStatus === ancestorNode.payloadStatus) {
1758
1747
  return true;
1759
1748
  }
1760
1749
  }