-
-
Notifications
You must be signed in to change notification settings - Fork 471
feat: integrate fork-choice compliance spec test suite #9314
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
843d220
59c5715
35cca8c
6649551
01d5438
b1bf28a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,5 @@ | ||||||||||||||||||||||||||||||||||||||
| import {BitArray} from "@chainsafe/ssz"; | ||||||||||||||||||||||||||||||||||||||
| import {GENESIS_EPOCH, PTC_SIZE} from "@lodestar/params"; | ||||||||||||||||||||||||||||||||||||||
| import {EFFECTIVE_BALANCE_INCREMENT, GENESIS_EPOCH, PTC_SIZE} from "@lodestar/params"; | ||||||||||||||||||||||||||||||||||||||
| import {DataAvailabilityStatus, computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition"; | ||||||||||||||||||||||||||||||||||||||
| import {Epoch, RootHex, Slot} from "@lodestar/types"; | ||||||||||||||||||||||||||||||||||||||
| import {bitCount, toRootHex} from "@lodestar/utils"; | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -1541,6 +1541,53 @@ export class ProtoArray { | |||||||||||||||||||||||||||||||||||||
| return correctJustified && correctFinalized; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| /** Weight is converted from increment units to Gwei. */ | ||||||||||||||||||||||||||||||||||||||
| getViableHeads(currentSlot: Slot): {root: RootHex; weight: number}[] { | ||||||||||||||||||||||||||||||||||||||
| // Mirror the spec's `get_filtered_block_tree`, which is rooted at the store's justified | ||||||||||||||||||||||||||||||||||||||
| // checkpoint: a viable head is a leaf (no viable descendant, i.e. `bestChild === undefined`) | ||||||||||||||||||||||||||||||||||||||
| // that descends from the justified checkpoint block AND is itself viable for head. Iterating | ||||||||||||||||||||||||||||||||||||||
| // all nodes without the justified-descendant filter would wrongly include FFG-viable leaves | ||||||||||||||||||||||||||||||||||||||
| // that hang off the finalized checkpoint on a branch not under the current justified checkpoint. | ||||||||||||||||||||||||||||||||||||||
| const justifiedIndex = this.getDefaultNodeIndex(this.justifiedRoot); | ||||||||||||||||||||||||||||||||||||||
| const justifiedSlot = justifiedIndex !== undefined ? this.getNodeByIndex(justifiedIndex)?.slot : undefined; | ||||||||||||||||||||||||||||||||||||||
| // Gloas payload-status variants share a blockRoot and more than one can be a leaf (EMPTY and | ||||||||||||||||||||||||||||||||||||||
| // FULL are both parented under PENDING); the spec's filtered tree is keyed by block root, so | ||||||||||||||||||||||||||||||||||||||
| // emit each root at most once. Which variant's weight the spec expects is an open gloas | ||||||||||||||||||||||||||||||||||||||
| // divergence — deterministically keep the heaviest qualifying variant. | ||||||||||||||||||||||||||||||||||||||
| const weightByRoot = new Map<RootHex, number>(); | ||||||||||||||||||||||||||||||||||||||
| for (const node of this.nodes) { | ||||||||||||||||||||||||||||||||||||||
| if (node.bestChild !== undefined || !this.nodeIsViableForHead(node, currentSlot)) { | ||||||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| if (this.justifiedEpoch !== GENESIS_EPOCH && !this.descendsFromJustified(node, justifiedSlot)) { | ||||||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| const prev = weightByRoot.get(node.blockRoot); | ||||||||||||||||||||||||||||||||||||||
| if (prev === undefined || node.weight > prev) { | ||||||||||||||||||||||||||||||||||||||
| weightByRoot.set(node.blockRoot, node.weight); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| return Array.from(weightByRoot.entries()).map(([root, weight]) => ({ | ||||||||||||||||||||||||||||||||||||||
| root, | ||||||||||||||||||||||||||||||||||||||
| weight: weight * EFFECTIVE_BALANCE_INCREMENT, | ||||||||||||||||||||||||||||||||||||||
| })); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||
| * True if `node` is the justified checkpoint block or one of its descendants. | ||||||||||||||||||||||||||||||||||||||
| * Parent slots are non-increasing, so the walk stops once it passes the justified block's slot. | ||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||
| private descendsFromJustified(node: ProtoNode, justifiedSlot: Slot | undefined): boolean { | ||||||||||||||||||||||||||||||||||||||
| let current: ProtoNode | undefined = node; | ||||||||||||||||||||||||||||||||||||||
| while (current !== undefined && (justifiedSlot === undefined || current.slot >= justifiedSlot)) { | ||||||||||||||||||||||||||||||||||||||
| if (current.blockRoot === this.justifiedRoot) { | ||||||||||||||||||||||||||||||||||||||
| return true; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| current = current.parent !== undefined ? this.getNodeByIndex(current.parent) : undefined; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1545
to
+1589
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The current implementation of In Lodestar, To maintain accuracy for production use cases (even if compliance tests currently use smaller weights), this should return
Suggested change
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||
| * Return `true` if `node` is equal to or a descendant of the finalized node. | ||||||||||||||||||||||||||||||||||||||
| * This function helps improve performance of nodeIsViableForHead a lot by avoiding | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update the return type to
bigintto match the fix inProtoArrayand avoid precision loss.