Skip to content

Fix and complete BOLT10 DNS bootstrap (DnsSeedClient) to work with public seeds (e.g., lseed.bitcoinstats.com) #73

@nGoline

Description

@nGoline

Summary

Repair and finish the BOLT10 DNS bootstrap client so it conforms 100% to the spec and interoperates with known public DNS seeders (e.g., lseed.bitcoinstats.com). Implement a DNS bootstrap service that runs when the node has fewer than N peers, and add comprehensive unit tests and integration tests (against real seeders) to ensure correctness and ongoing compatibility.

Background / Motivation

  • Current DnsSeedClient implementation is commented out and does not fully follow BOLT10. As a result, it fails to resolve peers from public seeders like lseed.bitcoinstats.com.
  • The BOLT10 DNS bootstrap process is part of initial peer discovery. We need a reliable implementation so nodes can automatically find peers if their peer list is short.
  • The reference server lseed can found at: https://github.com/cdecker/lseed. Specification: https://github.com/lightning/bolts/blob/master/10-dns-bootstrap.md

Scope

  • Reimplement DnsSeedClient according to BOLT10 and align with the behavior of public lseed instances.
  • Implement a DNS bootstrap service (background job) that integrates with existing service patterns. It should run if the node’s known peers < configurable threshold and fetch additional peers from the configured seeds.
  • Write tests:
    • Unit tests for record parsing, decoding of pubkeys, IPv4/IPv6 support, SRV resolution logic, error handling.
    • Integration tests against real DNS bootstrap services (e.g., lseed.bitcoinstats.com). These tests should be skipped in CI by default if DNS/network is unreliable but runnable locally and in controlled environments.
  • Make the service configurable via NodeOptions (seed list, thresholds, timeouts, TCP/UDP choice, IPv4/IPv6 selection, optional custom resolvers).

Non‑Goals

  • Implementing peer connection logic itself (beyond returning structured seed results)—that is handled by other components.
  • Creating a proprietary seed server. We only consume public servers per the spec.

Proposed Changes

  1. src/NLightning.Infrastructure/Protocol/Services/DnsSeedClient.cs

    • Restore and rework the implementation to:
      • Perform SRV lookups per BOLT10 for the appropriate service labels (and fallbacks) used by public seeders.
      • Resolve target hostnames to A and/or AAAA records depending on IPv4/IPv6 mode.
      • Correctly decode the node public key from the SRV target label per the spec/lseed conventions (bech32 payload, correct HRP, proper 5↔8‑bit conversion, validation of sizes).
      • Capture the advertised port from SRV records.
      • Shuffle and select up to the requested number of nodes.
      • Provide robust error handling and partial success (continue across seeds and records).
    • Validate that the prior assumptions (e.g., HRP "ln", single‑label bech32 decoding) match the current lseed behavior; adjust to match spec if different.
    • Expose a clean result model (pubkey as 33‑byte compressed key or 32‑byte x‑only public key per spec, plus IPEndPoint).
  2. New/Updated Service

    • Create a DNS Bootstrap background service (or integrate into the existing service orchestration) that:
      • Periodically checks the known connected peer count.
      • If below threshold N (configurable), queries the configured seed servers and attempts to add/connect to returned nodes.
      • Respects NodeOptions.NetworkTimeout, DnsSeedServers, and IPv4/IPv6 preferences.
  3. Configuration

    • src/NLightning.Domain/Node/Options/NodeOptions.cs
      • Ensure DnsSeedServers default is sensible and includes at least one well‑known public seeder for the network in use. Current default is ["nlseed.nlightn.ing"]; consider supplementing with lseed.bitcoinstats.com for mainnet.
      • Add settings (if not present already) for:
        • Bootstrap threshold (min peer count)
        • IPv4/IPv6 preference and whether to use TCP‑only for DNS queries
        • Optional custom resolvers (e.g., 8.8.8.8)
  4. Tests

    • Unit tests for DnsSeedClient covering:
      • SRV parsing and port extraction
      • Target label decoding into pubkeys (valid and invalid cases)
      • A/AAAA record handling, IPv4/IPv6 toggling
      • Shuffling/selection and error resilience
    • Integration tests (see the attached file) in test/NLightning.Integration.Tests/BOLT10/DNSBootstrapTests.cs:
      • Revive and adapt tests to query real seeders like lseed.bitcoinstats.com.
      • Skip in CI by default when network DNS is unreliable (retain the TCP‑only option for better reliability, similar to the commented tests).

Acceptance Criteria

  • DnsSeedClient correctly discovers nodes from lseed.bitcoinstats.com (and similar public seeders) on both IPv4 and IPv6 where available.
  • Node public keys are decoded per the spec and sized/validated correctly.
  • DNS bootstrap service kicks in when peer count < threshold and attempts to fill to the threshold using configured seeds.
  • Unit tests cover core logic; integration tests succeed locally and are conditionally skipped in CI as needed.
  • Configuration is documented and defaults are sensible for mainnet/testnet.

Implementation Notes / References

  • Spec: BOLT Implement Bolt9 #10 — DNS Bootstrap: https://github.com/lightning/bolts/blob/master/10-dns-bootstrap.md
  • Seed logic reference: https://github.com/cdecker/lseed
  • Attached files (for context and places to modify):
    • src/NLightning.Infrastructure/Protocol/Services/DnsSeedClient.cs (current, commented implementation)
    • src/NLightning.Domain/Node/Options/NodeOptions.cs (contains DnsSeedServers and related options)
    • test/NLightning.Integration.Tests/BOLT10/DNSBootstrapTests.cs (commented integration tests)
  • Past implementation details (to re‑evaluate against spec):
    • SRV → A/AAAA resolution
    • Bech32 decoding of the first label (HRP and payload length must match spec)
    • Bit‑conversion logic (ensure exact reproduction of spec and error handling)

Risks / Considerations

  • Public DNS seeders may rate limit or throttle; integration tests should be conservative and optionally target a test domain.
  • DNS over UDP can be flaky in CI; prefer TCP‑only in CI, or skip entirely in CI as done previously.
  • Ensure decoding logic does not accept malformed or truncated pubkeys; fail fast with clear diagnostics.

Testing Plan

  • Restore and extend DNSBootstrapTests with:
    • [InlineData(true)] and [InlineData(false)] to toggle TCP‑only
    • Separate IPv4/IPv6 scenarios
    • Seed lists including lseed.bitcoinstats.com
    • Conditional skip when CI=true and not TCP‑only
  • Add unit tests with mocked DNS responses to cover edge cases without network dependency.

Definition of Done

  • Implementation merged with tests.
  • Can successfully retrieve at least one node from lseed.bitcoinstats.com locally (documented in test output or README).
  • Documentation updated (README or docs) explaining DNS bootstrap configuration and behavior.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthelp wantedExtra attention is needed

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions