mirror of
https://github.com/luxfi/node.git
synced 2026-07-27 03:39:39 +00:00
/v1/health's `bootstrapped` check publishes chains.Nets.Bootstrapping()
verbatim as its message. Nets.chains is keyed by NET id, and the aggregate
appended the map key rather than asking the net which of its chains had not
converged. So every stuck primary-network chain surfaced as one ID,
11111111111111111111111111111111LpoYY — constants.PrimaryNetworkID, i.e.
ids.Empty — a "chain" the chain manager has never heard of. An operator who
went looking for it got "there is no chain with alias/ID", and N stuck chains
collapsed into a single indistinguishable entry that named none of them.
Measured on lux-devnet luxd-0 (v1.36.23), POST health.health:
"bootstrapped":{"message":["11111111111111111111111111111111LpoYY"],
"error":"chains not bootstrapped","contiguousFailures":3213}
The net owns the bootstrapping set, so the net is what can name those chains:
nets.Net grows Bootstrapping() []ids.ID and chains.Nets aggregates those
instead of its own keys. One place holds the set; one place reads it.
The existing TestNetsBootstrapping asserted the defect (require.Contains
bootstrapping, netID) — that assertion is why it survived review. It now
demands the chain ID and refuses the net ID.
This also cuts the first tag containing dada5a31, the GET /v1/health encoder
fix: apihealth.APIReply carries a time.Duration per check, jsonv2 has no
default representation for it, so every GET degraded to
{"healthy":…,"error":"health reply encode failed"} while the status code still
looked right. Reproduced here directly —
json: cannot marshal from Go time.Duration within "/checks/network/duration"
That fix landed on main on 2026-07-25 but no tag ever carried it: v1.36.28
points at 52de3948, seven commits behind. The fleet runs v1.36.2/23/24, all of
which predate it.
Tests (GOWORK=off CGO_ENABLED=0):
chains ok — TestNetsBootstrappingReportsChainsNotNets fails against the
old aggregate with exactly ids.Empty in the list
nets ok — TestNetBootstrappingNamesTheChains
health ok — the three handler tests fail against the jsonv2 encoder
(checks decode empty) and pass against encoding/json
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
158 lines
3.6 KiB
Go
158 lines
3.6 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package version
|
|
|
|
import (
|
|
"github.com/go-json-experiment/json"
|
|
"strconv"
|
|
"time"
|
|
|
|
_ "embed"
|
|
)
|
|
|
|
const (
|
|
Client = "luxd"
|
|
// RPCChainVMProtocol should be bumped anytime changes are made which
|
|
// require the plugin vm to upgrade to latest node release to be
|
|
// compatible.
|
|
RPCChainVMProtocol uint = 42
|
|
)
|
|
|
|
// These variables are set at build time via ldflags from git tag:
|
|
//
|
|
// go build -ldflags "-X github.com/luxfi/node/version.VersionMajor=1 \
|
|
// -X github.com/luxfi/node/version.VersionMinor=22 \
|
|
// -X github.com/luxfi/node/version.VersionPatch=19"
|
|
//
|
|
// Build with scripts/build.sh to automatically inject version from git tags.
|
|
var (
|
|
VersionMajor = ""
|
|
VersionMinor = ""
|
|
VersionPatch = ""
|
|
)
|
|
|
|
// These are globals that describe network upgrades and node versions
|
|
var (
|
|
Current *Semantic
|
|
CurrentApp *Application
|
|
|
|
MinimumCompatibleVersion = &Application{
|
|
Name: Client,
|
|
Major: 1,
|
|
Minor: 13,
|
|
Patch: 0,
|
|
}
|
|
PrevMinimumCompatibleVersion = &Application{
|
|
Name: Client,
|
|
Major: 1,
|
|
Minor: 12,
|
|
Patch: 0,
|
|
}
|
|
|
|
CurrentDatabase = DatabaseVersion1_4_5
|
|
PrevDatabase = DatabaseVersion1_0_0
|
|
|
|
DatabaseVersion1_4_5 = &Semantic{
|
|
Major: 1,
|
|
Minor: 4,
|
|
Patch: 5,
|
|
}
|
|
DatabaseVersion1_0_0 = &Semantic{
|
|
Major: 1,
|
|
Minor: 0,
|
|
Patch: 0,
|
|
}
|
|
|
|
//go:embed compatibility.json
|
|
rpcChainVMProtocolCompatibilityBytes []byte
|
|
// RPCChainVMProtocolCompatibility maps RPCChainVMProtocol versions to the
|
|
// set of node versions that supported that version. This is not used
|
|
// by node, but is useful for downstream libraries.
|
|
RPCChainVMProtocolCompatibility map[uint][]*Semantic
|
|
)
|
|
|
|
// Default version for tests/development when not set via ldflags
|
|
// These should match the latest git tag
|
|
const (
|
|
defaultMajor = 1
|
|
defaultMinor = 36
|
|
defaultPatch = 29
|
|
)
|
|
|
|
func init() {
|
|
// Version is set via ldflags at build time from git tag
|
|
// If not set, use defaults (for tests and go run)
|
|
var major, minor, patch int
|
|
|
|
if VersionMajor != "" {
|
|
var err error
|
|
major, err = strconv.Atoi(VersionMajor)
|
|
if err != nil {
|
|
panic("invalid VersionMajor: " + VersionMajor)
|
|
}
|
|
} else {
|
|
major = defaultMajor
|
|
}
|
|
|
|
if VersionMinor != "" {
|
|
var err error
|
|
minor, err = strconv.Atoi(VersionMinor)
|
|
if err != nil {
|
|
panic("invalid VersionMinor: " + VersionMinor)
|
|
}
|
|
} else {
|
|
minor = defaultMinor
|
|
}
|
|
|
|
if VersionPatch != "" {
|
|
var err error
|
|
patch, err = strconv.Atoi(VersionPatch)
|
|
if err != nil {
|
|
panic("invalid VersionPatch: " + VersionPatch)
|
|
}
|
|
} else {
|
|
patch = defaultPatch
|
|
}
|
|
|
|
Current = &Semantic{
|
|
Major: major,
|
|
Minor: minor,
|
|
Patch: patch,
|
|
}
|
|
CurrentApp = &Application{
|
|
Name: Client,
|
|
Major: Current.Major,
|
|
Minor: Current.Minor,
|
|
Patch: Current.Patch,
|
|
}
|
|
|
|
// Parse RPC compatibility map
|
|
var parsedRPCChainVMCompatibility map[uint][]string
|
|
if err := json.Unmarshal(rpcChainVMProtocolCompatibilityBytes, &parsedRPCChainVMCompatibility); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
RPCChainVMProtocolCompatibility = make(map[uint][]*Semantic)
|
|
for rpcChainVMProtocol, versionStrings := range parsedRPCChainVMCompatibility {
|
|
versions := make([]*Semantic, len(versionStrings))
|
|
for i, versionString := range versionStrings {
|
|
version, err := Parse(versionString)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
versions[i] = version
|
|
}
|
|
RPCChainVMProtocolCompatibility[rpcChainVMProtocol] = versions
|
|
}
|
|
}
|
|
|
|
func GetCompatibility(minCompatibleTime time.Time) Compatibility {
|
|
return NewCompatibility(
|
|
CurrentApp,
|
|
MinimumCompatibleVersion,
|
|
minCompatibleTime,
|
|
PrevMinimumCompatibleVersion,
|
|
)
|
|
}
|