@lodestar/fork-choice 1.45.0-dev.905415417a → 1.45.0-dev.955b4c884a

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 (37) hide show
  1. package/lib/forkChoice/fastConfirmation/data.d.ts.map +1 -1
  2. package/lib/forkChoice/fastConfirmation/data.js +1 -0
  3. package/lib/forkChoice/fastConfirmation/data.js.map +1 -1
  4. package/lib/forkChoice/fastConfirmation/types.d.ts +3 -0
  5. package/lib/forkChoice/fastConfirmation/types.d.ts.map +1 -1
  6. package/lib/forkChoice/fastConfirmation/types.js.map +1 -1
  7. package/lib/forkChoice/fastConfirmation/utils.d.ts +3 -3
  8. package/lib/forkChoice/fastConfirmation/utils.d.ts.map +1 -1
  9. package/lib/forkChoice/fastConfirmation/utils.js +27 -19
  10. package/lib/forkChoice/fastConfirmation/utils.js.map +1 -1
  11. package/lib/forkChoice/forkChoice.d.ts +25 -7
  12. package/lib/forkChoice/forkChoice.d.ts.map +1 -1
  13. package/lib/forkChoice/forkChoice.js +23 -12
  14. package/lib/forkChoice/forkChoice.js.map +1 -1
  15. package/lib/forkChoice/interface.d.ts +10 -2
  16. package/lib/forkChoice/interface.d.ts.map +1 -1
  17. package/lib/forkChoice/interface.js.map +1 -1
  18. package/lib/index.d.ts +1 -1
  19. package/lib/index.d.ts.map +1 -1
  20. package/lib/index.js +1 -1
  21. package/lib/index.js.map +1 -1
  22. package/lib/protoArray/computeDeltas.d.ts.map +1 -1
  23. package/lib/protoArray/computeDeltas.js +19 -15
  24. package/lib/protoArray/computeDeltas.js.map +1 -1
  25. package/lib/protoArray/protoArray.d.ts +19 -0
  26. package/lib/protoArray/protoArray.d.ts.map +1 -1
  27. package/lib/protoArray/protoArray.js +63 -4
  28. package/lib/protoArray/protoArray.js.map +1 -1
  29. package/package.json +9 -9
  30. package/src/forkChoice/fastConfirmation/data.ts +1 -0
  31. package/src/forkChoice/fastConfirmation/types.ts +4 -0
  32. package/src/forkChoice/fastConfirmation/utils.ts +39 -16
  33. package/src/forkChoice/forkChoice.ts +26 -12
  34. package/src/forkChoice/interface.ts +7 -12
  35. package/src/index.ts +1 -1
  36. package/src/protoArray/computeDeltas.ts +21 -17
  37. package/src/protoArray/protoArray.ts +68 -4
@@ -672,6 +672,28 @@ export class ProtoArray {
672
672
  this.maybeUpdateBestChildAndDescendant(pendingIndex, fullIndex, currentSlot, proposerBoostRoot);
673
673
  }
674
674
 
