Skip to content

[Feature] Support domain names in node.backup.members and seed.node.ip.list #6634

@Sunny6889

Description

@Sunny6889

Problem Statement

Currently, node.backup.members and seed.node.ip.list in the node configuration only accept raw IP addresses. This creates operational friction in dynamic or cloud-native deployments where:

  • Infrastructure IP addresses change frequently (auto-scaling groups, cloud instances, Kubernetes pods)
  • Operators prefer to manage a small set of stable DNS records rather than updating config files across many nodes whenever IPs rotate
  • High-availability backup setups require the member list to stay accurate even as IPs change at runtime

Neither field documents or handles hostname inputs — any domain name silently fails to resolve, causing nodes to be silently dropped from the member/seed list.

Who benefits: Node operators running large-scale deployments, SR infrastructure teams, and any operator managing nodes on infrastructure with dynamic IP allocation.

Proposed Solution

Extend the parsers for both node.backup.members and seed.node.ip.list to accept hostname entries in addition to raw IPv4/IPv6 addresses.

Domain resolution should reuse the DNS resolution pattern from the libp2p library (see tronprotocol/libp2p#130) — specifically the dnsjava SimpleResolver with explicit per-query timeout — rather than re-implementing resolution logic. Note: libp2p's existing lookUpTxt queries TXT records for node discovery; for resolving hostnames to IPs (A/AAAA records) a parallel lookUpA function following the same pattern is needed.

The two fields have different reliability requirements and therefore adopt different resolution strategies:

Field Resolution timing Startup failure on DNS error Periodic re-resolution
node.backup.members Synchronous, blocks startup until done Fatal if entry fails Yes (fixed interval constant in BackupManager)
seed.node.ip.list Asynchronous, does not block startup Warning per entry, startup continues No (p2p handles dynamic expansion)

Specification

Configuration Changes

node.backup.members — extend to accept hostnames (no port, since the backup port is global). No new config options are added; the re-resolution interval is a fixed constant inside BackupManager:

node.backup {
  port = 10001
  priority = 8
  keepAliveInterval = 3000

  // support both peer's ip or domain list, but only fill one of them
  members = [
    // "192.168.1.10",            <- IP, used as-is
    // "backup-node.example.com"  <- domain, resolved at startup and refreshed periodically
  ]
}

seed.node.ip.list — extend to accept host:port where host may be a domain name. No new config options are added; resolution is asynchronous and best-effort:

seed.node = {
  // List of seed nodes. Entries may be IP:port or domain:port.
  ip.list = [
    "52.8.46.215:18888",           // IP:port — used as-is
    "seed1.tron.network:18888"     // domain:port — resolved asynchronously at startup
  ]
}

Resolution Behavior

node.backup.members (high-reliability, synchronous):

  • Due to the high reliability requirements of primary/standby election, domain resolution is synchronous and blocks node startup until resolution finished.
  • If the domain entry failed to resolve, the node refuses to start and logs a prominent fatal error with the exact hostname and remediation advice:
    [FATAL] Failed to start: cannot resolve backup member "backup-node.example.com".
    Please check DNS configuration or replace the entry with a reachable IP address.
    
  • After startup, a background task re-resolves the domain entry on a periodic schedule (interval defined as a constant in BackupManager, not configurable).
    • On refresh, successfully resolved IP replace the previous one for that domain.
    • If the domain temporarily fails to resolve on refresh, the last known IP is retained and a warning is logged — the node does not stop.

seed.node.ip.list (best-effort, asynchronous):

  • To avoid lengthening startup time, domain entries are resolved asynchronously in the background. Peer discovery begins immediately using raw IP entries; resolved IPs are added to the seed pool as results arrive.
  • All domain lookups are submitted in parallel so resolution finishes as quickly as possible.
  • Per-entry failures are logged as warnings; the entry is skipped and startup always continues:
    [WARN] Cannot resolve seed node "seed1.tron.network" — skipping. Check DNS or update ip.list.
    
  • No periodic re-resolution after startup. The p2p protocol dynamically discovers and expands the peer list; the seed list is only used for initial bootstrap.

API Changes

None — this is a configuration parsing enhancement only.

Protocol Changes

None.

Scope of Impact

  • Network layer (peer discovery, backup node election)
  • Configuration parsing (Args.java, CommonParameter.java)

Breaking Changes

None. All existing IP-only configurations remain valid.

Backward Compatibility

Fully backward compatible. Raw IP entries continue to work as-is; the parser treats an entry as a domain only when it is not a valid IP literal (e.g., via Guava's InetAddresses.isInetAddress()).

Implementation

Ideas regarding implementation:

  1. In Args.java, after reading node.backup.members and seed.node.ip.list, pass each entry through a helper that distinguishes IP literals from hostnames.
  2. Invoke the DNS resolver interface exposed by the libp2p library to perform hostname-to-IP resolution.
  3. For node.backup.members:
    • At startup, submit the domain entry to the resolver and wait synchronously; fail fast with a descriptive message if the resolution failed.
    • In BackupManager, add a ScheduledExecutorService task that re-resolves the domain entry at a fixed interval (e.g. 10 minutes, defined as a constant) and atomically swaps the live member ip set. On refresh failure, retain the last known IP and log a warning.
  4. For seed.node.ip.list:
    • At startup, submit all domain entries to a thread pool asynchronously (fire-and-forget with callbacks); node startup continues immediately using raw IP entries.
    • Each callback logs WARN on failure or adds resolved IPs to the seed pool on success.
    • No scheduled re-resolution task needed.

Are you willing to implement this feature?

Yes.

Estimated Complexity

Medium — the core parsing/resolution change is straightforward, but the periodic re-resolution in BackupManager and the synchronous-vs-asynchronous split require careful implementation and testing.

Testing Strategy

Test Scenarios

node.backup.members:

  • IP entry: behavior unchanged.
  • Hostname entry: resolved IP used correctly by backup election.
  • For unresolvable hostname at startup: node refuses to start with a clear fatal error message.
  • Periodic refresh: updated IP reflected in member set without restart.
  • Transient refresh failure: last known IP retained, warning logged, node continues.

seed.node.ip.list:

  • IP-only entries: behavior unchanged.
  • Hostname entries: resolved IPs used as initial seeds.
  • Mixed IP + hostname entries: both work correctly.
  • Some or all hostnames unresolvable: warnings logged per entry, node starts and continues with available IPs.
  • Asynchronous resolution: startup is not delayed; domain lookups complete in the background.
  • Parallel resolution: all domain lookups submitted concurrently, total resolution time bounded by the slowest single lookup.

Performance Considerations

  • node.backup.members resolution is synchronous and blocks startup.
  • seed.node.ip.list resolution is asynchronous and does not add to startup time; raw IP entries are usable immediately.
  • Per-lookup timeout: libp2p's SimpleResolver uses setTimeout(Duration.ofMillis(1000)) per attempt with up to 5 retries (worst-case ~5 s per domain). The same configuration should be reused for consistency.
  • Periodic re-resolution in BackupManager must run on a dedicated scheduled thread, not on the backup UDP event loop.

Alternatives Considered

  • Re-implement DNS resolution in java-tron — rejected to avoid duplicating logic already maintained in the libp2p library.
  • Periodic refresh for seed nodes — rejected; seed nodes are numerous and the p2p protocol already handles dynamic peer discovery after bootstrap, so the added complexity is not justified.

Additional Context

Related Issues/PRs

References

  • Current config: framework/src/main/resources/config.confnode.backup, seed.node
  • Backup member usage: framework/src/main/java/org/tron/common/backup/BackupManager.java
  • Seed node config parsing: framework/src/main/java/org/tron/core/config/args/Args.java

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    In Progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions