mirror of
https://github.com/luxfi/node.git
synced 2026-10-30 15:24:05 +00:00
Two packages were named for the same word and meant different things. network/ dialed peers, exchanged keys, throttled and tracked them; nets/ tracked which chains share a validator set and when they have all bootstrapped. One letter apart, and neither name said which was which. The peer layer is mesh — the word this estate already uses for it, in lux-rs/node's own mesh.rs. That frees network for the thing that is actually a network: a set of chains sharing a validator set. A network holds chains; a chain belongs to one network. github.com/luxfi/p2p stays what it is, the gossip library the VMs use. Three concerns, three names, none of them borrowed from another. Co-authored-by: Hanzo Dev <[email protected]>
114 lines
3.4 KiB
Go
114 lines
3.4 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package chains
|
|
|
|
import (
|
|
"errors"
|
|
"sync"
|
|
|
|
"github.com/luxfi/constants"
|
|
"github.com/luxfi/ids"
|
|
"github.com/luxfi/node/network"
|
|
)
|
|
|
|
var ErrNoPrimaryNetworkConfig = errors.New("no net config for primary network found")
|
|
|
|
// Nets holds the currently running chains on this node
|
|
type Nets struct {
|
|
nodeID ids.NodeID
|
|
configs map[ids.ID]network.Config
|
|
|
|
lock sync.RWMutex
|
|
chains map[ids.ID]network.Net
|
|
}
|
|
|
|
// GetOrCreate returns a chain running on this node, or creates one if it was
|
|
// not running before. Returns the chain and if the chain was created.
|
|
func (s *Nets) GetOrCreate(chainID ids.ID) (network.Net, bool) {
|
|
s.lock.Lock()
|
|
defer s.lock.Unlock()
|
|
|
|
if chain, ok := s.chains[chainID]; ok {
|
|
return chain, false
|
|
}
|
|
|
|
// Default to the primary network config if a net config was not
|
|
// specified
|
|
config, ok := s.configs[chainID]
|
|
if !ok {
|
|
config = s.configs[constants.PrimaryNetworkID]
|
|
}
|
|
|
|
chain := network.New(s.nodeID, config)
|
|
s.chains[chainID] = chain
|
|
|
|
return chain, true
|
|
}
|
|
|
|
// IsChainBootstrapped reports whether the given chain has finished initial sync
|
|
// (reached the network frontier and transitioned its VM to normal operation) on
|
|
// this node — Bootstrapped(chainID) was called for it in its validation net. A
|
|
// chain that is merely tracked (its sync goroutine launched) but has NOT converged
|
|
// reads false. This is the per-chain truth manager.IsBootstrapped / info.isBootstrapped
|
|
// key on, replacing the mere-existence test that returned true the instant a chain
|
|
// was added to the manager (the premature-true masking bug: a C-Chain stalled at
|
|
// genesis reported bootstrapped=true). A chainID is added to exactly one net's
|
|
// tracking, so the first net that reports it bootstrapped is authoritative.
|
|
func (s *Nets) IsChainBootstrapped(chainID ids.ID) bool {
|
|
if s == nil {
|
|
return false // no net tracking wired ⇒ nothing has been marked bootstrapped
|
|
}
|
|
s.lock.RLock()
|
|
defer s.lock.RUnlock()
|
|
|
|
for _, chain := range s.chains {
|
|
if chain.IsChainBootstrapped(chainID) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Bootstrapping returns the chainIDs of any chains that are still
|
|
// bootstrapping.
|
|
//
|
|
// s.chains is keyed by NET id, not chain id. Reporting the key named the net
|
|
// instead of the chain: every primary-network chain that failed to converge
|
|
// surfaced in /v1/health as the single ID
|
|
// "11111111111111111111111111111111LpoYY" — constants.PrimaryNetworkID, i.e.
|
|
// ids.Empty — a "chain" the chain manager has never heard of, so the operator
|
|
// chasing it got "there is no chain with alias/ID". Worse, N stuck chains
|
|
// collapsed into one indistinguishable entry. Ask each net which of ITS chains
|
|
// are still bootstrapping; the net owns that set.
|
|
func (s *Nets) Bootstrapping() []ids.ID {
|
|
s.lock.RLock()
|
|
defer s.lock.RUnlock()
|
|
|
|
chainsBootstrapping := make([]ids.ID, 0, len(s.chains))
|
|
for _, chain := range s.chains {
|
|
chainsBootstrapping = append(chainsBootstrapping, chain.Bootstrapping()...)
|
|
}
|
|
|
|
return chainsBootstrapping
|
|
}
|
|
|
|
// NewNets returns an instance of Nets
|
|
func NewNets(
|
|
nodeID ids.NodeID,
|
|
configs map[ids.ID]network.Config,
|
|
) (*Nets, error) {
|
|
if _, ok := configs[constants.PrimaryNetworkID]; !ok {
|
|
return nil, ErrNoPrimaryNetworkConfig
|
|
}
|
|
|
|
s := &Nets{
|
|
nodeID: nodeID,
|
|
configs: configs,
|
|
chains: make(map[ids.ID]network.Net),
|
|
}
|
|
|
|
_, _ = s.GetOrCreate(constants.PrimaryNetworkID)
|
|
return s, nil
|
|
}
|