675
+ /**
676
+ * Count gloas blocks with fromSlot <= slot <= toSlot and how many of them have a revealed
677
+ * payload (FULL variant exists). Used by the builder circuit breaker.
678
+ */
679
+ getPayloadRevealCounts(fromSlot: Slot, toSlot: Slot): {blocksPresent: number; payloadsRevealed: number} {
680
+ let blocksPresent = 0;
681
+ let payloadsRevealed = 0;
682
+ // Full scan, nodes are in import order not slot order (an old block can be imported after newer
683
+ // ones during sync or reorg resolution), so we cannot stop early on an out-of-window slot
684
+ for (const node of this.nodes) {
685
+ // Count each gloas block once via its PENDING variant, pre-gloas nodes are FULL only
686
+ if (node.slot < fromSlot || node.slot > toSlot || node.payloadStatus !== PayloadStatus.PENDING) {
687
+ continue;
688
+ }
689
+ blocksPresent++;
690
+ if (this.hasPayload(node.blockRoot)) {
691
+ payloadsRevealed++;
692
+ }
693
+ }
694
+ return {blocksPresent, payloadsRevealed};
695
+ }
696
+
675
697
  /**
676
698
  * Update PTC votes for multiple validators attesting to a block
677
699
  * Spec: gloas/fork-choice.md#new-notify_ptc_messages
@@ -1541,6 +1563,38 @@ export class ProtoArray {
1541
1563
  return correctJustified && correctFinalized;
1542
1564
  }
1543
1565
 
1566
+ /** Weights are in EFFECTIVE_BALANCE_INCREMENT units (NOT Gwei); callers scale as needed. */
1567
+ getViableHeads(currentSlot: Slot): {root: RootHex; payloadStatus: PayloadStatus; weight: number}[] {
1568
+ // Mirror the spec's `get_filtered_block_tree`, which is rooted at the store's justified
1569
+ // checkpoint: a viable head is a leaf (no viable descendant, i.e. `bestChild === undefined`)
1570
+ // that descends from the justified checkpoint block AND is itself viable for head. Iterating
1571
+ // all nodes without the justified-descendant filter would wrongly include FFG-viable leaves
1572
+ // that hang off the finalized checkpoint on a branch not under the current justified checkpoint.
1573
+ const justifiedVariant = this.getDefaultVariant(this.justifiedRoot);
1574
+ // Gloas payload-status variants of one blockRoot are distinct nodes in the spec's filtered
1575
+ // tree, identified by (root, payload_status, weight) — emit one entry per variant.
1576
+ const heads: {root: RootHex; payloadStatus: PayloadStatus; weight: number}[] = [];
1577
+ for (const node of this.nodes) {
1578
+ if (node.bestChild !== undefined || !this.nodeIsViableForHead(node, currentSlot)) {
1579
+ continue;
1580
+ }
1581
+ if (this.justifiedEpoch !== GENESIS_EPOCH) {
1582
+ // Same-root short-circuit: every payload-status variant of the justified block itself is
1583
+ // in the filtered tree, but `isDescendant` from the default (PENDING) variant does not
1584
+ // reach the sibling EMPTY/FULL variants of the same root.
1585
+ const descendsFromJustified =
1586
+ node.blockRoot === this.justifiedRoot ||
1587
+ (justifiedVariant !== undefined &&
1588
+ this.isDescendant(this.justifiedRoot, justifiedVariant, node.blockRoot, node.payloadStatus));
1589
+ if (!descendsFromJustified) {
1590
+ continue;
1591
+ }
1592
+ }
1593
+ heads.push({root: node.blockRoot, payloadStatus: node.payloadStatus, weight: node.weight});
1594
+ }
1595
+ return heads;
1596
+ }
1597
+
1544
1598
  /**
1545
1599
  * Return `true` if `node` is equal to or a descendant of the finalized node.
1546
1600
  * This function helps improve performance of nodeIsViableForHead a lot by avoiding
@@ -1941,6 +1995,11 @@ export class ProtoArray {
1941
1995
  * Returns `true` if the `descendantRoot` has an ancestor with `ancestorRoot`.
1942
1996
  * Always returns `false` if either input roots are unknown.
1943
1997
  * Still returns `true` if `ancestorRoot` === `descendantRoot` and payload statuses match.
1998
+ *
1999
+ * Gloas payload-status matching: a `PENDING` ancestor matches any payload variant
2000
+ * (PENDING/EMPTY/FULL) of the same block, so this can also return `true` for the same
2001
+ * root when statuses differ (e.g. ancestor `PENDING`, descendant `EMPTY`/`FULL`).
2002
+ * `EMPTY` and `FULL` are mutually exclusive siblings and never match each other.
1944
2003
  */
1945
2004
  isDescendant(
1946
2005
  ancestorRoot: RootHex,
@@ -1958,11 +2017,16 @@ export class ProtoArray {
1958
2017
  }
1959
2018
 
1960
2019
  for (const node of this.iterateAncestorNodes(descendantRoot, descendantPayloadStatus)) {
1961
- if (node.slot < ancestorNode.slot) {
1962
- return false;
2020
+ if (node.blockRoot === ancestorNode.blockRoot) {
2021
+ // Gloas is_ancestor: a PENDING ancestor matches any payload variant of the same block.
2022
+ return (
2023
+ node.payloadStatus === ancestorNode.payloadStatus || ancestorNode.payloadStatus === PayloadStatus.PENDING
2024
+ );
1963
2025
  }
1964
- if (node.blockRoot === ancestorNode.blockRoot && node.payloadStatus === ancestorNode.payloadStatus) {
1965
- return true;
2026
+ // Ancestors are iterated in decreasing slot, so once we reach the ancestor's slot
2027
+ // without a root match it cannot be in this chain.
2028
+ if (node.slot <= ancestorNode.slot) {
2029
+ return false;
1966
2030
  }
1967
2031
  }
1968
2032
  return false;