Files
zeekayandHanzo Dev be53ad78ac consensus: comments state the invariant, not the incident
Comments across this tree named hosts, validator ids, clusters, ticket numbers
and heights observed on running networks. The repository is public, so each one
turned a reader of the code into a reader of our operations, and each aged badly:
the rule stays true, the anecdote does not.

Rewritten rather than deleted. Almost every one was standing in for something
real that was learned expensively, so the anecdote is replaced by the rule that
made it wrong — a reader now gets the reason the code has its shape, which is the
part worth keeping. One test went entirely: it read captured files from a fixed
path keyed by host name and skipped everywhere else, so it was evidence rather
than a test, and its one reusable claim is already covered.

Comments and test data only; no executable change.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-14 14:57:08 -07:00

796 lines
22 KiB
Go

// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package wire
import (
"context"
"fmt"
"testing"
)
// --- NonePolicy edge cases ---
func TestNonePolicyVerifyWrongPolicy(t *testing.T) {
policy := NewNonePolicy()
cert := &Certificate{PolicyID: PolicyQuorum}
ok, err := policy.Verify(context.Background(), cert)
if err != nil {
t.Fatal(err)
}
if ok {
t.Error("NonePolicy should reject certificate with wrong policy ID")
}
}
func TestNonePolicyOnVote(t *testing.T) {
policy := NewNonePolicy()
vote := NewVote(EmptyCandidateID, EmptyVoterID, 0, true)
err := policy.OnVote(context.Background(), vote)
if err != nil {
t.Errorf("NonePolicy.OnVote should always return nil, got %v", err)
}
}
func TestNonePolicyMaybeFinalizeUnknownCandidate(t *testing.T) {
policy := NewNonePolicy()
cert, err := policy.MaybeFinalize(context.Background(), DeriveItemID([]byte("unknown")))
if err != nil {
t.Fatal(err)
}
if cert != nil {
t.Error("should return nil for unknown candidate")
}
}
func TestNonePolicyMaybeFinalizeCached(t *testing.T) {
ctx := context.Background()
policy := NewNonePolicy()
c := NewCandidate([]byte("d"), []byte("p"), EmptyCandidateID, 1)
policy.OnCandidate(ctx, c)
cert1, _ := policy.MaybeFinalize(ctx, c.ID)
cert2, _ := policy.MaybeFinalize(ctx, c.ID)
if cert1 != cert2 {
t.Error("should return cached certificate")
}
}
func TestNonePolicyCandidateLimit(t *testing.T) {
ctx := context.Background()
policy := NewNonePolicy()
// Fill to capacity
for i := 0; i < maxCandidates; i++ {
c := NewCandidate([]byte("d"), []byte(fmt.Sprintf("p%d", i)), EmptyCandidateID, uint64(i))
if err := policy.OnCandidate(ctx, c); err != nil {
t.Fatalf("should accept candidate %d: %v", i, err)
}
}
// One more should fail
c := NewCandidate([]byte("d"), []byte("overflow"), EmptyCandidateID, maxCandidates)
err := policy.OnCandidate(ctx, c)
if err == nil {
t.Error("should reject candidate beyond limit")
}
}
// --- QuorumPolicy edge cases ---
func TestQuorumPolicyVerify(t *testing.T) {
policy := NewQuorumPolicy(3, 5)
ctx := context.Background()
// Wrong policy ID
ok, _ := policy.Verify(ctx, &Certificate{PolicyID: PolicyNone})
if ok {
t.Error("should reject wrong policy ID")
}
// Empty proof
ok, _ = policy.Verify(ctx, &Certificate{PolicyID: PolicyQuorum})
if ok {
t.Error("should reject empty proof")
}
// Proof present but signers too short
ok, _ = policy.Verify(ctx, &Certificate{
PolicyID: PolicyQuorum,
Proof: []byte("proof"),
Signers: []byte("short"),
})
if ok {
t.Error("should reject short signers")
}
// Valid: proof and enough signers (3 * 32 bytes)
signers := make([]byte, 3*32)
ok, _ = policy.Verify(ctx, &Certificate{
PolicyID: PolicyQuorum,
Proof: []byte("proof"),
Signers: signers,
})
if !ok {
t.Error("should accept valid certificate")
}
}
func TestQuorumPolicyVoteBeforeCandidate(t *testing.T) {
ctx := context.Background()
policy := NewQuorumPolicy(1, 1)
// Vote for an unknown candidate -- should create vote map on the fly
voter := DeriveVoterID("agent", []byte("a"))
candidateID := DeriveItemID([]byte("unknown"))
vote := NewVote(candidateID, voter, 0, true)
err := policy.OnVote(ctx, vote)
if err != nil {
t.Errorf("should accept vote for unknown candidate: %v", err)
}
}
func TestQuorumPolicyRejectVotesNotPreferred(t *testing.T) {
ctx := context.Background()
policy := NewQuorumPolicy(1, 1)
c := NewCandidate([]byte("d"), []byte("p"), EmptyCandidateID, 1)
policy.OnCandidate(ctx, c)
// Vote with preference=false (reject)
voter := DeriveVoterID("agent", []byte("a"))
vote := NewVote(c.ID, voter, 0, false)
vote.Signature = []byte{SigBLS, 1}
policy.OnVote(ctx, vote)
cert, _ := policy.MaybeFinalize(ctx, c.ID)
if cert != nil {
t.Error("should not finalize with only reject votes")
}
}
func TestQuorumPolicyCandidateLimit(t *testing.T) {
ctx := context.Background()
policy := NewQuorumPolicy(1, 1)
for i := 0; i < maxCandidates; i++ {
c := NewCandidate([]byte("d"), []byte(fmt.Sprintf("p%d", i)), EmptyCandidateID, uint64(i))
if err := policy.OnCandidate(ctx, c); err != nil {
t.Fatalf("failed at %d: %v", i, err)
}
}
c := NewCandidate([]byte("d"), []byte("overflow"), EmptyCandidateID, maxCandidates)
if err := policy.OnCandidate(ctx, c); err == nil {
t.Error("should reject beyond limit")
}
}
// --- SamplePolicy edge cases ---
func TestSamplePolicyVerify(t *testing.T) {
policy := NewSamplePolicy(3, 0.6, 2)
ctx := context.Background()
// Wrong policy
ok, _ := policy.Verify(ctx, &Certificate{PolicyID: PolicyNone})
if ok {
t.Error("should reject wrong policy")
}
// Short proof
ok, _ = policy.Verify(ctx, &Certificate{PolicyID: PolicySampleConvergence, Proof: []byte{1}})
if ok {
t.Error("should reject short proof")
}
// Low confidence
proof := make([]byte, 9)
proof[0] = 1 // confidence=1, beta=2
ok, _ = policy.Verify(ctx, &Certificate{PolicyID: PolicySampleConvergence, Proof: proof})
if ok {
t.Error("should reject low confidence")
}
// Sufficient confidence
proof[0] = 3
ok, _ = policy.Verify(ctx, &Certificate{PolicyID: PolicySampleConvergence, Proof: proof})
if !ok {
t.Error("should accept sufficient confidence")
}
}
func TestSamplePolicyVoteUnknownCandidate(t *testing.T) {
policy := NewSamplePolicy(3, 0.6, 2)
vote := NewVote(DeriveItemID([]byte("x")), EmptyVoterID, 0, true)
err := policy.OnVote(context.Background(), vote)
if err != nil {
t.Errorf("should silently ignore vote for unknown candidate: %v", err)
}
}
func TestSamplePolicyConvergesToReject(t *testing.T) {
ctx := context.Background()
policy := NewSamplePolicy(3, 0.6, 2)
c := NewCandidate([]byte("d"), []byte("p"), EmptyCandidateID, 1)
policy.OnCandidate(ctx, c)
// 2 rounds of reject votes (all false)
for round := uint64(0); round < 2; round++ {
for i := 0; i < 3; i++ {
voter := DeriveVoterID("a", []byte{byte(i)})
vote := NewVote(c.ID, voter, round, false)
policy.OnVote(ctx, vote)
}
}
cert, _ := policy.MaybeFinalize(ctx, c.ID)
if cert != nil {
t.Error("should not produce cert when converged to reject")
}
}
func TestSamplePolicyPreferenceFlip(t *testing.T) {
ctx := context.Background()
policy := NewSamplePolicy(3, 0.6, 3) // beta=3
c := NewCandidate([]byte("d"), []byte("p"), EmptyCandidateID, 1)
policy.OnCandidate(ctx, c)
// Round 0: yes (confidence 1)
for i := 0; i < 3; i++ {
voter := DeriveVoterID("a", []byte{byte(i)})
policy.OnVote(ctx, NewVote(c.ID, voter, 0, true))
}
// Round 1: no -- preference flips, confidence resets to 1
for i := 0; i < 3; i++ {
voter := DeriveVoterID("a", []byte{byte(i)})
policy.OnVote(ctx, NewVote(c.ID, voter, 1, false))
}
// Round 2: yes -- preference flips again, confidence 1
for i := 0; i < 3; i++ {
voter := DeriveVoterID("a", []byte{byte(i)})
policy.OnVote(ctx, NewVote(c.ID, voter, 2, true))
}
cert, _ := policy.MaybeFinalize(ctx, c.ID)
if cert != nil {
t.Error("should not finalize -- confidence never reached beta=3")
}
}
func TestSamplePolicyCandidateLimit(t *testing.T) {
ctx := context.Background()
policy := NewSamplePolicy(1, 1.0, 1)
for i := 0; i < maxCandidates; i++ {
c := NewCandidate([]byte("d"), []byte(fmt.Sprintf("p%d", i)), EmptyCandidateID, uint64(i))
if err := policy.OnCandidate(ctx, c); err != nil {
t.Fatalf("failed at %d: %v", i, err)
}
}
c := NewCandidate([]byte("d"), []byte("overflow"), EmptyCandidateID, maxCandidates)
if err := policy.OnCandidate(ctx, c); err == nil {
t.Error("should reject beyond limit")
}
}
// --- L1Policy ---
type mockL1Verifier struct {
proofs map[CandidateID][]byte
verifyFunc func(ctx context.Context, id CandidateID, proof []byte) (bool, error)
}
func (m *mockL1Verifier) GetInclusionProof(ctx context.Context, id CandidateID) ([]byte, error) {
p, ok := m.proofs[id]
if !ok {
return nil, nil
}
return p, nil
}
func (m *mockL1Verifier) VerifyInclusion(ctx context.Context, id CandidateID, proof []byte) (bool, error) {
if m.verifyFunc != nil {
return m.verifyFunc(ctx, id, proof)
}
return len(proof) > 0, nil
}
func TestL1PolicyFullLifecycle(t *testing.T) {
ctx := context.Background()
verifier := &mockL1Verifier{proofs: make(map[CandidateID][]byte)}
policy := NewL1Policy(verifier)
if policy.PolicyID() != PolicyL1Inclusion {
t.Error("wrong policy ID")
}
c := NewCandidate([]byte("d"), []byte("p"), EmptyCandidateID, 1)
if err := policy.OnCandidate(ctx, c); err != nil {
t.Fatal(err)
}
// OnVote is a no-op
if err := policy.OnVote(ctx, NewVote(c.ID, EmptyVoterID, 0, true)); err != nil {
t.Errorf("OnVote should return nil: %v", err)
}
// Not included yet
cert, _ := policy.MaybeFinalize(ctx, c.ID)
if cert != nil {
t.Error("should not finalize without L1 inclusion")
}
// Simulate L1 inclusion
verifier.proofs[c.ID] = []byte("merkle-proof")
cert, _ = policy.MaybeFinalize(ctx, c.ID)
if cert == nil {
t.Fatal("should finalize with L1 inclusion proof")
}
if cert.PolicyID != PolicyL1Inclusion {
t.Error("wrong cert policy ID")
}
// Cached return
cert2, _ := policy.MaybeFinalize(ctx, c.ID)
if cert2 != cert {
t.Error("should return cached cert")
}
}
func TestL1PolicyVerify(t *testing.T) {
ctx := context.Background()
verifier := &mockL1Verifier{
proofs: make(map[CandidateID][]byte),
verifyFunc: func(_ context.Context, _ CandidateID, proof []byte) (bool, error) {
return string(proof) == "valid", nil
},
}
policy := NewL1Policy(verifier)
// Wrong policy ID
ok, _ := policy.Verify(ctx, &Certificate{PolicyID: PolicyNone})
if ok {
t.Error("should reject wrong policy")
}
// Valid proof
ok, _ = policy.Verify(ctx, &Certificate{PolicyID: PolicyL1Inclusion, Proof: []byte("valid")})
if !ok {
t.Error("should accept valid proof")
}
// Invalid proof
ok, _ = policy.Verify(ctx, &Certificate{PolicyID: PolicyL1Inclusion, Proof: []byte("invalid")})
if ok {
t.Error("should reject invalid proof")
}
}
func TestL1PolicyUnknownCandidate(t *testing.T) {
ctx := context.Background()
verifier := &mockL1Verifier{proofs: make(map[CandidateID][]byte)}
policy := NewL1Policy(verifier)
cert, err := policy.MaybeFinalize(ctx, DeriveItemID([]byte("unknown")))
if err != nil {
t.Fatal(err)
}
if cert != nil {
t.Error("should return nil for unknown candidate")
}
}
func TestL1PolicyCandidateLimit(t *testing.T) {
ctx := context.Background()
verifier := &mockL1Verifier{proofs: make(map[CandidateID][]byte)}
policy := NewL1Policy(verifier)
for i := 0; i < maxCandidates; i++ {
c := NewCandidate([]byte("d"), []byte(fmt.Sprintf("p%d", i)), EmptyCandidateID, uint64(i))
if err := policy.OnCandidate(ctx, c); err != nil {
t.Fatalf("failed at %d: %v", i, err)
}
}
c := NewCandidate([]byte("d"), []byte("overflow"), EmptyCandidateID, maxCandidates)
if err := policy.OnCandidate(ctx, c); err == nil {
t.Error("should reject beyond limit")
}
}
// --- QuantumPolicy additional edge cases ---
func TestQuantumPolicySetRequireRT(t *testing.T) {
policy := NewQuantumPolicy(1)
policy.SetRequireRT(false)
ctx := context.Background()
c := NewCandidate([]byte("d"), []byte("p"), EmptyCandidateID, 1)
policy.OnCandidate(ctx, c)
// BLS-only should be accepted after disabling RT requirement
voter := DeriveVoterID("a", []byte("v"))
vote := NewVote(c.ID, voter, 0, true)
vote.Signature = []byte{SigBLS, 1, 2, 3}
err := policy.OnVote(ctx, vote)
if err != nil {
t.Errorf("BLS should be accepted with RT disabled: %v", err)
}
}
func TestQuantumPolicyRejectVoteNoPreference(t *testing.T) {
policy := NewQuantumPolicy(1)
ctx := context.Background()
c := NewCandidate([]byte("d"), []byte("p"), EmptyCandidateID, 1)
policy.OnCandidate(ctx, c)
// Vote with preference=false -- silently ignored
vote := NewVote(c.ID, DeriveVoterID("a", []byte("v")), 0, false)
vote.Signature = []byte{SigQuasar, 0, 2, 1, 2, 3, 4}
err := policy.OnVote(ctx, vote)
if err != nil {
t.Errorf("reject vote should be silently ignored: %v", err)
}
}
func TestQuantumPolicyEmptySignatureRTRequired(t *testing.T) {
policy := NewQuantumPolicy(1)
ctx := context.Background()
c := NewCandidate([]byte("d"), []byte("p"), EmptyCandidateID, 1)
policy.OnCandidate(ctx, c)
vote := NewVote(c.ID, DeriveVoterID("a", []byte("v")), 0, true)
// No signature
err := policy.OnVote(ctx, vote)
if err == nil {
t.Error("should reject empty signature when RT required")
}
rtErr, ok := err.(*RTRequirementError)
if !ok {
t.Errorf("expected RTRequirementError, got %T", err)
}
if rtErr.Error() == "" {
t.Error("error message should not be empty")
}
}
func TestQuantumPolicyEmptySignatureRTNotRequired(t *testing.T) {
policy := NewQuantumPolicyWithOptions(1, false)
ctx := context.Background()
c := NewCandidate([]byte("d"), []byte("p"), EmptyCandidateID, 1)
policy.OnCandidate(ctx, c)
vote := NewVote(c.ID, DeriveVoterID("a", []byte("v")), 0, true)
err := policy.OnVote(ctx, vote)
if err != nil {
t.Errorf("empty sig should be ok when RT not required: %v", err)
}
}
func TestQuantumPolicyQuasarTooShort(t *testing.T) {
policy := NewQuantumPolicy(1)
ctx := context.Background()
c := NewCandidate([]byte("d"), []byte("p"), EmptyCandidateID, 1)
policy.OnCandidate(ctx, c)
vote := NewVote(c.ID, DeriveVoterID("a", []byte("v")), 0, true)
vote.Signature = []byte{SigQuasar, 0} // too short
err := policy.OnVote(ctx, vote)
if err == nil {
t.Error("should reject too-short Quasar signature")
}
}
func TestQuantumPolicyQuasarZeroBLS(t *testing.T) {
policy := NewQuantumPolicy(1)
ctx := context.Background()
c := NewCandidate([]byte("d"), []byte("p"), EmptyCandidateID, 1)
policy.OnCandidate(ctx, c)
vote := NewVote(c.ID, DeriveVoterID("a", []byte("v")), 0, true)
vote.Signature = []byte{SigQuasar, 0, 0, 1} // bls_len=0
err := policy.OnVote(ctx, vote)
if err == nil {
t.Error("should reject zero-length BLS in Quasar")
}
}
func TestQuantumPolicyQuasarTruncatedBLS(t *testing.T) {
policy := NewQuantumPolicy(1)
ctx := context.Background()
c := NewCandidate([]byte("d"), []byte("p"), EmptyCandidateID, 1)
policy.OnCandidate(ctx, c)
vote := NewVote(c.ID, DeriveVoterID("a", []byte("v")), 0, true)
vote.Signature = []byte{SigQuasar, 0, 10} // claims 10 bytes BLS but has 0
err := policy.OnVote(ctx, vote)
if err == nil {
t.Error("should reject truncated BLS in Quasar")
}
}
func TestQuantumPolicyFinalizationAndVerify(t *testing.T) {
ctx := context.Background()
policy := NewQuantumPolicy(2)
c := NewCandidate([]byte("d"), []byte("p"), EmptyCandidateID, 1)
policy.OnCandidate(ctx, c)
// Add 2 Quasar votes (threshold=2)
for i := 0; i < 2; i++ {
voter := DeriveVoterID("a", []byte{byte(i)})
blsSig := make([]byte, 48)
blsSig[0] = byte(i)
rtSig := make([]byte, 32)
rtSig[0] = byte(i)
sig := []byte{SigQuasar, 0, byte(len(blsSig))}
sig = append(sig, blsSig...)
sig = append(sig, rtSig...)
vote := NewVote(c.ID, voter, 0, true)
vote.Signature = sig
if err := policy.OnVote(ctx, vote); err != nil {
t.Fatalf("vote %d failed: %v", i, err)
}
}
cert, err := policy.MaybeFinalize(ctx, c.ID)
if err != nil {
t.Fatal(err)
}
if cert == nil {
t.Fatal("should finalize with 2 votes")
}
if cert.PolicyID != PolicyQuantum {
t.Error("wrong policy ID on cert")
}
// Verify
ok, _ := policy.Verify(ctx, cert)
if !ok {
t.Error("should verify own certificate")
}
// Cached
cert2, _ := policy.MaybeFinalize(ctx, c.ID)
if cert2 != cert {
t.Error("should return cached cert")
}
}
func TestQuantumPolicyVerifyEdgeCases(t *testing.T) {
policy := NewQuantumPolicy(1)
ctx := context.Background()
// Wrong policy
ok, _ := policy.Verify(ctx, &Certificate{PolicyID: PolicyNone})
if ok {
t.Error("should reject wrong policy")
}
// Short proof
ok, _ = policy.Verify(ctx, &Certificate{PolicyID: PolicyQuantum, Proof: []byte{SigQuasar}})
if ok {
t.Error("should reject short proof")
}
// Wrong scheme byte
proof := make([]byte, 33)
proof[0] = SigBLS // not SigQuasar
ok, _ = policy.Verify(ctx, &Certificate{PolicyID: PolicyQuantum, Proof: proof})
if ok {
t.Error("should reject non-Quasar scheme byte")
}
}
func TestQuantumPolicyMaybeFinalizeBelowThreshold(t *testing.T) {
ctx := context.Background()
policy := NewQuantumPolicy(3)
c := NewCandidate([]byte("d"), []byte("p"), EmptyCandidateID, 1)
policy.OnCandidate(ctx, c)
// Only 1 vote (threshold=3)
voter := DeriveVoterID("a", []byte("v"))
sig := []byte{SigQuasar, 0, 2, 1, 2, 3, 4}
vote := NewVote(c.ID, voter, 0, true)
vote.Signature = sig
policy.OnVote(ctx, vote)
cert, _ := policy.MaybeFinalize(ctx, c.ID)
if cert != nil {
t.Error("should not finalize below threshold")
}
}
func TestQuantumPolicyUnknownCandidate(t *testing.T) {
policy := NewQuantumPolicy(1)
cert, _ := policy.MaybeFinalize(context.Background(), DeriveItemID([]byte("nope")))
if cert != nil {
t.Error("should return nil for unknown")
}
}
func TestQuantumPolicyCandidateLimit(t *testing.T) {
ctx := context.Background()
policy := NewQuantumPolicy(1)
for i := 0; i < maxCandidates; i++ {
c := NewCandidate([]byte("d"), []byte(fmt.Sprintf("p%d", i)), EmptyCandidateID, uint64(i))
if err := policy.OnCandidate(ctx, c); err != nil {
t.Fatalf("failed at %d: %v", i, err)
}
}
c := NewCandidate([]byte("d"), []byte("overflow"), EmptyCandidateID, maxCandidates)
if err := policy.OnCandidate(ctx, c); err == nil {
t.Error("should reject beyond limit")
}
}
func TestQuantumPolicyUnknownSchemeRTRequired(t *testing.T) {
policy := NewQuantumPolicy(1)
ctx := context.Background()
c := NewCandidate([]byte("d"), []byte("p"), EmptyCandidateID, 1)
policy.OnCandidate(ctx, c)
vote := NewVote(c.ID, DeriveVoterID("a", []byte("v")), 0, true)
vote.Signature = []byte{0xFF, 1, 2, 3} // unknown scheme
err := policy.OnVote(ctx, vote)
if err == nil {
t.Error("should reject unknown scheme when RT required")
}
}
func TestQuantumPolicyUnknownSchemeRTNotRequired(t *testing.T) {
policy := NewQuantumPolicyWithOptions(1, false)
ctx := context.Background()
c := NewCandidate([]byte("d"), []byte("p"), EmptyCandidateID, 1)
policy.OnCandidate(ctx, c)
vote := NewVote(c.ID, DeriveVoterID("a", []byte("v")), 0, true)
vote.Signature = []byte{0xFF, 1, 2, 3}
err := policy.OnVote(ctx, vote)
if err != nil {
t.Errorf("should ignore unknown scheme when RT not required: %v", err)
}
}
func TestQuantumPolicyCoronaOnlyRTNotRequired(t *testing.T) {
policy := NewQuantumPolicyWithOptions(1, false)
ctx := context.Background()
c := NewCandidate([]byte("d"), []byte("p"), EmptyCandidateID, 1)
policy.OnCandidate(ctx, c)
vote := NewVote(c.ID, DeriveVoterID("a", []byte("v")), 0, true)
vote.Signature = []byte{SigCorona, 4, 5, 6}
err := policy.OnVote(ctx, vote)
if err != nil {
t.Errorf("RT-only vote should be accepted when RT not required: %v", err)
}
}
// --- sigSchemeToString ---
func TestSigSchemeToString(t *testing.T) {
tests := []struct {
scheme byte
expect string
}{
{SigNone, "SigNone"},
{SigEd25519, "SigEd25519"},
{SigBLS, "SigBLS"},
{SigCorona, "SigCorona"},
{SigQuasar, "SigQuasar"},
{0xFF, "Unknown"},
}
for _, tt := range tests {
got := sigSchemeToString(tt.scheme)
if got != tt.expect {
t.Errorf("sigSchemeToString(%d) = %s, want %s", tt.scheme, got, tt.expect)
}
}
}
// --- HostnameValidationError.Error() ---
func TestHostnameValidationErrorMessage(t *testing.T) {
e := &HostnameValidationError{Address: v4(203, 0, 113, 4), Reason: "bad"}
msg := e.Error()
if msg == "" {
t.Error("error message should not be empty")
}
}
// --- ValidatePeerAddress ---
func TestValidatePeerAddress(t *testing.T) {
// Valid
if err := ValidatePeerAddress("node1.lux.network:9651"); err != nil {
t.Errorf("valid hostname should pass: %v", err)
}
// A peer is named, never numbered: an address literal binds a peer to a
// location instead of an identity, so the validator rejects it.
if err := ValidatePeerAddress(v4(203, 0, 113, 1) + ":9651"); err == nil {
t.Error("IP literal should be rejected")
}
}
// --- RTRequirementError.Error() ---
func TestRTRequirementErrorMessage(t *testing.T) {
e := &RTRequirementError{Reason: "test reason"}
if e.Error() != "RT signature required: test reason" {
t.Errorf("unexpected error: %s", e.Error())
}
}
// --- CredentialValidationError.Error() ---
func TestCredentialValidationErrorMessage(t *testing.T) {
e := &CredentialValidationError{Index: 0, Expected: 100, Got: 50, Reason: "mismatch"}
if e.Error() != "mismatch" {
t.Errorf("unexpected: %s", e.Error())
}
}
// --- FinalityWitnesses parallel-witness model ---
func TestPolicyWitnessesRoundtrip(t *testing.T) {
cases := []struct {
policy PolicyID
expected FinalityWitnesses
}{
{PolicyQuorum, WitnessP},
{PolicyPQ, WitnessP | WitnessQ},
{PolicyPZ, WitnessP | WitnessZ},
{PolicyQuantum, WitnessP | WitnessQ | WitnessZ},
}
for _, c := range cases {
got := c.policy.Witnesses()
if got != c.expected {
t.Errorf("policy %d witnesses=%b want %b", c.policy, got, c.expected)
}
if PolicyForWitnesses(got) != c.policy {
t.Errorf("policy %d roundtrip failed: PolicyForWitnesses(%b)=%d", c.policy, got, PolicyForWitnesses(got))
}
if err := got.Validate(); err != nil {
t.Errorf("policy %d witnesses must validate: %v", c.policy, err)
}
}
}
func TestFinalityWitnessesValidate(t *testing.T) {
if err := FinalityWitnesses(0).Validate(); err == nil {
t.Error("empty witness set must require P")
}
if err := WitnessQ.Validate(); err == nil {
t.Error("Q without P must fail")
}
if err := (WitnessP | 0x80).Validate(); err == nil {
t.Error("unknown bit must fail")
}
if err := WitnessP.Validate(); err != nil {
t.Errorf("WitnessP alone must validate: %v", err)
}
}
func TestFinalityWitnessesHas(t *testing.T) {
full := WitnessP | WitnessQ | WitnessZ
if !full.Has(WitnessP) {
t.Error("PQZ must contain P")
}
if !full.Has(WitnessQ | WitnessZ) {
t.Error("PQZ must contain QZ")
}
if WitnessP.Has(WitnessQ) {
t.Error("P must not contain Q")
}
}