< Summary - Combined Code Coverage

Information
Class: NLightning.Infrastructure.Protocol.Services.DnsSeedClient
Assembly: NLightning.Infrastructure
File(s): /home/runner/work/nlightning/nlightning/src/NLightning.Infrastructure/Protocol/Services/DnsSeedClient.cs
Tag: 30_15166811759
Line coverage
0%
Covered lines: 0
Uncovered lines: 49
Coverable lines: 49
Total lines: 126
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 36
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_Pubkey()100%210%
FindNodes(...)0%420200%
GetIp(...)0%620%
GetPublicKey(...)100%210%
ConvertBits(...)0%210140%

File(s)

/home/runner/work/nlightning/nlightning/src/NLightning.Infrastructure/Protocol/Services/DnsSeedClient.cs

#LineLine coverage
 1using System.Net;
 2using DnsClient;
 3using DnsClient.Protocol;
 4
 5namespace NLightning.Infrastructure.Protocol.Services;
 6
 7public static class DnsSeedClient
 8{
 09    public record NodeRecord(byte[] Pubkey, IPEndPoint Endpoint);
 10
 11    /// <summary>
 12    /// Find Nodes from DNS seed domains
 13    /// </summary>
 14    /// <param name="nodeCount">Records to return</param>
 15    /// <param name="seeds">List of seed domains</param>
 16    /// <param name="ipV6">Return IPv6 endpoints</param>
 17    /// <param name="useTcp">Use TCP Only</param>
 18    /// <param name="nameServers">Provide your own nameservers to override system</param>
 19    /// <returns></returns>
 20    public static List<NodeRecord> FindNodes(int nodeCount, List<string> seeds, bool ipV6 = false, bool useTcp = false, 
 21    {
 022        var opts = nameServers.Length != 0 ? new LookupClientOptions(nameServers) : new LookupClientOptions();
 023        opts.UseTcpOnly = useTcp;
 024        var client = new LookupClient(opts);
 025        var list = new List<NodeRecord>();
 026        foreach (var dnsSeed in seeds)
 27        {
 028            if (list.Count < nodeCount)
 29            {
 30                try
 31                {
 032                    var srvResult = client.Query(dnsSeed, QueryType.SRV);
 033                    if (srvResult.HasError)
 034                        continue;
 35
 036                    var srvShuffled = srvResult.Answers.OrderBy(_ => Guid.NewGuid()).ToList();
 37
 038                    foreach (var srv in srvShuffled.SrvRecords())
 39                    {
 040                        if (list.Count >= nodeCount)
 41                        {
 42                            continue;
 43                        }
 44
 045                        var result = client.Query(srv.Target, ipV6 ? QueryType.AAAA : QueryType.A);
 46
 047                        if (result.Answers.Count <= 0)
 48                        {
 49                            continue;
 50                        }
 51
 052                        var publicKey = GetPublicKey(srv);
 053                        var ip = GetIp(result.Answers[0]);
 54
 055                        if (ip != "0.0.0.0" && ip != "[::0]")
 56                        {
 057                            list.Add(new NodeRecord(publicKey, new IPEndPoint(IPAddress.Parse(ip), srv.Port)));
 58                        }
 59                    }
 060                }
 061                catch
 62                {
 063                }
 64            }
 65            else
 66            {
 67                break;
 68            }
 69        }
 70
 071        return list;
 72    }
 73
 74    private static string GetIp(DnsResourceRecord answer)
 75    {
 076        if (answer is ARecord record)
 77        {
 078            return record.Address.ToString();
 79        }
 80
 081        return $"[{((AaaaRecord)answer).Address}]";
 82    }
 83
 84    private static byte[] GetPublicKey(SrvRecord srv)
 85    {
 086        var bech32 = srv.Target.Value.Split('.').First();
 087        var bech32Encoder = NBitcoin.DataEncoders.Encoders.Bech32("ln");
 088        var bech32Data5Bits = bech32Encoder.DecodeDataRaw(bech32, out _);
 089        var bech32Data8Bits = ConvertBits(bech32Data5Bits, 5, 8, false);
 090        return bech32Data8Bits;
 91    }
 92
 93    /*
 94     * The following method was copied from NBitcoin
 95     * https://github.com/MetacoSA/NBitcoin/blob/23beaaab48f2038dca24a6020e71cee0b14cd55f/NBitcoin/DataEncoders/Bech32En
 96     */
 97    private static byte[] ConvertBits(IEnumerable<byte> data, int fromBits, int toBits, bool pad = true)
 98    {
 099        var num1 = 0;
 0100        var num2 = 0;
 0101        var num3 = (1 << toBits) - 1;
 0102        var byteList = new List<byte>();
 0103        foreach (var num4 in data)
 104        {
 0105            if (num4 >> fromBits > 0)
 0106                throw new FormatException("Invalid Bech32 string");
 0107            num1 = num1 << fromBits | num4;
 0108            num2 += fromBits;
 0109            while (num2 >= toBits)
 110            {
 0111                num2 -= toBits;
 0112                byteList.Add((byte)(num1 >> num2 & num3));
 113            }
 114        }
 115
 0116        if (pad)
 117        {
 0118            if (num2 > 0)
 0119                byteList.Add((byte)(num1 << toBits - num2 & num3));
 120        }
 0121        else if (num2 >= fromBits || (byte)(num1 << toBits - num2 & num3) != 0)
 0122            throw new FormatException("Invalid Bech32 string");
 123
 0124        return [.. byteList];
 125    }
 126}