> ## 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.

# PeerId

> Ethereum peer identifiers (enode URLs) for P2P networking

# PeerId

Type-safe Ethereum peer identifiers (enode URLs) for peer-to-peer networking.

## Overview

[Branded](/getting-started/branded-types) `string` type representing an Ethereum peer identifier in enode URL format. Enode URLs uniquely identify Ethereum nodes on the P2P network and contain the node's public key, IP address, and connection ports.

## Quick Start

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

    const enode = "enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@10.3.58.6:30303"

    // Create peer ID
    const peerId = PeerId.from(enode)

    // Convert to string
    PeerId.toString(peerId)  // Returns the enode URL

    // Compare peer IDs
    const other = PeerId.from(enode)
    PeerId.equals(peerId, other)  // true
    ```
  </Tab>

  <Tab title="Parse Enode">
    ```typescript theme={null}
    import * as PeerId from '@tevm/voltaire/PeerId'

    const enode = "enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@10.3.58.6:30303?discport=30301"

    const peerId = PeerId.from(enode)
    const components = PeerId.parse(peerId)

    console.log(components)
    // {
    //   publicKey: "6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0",
    //   ip: "10.3.58.6",
    //   port: 30303,
    //   discoveryPort: 30301
    // }
    ```
  </Tab>

  <Tab title="Bootnode Connection">
    ```typescript theme={null}
    import * as PeerId from '@tevm/voltaire/PeerId'

    // Mainnet bootnodes
    const MAINNET_BOOTNODES = [
      "enode://d860a01f9722d78051619d1e2351aba3f43f943f6f00718d1b9baa4101932a1f5011f16bb2b1bb35db20d6fe28fa0bf09636d26a87d31de9ec6203eeedb1f666@18.138.108.67:30303",
      "enode://22a8232c3abc76a16ae9d6c3b164f98775fe226f0917b0ca871128a74a8e9630b458460865bab457221f1d448dd9791d24c4e5d88786180ac185df813a68d4de@3.209.45.79:30303"
    ]

    // Connect to bootnodes
    for (const bootnode of MAINNET_BOOTNODES) {
      const peerId = PeerId.from(bootnode)
      const { ip, port } = PeerId.parse(peerId)
      console.log(`Connecting to ${ip}:${port}`)
    }
    ```
  </Tab>
</Tabs>

## Enode URL Format

```
enode://<node-id>@<ip>:<port>?discport=<discovery-port>
```

| Component  | Description                       | Example           |
| ---------- | --------------------------------- | ----------------- |
| `node-id`  | 128-char hex secp256k1 public key | `6f8a80d14311...` |
| `ip`       | IPv4 or IPv6 address              | `10.3.58.6`       |
| `port`     | TCP port for RLPx                 | `30303`           |
| `discport` | UDP port for discovery (optional) | `30301`           |

## Type Definitions

```typescript theme={null}
// Branded peer ID type
type PeerIdType = string & { readonly [brand]: "PeerId" }

// Parsed enode components
type EnodeComponents = {
  /** Node public key (128 hex chars) */
  readonly publicKey: string
  /** IP address (IPv4 or IPv6) */
  readonly ip: string
  /** TCP port for RLPx */
  readonly port: number
  /** UDP port for discovery (optional) */
  readonly discoveryPort?: number
}
```

## API Reference

### Constructors

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

// From enode URL string
const peerId = PeerId.from("enode://abc123...@192.168.1.1:30303")
```

### Methods

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

const peerId = PeerId.from(enodeUrl)

// Convert to string
PeerId.toString(peerId)  // Returns enode URL

// Parse into components
PeerId.parse(peerId)     // Returns EnodeComponents

// Equality check
PeerId.equals(peerId, otherPeerId)  // boolean
```

## Use Cases

### Node Discovery

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

// Parse discovered node info
function parseDiscoveredNode(enodeUrl: string) {
  const peerId = PeerId.from(enodeUrl)
  const { publicKey, ip, port, discoveryPort } = PeerId.parse(peerId)

  return {
    nodeId: publicKey,
    endpoint: `${ip}:${port}`,
    discoveryEndpoint: discoveryPort ? `${ip}:${discoveryPort}` : `${ip}:${port}`
  }
}
```

