mirror of
https://github.com/luxfi/consensus.git
synced 2026-09-24 00:26:58 +00:00
When a slot-leader proposer is down, each healthy validator builds its OWN block at the next height (own clock -> own blkID). The alpha-of-K finality cert needs alpha votes on ONE block, but the votes split across the competing siblings, no cert assembles, and the chain HALTS the moment one proposer is down (observed: devnet stuck at height 36 with 4/5 validators healthy). Root cause: the VM kept building on the last FINALIZED block, so every node re-proposed the same height instead of building on a verified-but-unfinalized sibling. There was no convergence onto one build target. Fix (matches avalanchego snowman, which steers the VM to its preferred non-finalized tip via SetPreference after every poll): - Add ChainConsensus.PreferredBuildTip / Transitive.PreferredBuildTip — the DETERMINISTIC build target: descend from the finalized tip through verified, non-rejected children, lowest-ID per level, to the deepest verified tip. Every node with the same block tree picks the SAME chain. - followVerifiedBlock steers the inner VM to PreferredBuildTip on adopt, so validators build H+1 on top of one verified block at H and CONVERGE; the alpha-of-K votes then land on a single block and finalize. Decomplected from the finality Preference (UNCHANGED — still the cert tip; the conformance suite pins that contract). Build hint only: finality stays governed by the alpha-of-K cert on c.ledger, so this cannot affect safety, only liveness. Tests: TestPreference_ConvergesSiblings_NoDownLeaderHalt (deterministic lowest-ID build tip across competing siblings, deepest-verified follow, rejected-sibling skip), TestPreference_NoChildren_ReturnsFinalizedTip (no regression). Full engine/... suite green; nil-VM path guarded.