mirror of
https://github.com/luxfi/node.git
synced 2026-07-27 03:39:39 +00:00
v1.36.13: durable rejoin fix now fires for the C-Chain (discriminate on validating Net, not blockchain ID)
The #66/#74 durable rejoin fix was INERT for the C-Chain — the chain whose 40h
mainnet freeze motivated it. chains/manager.go gated expectsStakedBeacons on
ids.IsNativeChain(chainParams.ID) (the blockchain ID), but ids.IsNativeChain only
matches the symbolic 111...C alias; every deployed C/X/Q has a HASH blockchain ID
(devnet 21HieZng, mainnet 2wRdZG), so isNativeChain was ALWAYS false and under the
production --skip-bootstrap=true the beacons were emptied -> a behind C-Chain named
its stale local tip the frontier and never caught up. Verified on devnet v1.36.12:
C-Chain wedged at height 0 ('using empty beacons for single-node mode').
Fix: discriminate on the VALIDATING NET (chainParams.ChainID == PrimaryNetworkID)
via new chainValidatesOnPrimaryNetwork — PrimaryNetworkID for C/X/Q, the sovereign
net ID for L2s. C/X/Q now keep staked beacons under --skip-bootstrap (peer-sync a
behind validator); L2s keep the empty-beacon single-node path. New regression
TestChainValidatesOnPrimaryNetwork_RealHashChainID exercises the real discriminator
with hash IDs; TestRED_EmptyStakedSetFailsSafe still green (forged-frontier gate intact).
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
This commit is contained in:
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.36.13]
|
||||
|
||||
### Fixed
|
||||
- **The durable rejoin fix (#66/#74) shipped INERT for the C-Chain — the exact chain whose 40h mainnet freeze motivated it.** `chains/manager.go` gated `expectsStakedBeacons` on `ids.IsNativeChain(chainParams.ID)` — the *blockchain* ID. But `ids.IsNativeChain` only matches the symbolic `111…C` alias form, and every deployed C/X/Q carries a **hash** blockchain ID (devnet C `21HieZng…`, mainnet C `2wRdZG…`); only the P-chain has a symbolic blockchain ID (`111…P`), and it is excluded as the platform chain. So `isNativeChain` was **always false** for the real C-Chain → `expectsStakedBeacons=false` → under the production `--skip-bootstrap=true` the beacon set was emptied → a behind C-Chain named its STALE local tip the frontier and never caught up (verified on devnet v1.36.12: C-Chain wedged at height 0 with "using empty beacons for single-node mode"). Fix: discriminate on the **validating Net** (`chainParams.ChainID == constants.PrimaryNetworkID`) via new `chainValidatesOnPrimaryNetwork`, which is `PrimaryNetworkID` for C/X/Q and each sovereign L1's own net ID for an L2 — so C/X/Q now keep their staked beacons under `--skip-bootstrap` (peer-sync a behind validator) while L2s keep the empty-beacon single-node path. Regression test `TestChainValidatesOnPrimaryNetwork_RealHashChainID` exercises the real discriminator with hash chain IDs (the prior hardcoded-bool tests could not catch this); `TestRED_EmptyStakedSetFailsSafe` still passes (forged-frontier gate intact).
|
||||
|
||||
## [1.36.12]
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
consensuschain "github.com/luxfi/consensus/engine/chain"
|
||||
cblock "github.com/luxfi/consensus/engine/chain/block"
|
||||
chainbootstrap "github.com/luxfi/consensus/engine/chain/bootstrap"
|
||||
"github.com/luxfi/constants"
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/math/set"
|
||||
@@ -2052,6 +2053,39 @@ func TestChainExpectsStakedBeacons_SybilDrivesNotSkipBootstrap(t *testing.T) {
|
||||
"the platform chain anchors to its OWN CustomBeacons, never the staked-set frontier quorum")
|
||||
}
|
||||
|
||||
// TestChainValidatesOnPrimaryNetwork_RealHashChainID is the regression the hardcoded-bool test
|
||||
// above could NOT catch: it exercises the ACTUAL discriminator buildChain feeds into
|
||||
// chainExpectsStakedBeacons. The durable rejoin fix (#66/#74) shipped INERT in production because
|
||||
// the discriminator keyed off the blockchain ID via ids.IsNativeChain — false for every deployed
|
||||
// C/X/Q (they carry HASH blockchain IDs; ids.IsNativeChain only matches the symbolic 111...C alias
|
||||
// form, which no deployed chain uses). So a real behind C-Chain still got empty beacons under
|
||||
// --skip-bootstrap and wedged. The fix keys off the validating Net (chainParams.ChainID) instead.
|
||||
func TestChainValidatesOnPrimaryNetwork_RealHashChainID(t *testing.T) {
|
||||
// Real deployed C-Chain blockchain IDs (devnet + mainnet) are HASHES, and ids.IsNativeChain
|
||||
// is false for them — the exact trap that disabled the fix.
|
||||
for _, s := range []string{
|
||||
"21HieZngQW8unBnSTbdQ9PcPAz6hhPLGrPzZhTvjC8KgjE95Bg", // devnet C-Chain
|
||||
"2wRdZGeca1qkxzNCq88NWDF5nJ5A9o623vRJKd3FsjRYvuVvvt", // mainnet C-Chain
|
||||
} {
|
||||
id, err := ids.FromString(s)
|
||||
require.NoError(t, err)
|
||||
require.False(t, ids.IsNativeChain(id),
|
||||
"trap: ids.IsNativeChain is false for real hash C-Chain ID %s — do NOT discriminate on the blockchain ID", s)
|
||||
}
|
||||
|
||||
// C/X/Q validate on the PRIMARY NETWORK: chainParams.ChainID == PrimaryNetworkID. That is the
|
||||
// signal buildChain now passes, so the durable fix fires for the real (hash-ID) C-Chain.
|
||||
require.True(t, chainValidatesOnPrimaryNetwork(constants.PrimaryNetworkID))
|
||||
require.True(t, chainExpectsStakedBeacons(true, chainValidatesOnPrimaryNetwork(constants.PrimaryNetworkID), false),
|
||||
"a sybil-protected primary-network non-platform chain (C/X/Q) MUST expect staked beacons regardless of its hash blockchain ID")
|
||||
|
||||
// An L2 validates on its OWN sovereign net, not the primary network → stays on the
|
||||
// empty-beacon single-node path (behavior unchanged for L2s).
|
||||
l2Net := ids.GenerateTestID()
|
||||
require.False(t, chainValidatesOnPrimaryNetwork(l2Net))
|
||||
require.False(t, chainExpectsStakedBeacons(true, chainValidatesOnPrimaryNetwork(l2Net), false))
|
||||
}
|
||||
|
||||
// TestNodeBootstrap_SelfOnlyStakedSet_ReportsNoBeacons covers the single-VALIDATOR counterpart of
|
||||
// the fix: a sybil-protected chain whose staked set is EXACTLY this node (a single-validator
|
||||
// devnet, or the sole validator of an L1) has no OTHER beacon to sync from, so FrontierTip reports
|
||||
|
||||
+24
-3
@@ -1116,7 +1116,13 @@ func (m *manager) buildChain(chainParams ChainParameters, sb nets.Net) (*chainIn
|
||||
// NOT "single-node → done". Driven by sybil-protection, NOT --skip-bootstrap: a production
|
||||
// validator sets skip-bootstrap and that must NOT make it masquerade as single-node and
|
||||
// wedge behind at its stale local tip (tasks #66/#74). See chainExpectsStakedBeacons.
|
||||
expectsStakedBeacons := chainExpectsStakedBeacons(m.SybilProtectionEnabled, ids.IsNativeChain(chainParams.ID), isPlatformChain)
|
||||
// Discriminate on the validating Net (chainParams.ChainID), NOT the blockchain ID:
|
||||
// deployed C/X/Q carry HASH blockchain IDs, and ids.IsNativeChain only matches the
|
||||
// symbolic 111...C alias form (no deployed chain has it). Keying off the blockchain ID
|
||||
// (the prior ids.IsNativeChain(chainParams.ID)) was therefore ALWAYS false for the real
|
||||
// C-Chain, leaving this fix inert — the exact wedge #66/#74 set out to kill fired anyway.
|
||||
isPrimaryNetworkChain := chainValidatesOnPrimaryNetwork(chainParams.ChainID)
|
||||
expectsStakedBeacons := chainExpectsStakedBeacons(m.SybilProtectionEnabled, isPrimaryNetworkChain, isPlatformChain)
|
||||
|
||||
// skip-bootstrap forces empty beacons (single-node immediate-start) for every chain EXCEPT
|
||||
// one that syncs against the staked set — those MUST always catch a behind validator up from
|
||||
@@ -2675,8 +2681,23 @@ func (m *manager) getOrMakeVMGatherer(vmID ids.ID) (metrics.MultiGatherer, error
|
||||
// anchors to its own CustomBeacons (not the staked set), so it is excluded here as before; a
|
||||
// single-VALIDATOR staked net (self-only set) is handled downstream by FrontierTip's
|
||||
// hasExternalBeacons rule, which reads the LOADED set.
|
||||
func chainExpectsStakedBeacons(sybilProtectionEnabled, isNativeChain, isPlatformChain bool) bool {
|
||||
return sybilProtectionEnabled && isNativeChain && !isPlatformChain
|
||||
func chainExpectsStakedBeacons(sybilProtectionEnabled, isPrimaryNetworkChain, isPlatformChain bool) bool {
|
||||
return sybilProtectionEnabled && isPrimaryNetworkChain && !isPlatformChain
|
||||
}
|
||||
|
||||
// chainValidatesOnPrimaryNetwork reports whether a chain's validating Net IS the primary
|
||||
// network — the correct discriminator for the "native" C/X/Q/... set that syncs its bootstrap
|
||||
// frontier against the primary-network STAKED validator set. It keys off the validating Net
|
||||
// (subnet) ID, NOT the blockchain ID: deployed C/X/Q carry HASH blockchain IDs, whereas
|
||||
// ids.IsNativeChain only ever matches the symbolic 111...C alias form that NO deployed chain
|
||||
// uses (only the P-chain, at PlatformChainID=111...P, has a symbolic blockchain ID — and it is
|
||||
// excluded as the platform chain anyway). Keying the durable-rejoin discriminator off the
|
||||
// blockchain ID (the prior ids.IsNativeChain(chainParams.ID)) therefore silently excluded every
|
||||
// real C/X/Q and left the fix inert across restarts (#66/#74). The validating Net is
|
||||
// PrimaryNetworkID for C/X/Q and each sovereign L1's own net ID for an L2, so this correctly
|
||||
// keeps the empty-beacon single-node path for L2s while re-enabling peer-sync for C/X/Q.
|
||||
func chainValidatesOnPrimaryNetwork(validatingNetID ids.ID) bool {
|
||||
return validatingNetID == constants.PrimaryNetworkID
|
||||
}
|
||||
|
||||
// emptyValidatorManager implements validators.Manager with no validators
|
||||
|
||||
@@ -77,7 +77,7 @@ var (
|
||||
const (
|
||||
defaultMajor = 1
|
||||
defaultMinor = 36
|
||||
defaultPatch = 12
|
||||
defaultPatch = 13
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
Reference in New Issue
Block a user