Documentation
¶
Overview ¶
Package protocol implements the Discovery v4 wire protocol.
The discv4 protocol uses UDP packets with the following structure:
- MAC (32 bytes): Keccak256 hash of signature + packet data
- Signature (65 bytes): ECDSA signature over packet hash
- Packet type (1 byte): Message type identifier
- RLP-encoded message data
Total header size: 97 bytes (32 + 65)
Index ¶
- Constants
- Variables
- func Decode(input []byte) (Packet, Pubkey, []byte, error)
- func DecodePubkey(curve elliptic.Curve, p Pubkey) (*ecdsa.PublicKey, error)
- func Encode(priv *ecdsa.PrivateKey, req Packet) (packet, hash []byte, err error)
- func EncodePacket(priv *ecdsa.PrivateKey, req Packet) ([]byte, error)
- func Expired(ts uint64) bool
- func MakeExpiration(d time.Duration) uint64
- type ENRRequest
- type ENRResponse
- type Endpoint
- type Findnode
- type Handler
- func (h *Handler) AllNodes() []*node.Node
- func (h *Handler) Findnode(n *node.Node, target []byte) ([]*node.Node, error)
- func (h *Handler) GetNode(id node.ID) *node.Node
- func (h *Handler) HandlePacket(data []byte, from *net.UDPAddr, localAddr *net.UDPAddr) (err error)
- func (h *Handler) Ping(n *node.Node) (*Pong, error)
- func (h *Handler) RequestENR(n *node.Node) (*enr.Record, error)
- func (h *Handler) Stats() map[string]interface{}
- type HandlerConfig
- type Neighbors
- type NodeRecord
- type OnENRRequestCallback
- type OnFindnodeCallback
- type OnNodeSeenCallback
- type OnPingCallback
- type OnPongReceivedCallback
- type Packet
- type PendingNeighborsResponse
- type PendingRequest
- type Ping
- type Pong
- type Pubkey
- type Transport
Constants ¶
const ( PingPacket = iota + 1 // zero is reserved PongPacket FindnodePacket NeighborsPacket ENRRequestPacket ENRResponsePacket )
Packet type constants
const MaxNeighbors = 12
MaxNeighbors is the maximum number of nodes in a Neighbors packet. This limit ensures packets fit within the 1280 byte MTU.
Variables ¶
var ( // ErrPacketTooSmall is returned when a packet is smaller than the minimum size ErrPacketTooSmall = errors.New("packet too small") // ErrBadHash is returned when the MAC hash doesn't match ErrBadHash = errors.New("bad hash") // ErrBadSignature is returned when signature recovery fails ErrBadSignature = errors.New("bad signature") // ErrUnknownPacket is returned for unknown packet types ErrUnknownPacket = errors.New("unknown packet type") // ErrExpired is returned when a packet has expired ErrExpired = errors.New("packet expired") )
Functions ¶
func Decode ¶
Decode decodes a discv4 UDP packet.
Returns:
- packet: The decoded packet message
- fromKey: The sender's public key (64 bytes, uncompressed without 0x04)
- hash: The packet hash (used as reply token)
- error: Any decoding error
The packet structure is:
[MAC 32][Signature 65][Type 1][RLP Data...]
func DecodePubkey ¶
DecodePubkey decodes a wire-format public key to ECDSA format.
func Encode ¶
func Encode(priv *ecdsa.PrivateKey, req Packet) (packet, hash []byte, err error)
Encode encodes a discv4 packet with signature.
Returns:
- packet: The complete encoded packet
- hash: The packet hash (used as reply token)
- error: Any encoding error
The packet structure is:
[MAC 32][Signature 65][Type 1][RLP Data...]
func EncodePacket ¶
func EncodePacket(priv *ecdsa.PrivateKey, req Packet) ([]byte, error)
EncodePacket is a convenience function to encode a packet.
This is useful when you just need the packet bytes without the hash.
func MakeExpiration ¶
MakeExpiration creates an expiration timestamp for the given duration from now.
Types ¶
type ENRRequest ¶
type ENRRequest struct {
// Expiration is the UNIX timestamp when this packet expires
Expiration uint64
// Rest allows forward compatibility
Rest []rlp.RawValue `rlp:"tail"`
}
ENRRequest represents an ENRREQUEST message.
ENRRequest queries for the node's current ENR record. This allows nodes to retrieve updated ENR information (added by EIP-868).
type ENRResponse ¶
type ENRResponse struct {
// ReplyTok is the hash of the ENRREQUEST packet we're responding to
ReplyTok []byte
// Record is the sender's ENR record
Record *enr.Record
// Rest allows forward compatibility
Rest []rlp.RawValue `rlp:"tail"`
}
ENRResponse represents an ENRRESPONSE message (reply to ENRREQUEST).
ENRResponse contains the node's current ENR record.
type Endpoint ¶
type Endpoint struct {
// IP is the IP address (4 bytes for IPv4, 16 for IPv6)
IP net.IP
// UDP is the UDP port
UDP uint16
// TCP is the TCP port
TCP uint16
}
Endpoint represents a network endpoint.
This is used in PING/PONG messages to communicate address information.
func NewEndpoint ¶
NewEndpoint creates an endpoint from a UDP address.
type Findnode ¶
type Findnode struct {
// Target is the public key we're searching for neighbors of
// The response should contain nodes close to this target
Target Pubkey
// Expiration is the UNIX timestamp when this packet expires
Expiration uint64
// Rest allows forward compatibility
Rest []rlp.RawValue `rlp:"tail"`
}
Findnode represents a FINDNODE request.
Findnode queries for nodes close to a target in the Kademlia DHT. The sender must have an active bond (recent PING/PONG exchange) before the recipient will respond.
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler handles incoming and outgoing discv4 protocol messages.
The handler is responsible for:
- Encoding/decoding packets
- Processing PING, PONG, FINDNODE, NEIGHBORS, ENRREQUEST, ENRRESPONSE
- Bond tracking and validation
- Request/response matching
- Callbacks for application logic
func NewHandler ¶
func NewHandler(ctx context.Context, config HandlerConfig, transport Transport) *Handler
NewHandler creates a new protocol handler.
func (*Handler) HandlePacket ¶
HandlePacket processes an incoming UDP packet.
This is called by the transport layer when a packet is received. The localAddr parameter is the local address that received the packet.
func (*Handler) RequestENR ¶
RequestENR sends an ENRREQUEST to a node.
type HandlerConfig ¶
type HandlerConfig struct {
// PrivateKey is our node's private key
PrivateKey *ecdsa.PrivateKey
// LocalENR is our node's ENR record (optional)
LocalENR *enr.Record
// LocalAddr is our listening address
LocalAddr *net.UDPAddr
// BondExpiration is how long bonds last (default 24 hours)
BondExpiration time.Duration
// RequestTimeout is how long to wait for responses (default 500ms)
RequestTimeout time.Duration
// ExpirationWindow is the acceptable time range for packet expiration (default 20s)
ExpirationWindow time.Duration
// Callbacks (all optional)
OnPing OnPingCallback
OnPongReceived OnPongReceivedCallback
OnFindnode OnFindnodeCallback
OnENRRequest OnENRRequestCallback
OnNodeSeen OnNodeSeenCallback
}
HandlerConfig contains configuration for the protocol handler.
type Neighbors ¶
type Neighbors struct {
// Nodes is the list of nodes close to the target
Nodes []NodeRecord
// Expiration is the UNIX timestamp when this packet expires
Expiration uint64
// Rest allows forward compatibility
Rest []rlp.RawValue `rlp:"tail"`
}
Neighbors represents a NEIGHBORS response (reply to FINDNODE).
Neighbors contains up to 12 node records. If more nodes need to be sent, multiple Neighbors packets are used.
type NodeRecord ¶
type NodeRecord struct {
// IP is the node's IP address (4 bytes for IPv4, 16 for IPv6)
IP net.IP
// UDP is the UDP port for discovery
UDP uint16
// TCP is the TCP port for RLPx
TCP uint16
// ID is the node's public key
ID Pubkey
}
NodeRecord represents information about a node in the DHT.
This is used in NEIGHBORS responses to communicate node information.
type OnENRRequestCallback ¶
OnENRRequestCallback is called when an ENRREQUEST is received.
type OnFindnodeCallback ¶
OnFindnodeCallback is called when a FINDNODE request is received. Returns the list of nodes to include in the response.
type OnNodeSeenCallback ¶
OnNodeSeenCallback is called when we receive any valid packet from a node.
type OnPingCallback ¶
OnPingCallback is called when a PING request is received.
type OnPongReceivedCallback ¶
OnPongReceivedCallback is called when a PONG response is received. The ip and port parameters contain our external address as seen by the remote peer.
type Packet ¶
type Packet interface {
// Name returns the packet name for logging
Name() string
// Kind returns the packet type byte
Kind() byte
}
Packet is the interface for all discv4 messages.
func DecodePacket ¶
DecodePacket is a convenience function to decode a packet.
This is useful when you don't need the sender key or hash.
type PendingNeighborsResponse ¶
type PendingNeighborsResponse struct {
// Nodes accumulated so far
Nodes []*node.Node
// CreatedAt is when we received the first packet
CreatedAt time.Time
// LastRecv is when we received the last packet
LastRecv time.Time
}
PendingNeighborsResponse tracks a multi-packet NEIGHBORS response.
type PendingRequest ¶
type PendingRequest struct {
// RequestHash is the hash of the outgoing packet (used as reply token)
RequestHash []byte
// ToNode is the destination node
ToNode *node.Node
// PacketType is the type of request
PacketType byte
// CreatedAt is when the request was created
CreatedAt time.Time
// Timeout is when the request expires
Timeout time.Time
// ResponseChan receives the response (or nil on timeout)
ResponseChan chan interface{}
}
PendingRequest tracks an outgoing request waiting for a response.
type Ping ¶
type Ping struct {
// Version is the discovery protocol version (currently 4)
Version uint
// From is the sender's endpoint information
From Endpoint
// To is the recipient's endpoint (as known by sender)
To Endpoint
// Expiration is the UNIX timestamp when this packet expires
Expiration uint64
// ENRSeq is the sender's ENR sequence number (optional, EIP-868)
ENRSeq uint64 `rlp:"optional"`
// Rest allows forward compatibility with future fields
Rest []rlp.RawValue `rlp:"tail"`
}
Ping represents a PING message.
Ping is used for:
- Liveness check
- Endpoint verification (NAT detection)
- Establishing bonds before FINDNODE
- ENR sequence number exchange (EIP-868)
type Pong ¶
type Pong struct {
// To is the recipient's endpoint as seen by the sender
// This allows the recipient to discover their external address
To Endpoint
// ReplyTok is the hash of the PING packet we're responding to
// This allows the requester to match PONG to PING
ReplyTok []byte
// Expiration is the UNIX timestamp when this packet expires
Expiration uint64
// ENRSeq is the sender's ENR sequence number (optional, EIP-868)
ENRSeq uint64 `rlp:"optional"`
// Rest allows forward compatibility
Rest []rlp.RawValue `rlp:"tail"`
}
Pong represents a PONG message (reply to PING).
Pong is used to:
- Confirm liveness
- Report the sender's external IP/port (for NAT traversal)
- Establish a bond with the requester
- Exchange ENR sequence numbers
type Pubkey ¶
type Pubkey [64]byte
Pubkey represents an encoded 64-byte secp256k1 public key.
This is the uncompressed public key format (X and Y coordinates, 32 bytes each) without the 0x04 prefix.
func EncodePubkey ¶
EncodePubkey encodes an ECDSA public key to the wire format.