Skip to content

Discovery

Discovery protocols are essential for blockchain P2P networks as they enable nodes to find and connect to each other without needing pre-configured addresses. This chapter provides comprehensive coverage of how blockchain nodes discover peers, including Ethereum’s DiscV5, DNS discovery, and bootnode infrastructure.


┌─────────────────────────────────────────────────────────────────────────────┐
│ DISCOVERY PROTOCOLS │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ DISCV5 (Discovery V5) │ │
│ │ │ │
│ │ • Current Ethereum discovery protocol │ │
│ │ • Kademlia-based DHT │ │
│ │ • Supports topic advertisement │ │
│ │ • ENR-based node records │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ DNS DISCOVERY │ │
│ │ │ │
│ │ • Domain name-based node lists │ │
│ │ • Used by many blockchain networks │ │
│ │ • Reliable and easy to maintain │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ BOOTNODES │ │
│ │ │ │
│ │ • Pre-configured trusted nodes │ │
│ │ • Entry point for new nodes │ │
│ │ • Fallback when DHT fails │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
MethodTypeComplexityReliabilityUse Case
DiscV5DHTHighHighEthereum mainnet
DNS DiscoveryStaticLowVery HighAll networks
BootnodesStaticLowHighAll networks
Static PeersManualVery LowMediumPrivate networks

┌─────────────────────────────────────────────────────────────────┐
│ DISCV5 KADEMLIA DHT │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Each node has a unique node ID (256-bit random number) │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ KADEMLIA TABLE (k-buckets) │ │
│ │ │ │
│ │ Bucket 0: Nodes with very similar ID (distance 0-1) │ │
│ │ Bucket 1: Nodes with distance 1-2 │ │
│ │ Bucket 2: Nodes with distance 2-4 │ │
│ │ ... │ │
│ │ Bucket 255: Nodes with very different ID │ │
│ │ │ │
│ │ Each bucket holds up to k=16 nodes │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ FIND NODE Request: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 1. Calculate distance between my ID and target ID │ │
│ │ 2. Query closest nodes in relevant buckets │ │
│ │ 3. Repeat with closer nodes until can't find closer │ │
│ │ 4. Return k closest nodes found │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Terminal window
# Enable DiscV5 on Geth
geth \
--mainnet \
--v5disc \
--discv5.listenaddr "0.0.0.0:30303" \
--discv5.discoverylimit 100 \
--discv5.enr "true" \
--discv5.netrestrict "10.0.0.0/8"
# Check DiscV5 status via RPC
# eth.nodeInfo returns ENR with discv5 info
# Lighthouse (Ethereum consensus)
lighthouse beacon_node \
--network mainnet \
--enr-auto-update \
--discv5 true \
--discv5-port 9000 \
--discv5-ip 0.0.0.0
┌─────────────────────────────────────────────────────────────────┐
│ ENR STRUCTURE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ENR is a signed, self-certifying record containing: │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ REQUIRED FIELDS: │ │
│ │ ─────────────────── │ │
│ │ - seq: Sequence number (incremented on each update) │ │
│ │ - id: Protocol identifier (e.g., "v4") │ │
│ │ - secp256k1: Compressed public key │ │
│ │ - ip: IPv4 address │ │
│ │ - tcp: TCP port (optional) │ │
│ │ - udp: UDP port (optional) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ COMMON OPTIONAL FIELDS: │ │
│ │ ──────────────────────── │ │
│ │ - ip6: IPv6 address │ │
│ │ - tcp6: IPv6 TCP port │ │
│ │ - udp6: IPv6 UDP port │ │
│ │ - eth: Ethereum chain data │ │
│ │ - chainId: Chain identifier │ │
│ │ - network: Network ID │ │
│ │ - genesis: Genesis hash │ │
│ │ - forkId: Current fork identifier │ │
│ │ - attnets: Attestation subnet bits │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ Example ENR: │
│ ━━━━━━━━━━━━ │
│ enr:-KG4QOtcL...@bootnode.mainnet.ethdisco.net:30303 │
│ │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ DNS DISCOVERY WORKFLOW │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐
│ │ New │ │ DNS │
│ │ Node │ │ Server │
│ └────┬─────┘ └────┬─────┘
│ │ │
│ │ 1. Query DNS for ethereum nodes │
│ │─────────────────────────────────────────────────────▶│
│ │ │
│ │ 2. Return list of ENR records │
│ │◀────────────────────────────────────────────────────│
│ │ │
│ │ 3. Connect to discovered nodes │
│ │─────────────────────────────────────────────────────▶│
│ │ │
│ DNS Records: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ nodes.ethereum.org IN TXT "enr:-I..@1.2.3.4:30303" │ │
│ │ nodes.ethereum.org IN TXT "enr:-I..@5.6.7.8:30303" │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Terminal window
# Geth with DNS discovery
geth \
--mainnet \
--discovery.dns "nodes.ethereum.org" \
--dns.anchors "enr:-Iu4..."
# Use multiple DNS servers
geth \
--mainnet \
--discovery.dns "dns1.example.com,dns2.example.com"
# Custom DNS configuration
geth \
--mainnet \
--discovery.dns "my-nodes.example.com" \
--discovery.dnsseg "nodes"
# TXT record format
# v=1; e=<ENR-base64>; ip=<IPv4>; ip6=<IPv6>; tcp=<port>; udp=<port>
# Example
nodes.example.com IN TXT "v=1; e=nP3Z...; ip=1.2.3.4; tcp=30303; udp=30303"

