Files
consensus/engine/bft/engine_test.go
T
zeekay ca541515d8 consensus: wire luxfi/bft as fourth engine factory
The consensus toolkit now exposes four orthogonal paradigms:

  NewChain — linear Snow-family metastable (Nova)
  NewDAG   — DAG Snow-family metastable (Nebula)
  NewPQ    — post-quantum threshold Quasar
  NewBFT   — classical leader-rotation BFT (Simplex/HotStuff family)

NewBFT(cfg BFTConfig) wraps a fully-configured luxbft.Epoch as a
consensus.Engine. The application owns the Epoch's wiring (Storage,
Communication, Signer, BlockBuilder, WAL); the consensus toolkit
owns the lifecycle.

Orthogonality preserved across the three axes:
  - consensus paradigm   — picks engine (Chain/DAG/PQ/BFT)
  - ChainSecurityProfile — picks admissible primitives (strict/permissive/fips)
  - FinalitySchemeID     — picks the threshold kernel (Pulsar/Corona/MPTC)

A BFT engine under a strict-PQ profile with Pulsar-M-65 finality is
a valid production combination: leader-rotation ordering with
PQ-threshold-signed cert envelopes — exactly the posture a
permissioned subnet might want.

Implementation:
  engine/bft/engine.go      — thin lifecycle adapter (Start/Stop/
                              HealthCheck/IsBootstrapped/AdvanceTime/
                              HandleMessage)
  engine/bft/engine_test.go — 6 nil-safety + fail-closed tests
  consensus.go              — NewBFT factory, BFT type alias,
                              BFTConfig re-export, MustNewBFT

go.mod requires github.com/luxfi/bft v0.1.5.
2026-05-11 20:28:46 -07:00

77 lines
2.6 KiB
Go

// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package bft
import (
"context"
"errors"
"testing"
)
// TestEngine_NilEpoch_Returns_Nil_From_NewEngine asserts the NewEngine
// constructor refuses a nil epoch — the wrapper assumes a non-nil
// inner Epoch on every call path.
func TestEngine_NilEpoch_Returns_Nil_From_NewEngine(t *testing.T) {
if got := NewEngine(nil); got != nil {
t.Fatalf("NewEngine(nil) = %v, want nil", got)
}
}
// TestEngine_NilWrapper_IsBootstrapped_False asserts a nil *Engine is
// safe to call IsBootstrapped on and returns false. The consensus
// toolkit's Engine interface is invoked through interface values
// where nil is a representable state, so the methods must be
// nil-safe.
func TestEngine_NilWrapper_IsBootstrapped_False(t *testing.T) {
var e *Engine
if e.IsBootstrapped() {
t.Fatal("nil *Engine.IsBootstrapped() = true, want false")
}
}
// TestEngine_NilEpoch_Start_Returns_ErrNilEpoch asserts the
// fail-closed contract: a wrapper constructed with a literal struct
// (no Epoch) refuses Start with ErrNilEpoch rather than silently
// no-op'ing.
func TestEngine_NilEpoch_Start_Returns_ErrNilEpoch(t *testing.T) {
e := &Engine{} // bypass NewEngine to get a nil-epoch wrapper
err := e.Start(context.Background(), 0)
if !errors.Is(err, ErrNilEpoch) {
t.Fatalf("Start with nil epoch: got %v, want ErrNilEpoch", err)
}
if e.IsBootstrapped() {
t.Fatal("IsBootstrapped() = true after failed Start, want false")
}
}
// TestEngine_NilEpoch_HealthCheck_Returns_ErrNilEpoch mirrors the
// Start contract: HealthCheck reports the nil-epoch condition rather
// than returning a fake "healthy" status.
func TestEngine_NilEpoch_HealthCheck_Returns_ErrNilEpoch(t *testing.T) {
e := &Engine{}
_, err := e.HealthCheck(context.Background())
if !errors.Is(err, ErrNilEpoch) {
t.Fatalf("HealthCheck with nil epoch: got %v, want ErrNilEpoch", err)
}
}
// TestEngine_NilEpoch_Stop_NoOp asserts Stop on a nil-epoch wrapper
// is a safe no-op (returns nil) rather than panicking or returning
// ErrNilEpoch. Stop is on the cleanup path and should never fail.
func TestEngine_NilEpoch_Stop_NoOp(t *testing.T) {
e := &Engine{}
if err := e.Stop(context.Background()); err != nil {
t.Fatalf("Stop with nil epoch: got %v, want nil", err)
}
}
// TestEngine_NilWrapper_Epoch_Returns_Nil asserts the Epoch() escape
// hatch is nil-safe.
func TestEngine_NilWrapper_Epoch_Returns_Nil(t *testing.T) {
var e *Engine
if got := e.Epoch(); got != nil {
t.Fatalf("nil *Engine.Epoch() = %v, want nil", got)
}
}