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
Type-safe Ethereum peer identifiers (enode URLs) for peer-to-peer networking.
Overview
Branded 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
Basic Usage
Parse Enode
Bootnode Connection
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
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
// }
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}`)
}
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
// 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
import * as PeerId from '@tevm/voltaire/PeerId'
// From enode URL string
const peerId = PeerId.from("enode://abc123...@192.168.1.1:30303")
Methods
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
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
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
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
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
const MAINNET_BOOTNODES = [
"enode://d860a01f9722d78051619d1e2351aba3f43f943f6f00718d1b9baa4101932a1f5011f16bb2b1bb35db20d6fe28fa0bf09636d26a87d31de9ec6203eeedb1f666@18.138.108.67:30303",
"enode://22a8232c3abc76a16ae9d6c3b164f98775fe226f0917b0ca871128a74a8e9630b458460865bab457221f1d448dd9791d24c4e5d88786180ac185df813a68d4de@3.209.45.79:30303"
]
Sepolia
const SEPOLIA_BOOTNODES = [
"enode://9246d00bc8fd1742e5ad2428b80fc4dc45d786283e05ef6edbd9002cbc335d40998444732fbe921cb88e1d2c73d1b1de53bae6a2237996e9bfe14f871baf7066@18.168.182.86:30303"
]
References