Documentation
¶
Overview ¶
Package node provides core types for representing network nodes.
A Node combines:
- Identity: ENR record with node metadata
- Network info: IP address, UDP/TCP ports
- Statistics: Last seen, failure counts, RTT
Nodes are the fundamental unit in the discv5 peer discovery system.
Index ¶
- Variables
- func BucketIndex(local, remote ID) int
- func BuildPeerID(pubKey *ecdsa.PublicKey) string
- func CloserTo(target, a, b ID) bool
- func Compare(target, a, b ID) int
- func GetIPVersion(ip net.IP) int
- func IsLANAddress(ip net.IP) bool
- func IsNetworkError(err error) bool
- func IsProtocolError(err error) bool
- func IsRoutableAddress(ip net.IP) bool
- func IsSameNetwork(ip1, ip2 net.IP) bool
- func IsTimeout(err error) bool
- func IsWANAddress(ip net.IP) bool
- func LogDistance(a, b ID) int
- func NormalizeIP(ip net.IP) net.IP
- func ParseNodeAddr(addrStr string) (*net.UDPAddr, error)
- func SameIP(ip1, ip2 net.IP) bool
- func ValidateUDPAddr(addr *net.UDPAddr) error
- type ForkScoringInfo
- type ID
- type Node
- func (n *Node) Addr() *net.UDPAddr
- func (n *Node) CalculateScore(forkInfo *ForkScoringInfo) float64
- func (n *Node) Digest() [4]byte
- func (n *Node) GetStats() Stats
- func (n *Node) ID() ID
- func (n *Node) IP() net.IP
- func (n *Node) IncrementFailureCount()
- func (n *Node) PeerID() string
- func (n *Node) PublicKey() *ecdsa.PublicKey
- func (n *Node) Record() *enr.Record
- func (n *Node) ResetFailureCount()
- func (n *Node) SetFailureCount(count int)
- func (n *Node) SetLastPing(t time.Time)
- func (n *Node) SetLastSeen(t time.Time)
- func (n *Node) SetStats(sharedStats *stats.SharedStats)
- func (n *Node) SetSuccessCount(count int)
- func (n *Node) String() string
- func (n *Node) TCPPort() uint16
- func (n *Node) UDPPort() uint16
- func (n *Node) UpdateENR(newRecord *enr.Record) bool
- func (n *Node) UpdateRTT(rtt time.Duration)
- type Stats
Constants ¶
This section is empty.
Variables ¶
var ( // ErrInvalidAddress is returned when a network address is invalid. ErrInvalidAddress = errors.New("node: invalid network address") // ErrInvalidPort is returned when a port number is invalid. ErrInvalidPort = errors.New("node: invalid port number") // ErrInvalidNodeID is returned when a node ID is invalid. ErrInvalidNodeID = errors.New("node: invalid node ID") // ErrInvalidENR is returned when an ENR record is invalid. ErrInvalidENR = errors.New("node: invalid ENR record") // ErrMulticastNotSupported is returned for multicast addresses. ErrMulticastNotSupported = errors.New("node: multicast addresses not supported") // ErrNodeNotFound is returned when a node is not in the database. ErrNodeNotFound = errors.New("node: node not found") // ErrNodeAlreadyExists is returned when trying to add a duplicate node. ErrNodeAlreadyExists = errors.New("node: node already exists") // ErrTimeout is returned when an operation times out. ErrTimeout = errors.New("node: operation timed out") // ErrNetworkError is returned for network-related errors. ErrNetworkError = errors.New("node: network error") // ErrProtocolError is returned for protocol violations. ErrProtocolError = errors.New("node: protocol error") )
Functions ¶
func BucketIndex ¶
BucketIndex returns the bucket index for a given distance.
This is the same as LogDistance but named more clearly for routing table use.
func BuildPeerID ¶
func CloserTo ¶
CloserTo checks if node a is closer to target than node b.
Equivalent to Compare(target, a, b) < 0, but more readable.
Example:
if CloserTo(target, node1.ID(), node2.ID()) {
// node1 is closer to target
}
func Compare ¶
Compare compares the distance from target to a vs target to b.
Returns:
- -1 if a is closer to target than b
- 0 if a and b are equidistant from target
- 1 if b is closer to target than a
This is used for sorting nodes by distance in discovery operations.
Example:
// Sort nodes by distance to target
sort.Slice(nodes, func(i, j int) bool {
return Compare(target, nodes[i].ID(), nodes[j].ID()) < 0
})
func GetIPVersion ¶
GetIPVersion returns the IP version (4 or 6) of an address.
Returns:
- 4 for IPv4 addresses
- 6 for IPv6 addresses
- 0 for invalid/nil addresses
func IsLANAddress ¶
IsLANAddress checks if an IP address is a private/local address.
Returns true for:
- 10.0.0.0/8 (RFC1918)
- 172.16.0.0/12 (RFC1918)
- 192.168.0.0/16 (RFC1918)
- fc00::/7 (IPv6 ULA)
- fe80::/10 (IPv6 link-local)
- 127.0.0.0/8 (loopback)
- ::1 (IPv6 loopback)
This is used to prevent serving LAN addresses to WAN peers.
Example:
if IsLANAddress(node.IP()) {
// Don't serve to WAN requesters
}
func IsNetworkError ¶
IsNetworkError checks if an error is a network error.
func IsProtocolError ¶
IsProtocolError checks if an error is a protocol error.
func IsRoutableAddress ¶
IsRoutableAddress checks if an IP address is globally routable.
Returns false for:
- Private addresses (RFC1918, ULA)
- Loopback addresses
- Link-local addresses
- Multicast addresses
- Unspecified addresses (0.0.0.0, ::)
Example:
if !IsRoutableAddress(node.IP()) {
// Skip this node in public discovery
}
func IsSameNetwork ¶
IsSameNetwork checks if two IP addresses are on the same network.
For IPv4, this checks if they're both LAN or both WAN. This is used to determine if nodes can directly communicate.
Example:
if !IsSameNetwork(localIP, remoteIP) {
// May need NAT traversal
}
func IsWANAddress ¶
IsWANAddress checks if an IP address is a publicly routable address.
This is the inverse of IsLANAddress - returns true for public internet IPs.
Example:
if IsWANAddress(requester.IP) && IsLANAddress(node.IP()) {
// Don't serve LAN node to WAN requester
return false
}
func LogDistance ¶
LogDistance calculates the logarithmic distance (bucket index) between two node IDs.
Returns the position of the most significant bit in the XOR distance, which determines the Kademlia bucket (0-255).
A distance of 0 means the nodes are identical (returns -1). A distance with MSB at position N means the nodes differ starting at bit N.
Example:
logDist := LogDistance(id1, id2) // logDist is the bucket index (0-255) for the routing table
func NormalizeIP ¶
NormalizeIP normalizes an IP address for consistent comparison.
IPv4 addresses are returned in 4-byte form. IPv6 addresses are returned in 16-byte form.
func ParseNodeAddr ¶
ParseNodeAddr parses a node address string in the format "ip:port".
Example:
addr, err := ParseNodeAddr("192.168.1.1:9000")
func SameIP ¶
SameIP checks if two IP addresses are the same.
This handles IPv4 vs IPv6 representation differences.
Example:
if SameIP(node1.IP(), node2.IP()) {
// Same node or same host
}
func ValidateUDPAddr ¶
ValidateUDPAddr checks if a UDP address is valid for discv5 communication.
Returns an error if:
- Address is nil
- IP is nil or unspecified
- Port is 0
- IP is multicast
Example:
if err := ValidateUDPAddr(addr); err != nil {
return fmt.Errorf("invalid address: %w", err)
}
Types ¶
type ForkScoringInfo ¶
type ForkScoringInfo struct {
// CurrentForkDigest is the current expected fork digest
CurrentForkDigest [4]byte
// PreviousForkDigest is the previous fork digest (current - 1)
PreviousForkDigest [4]byte
// GenesisForkDigest is the genesis fork digest
GenesisForkDigest [4]byte
// GracePeriodEnd is when the grace period for the previous fork ends
// If zero, there is no grace period active
GracePeriodEnd time.Time
}
ForkScoringInfo contains fork digest information for node scoring.
type ID ¶
type ID [32]byte
ID represents a unique node identifier (32 bytes).
The node ID is derived from the node's public key:
nodeID = keccak256(uncompressed_pubkey[1:])
This ID is used in the Kademlia DHT for routing and distance calculations.
func Distance ¶
Distance calculates the XOR distance between two node IDs.
In Kademlia, distance is defined as the XOR of two node IDs. This creates a metric space where:
- d(x, x) = 0 (distance to self is zero)
- d(x, y) = d(y, x) (symmetric)
- d(x, z) <= d(x, y) + d(y, z) (triangle inequality)
The distance is returned as the ID itself (32 bytes).
Example:
id1 := PubkeyToID(pubKey1) id2 := PubkeyToID(pubKey2) dist := Distance(id1, id2)
func FindClosest ¶
FindClosest finds the k closest node IDs to the target from a list.
The result is sorted by distance (closest first). If the list contains fewer than k nodes, all nodes are returned.
Example:
target := localNode.ID()
nodeIDs := []ID{id1, id2, id3, id4, id5}
closest := FindClosest(target, nodeIDs, 3) // Get 3 closest
func PubkeyToID ¶
PubkeyToID converts a public key to a node ID.
Example:
privKey, _ := crypto.GenerateKey() nodeID := PubkeyToID(&privKey.PublicKey)
type Node ¶
type Node struct {
// contains filtered or unexported fields
}
Node represents a network node in the discv5 protocol.
It combines the node's ENR record with additional runtime information like network statistics and last seen time.
func New ¶
New creates a new Node from an ENR record.
The node ID and network address are extracted from the ENR. Returns an error if the ENR is missing required fields.
Example:
privKey, _ := crypto.GenerateKey()
record, _ := enr.CreateSignedRecord(
privKey,
"ip", net.IPv4(192, 168, 1, 1),
"udp", uint16(9000),
)
node, err := New(record)
func (*Node) CalculateScore ¶
func (n *Node) CalculateScore(forkInfo *ForkScoringInfo) float64
CalculateScore computes a quality score including fork digest compatibility.
The score considers:
- RTT (lower is better): 30% weight
- Success rate: 25% weight
- Uptime (time since first seen): 15% weight
- Recency (time since last seen): 10% weight
- Fork digest compatibility: 20% weight
Fork digest scoring:
- Current fork digest: 1.0 multiplier
- Previous fork (in grace period): 0.8 multiplier
- Genesis fork (syncing clients): 0.5 multiplier
- Previous fork (expired grace): 0.2 multiplier (outdated clients)
- Unknown/no fork data: 0.3 multiplier
Returns a score between 0.0 (worst) and 1.0 (best).
func (*Node) IncrementFailureCount ¶
func (n *Node) IncrementFailureCount()
IncrementFailureCount increases the failure count by 1.
func (*Node) PeerID ¶
PeerID returns the libp2p peer ID for this node.
The peer ID is constructed from the secp256k1 public key using the libp2p format:
- Compressed secp256k1 public key (33 bytes)
- Wrapped in libp2p PublicKey protobuf message:
- Field 1 (Type): 0x08 0x02 (secp256k1 = 2)
- Field 2 (Data): 0x12 0x21 [33 bytes of compressed key]
- Wrapped in IDENTITY multihash (code 0x00)
- Base58 encoded
Example output: "16Uiu2HAkyttpvpDTRdEnUqSPvbDpRgbSgrmeqTqi4R7EWECG5jso"
func (*Node) ResetFailureCount ¶
func (n *Node) ResetFailureCount()
ResetFailureCount resets the failure count to 0 and increments success count.
func (*Node) SetFailureCount ¶
SetFailureCount sets the failure count.
func (*Node) SetLastPing ¶
SetLastPing updates the last ping time.
func (*Node) SetLastSeen ¶
SetLastSeen updates the last seen time.
func (*Node) SetStats ¶ added in v0.0.2
func (n *Node) SetStats(sharedStats *stats.SharedStats)
SetStats replaces the node's stats with a shared stats pointer. This allows the node to update stats owned by a parent node.
func (*Node) SetSuccessCount ¶
SetSuccessCount sets the success count.
func (*Node) String ¶
String returns a human-readable representation of the node.
Format: Node[id=abc123..., addr=192.168.1.1:9000, seen=1m ago]