┌─────────────────────────────────────────────────────────────────┐
│ BOOTNODE ARCHITECTURE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Bootnodes serve as entry points to the P2P network: │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ NEW NODE │ │
│ │ (has no peers) │ │
│ └────────────────────────┬────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ BOOTNODE │ │
│ │ (well-known, always online) │ │
│ │ │ │
│ │ Mainnet Bootnodes: │ │
│ │ ┌────────────────────────────────────────────────┐ │ │
│ │ │ enr:-KG4QO...@bootnode1.ethdisco.net:30303 │ │ │
│ │ │ enr:-L4sU...@bootnode2.ethdisco.net:30303 │ │ │
│ │ │ enr:-LK4UC...@bootnode3.ethdisco.net:30303 │ │ │
│ │ └────────────────────────────────────────────────┘ │ │
│ └────────────────────────┬────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ FULL P2P NETWORK │ │
│ │ │ │
│ │ New node now has peers and can continue discovering │ │
│ │ more peers through the network │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Terminal window
# Default bootnodes (built into client)
geth --mainnet
# Custom bootnodes
geth \
--mainnet \
--bootnodes "enr:-KG4QO...@1.2.3.4:30303,enr:-LK4UC...@5.6.7.8:30303"
# Bootnodes for different networks
# Goerli
geth --goerli --bootnodes "enr:-K64Q..."
# Sepolia
geth --sepolia --bootnodes "enr:-MS4L..."
# Run your own bootnode
bootnode \
--nodekey /path/to/nodekey \
--addr 0.0.0.0:30303 \
--writeaddress # Print ENR to use
NetworkDNS DiscoveryENR List
Ethereum Mainnetnodes.ethereum.orgethdisco.net
Goerlinodes.goerli.ethdevops.io-
Sepolianodes.sepolia.ethdevops.io-

Terminal window
# Check if node is discoverable
geth attach http://localhost:8545
# Then run:
admin.nodeInfo.enr
# Check connected peers
eth.peerCount
# Check discovery service logs
journalctl -u geth | grep -i discv5
journalctl -u geth | grep -i discovery
# Test DNS resolution
dig nodes.ethereum.org
nslookup bootnode.mainnet.ethdisco.net
IssueCauseSolution
No peers foundDiscovery disabledEnable --v5disc or --discovery.dns
Firewall blockingUDP blockedAllow UDP 30303
Wrong networkUsing testnet bootnodes on mainnetUse correct bootnode list
NAT issuePort not forwardedConfigure port forwarding

QuestionAnswer
What is DiscV5?Ethereum’s Kademlia-based discovery protocol
What is an ENR?Ethereum Node Record - self-certifying node metadata
How do bootnodes work?Pre-configured nodes that new nodes connect to initially
What is DNS discovery?Using DNS TXT records to find node ENR addresses
Why is peer discovery important?Enables decentralized network without central servers

  • DiscV5 is the primary Ethereum discovery protocol
  • DNS discovery provides reliable fallback
  • Bootnodes are essential for network entry
  • ENR contains all node metadata
  • Proper configuration ensures good network connectivity

In Chapter 25: Network Ports & Firewall Configuration, we’ll explore port configuration and security.


Last Updated: 2026-02-20