PeerId
Type-safe Ethereum peer identifiers (enode URLs) for peer-to-peer networking.Overview
Brandedstring 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
Copy
Ask AI
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
Copy
Ask AI
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
// }
Copy
Ask AI
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 URL Format
Copy
Ask AI
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
Copy
Ask AI
// 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
Copy
Ask AI
import * as PeerId from '@tevm/voltaire/PeerId'
// From enode URL string
const peerId = PeerId.from("enode://[email protected]:30303")
Methods
Copy
Ask AI
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
Copy
Ask AI
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
Copy
Ask AI
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
Copy
Ask AI
import * as PeerId from '@tevm/voltaire/PeerId'
// Geth static-nodes.json format
const staticNodes = [
"enode://[email protected]:30303",
"enode://[email protected]: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
Copy
Ask AI
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
Copy
Ask AI
const MAINNET_BOOTNODES = [
"enode://d860a01f9722d78051619d1e2351aba3f43f943f6f00718d1b9baa4101932a1f5011f16bb2b1bb35db20d6fe28fa0bf09636d26a87d31de9ec6203eeedb1f666@18.138.108.67:30303",
"enode://22a8232c3abc76a16ae9d6c3b164f98775fe226f0917b0ca871128a74a8e9630b458460865bab457221f1d448dd9791d24c4e5d88786180ac185df813a68d4de@3.209.45.79:30303"
]
Sepolia
Copy
Ask AI
const SEPOLIA_BOOTNODES = [
"enode://9246d00bc8fd1742e5ad2428b80fc4dc45d786283e05ef6edbd9002cbc335d40998444732fbe921cb88e1d2c73d1b1de53bae6a2237996e9bfe14f871baf7066@18.168.182.86:30303"
]
Related
- PeerInfo - Connected peer information
- NodeInfo - Local node information
- NetworkId - Network identifiers
References
- Ethereum Network Addresses - Enode format
- devp2p Protocol - P2P networking
- Geth admin_addPeer - RPC method

