Files
zeekayandHanzo Dev 37e2940ead mesh is the peer layer, network is the validator set
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]>
2026-09-07 21:17:09 -07:00

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
}