Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 19 additions & 12 deletions packages/fork-choice/src/protoArray/protoArray.ts
Original file line number Diff line number Diff line change
Expand Up @@ -700,22 +700,29 @@ export class ProtoArray {
let full = 0;
let empty = 0;

for (const node of this.getAllAncestorNodes(headRoot, headPayloadStatus)) {
// Walk the canonical chain newest-first (resolved head, then ancestors via getParentNodeIndex).
// Ancestors are strictly slot-descending, so we stop as soon as a node falls below `fromSlot`
// instead of materializing the whole chain back to the anchor as `getAllAncestorNodes` does.
// This keeps the scan O(window) rather than O(chain-to-anchor), relevant under prolonged non-finality.
const headIndex = this.getNodeIndexByRootAndStatus(headRoot, headPayloadStatus);
let node = headIndex !== undefined ? this.nodes[headIndex] : undefined;

while (node !== undefined && node.slot >= fromSlot) {
if (
node.slot === GENESIS_SLOT ||
node.slot < fromSlot ||
node.slot > toSlot ||
!isGloasBlock(node) ||
node.payloadStatus === PayloadStatus.PENDING
node.slot !== GENESIS_SLOT &&
node.slot <= toSlot &&
isGloasBlock(node) &&
node.payloadStatus !== PayloadStatus.PENDING
) {
continue;
if (node.payloadStatus === PayloadStatus.FULL) {
full++;
} else {
empty++;
}
}

if (node.payloadStatus === PayloadStatus.FULL) {
full++;
} else {
empty++;
}
const parentIndex = this.getParentNodeIndex(node);
node = parentIndex === undefined ? undefined : this.nodes[parentIndex];
}

return {full, empty};
Expand Down