mirror of
https://github.com/luxfi/consensus.git
synced 2026-09-24 00:26:58 +00:00
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:
@@ -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:
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user