mirror of
https://github.com/luxfi/consensus.git
synced 2026-09-24 00:26:58 +00:00
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]>
25 lines
973 B
Go
25 lines
973 B
Go
package config
|
|
|
|
import "testing"
|
|
|
|
// AlphaForK must return the SMALLEST sample-vote count that reaches the 69%
|
|
// agreement threshold: at or above 69% of K, and one vote fewer must fall short.
|
|
// Rounding down anywhere here lets a chain finalize under the Byzantine bound;
|
|
// rounding up more than necessary costs liveness. Checked across every K a
|
|
// committee is plausibly sized at rather than a handful of sampled rows.
|
|
func TestAlphaForKIsTheCeilingOfTheThreshold(t *testing.T) {
|
|
for k := 1; k <= 1000; k++ {
|
|
alpha := AlphaForK(k)
|
|
|
|
if float64(alpha) < float64(k)*ConsensusSuperMajority {
|
|
t.Fatalf("AlphaForK(%d) = %d, under the %.0f%% threshold", k, alpha, ConsensusSuperMajority*100)
|
|
}
|
|
if alpha > 1 && float64(alpha-1) >= float64(k)*ConsensusSuperMajority {
|
|
t.Fatalf("AlphaForK(%d) = %d, but %d already clears the threshold", k, alpha, alpha-1)
|
|
}
|
|
if alpha > k {
|
|
t.Fatalf("AlphaForK(%d) = %d, more votes than the sample holds", k, alpha)
|
|
}
|
|
}
|
|
}
|