Files
zeekayandHanzo Dev 4abf37c952 config: K is a number of draws, not a headcount
The live guard refused to start a chain whose K was below the number of
validators that existed. But sampling is stake-weighted: a validator is drawn in
proportion to what it staked, however many validators there are, and K only
sets how many draws a poll makes. Tying K to the headcount gave a validator
holding a billionth of the stake the same standing as one holding a fifth, and
refused to boot a producing chain because a small staker had joined.

The guard keeps what makes a committee safe — the overlap bound and at least
single-fault tolerance — and stops counting heads. The tier floor stays a
reported target: refusing to start does not add validators, it pins every node
on whatever it last booted.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-16 11:42:58 -07:00

19 lines
733 B
Go

package config
import "math"
// ConsensusSuperMajority is the 69% agreement threshold (LP-CONSENSUS-69),
// two points above the traditional 67% BFT bound.
//
// This is the float form, for sizing a sample. Deciding whether a given set of
// votes carries a quorum is exact integer arithmetic over stake — see
// quorum_threshold.go. Do not reintroduce a float predicate here: rounding
// twice, two different ways, is how a chain disagrees with itself.
const ConsensusSuperMajority = 0.69
// AlphaForK returns the votes needed out of a K-node sample to reach
// ConsensusSuperMajority, rounding up so the threshold is never understated.
func AlphaForK(k int) int {
return int(math.Ceil(float64(k) * ConsensusSuperMajority))
}