PeerInfo
Type-safe structure for connected peer information returned byadmin_peers RPC method.
Overview
PeerInfo represents metadata about a connected Ethereum peer, including identity, capabilities, network connection details, and protocol-specific state. This data is returned by the admin_peers RPC method available in Geth and compatible clients.
Quick Start
- Basic Usage
- RPC Fetch
- Peer Analysis
Copy
Ask AI
import * as PeerInfo from '@tevm/voltaire/PeerInfo'
// Parse peer info from RPC response
const peerInfo = PeerInfo.from({
id: "enode://[email protected]:30303",
name: "Geth/v1.13.0-stable/linux-amd64/go1.21.0",
caps: ["eth/67", "eth/68", "snap/1"],
network: {
localAddress: "192.168.1.1:30303",
remoteAddress: "192.168.1.100:30303",
inbound: false,
trusted: false,
static: true
},
protocols: {
eth: {
version: 68,
difficulty: 58750003716598352816469n,
head: "0x1234..."
}
}
})
// Check capabilities
PeerInfo.hasCapability(peerInfo, "eth/68") // true
PeerInfo.hasCapability(peerInfo, "snap/1") // true
// Check connection direction
PeerInfo.isInbound(peerInfo) // false
Copy
Ask AI
import * as PeerInfo from '@tevm/voltaire/PeerInfo'
async function getConnectedPeers(rpcUrl: string) {
const response = await fetch(rpcUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'admin_peers',
params: [],
id: 1
})
})
const { result } = await response.json()
return result.map(PeerInfo.from)
}
const peers = await getConnectedPeers('http://localhost:8545')
console.log(`Connected to ${peers.length} peers`)
Copy
Ask AI
import * as PeerInfo from '@tevm/voltaire/PeerInfo'
function analyzePeers(peers: PeerInfo.PeerInfoType[]) {
return {
total: peers.length,
inbound: peers.filter(p => PeerInfo.isInbound(p)).length,
outbound: peers.filter(p => !PeerInfo.isInbound(p)).length,
withSnap: peers.filter(p => PeerInfo.hasCapability(p, "snap/1")).length,
clients: countClients(peers)
}
}
function countClients(peers: PeerInfo.PeerInfoType[]) {
const counts: Record<string, number> = {}
for (const peer of peers) {
const client = peer.name.split('/')[0]
counts[client] = (counts[client] || 0) + 1
}
return counts
}
Type Definition
Copy
Ask AI
type PeerInfoType = {
/** Peer ID (enode URL) */
readonly id: PeerIdType
/** Remote client identifier */
readonly name: string
/** Supported capabilities (e.g., ["eth/67", "snap/1"]) */
readonly caps: readonly string[]
/** Network connection information */
readonly network: {
/** Local endpoint (IP:PORT) */
readonly localAddress: string
/** Remote endpoint (IP:PORT) */
readonly remoteAddress: string
/** True if inbound connection */
readonly inbound: boolean
/** True if trusted peer */
readonly trusted: boolean
/** True if static node */
readonly static: boolean
}
/** Protocol-specific information */
readonly protocols: {
/** Ethereum protocol info */
readonly eth?: {
readonly version: ProtocolVersionType
readonly difficulty: BrandedUint
readonly head: BlockHashType
}
readonly [protocol: string]: unknown
}
}
API Reference
Constructors
Copy
Ask AI
import * as PeerInfo from '@tevm/voltaire/PeerInfo'
// From RPC response object
const peerInfo = PeerInfo.from(rpcResponse)
Methods
Copy
Ask AI
import * as PeerInfo from '@tevm/voltaire/PeerInfo'
const peerInfo = PeerInfo.from(data)
// Check if peer supports a capability
PeerInfo.hasCapability(peerInfo, "eth/68") // boolean
PeerInfo.hasCapability(peerInfo, "snap/1") // boolean
// Check connection direction
PeerInfo.isInbound(peerInfo) // boolean
Peer Properties
Capabilities
Thecaps array lists protocols the peer supports:
Copy
Ask AI
peerInfo.caps
// ["eth/66", "eth/67", "eth/68", "snap/1"]
// Common capabilities:
// eth/66, eth/67, eth/68 - Ethereum wire protocol versions
// snap/1 - Snap sync protocol
// les/4 - Light client protocol
// wit/0 - Witness protocol
Network Information
Copy
Ask AI
peerInfo.network.localAddress // "192.168.1.1:30303"
peerInfo.network.remoteAddress // "203.0.113.50:30303"
peerInfo.network.inbound // true if they connected to us
peerInfo.network.trusted // true if in trusted peers list
peerInfo.network.static // true if in static nodes list
Client Name
Copy
Ask AI
peerInfo.name
// "Geth/v1.13.0-stable/linux-amd64/go1.21.0"
// "Nethermind/v1.21.0/linux-x64/dotnet7.0.11"
// "Erigon/v2.55.0/linux-amd64/go1.21.0"
Protocol State
Copy
Ask AI
const eth = peerInfo.protocols.eth
eth?.version // Protocol version (e.g., 68)
eth?.difficulty // Peer's total difficulty
eth?.head // Peer's head block hash
Use Cases
Peer Monitoring Dashboard
Copy
Ask AI
import * as PeerInfo from '@tevm/voltaire/PeerInfo'
interface PeerStats {
totalPeers: number
inboundCount: number
outboundCount: number
clientDistribution: Record<string, number>
protocolSupport: Record<string, number>
}
async function getPeerStats(rpcUrl: string): Promise<PeerStats> {
const response = await fetch(rpcUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'admin_peers',
params: [],
id: 1
})
})
const { result } = await response.json()
const peers = result.map(PeerInfo.from)
const clientDist: Record<string, number> = {}
const protocolSupport: Record<string, number> = {}
for (const peer of peers) {
// Count clients
const client = peer.name.split('/')[0]
clientDist[client] = (clientDist[client] || 0) + 1
// Count protocol support
for (const cap of peer.caps) {
protocolSupport[cap] = (protocolSupport[cap] || 0) + 1
}
}
return {
totalPeers: peers.length,
inboundCount: peers.filter(p => PeerInfo.isInbound(p)).length,
outboundCount: peers.filter(p => !PeerInfo.isInbound(p)).length,
clientDistribution: clientDist,
protocolSupport
}
}
Filter Peers by Capability
Copy
Ask AI
import * as PeerInfo from '@tevm/voltaire/PeerInfo'
function getPeersWithCapability(
peers: PeerInfo.PeerInfoType[],
capability: string
): PeerInfo.PeerInfoType[] {
return peers.filter(p => PeerInfo.hasCapability(p, capability))
}
// Get peers that support snap sync
const snapPeers = getPeersWithCapability(peers, "snap/1")
// Get peers with latest eth protocol
const eth68Peers = getPeersWithCapability(peers, "eth/68")
Identify Sync Partners
Copy
Ask AI
import * as PeerInfo from '@tevm/voltaire/PeerInfo'
function findBestSyncPeers(
peers: PeerInfo.PeerInfoType[],
count: number = 5
): PeerInfo.PeerInfoType[] {
// Filter peers with eth protocol info
const ethPeers = peers.filter(p => p.protocols.eth)
// Sort by total difficulty (highest first)
ethPeers.sort((a, b) => {
const diffA = a.protocols.eth?.difficulty ?? 0n
const diffB = b.protocols.eth?.difficulty ?? 0n
return diffB > diffA ? 1 : diffB < diffA ? -1 : 0
})
// Return top N peers
return ethPeers.slice(0, count)
}
Connection Health Check
Copy
Ask AI
import * as PeerInfo from '@tevm/voltaire/PeerInfo'
interface ConnectionHealth {
healthy: boolean
issues: string[]
}
function checkConnectionHealth(
peers: PeerInfo.PeerInfoType[]
): ConnectionHealth {
const issues: string[] = []
// Check peer count
if (peers.length < 3) {
issues.push(`Low peer count: ${peers.length}`)
}
// Check inbound/outbound balance
const inbound = peers.filter(p => PeerInfo.isInbound(p)).length
const outbound = peers.length - inbound
if (inbound === 0) {
issues.push('No inbound connections (may be behind NAT)')
}
// Check client diversity
const clients = new Set(peers.map(p => p.name.split('/')[0]))
if (clients.size < 2 && peers.length > 5) {
issues.push('Low client diversity')
}
// Check protocol support
const eth68Support = peers.filter(p =>
PeerInfo.hasCapability(p, "eth/68")
).length
if (eth68Support === 0) {
issues.push('No peers support eth/68 protocol')
}
return {
healthy: issues.length === 0,
issues
}
}
Related
- PeerId - Peer identifiers (enode URLs)
- NodeInfo - Local node information
- NetworkId - Network identifiers
References
- Geth admin_peers - RPC documentation
- devp2p Protocol - P2P networking
- Ethereum Wire Protocol - eth protocol spec

