Files
consensus/engine
zeekayandHanzo Dev 422b4cb9b6 engine/chain: FIX #1 self-finality floor + FIX #3 canonical vote aggregation (v1.35.29)
FIX #1 (SAFETY — transient-count self-finality, mainnet 1085013 fork):
bftCommittee floors a presetK>1 committee at the minimal BFT size (K=4/alpha=3)
when the live validator count transiently reads 1..3 during a restart.
validators.Manager.Count under-reports (len(m.validators[net])) before the P-chain
finishes replaying the staker set; the old clamp turned that count=1 into K=1/alpha=1,
and a K==1 engine synthesizes a 1-of-1 token that BYPASSES the 2/3-by-stake gate, so a
lone live node self-finalized divergent blocks (luxd-0/luxd-1 forked 1085013..1085016).
With the floor K never reaches 1 for a multi-validator preset, so every K()==1
self-finality site now implies a genuinely single-validator chain (the only sound case);
a sub-quorum live set HALTS fail-closed (VerifyWeighted, already fail-closed on zero
stake) and reclampCommitteeLocked grows K up to the genuine set after the first real
finalize. Preserves the testnet down-clamp regression bftCommittee(11,5)->(5,4) and the
launch-single path (New()/K=1 untouched).

FIX #3 (LIVENESS — wrapper-split cert stall, testnet block 288):
assembleCertLocked aggregates verified votes across ALL sibling wrappers that share the
winner's canonicalRep (de-duped by NodeID), so alpha validators that executed the SAME
inner block under DIFFERENT proposervm wrappers combine into ONE cert instead of splitting
the quorum across outer-keyed pending blocks. Companions: emitConvergedVote now counts
abandoned siblings (includeAbandoned=true) so every node converges on the identical
winner; the v4 clone re-sign resolves inner->outer via pendingByCanonicalLocked (the old
pendingBlocks[innerCanonical] missed for wrapped blocks — a silent no-op that only worked
on bare sim blocks); snapshot re-offer uses the canonical-aggregated selfVotedForCanonicalLocked.

Tests (fail-without/pass-with, proven by temporary revert):
- transient_selffinality_floor_test.go: bftCommittee floor unit + NewRuntime construction
  (transient count=1 boots K=4 not K=1) + floored-committee halts without a real 4-of-5 cert.
- cert_canonical_aggregation_test.go: two validators sign one inner block under different
  wrappers -> one cert assembles; pendingByCanonical inner->outer resolve.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-07 12:25:14 -07:00
..
2025-12-19 08:49:11 -08:00