services

package
v0.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 9, 2025 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package services implements node discovery operations.

The services package provides:

  • Iterative FINDNODE lookups (discv5 + discv4)
  • PING/PONG operations (discv5 + discv4)
  • Random walks for table maintenance
  • ENR-based filtering during discovery
  • Dual protocol support (prefers v5, falls back to v4)

Index

Constants

View Source
const DefaultAlpha = 3

DefaultAlpha is the concurrency factor for lookups (Kademlia parameter).

View Source
const DefaultLookupTimeout = 30 * time.Second

DefaultLookupTimeout is the timeout for a complete lookup operation.

View Source
const DefaultMajorityThreshold = 0.75

DefaultMajorityThreshold is the percentage threshold for IP consensus (0.0-1.0)

View Source
const DefaultMinDistinctIPs = 3

DefaultMinDistinctIPs is the minimum number of distinct reporter IPs needed

View Source
const DefaultMinReports = 5

DefaultMinReports is the minimum number of PONG responses needed before considering IP valid

View Source
const DefaultRecentWindow = 5 * time.Minute

DefaultRecentWindow is the time window to consider reports "recent" for IP change detection

View Source
const DefaultReportExpiry = 30 * time.Minute

DefaultReportExpiry is how long to keep IP reports before expiring them

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// LocalNode is our node information
	LocalNode *nodedb.Node

	// NodeDB is the node database
	NodeDB *nodedb.NodeDB

	// Table is the routing table
	Table *nodedb.FlatTable

	// V5Handler is the discv5 protocol handler (may be nil)
	V5Handler *protocol.Handler

	// V4Service is the discv4 service (may be nil)
	V4Service *discv4.Service

	// Database for bad node tracking (may be nil)
	Database interface {
		IsBadNode(nodeID []byte, layer db.NodeLayer, recheckInterval time.Duration) (isBad bool, shouldRecheck bool, reason string, err error)
	}

	// Layer is the layer being looked up
	Layer db.NodeLayer

	// Alpha is the concurrency factor (default 3)
	Alpha int

	// LookupTimeout is the timeout for lookup operations
	LookupTimeout time.Duration

	// OnNodeFound is called when a new node is discovered during lookup
	// The callback should handle admission checks and add the node if valid
	OnNodeFound func(*nodedb.Node) bool

	// Logger for debug messages
	Logger logrus.FieldLogger
}

Config contains configuration for the lookup service.

type IPDiscovery

type IPDiscovery struct {
	// contains filtered or unexported fields
}

IPDiscovery tracks external IP addresses and ports reported by peers via PONG messages.

It implements a consensus mechanism to detect the node's public IP address and port:

  • Collects IP:Port from PONG responses (shows our address as seen by remote peer)
  • Tracks IPv4 and IPv6 independently (separate consensus for each)
  • Requires minimum number of reports before considering an address valid
  • Requires minimum number of DISTINCT reporter IPs (prevents IP spoofing)
  • Requires majority threshold (e.g., 75%) for consensus
  • Expires old reports to handle IP/port changes

Works with both discv4 and discv5 protocols.

func NewIPDiscovery

func NewIPDiscovery(cfg IPDiscoveryConfig) *IPDiscovery

NewIPDiscovery creates a new IP discovery service.

func (*IPDiscovery) GetConsensusIP

func (ipd *IPDiscovery) GetConsensusIP() net.IP

GetConsensusIP returns the current consensus IPv4 address, or nil if no consensus. For IPv6, this returns nil. Use GetStats() for complete information.

func (*IPDiscovery) GetConsensusPort

func (ipd *IPDiscovery) GetConsensusPort() uint16

GetConsensusPort returns the current consensus IPv4 port, or 0 if no consensus.

func (*IPDiscovery) GetStats

func (ipd *IPDiscovery) GetStats() IPDiscoveryStats

GetStats returns current statistics.

func (*IPDiscovery) ReportIP

func (ipd *IPDiscovery) ReportIP(ip net.IP, port uint16, reporterID string, reporterIP net.IP)

ReportIP records an IP address and port from a PONG response.

Parameters:

  • ip: The IP address as reported by the remote peer (our external address)
  • port: The port as reported by the remote peer (our external port)
  • reporterID: The node ID of the peer that sent the PONG (for tracking)
  • reporterIP: The IP address of the reporter (to enforce distinct IP threshold)

func (*IPDiscovery) Reset

func (ipd *IPDiscovery) Reset()

Reset clears all reports and resets consensus state. This can be used when the node's network changes.

type IPDiscoveryConfig

type IPDiscoveryConfig struct {
	// MinReports is the minimum number of PONG responses needed (default: 5)
	MinReports int

	// MinDistinctIPs is the minimum number of distinct reporter IPs needed (default: 3)
	// This prevents a single malicious IP running multiple nodes from reaching consensus
	MinDistinctIPs int

	// MajorityThreshold is the percentage needed for consensus (default: 0.75)
	MajorityThreshold float64

	// ReportExpiry is how long to keep reports (default: 30 minutes)
	ReportExpiry time.Duration

	// RecentWindow is the time window to consider reports "recent" (default: 5 minutes)
	// Used for detecting IP changes - recent reports get priority
	RecentWindow time.Duration

	// OnConsensusReached is called when IP:Port consensus is reached or changes
	// isIPv6 indicates whether this is an IPv6 address (true) or IPv4 (false)
	OnConsensusReached func(ip net.IP, port uint16, isIPv6 bool)

	// Logger for debug messages
	Logger logrus.FieldLogger
}

