mirror of
https://github.com/luxfi/consensus.git
synced 2026-09-24 00:26:58 +00:00
The post-build guard (ownUndecidedCandidateLocked) already stops vote- splitting once a churned sibling is built, but the engine still called the VM's BuildBlock on EVERY PendingTxs and discarded the result — a rebuild storm under a 15-30s heartbeat/gas-escalator (the mainnet 1082880 condition). Align with AvalancheGo/Snowman: a mempool event is PERMISSION to build later, not a mandate to rebuild the in-flight candidate. buildBlocksLocked now consults ownUndecidedCandidateOnParentLocked(preference) BEFORE the VM call: if our own undecided candidate already occupies the tip, drain the signal, re-solicit that candidate, and skip BuildBlock entirely. Consensus owns proposal identity; the mempool owns only tx availability. Pure fast-path — never changes WHICH block finalizes. Conservative by construction: if preference has moved (candidate no longer on the tip) the lookup returns nil and we build on the new parent normally, with the post-build guards remaining the correctness backstop. Own proposals + K>1 only (K==1 finalizes inline; a gossiped block is never ours to stabilize). Tests (prebuild_gate_test.go): candidate-on-preference found; the three conservative fall-throughs (preference moved / decided / remote); and a 20-tick churn model that resolves to one stable candidate with no sibling leak. Existing quorum + proposal-stability tests still green. Co-authored-by: Hanzo Dev <[email protected]>