Documentation
¶
Index ¶
- Constants
- func NewV4NodeFromRecord(record *enr.Record, addr *net.UDPAddr) (*node.Node, error)
- func NewV5NodeFromRecord(record *enr.Record) (*discv5node.Node, error)
- type DB
- type DirtyFlags
- type FlatTable
- func (t *FlatTable) ActiveSize() int
- func (t *FlatTable) Add(n *Node) bool
- func (t *FlatTable) CanAddNodeByIP(n *Node) bool
- func (t *FlatTable) FindClosestNodes(target [32]byte, k int) []*Node
- func (t *FlatTable) Get(nodeID [32]byte) *Node
- func (t *FlatTable) GetActiveNodes() []*Node
- func (t *FlatTable) GetBucketNodes(bucketIndex int) []*Node
- func (t *FlatTable) GetNodesByDistance(targetID [32]byte, distances []uint, k int) []*Node
- func (t *FlatTable) GetNodesNeedingPing() []*Node
- func (t *FlatTable) GetRandomActiveNodes(k int) []*Node
- func (t *FlatTable) GetStats() TableStats
- func (t *FlatTable) LoadInitialNodesFromDB() error
- func (t *FlatTable) NumBucketsFilled() int
- func (t *FlatTable) PerformSweep()
- func (t *FlatTable) SetForkScoringInfo(info *ForkScoringInfo)
- func (t *FlatTable) Size() int
- type FlatTableConfig
- type ForkScoringInfo
- type IPLimiter
- type IPStats
- type Node
- func (n *Node) Addr() *net.UDPAddr
- func (n *Node) AvgRTT() time.Duration
- func (n *Node) CalculateScore(forkInfo *ForkScoringInfo) float64
- func (n *Node) ClearDirtyFlags()
- func (n *Node) ENR() *enr.Record
- func (n *Node) Enode() *enode.Enode
- func (n *Node) FailureCount() int
- func (n *Node) FirstSeen() time.Time
- func (n *Node) GetDirtyFlags() DirtyFlags
- func (n *Node) GetStats() NodeStats
- func (n *Node) HasV4() bool
- func (n *Node) HasV5() bool
- func (n *Node) ID() [32]byte
- func (n *Node) IDBytes() []byte
- func (n *Node) IncrementFailure()
- func (n *Node) IncrementFailureCount()
- func (n *Node) IncrementSuccess()
- func (n *Node) IsAlive(maxAge time.Duration, maxFailures int) bool
- func (n *Node) LastActive() time.Time
- func (n *Node) LastPing() time.Time
- func (n *Node) LastSeen() time.Time
- func (n *Node) MarkDirty(flags DirtyFlags)
- func (n *Node) NeedsPing(pingInterval time.Duration) bool
- func (n *Node) PeerID() string
- func (n *Node) PublicKey() *ecdsa.PublicKey
- func (n *Node) Record() *enr.Record
- func (n *Node) ResetFailureCount()
- func (n *Node) SetAddr(addr *net.UDPAddr)
- func (n *Node) SetFailureCount(count int)
- func (n *Node) SetFirstSeen(t time.Time)
- func (n *Node) SetLastActive(t time.Time)
- func (n *Node) SetLastPing(t time.Time)
- func (n *Node) SetLastSeen(t time.Time)
- func (n *Node) SetSuccessCount(count int)
- func (n *Node) SetV4(v4 *node.Node)
- func (n *Node) SetV5(v5 *discv5node.Node)
- func (n *Node) String() string
- func (n *Node) SuccessCount() int
- func (n *Node) UpdateENR(newRecord *enr.Record) bool
- func (n *Node) UpdateLastSeen()
- func (n *Node) UpdateRTT(rtt time.Duration)
- func (n *Node) V4() *node.Node
- func (n *Node) V5() *discv5node.Node
- type NodeChangedCallback
- type NodeDB
- func (ndb *NodeDB) Close()
- func (ndb *NodeDB) Count() int
- func (ndb *NodeDB) GetStats() NodeDBStats
- func (ndb *NodeDB) List() []*Node
- func (ndb *NodeDB) Load(id [32]byte) (*Node, error)
- func (ndb *NodeDB) LoadAll() ([]*Node, error)
- func (ndb *NodeDB) LoadInactiveNodes(limit int) []*Node
- func (ndb *NodeDB) LoadRandom(limit int) ([]*Node, error)
- func (ndb *NodeDB) LoadRandomNodes(limit int) []*Node
- func (ndb *NodeDB) QueueUpdate(n *Node) error
- type NodeDBStats
- type NodeStats
- type TableStats
Constants ¶
const ( // DefaultMaxActiveNodes is the maximum number of nodes to keep in the active state DefaultMaxActiveNodes = 500 // DefaultPingRate is the maximum number of pings per minute DefaultPingRate = 400 // DefaultSweepPercent is the percentage of active nodes to rotate during sweep DefaultSweepPercent = 10 )
FlatTable configuration constants
const ( RejectionIPLimit uint8 = 0x01 RejectionAdmission uint8 = 0x02 )
Rejection reason flags
const DefaultMaxFailures = 3
DefaultMaxFailures is the maximum consecutive failures before considering a node dead.
const DefaultMaxNodeAge = 24 * time.Hour
DefaultMaxNodeAge is the maximum time since last seen before considering a node dead.
const DefaultMaxNodesPerIP = 10
DefaultMaxNodesPerIP is the default maximum nodes per IP address.
const DefaultPingInterval = 30 * time.Second
DefaultPingInterval is how often we PING nodes to check liveness.
const RejectionLogTTL = 12 * time.Hour
RejectionLogTTL is how long we remember that we logged a rejection for a node.
Variables ¶
This section is empty.
Functions ¶
func NewV4NodeFromRecord ¶
NewV4NodeFromRecord creates a discv4 node from an ENR record and address. This is a helper for protocol support checks.
func NewV5NodeFromRecord ¶
func NewV5NodeFromRecord(record *enr.Record) (*discv5node.Node, error)
NewV5NodeFromRecord creates a discv5 node from an ENR record. This is a helper for protocol support checks.
Types ¶
type DB ¶
type DB interface {
StoreRejection(id [32]byte, reason uint8, timestamp time.Time) error
LoadRejection(id [32]byte) (flags uint8, timestamp time.Time, found bool, err error)
ExpireRejections(ttl time.Duration) (int, error)
}
DB is the interface for node database that supports rejection tracking.
type DirtyFlags ¶
type DirtyFlags uint8
DirtyFlags represents which fields need database updates.
const ( DirtyFull DirtyFlags = 0x01 // Full upsert (initial add) DirtyENR DirtyFlags = 0x02 // seq+enr+ip update DirtyLastActive DirtyFlags = 0x04 // last_active timestamp DirtyLastSeen DirtyFlags = 0x08 // last_seen timestamp DirtyProtocol DirtyFlags = 0x10 // has_v4/has_v5 flags DirtyStats DirtyFlags = 0x20 // packet stats (success/failure/rtt) )
type FlatTable ¶
type FlatTable struct {
// contains filtered or unexported fields
}
FlatTable is a flat node storage with capped active nodes.
Unlike the bucket-based Kademlia table, this maintains:
- All nodes in DB (active and inactive)
- Capped active nodes in memory (max 500)
- Distributed ping scheduling
- Periodic active/inactive rotation
func NewFlatTable ¶
func NewFlatTable(cfg FlatTableConfig) (*FlatTable, error)
NewFlatTable creates a new flat node table.
func (*FlatTable) ActiveSize ¶
ActiveSize returns the number of active nodes.
func (*FlatTable) Add ¶
Add adds a node to the active pool.
This method handles adding nodes to the active in-memory pool with the following strategy: - For nodes that already exist in active pool: updates ENR if newer. - For new nodes: adds to active pool even if over capacity (up to hard limit). - Hard limit: 2x maxActiveNodes. If reached, triggers immediate sweep. - IP limiter is still enforced.
This allows newly discovered nodes (which may not be working) to be added without rejecting them immediately. The next sweep will clean up excess nodes.
DB writes must be handled by caller.
func (*FlatTable) CanAddNodeByIP ¶
CanAddNodeByIP checks if we can add a node based on IP limits. This checks against all nodes (active + inactive) in the DB.
func (*FlatTable) FindClosestNodes ¶
FindClosestNodes finds the k closest active nodes to the target ID.
func (*FlatTable) Get ¶
Get retrieves a node by ID. First checks active nodes, then falls back to DB.
func (*FlatTable) GetActiveNodes ¶
GetActiveNodes returns a copy of all active nodes.
func (*FlatTable) GetBucketNodes ¶
GetBucketNodes is kept for compatibility but returns empty for flat table.
func (*FlatTable) GetNodesByDistance ¶
GetNodesByDistance returns nodes at specific distances with score-weighted random selection.
For each requested distance, it finds all matching nodes and selects up to k nodes with probability weighted by their score (RTT, success rate, fork compatibility).
This ensures:
- Different results on each call (randomized)
- Better nodes are returned more frequently (score-weighted)
- Specific distances are respected
func (*FlatTable) GetNodesNeedingPing ¶
GetNodesNeedingPing returns active nodes that need a PING check.
This implements distributed ping scheduling by limiting the number of nodes returned.
func (*FlatTable) GetRandomActiveNodes ¶
GetRandomActiveNodes returns up to k random active nodes.
func (*FlatTable) GetStats ¶
func (t *FlatTable) GetStats() TableStats
GetStats returns statistics about the table.
func (*FlatTable) LoadInitialNodesFromDB ¶
LoadInitialNodesFromDB loads random nodes from DB into the active pool.
func (*FlatTable) NumBucketsFilled ¶
NumBucketsFilled returns a compatibility value for the flat table. Since we don't have buckets, we return 1 if we have any active nodes, 0 otherwise.
func (*FlatTable) PerformSweep ¶
func (t *FlatTable) PerformSweep()
PerformSweep rotates nodes between active and inactive pools.
This should be called periodically (e.g., every 10 minutes). Only demotes nodes when over capacity. When at or under capacity, nodes are kept to allow newly discovered nodes to be tested before being demoted. Loads inactive nodes from DB and tries to promote them to fill available slots.
func (*FlatTable) SetForkScoringInfo ¶
func (t *FlatTable) SetForkScoringInfo(info *ForkScoringInfo)
SetForkScoringInfo updates the fork scoring information used for node ranking. This should be called periodically to reflect fork changes.
type FlatTableConfig ¶
type FlatTableConfig struct {
// LocalID is our node ID
LocalID [32]byte
// DB is the primary node storage
DB *NodeDB
// MaxActiveNodes is the maximum number of active nodes (default 500)
MaxActiveNodes int
// MaxNodesPerIP is the maximum nodes allowed per IP address
MaxNodesPerIP int
// PingInterval is how often to ping nodes
PingInterval time.Duration
// PingRate is maximum pings per minute (default 400)
PingRate int
// MaxNodeAge is the maximum time since last seen
MaxNodeAge time.Duration
// MaxFailures is the maximum consecutive failures
MaxFailures int
// SweepPercent is percentage of nodes to rotate during sweep (default 10%)
SweepPercent int
// NodeChangedCallback is called when a node is added or updated
NodeChangedCallback NodeChangedCallback
// Logger for debug messages
Logger logrus.FieldLogger
}
FlatTableConfig contains configuration for the flat table.
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 IPLimiter ¶
type IPLimiter struct {
// contains filtered or unexported fields
}
IPLimiter tracks and enforces per-IP node limits.
This prevents sybil attacks where an attacker tries to fill the routing table with many nodes from the same IP address.
func NewIPLimiter ¶
NewIPLimiter creates a new IP limiter.
Parameters:
- maxNodesPerIP: Maximum nodes allowed per IP (0 = unlimited)
func (*IPLimiter) Add ¶
Add registers a node with the IP limiter.
This should be called when a node is added to the routing table. Returns false if the IP limit is exceeded.
func (*IPLimiter) CanAdd ¶
CanAdd checks if a node can be added without exceeding IP limits.
Returns true if the node can be added, false if the IP limit is exceeded.
func (*IPLimiter) GetNodeCountForIP ¶
GetNodeCountForIP returns the number of nodes for a given IP.
func (*IPLimiter) GetTotalRejections ¶
GetTotalRejections returns the total number of rejected nodes due to IP limits.
type IPStats ¶
type IPStats struct {
UniqueIPs int
TotalNodes int
MaxNodesPerIP int
Rejections int
IPDistribution map[string]int // IP -> node count
}
GetStats returns statistics about IP usage.
type Node ¶
type Node struct {
// contains filtered or unexported fields
}
Node is a generic node type that can hold both discv4 and discv5 nodes.
A node can have:
- Only v4 (legacy execution layer nodes)
- Only v5 (consensus layer nodes)
- Both v4 and v5 (modern execution layer nodes)
The node is identified by its node ID which is consistent across protocols.
func NewFromV5 ¶
func NewFromV5(v5 *discv5node.Node, nodedb *NodeDB) *Node
NewFromV5 creates a generic Node from a discv5 node.
func (*Node) CalculateScore ¶
func (n *Node) CalculateScore(forkInfo *ForkScoringInfo) float64
CalculateScore computes a quality score for the node. Delegates to the v5 node if available.
func (*Node) ClearDirtyFlags ¶
func (n *Node) ClearDirtyFlags()
ClearDirtyFlags clears all dirty flags.
func (*Node) FailureCount ¶
FailureCount returns the number of failed communications.
func (*Node) GetDirtyFlags ¶
func (n *Node) GetDirtyFlags() DirtyFlags
GetDirtyFlags returns and clears the dirty flags atomically.
func (*Node) IncrementFailure ¶
func (n *Node) IncrementFailure()
IncrementFailure increments the failure counter.
func (*Node) IncrementFailureCount ¶
func (n *Node) IncrementFailureCount()
IncrementFailureCount increments the failure counter. Alias for IncrementFailure for consistency with other packages.
func (*Node) IncrementSuccess ¶
func (n *Node) IncrementSuccess()
IncrementSuccess increments the success counter and updates last seen.
func (*Node) IsAlive ¶
IsAlive checks if the node is considered alive. A node is alive if it has been seen recently and has acceptable failure rate.
func (*Node) LastActive ¶
LastActive returns the last active timestamp.
func (*Node) MarkDirty ¶
func (n *Node) MarkDirty(flags DirtyFlags)
MarkDirty marks specific fields as dirty (needing database update).
func (*Node) PeerID ¶
PeerID returns the libp2p peer ID for this node. Delegates to the v5 node if available, otherwise builds it from the public key.
func (*Node) ResetFailureCount ¶
func (n *Node) ResetFailureCount()
ResetFailureCount resets the failure count to 0 and increments the success count.
func (*Node) SetFailureCount ¶
SetFailureCount sets the failure count.
func (*Node) SetFirstSeen ¶
SetFirstSeen sets the first seen timestamp.
func (*Node) SetLastActive ¶
SetLastActive sets the last active timestamp and marks it dirty.
func (*Node) SetLastPing ¶
SetLastPing updates the last ping time.
func (*Node) SetLastSeen ¶
SetLastSeen updates the last seen timestamp.
func (*Node) SetSuccessCount ¶
SetSuccessCount sets the success count.
func (*Node) SetV5 ¶
func (n *Node) SetV5(v5 *discv5node.Node)
SetV5 sets the discv5 node and marks protocol support dirty.
func (*Node) SuccessCount ¶
SuccessCount returns the number of successful communications.
func (*Node) UpdateENR ¶
UpdateENR updates the node's ENR record if the new one has a higher sequence number. Returns true if the record was updated.
func (*Node) UpdateLastSeen ¶
func (n *Node) UpdateLastSeen()
UpdateLastSeen updates the last seen timestamp to now.
type NodeChangedCallback ¶
type NodeChangedCallback func(*Node)
NodeChangedCallback is called when a node is added or updated in the table.
type NodeDB ¶
type NodeDB struct {
// contains filtered or unexported fields
}
NodeDB wraps the Database and provides node storage with async updates. It operates on either el or cl table based on the layer configuration.
func NewNodeDB ¶
func NewNodeDB(ctx context.Context, database *db.Database, layer db.NodeLayer, logger logrus.FieldLogger) *NodeDB
NewNodeDB creates a new node database wrapper for the specified layer. layer should be either db.LayerEL or db.LayerCL.
func (*NodeDB) Close ¶
func (ndb *NodeDB) Close()
Close stops the update queue processor and waits for pending updates.
func (*NodeDB) GetStats ¶
func (ndb *NodeDB) GetStats() NodeDBStats
GetStats returns current database statistics.
func (*NodeDB) LoadInactiveNodes ¶
LoadInactiveNodes loads inactive nodes (not seen recently).
func (*NodeDB) LoadRandom ¶
LoadRandom loads a random sample of nodes (up to limit).
func (*NodeDB) LoadRandomNodes ¶
LoadRandomNodes loads a random sample of nodes (alias for LoadRandom).
func (*NodeDB) QueueUpdate ¶
QueueUpdate queues a node for database update. The node's dirty flags determine what gets updated.
type NodeDBStats ¶
type NodeDBStats struct {
QueueSize int // Current number of pending updates in queue
ProcessedUpdates int64 // Total updates processed
MergedUpdates int64 // Total updates merged with existing pending
FailedUpdates int64 // Total updates that failed
Transactions int64 // Total database transactions executed
TotalQueries int64 // Total database queries executed
OpenConnections int // Current number of open DB connections
}
NodeDBStats contains statistics about database operations.