IPDiscoveryConfig contains configuration for IP discovery

type IPDiscoveryStats

type IPDiscoveryStats struct {
	TotalReportsIPv4     int
	TotalReportsIPv6     int
	UniqueIPv4Addrs      int
	UniqueIPv6Addrs      int
	ConsensusReachedIPv4 bool
	ConsensusReachedIPv6 bool
	ConsensusIPv4Addr    string         // "IP:Port" format
	ConsensusIPv6Addr    string         // "IP:Port" format
	IPv4Reports          map[string]int // "IP:Port" -> count
	IPv6Reports          map[string]int // "IP:Port" -> count
}

IPDiscoveryStats contains statistics about IP discovery.

type LookupService

type LookupService struct {
	// contains filtered or unexported fields
}

LookupService manages node discovery operations. Supports both discv5 and discv4 protocols (prefers v5, falls back to v4).

func NewLookupService

func NewLookupService(cfg Config) *LookupService

NewLookupService creates a new lookup service.

func (*LookupService) CleanupQueryHistory

func (ls *LookupService) CleanupQueryHistory(maxAge time.Duration) int

CleanupQueryHistory removes stale entries from the query history. This should be called periodically to prevent unbounded growth. Entries older than the given duration are removed.

func (*LookupService) GetStats

func (ls *LookupService) GetStats() LookupStats

GetStats returns discovery statistics.

func (*LookupService) Lookup

func (ls *LookupService) Lookup(ctx context.Context, target node.ID, k int) ([]*nodedb.Node, error)

Lookup performs a node lookup by querying random nodes from the table.

Since we use a flat table without buckets, we simply:

  • Select 3 semi-random nodes (preferring alive ones)
  • Query them concurrently for nodes near the target
  • Add discovered nodes via callback

Parameters:

  • ctx: Context for cancellation and timeout
  • target: The target node ID to find
  • k: The number of closest nodes to return

Returns discovered nodes that were added to the table.

func (*LookupService) LookupWithFilter

func (ls *LookupService) LookupWithFilter(ctx context.Context, target node.ID, k int, filter enr.ENRFilter) ([]*nodedb.Node, error)

LookupWithFilter performs a lookup with an ENR filter.

Only nodes that pass the filter are included in the results.

func (*LookupService) RandomWalk

func (ls *LookupService) RandomWalk(ctx context.Context) ([]*nodedb.Node, error)

RandomWalk performs a random walk to discover new nodes.

This is used for routing table maintenance and exploring the network.

type LookupStats

type LookupStats struct {
	LookupsStarted   int
	LookupsCompleted int
	LookupsFailed    int
	NodesDiscovered  int
	LookupsV5        int // Lookups using discv5
	LookupsV4        int // Lookups using discv4
}

GetStats returns statistics about discovery operations.

type PingService

type PingService struct {
	// contains filtered or unexported fields
}

PingService handles PING/PONG operations for liveness checks. Supports both discv5 and discv4 protocols (prefers v5, falls back to v4).

func NewPingService

func NewPingService(v5Handler *protocol.Handler, v4Service *discv4.Service, logger logrus.FieldLogger) *PingService

NewPingService creates a new ping service with dual protocol support. At least one of v5Handler or v4Service must be provided.

func (*PingService) CheckProtocolSupport

func (ps *PingService) CheckProtocolSupport(n *nodedb.Node) (bool, bool, error)

CheckProtocolSupport checks which protocols (v4 and/or v5) a node supports.

This pings the node on BOTH discv4 and discv5 to determine actual protocol support. The node's V4/V5 fields are updated based on which protocols respond successfully.

This should be called at a lower frequency than regular aliveness checks (e.g., every 30 minutes) to discover protocol capabilities without excessive overhead.

Returns (v4Supported, v5Supported, error)

func (*PingService) CheckProtocolSupportMultiple

func (ps *PingService) CheckProtocolSupportMultiple(nodes []*nodedb.Node)

CheckProtocolSupportMultiple checks protocol support for multiple nodes in parallel.

This is useful for periodically verifying protocol capabilities across the table.

func (*PingService) GetStats

func (ps *PingService) GetStats() PingStats

GetStats returns PING statistics.

func (*PingService) Ping

func (ps *PingService) Ping(n *nodedb.Node) (bool, time.Duration, error)

Ping sends a PING to a node and waits for PONG.

Prefers discv5 if available, falls back to discv4. Returns true if the node responded, false on timeout. Also updates the node's RTT statistics.

func (*PingService) PingMultiple

func (ps *PingService) PingMultiple(nodes []*nodedb.Node) map[[32]byte]bool

PingMultiple sends PINGs to multiple nodes in parallel.

Returns a map of node ID to ping result (success/failure).

type PingStats

type PingStats struct {
	PingsSent     int
	PongsReceived int
	PingTimeouts  int
	PingsV5       int // Pings sent via discv5
	PingsV4       int // Pings sent via discv4
	AverageRTT    time.Duration
	SuccessRate   float64
}

PingStats returns statistics about PING operations.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL