Files
consensus/config/config.go
zeekay d335ca78d5 feat(config): CertPolicy record (LP-217) and drop LUX_ env prefix
- Introduce config/cert_policy.go: single CertPolicy record (Mode +
  Variant + TimeoutMs + Fallback) collapses three knobs from LP-217 /
  LP-202 / LP-204 into one operator-facing struct. Validated at chain
  genesis; refuses launch when invalid. Distinct from PQMode enum
  (pq_mode.go) — CertPolicy is the deployment knob, PQMode is the
  protocol-level identifier.
- Add config/cert_policy_test.go and config/bench_cert_policy_test.go
  covering validation matrix + fallback-tier degradation contract.
- PQModeFromEnv: drop legacy LUX_CONSENSUS_PQ_MODE fallback per the
  "one canonical, unprefixed name" directive. CONSENSUS_PQ_MODE is the
  only honoured env var.
- engine/pq/consensus.go: minor follow-up wiring.
- paper/* + PQ-GPU-AUDIT.md + README.md: align prose with CertPolicy
  framing and unprefixed env names.
2026-06-04 17:04:32 -07:00

317 lines
11 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package config
import (
"errors"
"time"
)
// Error variables for parameter validation
var (
ErrParametersInvalid = errors.New("invalid consensus parameters")
ErrInvalidK = errors.New("k must be >= 1")
ErrInvalidAlpha = errors.New("alpha must be between 0.66 and 1.0")
ErrInvalidBeta = errors.New("beta must be >= 1")
ErrBlockTimeTooLow = errors.New("block time must be >= 1ms")
ErrRoundTimeoutTooLow = errors.New("round timeout must be >= block time")
ErrKTooLowForMainnet = errors.New("K must be >= 11 for mainnet (networkID=1): low K enables cheap 51% attacks")
ErrKTooLowForTestnet = errors.New("K must be >= 5 for testnet (networkID=5): low K enables cheap 51% attacks")
)
// Parameters defines consensus parameters
type Parameters struct {
K int
Alpha float64 // For compatibility with Quasar
Beta uint32 // For compatibility with Quasar
AlphaPreference int
AlphaConfidence int
BetaVirtuous int
BetaRogue int
ConcurrentPolls int
ConcurrentRepolls int
OptimalProcessing int
MaxOutstandingItems int
MaxItemProcessingTime time.Duration
Parents int
BatchSize int
BlockTime time.Duration // For compatibility
RoundTO time.Duration // For compatibility
GasLimit uint64 // Per-block gas limit (0 = use chain default)
// PQMode selects which post-quantum signature paths the engine runs
// alongside BLS. Zero value (PQModeBLSOnly) preserves the classical
// fast path. See pq_mode.go for the full enum.
PQMode PQMode
}
// WithPQMode returns a copy of Parameters with the given PQ mode set.
// Use config.PQModeFromEnv to honour the CONSENSUS_PQ_MODE override.
func (p Parameters) WithPQMode(m PQMode) Parameters {
p.PQMode = m
return p
}
// PostQuantum reports whether this Parameters carries any PQ witness set
// on top of the classical BLS aggregate (i.e. PQMode != BLSOnly).
// Mirrors the simple boolean knob exposed to operators who don't want to
// pick a witness set explicitly.
func (p Parameters) PostQuantum() bool {
return p.PQMode.IsPostQuantum()
}
// WithPostQuantum collapses the five-way enum onto a boolean:
//
// true -> PQModeTripleQuantum // strongest available
// false -> PQModeBLSOnly // classical fast path
//
// For middle-ground modes (BLSPlusMLDSA, BLSPlusCorona, BLSPlusGroth16),
// call WithPQMode directly with the desired constant.
func (p Parameters) WithPostQuantum(on bool) Parameters {
p.PQMode = PQModeFromBool(on)
return p
}
// DefaultParams returns default parameters with 69% threshold
func DefaultParams() Parameters {
return Parameters{
K: 20,
Alpha: 0.69, // 69% threshold for BFT
Beta: 14, // Adjusted for 69% (was 15)
AlphaPreference: 14, // 70% of K for 69% threshold
AlphaConfidence: 14, // Matches AlphaPreference for 69%
BetaVirtuous: 14, // Virtuous confidence for 69%
BetaRogue: 20, // Rogue confidence remains high
ConcurrentPolls: 4,
ConcurrentRepolls: 4,
OptimalProcessing: 10,
MaxOutstandingItems: 1024,
MaxItemProcessingTime: 2 * time.Minute,
Parents: 2, // Reduced for efficiency
BatchSize: 30,
BlockTime: 100 * time.Millisecond,
RoundTO: 250 * time.Millisecond,
}
}
// MainnetParams returns mainnet parameters with 69% threshold
func MainnetParams() Parameters {
p := DefaultParams()
p.K = 21
p.AlphaPreference = 15 // ~71% of K for 69% threshold
p.AlphaConfidence = 15 // Matches AlphaPreference
p.BetaVirtuous = 15 // Virtuous confidence for 69%
p.BlockTime = 200 * time.Millisecond
p.RoundTO = 400 * time.Millisecond
return p
}
// TestnetParams returns testnet parameters with 69% threshold
func TestnetParams() Parameters {
p := DefaultParams()
p.K = 11
p.Alpha = 0.69 // 69% threshold
p.Beta = 8 // Adjusted for 69%
p.AlphaPreference = 8 // ~73% of K for 69% threshold
p.AlphaConfidence = 8 // Matches AlphaPreference
p.BetaVirtuous = 8 // Virtuous confidence for 69%
p.BlockTime = 100 * time.Millisecond
p.RoundTO = 225 * time.Millisecond
return p
}
// LocalParams returns local parameters with 2/3 threshold for 3-node networks.
// Uses 1ms block time for maximum throughput on localhost (zero network latency).
func LocalParams() Parameters {
p := DefaultParams()
p.K = 3
p.Alpha = 0.67 // 2/3 threshold
p.Beta = 2 // Adjusted for 2/3
p.AlphaPreference = 2 // 2 of 3 for preference
p.AlphaConfidence = 2 // 2 of 3 for confidence
p.BetaVirtuous = 2 // Virtuous confidence for 2/3
p.BlockTime = 1 * time.Millisecond
p.RoundTO = 5 * time.Millisecond
return p
}
// BurstParams returns parameters for maximum throughput burst mode.
// Designed for GPU EVM + Block-STM on high-bandwidth networks (800Gbps+).
// 1ms blocks × 100K txs/block (2.1B gas) = 100M TPS theoretical ceiling.
// Actual throughput bounded by GPU execution speed (Block-STM parallel).
func BurstParams() Parameters {
return Parameters{
K: 3,
Alpha: 0.67,
Beta: 2,
AlphaPreference: 2,
AlphaConfidence: 2,
BetaVirtuous: 2,
BetaRogue: 3,
ConcurrentPolls: 8,
ConcurrentRepolls: 8,
OptimalProcessing: 50,
MaxOutstandingItems: 8192,
MaxItemProcessingTime: 10 * time.Second,
Parents: 2,
BatchSize: 100,
BlockTime: 1 * time.Millisecond,
RoundTO: 5 * time.Millisecond,
GasLimit: 2_100_000_000, // 2.1B gas → 100K simple txs/block
}
}
// SoloGPUParams returns parameters for a single-node GPU-accelerated validator.
// Tuned for Apple Silicon (M1/M2/M3/M4) with unified memory:
// - 1ms blocks, K=1 self-vote (no network latency)
// - 1B gas limit — GPU EVM fills ~47K txs/block at 21K gas each
// - With C++ GPU EVM (1M TPS): ~1M TPS sustained
// - With Go EVM (188K TPS): ~188K TPS sustained
// - Consensus overhead: <13μs per block (measured 76K blocks/sec)
func SoloGPUParams() Parameters {
return Parameters{
K: 1,
Alpha: 1.0,
Beta: 1,
AlphaPreference: 1,
AlphaConfidence: 1,
BetaVirtuous: 1,
BetaRogue: 1,
ConcurrentPolls: 4,
ConcurrentRepolls: 4,
OptimalProcessing: 20,
MaxOutstandingItems: 4096,
MaxItemProcessingTime: 5 * time.Second,
Parents: 1,
BatchSize: 50,
BlockTime: 1 * time.Millisecond,
RoundTO: 5 * time.Millisecond,
GasLimit: 1_000_000_000, // 1B gas → 47K txs/block
}
}
// XChainParams returns X-Chain parameters with 2/3 threshold for 3-node networks
func XChainParams() Parameters {
p := DefaultParams()
p.K = 3
p.Alpha = 0.67 // 2/3 threshold
p.Beta = 2 // Adjusted for 2/3
p.AlphaPreference = 2 // 2 of 3 for preference
p.AlphaConfidence = 2 // 2 of 3 for confidence
p.BetaVirtuous = 2 // Virtuous confidence for 2/3
p.BlockTime = 1 * time.Millisecond
p.RoundTO = 5 * time.Millisecond
return p
}
// SingleValidatorParams returns parameters for single validator mainnet (K=1)
// This configuration is used for POA mode with a single staking validator
func SingleValidatorParams() Parameters {
return Parameters{
K: 1, // Single validator
Alpha: 1.0, // 100% threshold (only one validator)
Beta: 1, // Immediate finalization
AlphaPreference: 1, // Single validator preference
AlphaConfidence: 1, // Single validator confidence
BetaVirtuous: 1, // Immediate virtuous confidence
BetaRogue: 1, // No rogue behavior possible
ConcurrentPolls: 1, // Single poll at a time
ConcurrentRepolls: 1, // Single repoll if needed
OptimalProcessing: 1, // Process one at a time
MaxOutstandingItems: 256, // Reduced for single validator
MaxItemProcessingTime: 30 * time.Second, // Faster timeout for single validator
Parents: 1, // Single parent for linear chain
BatchSize: 10, // Smaller batches for single validator
BlockTime: 100 * time.Millisecond, // Fast block time
RoundTO: 200 * time.Millisecond, // Quick round timeout
}
}
// WithBlockTime returns a copy of Parameters with updated block time.
// Round timeout auto-scales: 5x for ultra-fast (<=1ms), 3x for fast (<10ms),
// 2.5x default. On localhost with GPU BLS, 1ms blocks + 5ms rounds is achievable.
func (p Parameters) WithBlockTime(blockTime time.Duration) Parameters {
p.BlockTime = blockTime
switch {
case blockTime <= time.Millisecond:
p.RoundTO = 5 * blockTime // 5ms for 1ms blocks
case blockTime < 10*time.Millisecond:
p.RoundTO = 3 * blockTime // 15ms for 5ms blocks
default:
p.RoundTO = blockTime*5/2 + time.Millisecond // 2.5x + 1ms
}
return p
}
// Validate validates parameters (compatibility method)
func (p Parameters) Validate() error {
return p.Valid()
}
// Valid validates parameters with threshold enforcement
func (p Parameters) Valid() error {
// Check K, Alpha, Beta first - these are always required
if p.K < 1 {
return ErrInvalidK
}
// Enforce minimum 2/3 threshold (with small tolerance for rounding)
if p.Alpha < 0.66 || p.Alpha > 1.0 {
return ErrInvalidAlpha
}
if p.Beta < 1 {
return ErrInvalidBeta
}
if p.BlockTime > 0 && p.BlockTime < time.Millisecond {
return ErrBlockTimeTooLow
}
if p.BlockTime > 0 && p.RoundTO > 0 && p.RoundTO < p.BlockTime {
return ErrRoundTimeoutTooLow
}
// Only validate other fields if they are set (non-zero)
if p.AlphaPreference != 0 && (p.AlphaPreference < 0 || p.AlphaPreference > p.K) {
return ErrParametersInvalid
}
if p.AlphaConfidence != 0 && (p.AlphaConfidence < 0 || p.AlphaConfidence > p.K) {
return ErrParametersInvalid
}
if p.BetaVirtuous < 0 {
return ErrParametersInvalid
}
if p.BetaRogue != 0 && p.BetaRogue < p.BetaVirtuous {
return ErrParametersInvalid
}
if p.ConcurrentPolls != 0 && p.ConcurrentPolls < 1 {
return ErrParametersInvalid
}
if p.OptimalProcessing != 0 && p.OptimalProcessing < 1 {
return ErrParametersInvalid
}
if p.MaxOutstandingItems != 0 && p.MaxOutstandingItems < 1 {
return ErrParametersInvalid
}
if p.MaxItemProcessingTime != 0 && p.MaxItemProcessingTime <= 0 {
return ErrParametersInvalid
}
return nil
}
// ValidateForNetwork validates parameters are safe for the given network.
// Mainnet (1) requires K >= 11, testnet (5) requires K >= 5.
// Local/devnet (>= 1337) allows any K.
func (p Parameters) ValidateForNetwork(networkID uint32) error {
if err := p.Valid(); err != nil {
return err
}
switch networkID {
case 1: // mainnet
if p.K < 11 {
return ErrKTooLowForMainnet
}
case 5: // testnet
if p.K < 5 {
return ErrKTooLowForTestnet
}
}
return nil
}