> ## Documentation Index
> Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# PeerInfo

> Connected peer information from admin_peers RPC

# PeerInfo

Type-safe structure for connected peer information returned by `admin_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

<Tabs>
  <Tab title="Basic Usage">
    ```typescript theme={null}
    import * as PeerInfo from '@tevm/voltaire/PeerInfo'

    // Parse peer info from RPC response
    const peerInfo = PeerInfo.from({
      id: "enode://abc123...@192.168.1.100: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
    ```
  </Tab>

  <Tab title="RPC Fetch">
    ```typescript theme={null}
    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`)
    ```
  </Tab>

  <Tab title="Peer Analysis">
    ```typescript theme={null}
    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
    }
    ```
  </Tab>
</Tabs>

## Type Definition

```typescript theme={null}
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

```typescript theme={null}
import * as PeerInfo from '@tevm/voltaire/PeerInfo'

// From RPC response object
const peerInfo = PeerInfo.from(rpcResponse)
```

### Methods

```typescript theme={null}
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

The `caps` array lists protocols the peer supports:

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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](/primitives/peer-id) - Peer identifiers (enode URLs)
* [NodeInfo](/primitives/node-info) - Local node information
* [NetworkId](/primitives/network-id) - Network identifiers

## References

* [Geth admin\_peers](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-admin#admin-peers) - RPC documentation
* [devp2p Protocol](https://github.com/ethereum/devp2p) - P2P networking
* [Ethereum Wire Protocol](https://github.com/ethereum/devp2p/blob/master/caps/eth.md) - eth protocol spec
