import { PeerHostRecord } from "../PeerHostRecord" ; import { promises as dnsPromises , SrvRecord } from "dns" ; import bech32 from "bech32" ; import { AddressType } from "../domain/AddressType" ; export interface DnsPeerQueryOptions { /**
     * The domain of the dns seed.
     */ dnsSeed : string ; /**
     * The realm byte used to specify what realm the returned nodes must support.
     */ realm ? : number ; /**
     * The address type bit field specifies the address types that should be returned.
     * It follows the format of the address descriptor type specified in BOLT #7.
     */ addressTypes ? : AddressType [ ] ; /**
     * The bech32-encoded node id used to retrive the result of a single node.
     */ nodeId ? : string ; /**
     * The number of desired reply records.
     */ desiredReplyRecords ? : number ; } /**
 * 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.
 */ export class DnsPeerQuery { private resolver : dnsPromises . Resolver ; constructor ( resolver ? ) { this . resolver = resolver || new dnsPromises . Resolver ( ) ; } param dnsPeerQueryOptions returns public 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 ; } private async _createPeerHostRecord ( peerSrvRecord ) { const peerAddress = await this . _resolveSrvNameToIp ( peerSrvRecord . name ) ; return new PeerHostRecord ( this . _getPublicKeyFromSrvRecord ( peerSrvRecord ) , peerAddress , peerSrvRecord . port ) ; } private _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 ; } private _getPublicKeyFromSrvRecord ( srvRecord ) { const domainComponents = srvRecord . name . split ( "." ) ; const { words } = bech32 . decode ( domainComponents [ 0 ] ) ; return Buffer . from ( bech32 . fromWords ( words ) ) ; } private _getPeerSrvRecords ( dnsSeed ) { return this . resolver . resolveSrv ( dnsSeed ) ; } private async _resolveSrvNameToIp ( hostname ) { const ipAddresses = await this . resolver . resolve ( hostname , "A" ) ; return ipAddresses ?. [ 0 ] ; } }