UNPKG

@node-lightning/wire

Version:
89 lines 3.93 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DnsPeerQuery = void 0; const PeerHostRecord_1 = require("../PeerHostRecord"); const dns_1 = require("dns"); const bech32_1 = __importDefault(require("bech32")); /** * This class implements the node discovery mechanism described * in BOLT #10. * The purpose of this component is to assist in the initial * node discovery process for nodes that have no known contacts, * and to help nodes discover the current network address of previously * known peers. A domain name server that implements BOLT #10 is * referred to as a DNS Seed and answers incoming DNS queries of * type A, AAAA, or SRV. */ class DnsPeerQuery { constructor(resolver) { this.resolver = resolver || new dns_1.promises.Resolver(); } /** * The query method starts by querying a DNS seed for SRV records. * This will result in a list of returned SRV records that each * represent a lightning node that can be connected to. Each record * is a subdomain of the dns seed where the first component of the * subdomain is the bech32 encoded public key of the node (also known * as the node_id). Each subdomain can subsequently be used to query * the DNS seed for the A (or AAA) records of the lightning node with * the specified node_id. The query method ends by constructing peer * host records using the port from the SRV records and the ip * address from the A (or AAA) records. * @param dnsPeerQueryOptions * @returns valid peer host records */ async query(dnsPeerQueryOptions) { const dnsSeed = this._buildUrl(dnsPeerQueryOptions); const peerSrvRecords = await this._getPeerSrvRecords(dnsSeed); const peerHostRecordPromises = []; for (const peerSrvRecord of peerSrvRecords) { peerHostRecordPromises.push(this._createPeerHostRecord(peerSrvRecord)); } const peerHostRecordSettlements = await Promise.allSettled(peerHostRecordPromises); const peers = peerHostRecordSettlements .filter(recordSettlement => recordSettlement?.status == "fulfilled") .map((p) => p.value); return peers; } async _createPeerHostRecord(peerSrvRecord) { const peerAddress = await this._resolveSrvNameToIp(peerSrvRecord.name); return new PeerHostRecord_1.PeerHostRecord(this._getPublicKeyFromSrvRecord(peerSrvRecord), peerAddress, peerSrvRecord.port); } _buildUrl(dnsPeerQueryOptions) { let { dnsSeed } = dnsPeerQueryOptions; const { realm, addressTypes, nodeId, desiredReplyRecords } = dnsPeerQueryOptions; if (desiredReplyRecords != null) { dnsSeed = `n${desiredReplyRecords}.${dnsSeed}`; } if (nodeId != null) { dnsSeed = `l${nodeId}.${dnsSeed}`; } if (addressTypes != null) { const a = addressTypes.reduce((bitField, addressType) => { return bitField | (1 << addressType); }, 0); dnsSeed = `a${a}.${dnsSeed}`; } if (realm != null) { dnsSeed = `r${realm}.${dnsSeed}`; } return dnsSeed; } _getPublicKeyFromSrvRecord(srvRecord) { const domainComponents = srvRecord.name.split("."); const { words } = bech32_1.default.decode(domainComponents[0]); return Buffer.from(bech32_1.default.fromWords(words)); } _getPeerSrvRecords(dnsSeed) { return this.resolver.resolveSrv(dnsSeed); } async _resolveSrvNameToIp(hostname) { const ipAddresses = await this.resolver.resolve(hostname, "A"); return ipAddresses?.[0]; } } exports.DnsPeerQuery = DnsPeerQuery; //# sourceMappingURL=DnsPeerQuery.js.map