@node-lightning/wire
Version:
Lightning Network Wire Protocol
89 lines • 3.93 kB
JavaScript
;
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