profiles: rename BFTConsensus -> Consensus (BFT is implied, not a flavor)

The function derives the lux/consensus ENGINE sampling params (alpha-of-K snowball:
K/alpha/beta) — Byzantine-safe by construction, so the prefix was noise. Clarified in
the doc that this is the agreement layer, distinct from Quasar (lux/quasar) which seals
each event in a post-quantum QuasarCert on top (the CR's spec.consensus.pqLayers).
This commit is contained in:
zeekay
2026-06-23 12:46:46 -07:00
parent 53c2265437
commit 8e1653d763
3 changed files with 21 additions and 13 deletions
+5 -5
View File
@@ -5,9 +5,9 @@ package profiles
import "testing"
// TestBFTConsensus_MatchesAvalanche pins the Avalanche-grade derivation: K=min(20,N),
// TestConsensus_MatchesAvalanche pins the Avalanche-grade derivation: K=min(20,N),
// alpha=ceil(0.75K) at the 15/20 ratio, BFT-safe at every size.
func TestBFTConsensus_MatchesAvalanche(t *testing.T) {
func TestConsensus_MatchesAvalanche(t *testing.T) {
cases := []struct {
n, wantK, wantAlpha int
}{
@@ -20,13 +20,13 @@ func TestBFTConsensus_MatchesAvalanche(t *testing.T) {
{50, 20, 15}, // capped at K=20, Avalanche
}
for _, c := range cases {
got := BFTConsensus(c.n)
got := Consensus(c.n)
if got.SampleSize != c.wantK || got.PreferenceQuorumSize != c.wantAlpha || got.ConfidenceQuorumSize != c.wantAlpha {
t.Errorf("BFTConsensus(%d) = K=%d alpha=%d, want K=%d alpha=%d",
t.Errorf("Consensus(%d) = K=%d alpha=%d, want K=%d alpha=%d",
c.n, got.SampleSize, got.PreferenceQuorumSize, c.wantK, c.wantAlpha)
}
if !IsByzantineSafe(got.SampleSize, got.PreferenceQuorumSize) {
t.Errorf("BFTConsensus(%d) = K=%d alpha=%d is NOT Byzantine-safe", c.n, got.SampleSize, got.PreferenceQuorumSize)
t.Errorf("Consensus(%d) = K=%d alpha=%d is NOT Byzantine-safe", c.n, got.SampleSize, got.PreferenceQuorumSize)
}
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "production",
"description": "Avalanche-grade BFT consensus for live multi-validator networks. K=5/alpha=4 (80% quorum, >= Avalanche's 15/20 = 75%), Byzantine-safe (2*4-5 = 3 >= 2). For the current 5-validator Lux primary networks; for larger sets derive via profiles.BFTConsensus (K=min(20,N), alpha=ceil(0.75K), e.g. K=20/alpha=15 = exactly Avalanche).",
"description": "Avalanche-grade BFT consensus for live multi-validator networks. K=5/alpha=4 (80% quorum, >= Avalanche's 15/20 = 75%), Byzantine-safe (2*4-5 = 3 >= 2). For the current 5-validator Lux primary networks; for larger sets derive via profiles.Consensus (K=min(20,N), alpha=ceil(0.75K), e.g. K=20/alpha=15 = exactly Avalanche).",
"consensus": {
"sample-size": 5,
"preference-quorum-size": 4,
+15 -7
View File
@@ -64,11 +64,20 @@ type NetworkConfig struct {
PingFrequency string `json:"ping-frequency"`
}
// BFTConsensus derives Byzantine-fault-tolerant consensus parameters matching
// Avalanche's safety profile for a validator set of size n. It is the single source
// of truth for consensus safety: a deploy should derive K/alpha from the LIVE
// validator count, never hardcode them (the live K=5/alpha=3 drift was sub-BFT —
// 2*3-5 = 1 < floor((5-1)/3)+1 = 2 — which the consensus engine correctly refuses).
// Consensus derives the sampling-consensus parameters (the lux/consensus engine's
// alpha-of-K snowball/snowman knobs: K=sample, alpha=quorum, beta=commit) for a
// validator set of size n. Consensus is Byzantine-fault-tolerant by construction —
// there is no non-BFT variant — so the result always satisfies the engine invariant
// 2*alpha - K >= floor((K-1)/3)+1; "BFT" is implied, not a flavor.
//
// This is the ENGINE/agreement layer, NOT post-quantum finality. Quasar (lux/quasar,
// the per-round QuasarCert + pqLayers in the CR's spec.consensus) seals each agreed
// event in a PQ weighted certificate ON TOP of this — a separate concern; this struct
// carries no PQ config.
//
// It is the single source of truth for sampling safety: a deploy derives K/alpha from
// the LIVE validator count, never hardcodes them (the live K=5/alpha=3 drift was
// sub-BFT — 2*3-5 = 1 < floor((5-1)/3)+1 = 2 — which the engine correctly refuses).
//
// - K (sample size) = min(n, 20) — Avalanche caps the poll sample at 20.
// - alpha (quorum) = ceil(0.75*K) — Avalanche's 15/20 = 75% ratio (K>=4).
@@ -76,10 +85,9 @@ type NetworkConfig struct {
// the Byzantine floor is used to preserve
// liveness (one tolerable fault).
//
// The result always satisfies the engine invariant 2*alpha - K >= floor((K-1)/3)+1.
// Examples: n=5 -> K=5,alpha=4 (80%); n=20+ -> K=20,alpha=15 (exactly Avalanche);
// n=3 -> K=3,alpha=2 (67%, BFT-minimal).
func BFTConsensus(n int) ConsensusConfig {
func Consensus(n int) ConsensusConfig {
k := n
if k < 1 {
k = 1