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

129 lines
5.3 KiB
Go

// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package mesh
import (
"sync"
"time"
"github.com/luxfi/ids"
"github.com/luxfi/math/set"
"github.com/luxfi/metric"
"github.com/luxfi/node/mesh/peer"
)
type metricsImpl struct {
// trackedChains does not include the primary network ID
trackedChains set.Set[ids.ID]
numTracked metric.Gauge
numPeers metric.Gauge
numChainPeers metric.GaugeVec
timeSinceLastMsgSent metric.Gauge
timeSinceLastMsgReceived metric.Gauge
sendFailRate metric.Gauge
connected metric.Counter
disconnected metric.Counter
acceptFailed metric.Counter
inboundConnRateLimited metric.Counter
inboundConnAllowed metric.Counter
tlsConnRejected metric.Counter
numUselessPeerListBytes metric.Counter
nodeUptimeWeightedAverage metric.Gauge
nodeUptimeRewardingStake metric.Gauge
peerConnectedLifetimeAverage metric.Gauge
lock sync.RWMutex
peerConnectedStartTimes map[ids.NodeID]float64
peerConnectedStartTimesSum float64
}
func newMetrics(
registry metric.Registry,
trackedChains set.Set[ids.ID],
) (*metricsImpl, error) {
metricsInstance := metric.NewWithRegistry("network", registry)
m := &metricsImpl{
trackedChains: trackedChains,
numPeers: metricsInstance.NewGauge("peers", "Number of network peers"),
numTracked: metricsInstance.NewGauge("tracked", "Number of currently tracked IPs attempting to be connected to"),
numChainPeers: metricsInstance.NewGaugeVec("peers_chain", "Number of peers that are validating a particular chain", []string{"chainID"}),
timeSinceLastMsgReceived: metricsInstance.NewGauge("time_since_last_msg_received", "Time (in ns) since the last msg was received"),
timeSinceLastMsgSent: metricsInstance.NewGauge("time_since_last_msg_sent", "Time (in ns) since the last msg was sent"),
sendFailRate: metricsInstance.NewGauge("send_fail_rate", "Portion of messages that recently failed to be sent over the network"),
connected: metricsInstance.NewCounter("times_connected", "Times this node successfully completed a handshake with a peer"),
disconnected: metricsInstance.NewCounter("times_disconnected", "Times this node disconnected from a peer it had completed a handshake with"),
acceptFailed: metricsInstance.NewCounter("accept_failed", "Times this node's listener failed to accept an inbound connection"),
inboundConnAllowed: metricsInstance.NewCounter("inbound_conn_throttler_allowed", "Times this node allowed (attempted to upgrade) an inbound connection"),
tlsConnRejected: metricsInstance.NewCounter("tls_conn_rejected", "Times this node rejected a connection due to an unsupported TLS certificate"),
numUselessPeerListBytes: metricsInstance.NewCounter("num_useless_peerlist_bytes", "Amount of useless bytes (i.e. information about nodes we already knew/don't want to connect to) received in PeerList messages"),
inboundConnRateLimited: metricsInstance.NewCounter("inbound_conn_throttler_rate_limited", "Times this node rejected an inbound connection due to rate-limiting"),
nodeUptimeWeightedAverage: metricsInstance.NewGauge("node_uptime_weighted_average", "This node's uptime average weighted by observing peer stakes"),
nodeUptimeRewardingStake: metricsInstance.NewGauge("node_uptime_rewarding_stake", "The percentage of total stake which thinks this node is eligible for rewards"),
peerConnectedLifetimeAverage: metricsInstance.NewGauge("peer_connected_duration_average", "The average duration of all peer connections in nanoseconds"),
peerConnectedStartTimes: make(map[ids.NodeID]float64),
}
// init chain tracker metrics with tracked chains
for chainID := range trackedChains {
// initialize to 0
chainIDStr := chainID.String()
m.numChainPeers.WithLabelValues(chainIDStr).Set(0)
}
return m, nil
}
func (m *metricsImpl) markConnected(peer peer.Peer) {
m.numPeers.Inc()
m.connected.Inc()
trackedChains := peer.TrackedChains()
for chainID := range m.trackedChains {
if trackedChains.Contains(chainID) {
m.numChainPeers.WithLabelValues(chainID.String()).Inc()
}
}
m.lock.Lock()
defer m.lock.Unlock()
now := float64(time.Now().UnixNano())
m.peerConnectedStartTimes[peer.ID()] = now
m.peerConnectedStartTimesSum += now
}
func (m *metricsImpl) markDisconnected(peer peer.Peer) {
m.numPeers.Dec()
m.disconnected.Inc()
trackedChains := peer.TrackedChains()
for chainID := range m.trackedChains {
if trackedChains.Contains(chainID) {
m.numChainPeers.WithLabelValues(chainID.String()).Dec()
}
}
m.lock.Lock()
defer m.lock.Unlock()
peerID := peer.ID()
start := m.peerConnectedStartTimes[peerID]
m.peerConnectedStartTimesSum -= start
delete(m.peerConnectedStartTimes, peerID)
}
func (m *metricsImpl) updatePeerConnectionLifetimeMetrics() {
m.lock.RLock()
defer m.lock.RUnlock()
avg := float64(0)
if n := len(m.peerConnectedStartTimes); n > 0 {
avgStartTime := m.peerConnectedStartTimesSum / float64(n)
avg = float64(time.Now().UnixNano()) - avgStartTime
}
m.peerConnectedLifetimeAverage.Set(avg)
}