engine/chain: purge 'snowman' — Lux consensus is Quasar/Nova on the chain engine (comment-only, no behavior change)

Removes the forbidden Avalanche term from code comments across the engine/chain package
(provenance/lineage notes and the "Snowman SAMPLE" phrasing). Reworded to preserve exact
technical meaning (α-of-K, β-witnessed, 2α−n>f, K=21/α=15 intact): engine/protocol name →
"the upstream linear-chain consensus" / "Quasar/Nova"; "Snowman sample" → "sample" /
"K-sample preset"; upstream file-path refs → the concept without the path. Comments only;
no identifier/type/func/behavior change. "Snowball" (a distinct term) left untouched.

Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
2026-07-09 10:50:09 -07:00
co-authored by Hanzo Dev
parent 68d3940df9
commit ed897a8010
11 changed files with 29 additions and 29 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
// or behind node fetches the chain from a peer's accepted frontier and re-executes
// it to the network tip, WITHOUT voting and WITHOUT requiring a stored α-of-K cert.
//
// This is a port of avalanche's proven snowman bootstrapper, adapted to the Lux
// This is a port of a proven linear-chain bootstrapper, adapted to the Lux
// engine's split architecture (the consensus engine owns the ACCEPT primitive —
// chain.Runtime.AcceptBootstrapBlock — and the node owns the TRANSPORT). The loop is
// the same:
+1 -1
View File
@@ -358,7 +358,7 @@ type StakeSource interface {
TotalStake(height uint64) uint64
// ValidatorCount returns the number of DISTINCT active validators at the given
// height — the round-scoped view-change's BFT committee size n (its POL/precommit
// count distinct validators, so n must be the LIVE set, not the Snowman sample K).
// count distinct validators, so n must be the LIVE set, not the sample K).
// Read from the SAME height-indexed set as Weight/TotalStake so the count-quorum and
// the stake-quorum are the identical set. 0 for an unresolved/empty set (view-change
// then keeps the configured committee, guarded by the 2α−n>f bound).
+1 -1
View File
@@ -35,7 +35,7 @@ import (
"github.com/luxfi/ids"
)
// genuineParams builds the config of a REAL n-validator chain: the Snowman/sample K and
// genuineParams builds the config of a REAL n-validator chain: the sample K and
// both α gates sized to the live set (K=n, α=bftAlpha(n)). View-change is on for n>1 (the
// round machine that converges a symmetric sibling split); a single validator needs none.
func genuineParams(n int) config.Parameters {
+5 -5
View File
@@ -1,11 +1,11 @@
// Copyright (C) 2019-2026, Lux Industries, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
// conformance_test.go — a faithful port of avalanchego's Snowman consensus
// conformance suite (snow/consensus/snowman/consensus_test.go, the ~30
// conformance_test.go — a faithful port of the upstream linear-chain consensus
// conformance suite (the upstream consensus_test.go, the ~30
// factory-driven `runConsensusTests` funcs) onto OUR ChainConsensus API. It
// proves the just-landed sibling-tolerant finality conforms to the proven
// Snowman accept/reject/reorg semantics that avalanchego's topological.go
// upstream accept/reject/reorg semantics that avalanchego's topological.go
// implements (acceptPreferredChild + rejectTransitively).
//
// WHY a re-port instead of running ava's suite directly: ava's `Consensus`
@@ -32,7 +32,7 @@
// a pure Snowball-trie internal (bit-prefix decisions) with no observable beyond
// "a block can't be accepted before its ancestor", it is mapped to the closest
// faithful ChainConsensus scenario with a comment; the safety assertion is never
// weakened. The naming follows the Lux convention (no Snowman in identifiers; it
// weakened. The naming follows the Lux convention (no upstream brand in identifiers; it
// is named here only as the upstream MODEL being conformed to, consistent with
// reorg_test.go).
//
@@ -976,7 +976,7 @@ func TestConformance_RecordPollRegressionIndegree(t *testing.T) {
// TestConformance_RandomizedConsistency ports RandomizedConsistencyTest — the
// fuzz/consistency safety proof. ADAPTED to be DETERMINISTIC (explicit seed, no
// time/unseeded randomness): a randomized sequence of sibling forks + cert
// selections, asserting the core Snowman SAFETY invariants never break under any
// selections, asserting the core SAFETY invariants never break under any
// interleaving:
//
// (1) at most ONE block is finalized per height (no fork);
+2 -2
View File
@@ -1543,7 +1543,7 @@ func (t *Transitive) rePollAllPending(ctx context.Context, base time.Duration) {
// it to an α-of-K cert — so it must keep re-soliciting until the block decides
// (then it leaves pendingBlocks and the re-poll quiesces). This is exactly
// avalanchego's contract: re-poll a PROCESSING block until it is decided, and
// only quiesce at NumProcessing()==0 (snow/engine/snowman voter.go +
// only quiesce at NumProcessing()==0 (the upstream voter.go +
// Engine.Gossip's 100ms repoll). Abandoning an own proposal after a fixed
// attempt cap was the Lux-only divergence that froze mainnet C-Chain: the
// substitute's canonical block stopped being re-solicited and the chain halted
@@ -2834,7 +2834,7 @@ func (t *Transitive) assembleCertLocked(pending *PendingBlock, blockID ids.ID) *
// the SAME P-chain height the position's set-root commits to (MEDIUM-1).
epochHeight := t.epochHeightLocked(pending)
// Cert COUNT threshold sized to the LIVE validator set (effectiveCommittee), NOT the oversized
// Snowman sample: MainnetParams α=15 is unreachable from a 5-validator set, so the ⅔-by-stake
// sample: MainnetParams α=15 is unreachable from a 5-validator set, so the ⅔-by-stake
// cert would never assemble (the 2026-07-09 freeze). bftAlpha over the SAME height-indexed set the
// ⅔-by-stake VerifyWeighted gate below reads keeps the count-quorum and the stake-quorum identical.
_, alpha := t.effectiveCommittee(epochHeight)
+1 -1
View File
@@ -163,7 +163,7 @@ type testValidatorSet struct {
// simValidatorCount, when simValidatorCountSet, OVERRIDES what ValidatorCount reports (the live
// committee size the round-scoped view-change sizes its POL/precommit quorum to). Lets a test
// model the mainnet condition where the current-map Manager read 0 validators at construction:
// with a forced 0 the view-change cannot shrink the Snowman preset (K=21/α=15) and FREEZES (the
// with a forced 0 the view-change cannot shrink the sample preset (K=21/α=15) and FREEZES (the
// pre-fix stall); unset, ValidatorCount reports the real len(ids).
simValidatorCount int
simValidatorCountSet bool
+4 -4
View File
@@ -15,10 +15,10 @@
// cert and replacing the ledger (applyCertLocked) — the import reconcile (SyncState) is
// the one other whole-value replacement.
//
// This mirrors avalanchego snow/consensus/snowman/topological.go, with finality's
// This mirrors the upstream linear-chain consensus's topological layer, with finality's
// trigger swapped from β-consecutive-polls to a quorum CERT: the preference tree +
// poll stays mutable and sibling-tolerant (topological.go here), while the
// committed-prefix advance — β-driven in Snowman — is this pure, cert-driven fold.
// committed-prefix advance — β-driven upstream — is this pure, cert-driven fold.
package chain
import (
@@ -29,7 +29,7 @@ import (
)
// The finality safety invariants — the vocabulary of the fold. Two are genuine
// α-of-K-cert properties pure Snowman does not need (its certs are β-witnessed, not
// α-of-K-cert properties the pure upstream engine does not need (its certs are β-witnessed, not
// external/attacker-chosen-Round): a SECOND valid cert for a DIFFERENT block at an
// already-decided height is equivocation evidence, never a silent second VM.Accept;
// and a cert for a block that does NOT descend from the finalized frontier conflicts
@@ -40,7 +40,7 @@ var (
// ErrHeightAlreadyFinalized: a DIFFERENT block is already finalized at the target
// height — two valid α-certs at one height across different rounds. The first
// finalizes; the second is refused and IS equivocation evidence. A genuine α-of-K
// safety property pure Snowman does not need.
// safety property the pure upstream engine does not need.
ErrHeightAlreadyFinalized = errors.New("chain: a different block is already finalized at this height (equivocation: two finalized blocks at one height)")
// ErrNonMonotonicFinalizedHeight: a finalize at or below the frontier with a
@@ -3,9 +3,9 @@
// multinode_mainnet_committee_test.go — the 2026-07-09 mainnet C-Chain finality-freeze
// regression: view-change must size its BFT committee from the LIVE validator set, not the
// oversized Snowman SAMPLE preset.
// oversized K-sample preset.
//
// EXACT mainnet condition reproduced: MainnetParams presets the Snowman sample at K=21/α=15
// EXACT mainnet condition reproduced: MainnetParams presets the sample at K=21/α=15
// (sized for a ≥21-validator network), but only 5 validators are live. The harness leaves
// cfg.Validators nil, so the construction-time bftCommittee clamp is skipped and consensus.K()
// stays 21 / Alpha() stays 15 — identical to the mainnet node whose current-map validator Manager
@@ -16,7 +16,7 @@
//
// The fix (integration.go viewCommittee): size the view-change committee from the SAME populated
// ⅔-by-stake StakeSource the cert reads — n = ValidatorCount (5), α = bftAlpha(5) = 4 — so a POL
// forms at 4 prevotes → precommit → one ⅔-by-stake cert → finalize. Snowman K=21 is left untouched
// forms at 4 prevotes → precommit → one ⅔-by-stake cert → finalize. The sample K=21 is left untouched
// (the chain still boots past the mainnet K≥11 floor); only the round machine's committee shrinks.
package chain
@@ -28,12 +28,12 @@ import (
"github.com/luxfi/ids"
)
// mainnetStormParams5VC is the storm-tuned 5-node harness base with the REAL MainnetParams Snowman
// mainnetStormParams5VC is the storm-tuned 5-node harness base with the REAL MainnetParams sample
// committee (K=21/α=15) and the round-scoped view-change ON — the exact live-mainnet config on a
// 5-validator set.
func mainnetStormParams5VC() config.Parameters {
p := stormParams5()
p.K = 21 // MainnetParams Snowman SAMPLE size (sized for ≥21 validators)
p.K = 21 // MainnetParams sample size (sized for ≥21 validators)
p.AlphaPreference = 15 // MainnetParams α — 15 DISTINCT prevotes, unreachable from 5 nodes
p.AlphaConfidence = 15
p.ViewChange = true
@@ -56,7 +56,7 @@ func TestViewChange_MainnetParams_5Validators_CommitteeFromStakeSource(t *testin
}
// CONTROL — the mainnet freeze reproduced. ValidatorCount unresolved (0), as on the node whose
// current-map Manager read 0 at construction: viewCommittee cannot shrink the Snowman preset, so
// current-map Manager read 0 at construction: viewCommittee cannot shrink the sample preset, so
// the round machine runs at α=15. Five validators can cast at most five distinct prevotes, so no
// POL(winner) can ever form → NOTHING finalizes. Safety holds (no fork) — this is a pure liveness
// freeze, exactly the live incident.
+2 -2
View File
@@ -22,8 +22,8 @@ import (
//
// THE FIX: Preference() returns the deterministic BUILD tip — the deepest verified
// block extending the finalized chain, lowest-ID sibling per level — so every node
// builds H+1 on the SAME block and the vote converges (matching avalanchego's
// snowman preference, which steers the VM to the preferred non-finalized tip).
// builds H+1 on the SAME block and the vote converges (matching the upstream
// linear-chain consensus's preference, which steers the VM to the preferred non-finalized tip).
func TestPreference_ConvergesSiblings_NoDownLeaderHalt(t *testing.T) {
ctx := context.Background()
c := NewChainConsensus(5, 4, 2)
+1 -1
View File
@@ -3,7 +3,7 @@
// reorg_test.go — the SIBLING-TOLERANT finality regression.
//
// THE BUG (fresh-net deadlock). The engine forked avalanchego's Snowman model by
// THE BUG (fresh-net deadlock). The engine forked the upstream linear-chain consensus model by
// adding a hard per-height gate (the old markFinalizedLocked invariant (c): a
// finalized block's parent MUST equal the current finalized tip) AND never reorged.
// When a cert finalized one child (A) of a parent while production/preference had
+5 -5
View File
@@ -3,7 +3,7 @@
// topological.go — the PREFERENCE LAYER, the mutable, sibling-tolerant block tree.
//
// This mirrors avalanchego snow/consensus/snowman/topological.go: the live block
// This mirrors the upstream linear-chain consensus's topological layer: the live block
// tree (blocks/tips), the build preference, and the vote/poll surface that drives
// each block's snowball instance. It is the half of avalanchego's Topological that
// stays MUTABLE — siblings coexist, votes accumulate, preference moves. The OTHER
@@ -14,7 +14,7 @@
//
// Method mapping (ours -> avalanchego Topological):
//
// Block / *Block -> snowman_block.go's snowmanBlock (the tree node)
// Block / *Block -> the upstream tree-node block
// AddBlock -> Add (admit a child of a known block)
// ProcessVote / Poll -> RecordPoll (accumulate votes into the per-block
// snowball driver; LIVENESS only — finality is the cert)
@@ -37,8 +37,8 @@ import (
"github.com/luxfi/ids"
)
// Block represents a block in the chain — the preference tree's node (avalanchego
// snowmanBlock). Tracks the value-chain linkage (id/parent/height), the pinned
// Block represents a block in the chain — the preference tree's node (the upstream tree
// node). Tracks the value-chain linkage (id/parent/height), the pinned
// P-chain epoch, the per-block Photon->Wave->Focus driver, and the decided flags.
type Block struct {
id ids.ID
@@ -280,7 +280,7 @@ func (c *ChainConsensus) Preference() ids.ID {
// it is a BUILD hint only — finality stays governed exclusively by the α-of-K cert
// folded into c.ledger (applyCertLocked), so advancing the build target past the
// finalized tip touches no finality decision and cannot affect safety, only
// liveness — exactly as avalanchego's snowman steers the VM to its preferred
// liveness — exactly as the upstream linear-chain consensus steers the VM to its preferred
// non-finalized tip.
func (c *ChainConsensus) PreferredBuildTip() ids.ID {
c.mu.RLock()