### Peer Management

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

class PeerList {
  private peers: Map<string, PeerId.PeerIdType> = new Map()

  add(enodeUrl: string): void {
    const peerId = PeerId.from(enodeUrl)
    const { publicKey } = PeerId.parse(peerId)
    this.peers.set(publicKey, peerId)
  }

  has(enodeUrl: string): boolean {
    const peerId = PeerId.from(enodeUrl)
    for (const existing of this.peers.values()) {
      if (PeerId.equals(existing, peerId)) {
        return true
      }
    }
    return false
  }

  getByPublicKey(publicKey: string): PeerId.PeerIdType | undefined {
    return this.peers.get(publicKey)
  }

  list(): string[] {
    return Array.from(this.peers.values()).map(PeerId.toString)
  }
}
```

### Static Node Configuration

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

// Geth static-nodes.json format
const staticNodes = [
  "enode://abc123...@192.168.1.10:30303",
  "enode://def456...@192.168.1.11:30303"
]

function validateStaticNodes(nodes: string[]): boolean {
  for (const node of nodes) {
    try {
      const peerId = PeerId.from(node)
      const { publicKey, port } = PeerId.parse(peerId)

      // Validate public key length
      if (publicKey.length !== 128) {
        console.error(`Invalid public key length: ${node}`)
        return false
      }

      // Validate port range
      if (port < 1 || port > 65535) {
        console.error(`Invalid port: ${node}`)
        return false
      }
    } catch (err) {
      console.error(`Invalid enode URL: ${node}`)
      return false
    }
  }
  return true
}
```

### RPC Integration

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

// Add peer via admin_addPeer
async function addPeer(rpcUrl: string, enodeUrl: string): Promise<boolean> {
  const peerId = PeerId.from(enodeUrl)

  const response = await fetch(rpcUrl, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'admin_addPeer',
      params: [PeerId.toString(peerId)],
      id: 1
    })
  })
  const { result } = await response.json()
  return result
}

// Remove peer via admin_removePeer
async function removePeer(rpcUrl: string, enodeUrl: string): Promise<boolean> {
  const peerId = PeerId.from(enodeUrl)

  const response = await fetch(rpcUrl, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'admin_removePeer',
      params: [PeerId.toString(peerId)],
      id: 1
    })
  })
  const { result } = await response.json()
  return result
}
```

## Common Bootnodes

### Mainnet

```typescript theme={null}
const MAINNET_BOOTNODES = [
  "enode://d860a01f9722d78051619d1e2351aba3f43f943f6f00718d1b9baa4101932a1f5011f16bb2b1bb35db20d6fe28fa0bf09636d26a87d31de9ec6203eeedb1f666@18.138.108.67:30303",
  "enode://22a8232c3abc76a16ae9d6c3b164f98775fe226f0917b0ca871128a74a8e9630b458460865bab457221f1d448dd9791d24c4e5d88786180ac185df813a68d4de@3.209.45.79:30303"
]
```

### Sepolia

```typescript theme={null}
const SEPOLIA_BOOTNODES = [
  "enode://9246d00bc8fd1742e5ad2428b80fc4dc45d786283e05ef6edbd9002cbc335d40998444732fbe921cb88e1d2c73d1b1de53bae6a2237996e9bfe14f871baf7066@18.168.182.86:30303"
]
```

## Related

* [PeerInfo](/primitives/peer-info) - Connected peer information
* [NodeInfo](/primitives/node-info) - Local node information
* [NetworkId](/primitives/network-id) - Network identifiers

## References

* [Ethereum Network Addresses](https://ethereum.org/en/developers/docs/networking-layer/network-addresses/) - Enode format
* [devp2p Protocol](https://github.com/ethereum/devp2p) - P2P networking
* [Geth admin\_addPeer](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-admin#admin-addpeer) - RPC method
