UNPKG

@lodestar/beacon-node

Version:

A Typescript implementation of the beacon chain

166 lines • 7.22 kB
import { bootstrap } from "@libp2p/bootstrap"; import { identify } from "@libp2p/identify"; import { mdns } from "@libp2p/mdns"; import { mplex } from "@libp2p/mplex"; import { prometheusMetrics } from "@libp2p/prometheus-metrics"; import { tcp } from "@libp2p/tcp"; import { createLibp2p } from "libp2p"; import { ENR } from "@chainsafe/enr"; import { noise } from "@chainsafe/libp2p-noise"; import { asCrypto, defaultCrypto } from "@chainsafe/libp2p-noise/crypto"; import { quic } from "@chainsafe/libp2p-quic"; import { defaultNetworkOptions } from "../options.js"; import { Eth2PeerDataStore } from "../peers/datastore.js"; export async function getDiscv5Multiaddrs(bootEnrs, quicEnabled) { const bootMultiaddrs = []; for (const enrStr of bootEnrs) { const enr = ENR.decodeTxt(enrStr); // Prefer QUIC over TCP when available const quicMultiaddr = quicEnabled ? (await enr.getFullMultiaddr("quic"))?.toString() : undefined; const tcpMultiaddr = (await enr.getFullMultiaddr("tcp"))?.toString(); const multiaddrWithPeerId = quicMultiaddr ?? tcpMultiaddr; if (multiaddrWithPeerId) { bootMultiaddrs.push(multiaddrWithPeerId); } } return bootMultiaddrs; } export async function createNodeJsLibp2p(privateKey, networkOpts = {}, nodeJsLibp2pOpts = {}) { const localMultiaddrs = networkOpts.localMultiaddrs || defaultNetworkOptions.localMultiaddrs; const disconnectThreshold = networkOpts.disconnectThreshold ?? defaultNetworkOptions.disconnectThreshold; const tcpEnabled = networkOpts.tcp ?? defaultNetworkOptions.tcp; const quicEnabled = networkOpts.quic ?? defaultNetworkOptions.quic; const { peerStoreDir, disablePeerDiscovery } = nodeJsLibp2pOpts; let datastore = undefined; if (peerStoreDir) { datastore = new Eth2PeerDataStore(peerStoreDir); await datastore.open(); } const peerDiscovery = []; if (!disablePeerDiscovery) { const bootMultiaddrs = [ ...(networkOpts.bootMultiaddrs ?? defaultNetworkOptions.bootMultiaddrs ?? []), // Append discv5.bootEnrs to bootMultiaddrs if requested ...(networkOpts.connectToDiscv5Bootnodes ? await getDiscv5Multiaddrs(networkOpts.discv5?.bootEnrs ?? [], quicEnabled) : []), ]; if ((bootMultiaddrs.length ?? 0) > 0) { peerDiscovery.push(bootstrap({ list: bootMultiaddrs })); } if (networkOpts.mdns) { peerDiscovery.push(mdns()); } } const transports = []; if (tcpEnabled) { transports.unshift(tcp({ // Reject connections when the server's connection count gets high maxConnections: networkOpts.maxPeers, // socket option: the maximum length of the queue of pending connections // https://nodejs.org/dist/latest-v18.x/docs/api/net.html#serverlisten // it's not safe if we increase this number backlog: 5, closeServerOnMaxConnections: { closeAbove: networkOpts.maxPeers ?? Infinity, listenBelow: networkOpts.maxPeers ?? Infinity, }, })); } if (quicEnabled) { const quicMultiaddrs = localMultiaddrs.filter((ma) => ma.includes("/quic-v1")); const hasIpv4Quic = quicMultiaddrs.some((ma) => ma.includes("/ip4/")); const hasIpv6Quic = quicMultiaddrs.some((ma) => ma.includes("/ip6/")); // Only add QUIC transport if at least one QUIC listen address is configured, // otherwise the transport constructor will throw if (hasIpv4Quic || hasIpv6Quic) { transports.unshift(quic({ handshakeTimeout: 5_000, maxIdleTimeout: 10_000, keepAliveInterval: 5_000, maxConcurrentStreamLimit: 256, maxStreamData: 10_000_000, maxConnectionData: 15_000_000, ipv4: hasIpv4Quic, ipv6: hasIpv6Quic, })); } } const noiseCrypto = { ...defaultCrypto, }; if (globalThis.Bun) { noiseCrypto.chaCha20Poly1305Decrypt = asCrypto.chaCha20Poly1305Decrypt; noiseCrypto.chaCha20Poly1305Encrypt = asCrypto.chaCha20Poly1305Encrypt; } return createLibp2p({ privateKey, nodeInfo: { name: "lodestar", version: networkOpts.version ?? "unknown", userAgent: networkOpts.private ? "" : networkOpts.version ? `lodestar/${networkOpts.version}` : "lodestar", }, addresses: { listen: localMultiaddrs, announce: [], }, connectionEncrypters: [noise({ crypto: noiseCrypto })], transports, streamMuxers: [mplex({ disconnectThreshold })], peerDiscovery, metrics: nodeJsLibp2pOpts.metrics ? prometheusMetrics({ collectDefaultMetrics: false, preserveExistingMetrics: true, registry: nodeJsLibp2pOpts.metricsRegistry, }) : undefined, connectionManager: { // dialer config maxParallelDials: 100, maxPeerAddrsToDial: 4, dialTimeout: 30_000, // the maximum number of pending connections libp2p will accept before it starts rejecting incoming connections. // make it the same to backlog option above maxIncomingPendingConnections: 5, }, // rely on lodestar's peer manager to ping peers connectionMonitor: { enabled: false, }, // for our purposes, we don't want peer store data to expire // see https://github.com/libp2p/js-libp2p/pull/3019 peerStore: { maxAddressAge: Infinity, maxPeerAge: Infinity, }, datastore, services: { identify: identify({ runOnConnectionOpen: false, }), // individual components are specified because the components object is a Proxy // and passing it here directly causes problems downstream, not to mention is slowwww components: (components) => ({ peerId: components.peerId, privateKey: components.privateKey, nodeInfo: components.nodeInfo, logger: components.logger, events: components.events, addressManager: components.addressManager, peerStore: components.peerStore, upgrader: components.upgrader, registrar: components.registrar, connectionManager: components.connectionManager, transportManager: components.transportManager, connectionGater: components.connectionGater, contentRouting: components.contentRouting, peerRouting: components.peerRouting, datastore: components.datastore, connectionProtector: components.connectionProtector, metrics: components.metrics, }), }, }); } //# sourceMappingURL=index.js.map