Skip to content

fix(peers): a relay-reached peer renders as [::]:0 — an unspecified address shown where an endpoint goes #253

Description

@MichaelTaylor3d

Task

dign peers renders a relay-reached peer's address as [::]:0 — the IPv6 unspecified address on
port 0, which is not an endpoint at all. Emit no address for such a peer so the renderer's existing
honest fallback shows instead.

Discovered during the light-client end-to-end verification on
https://github.com/DIG-Network/dig_ecosystem/issues/2760 (the 2026-08-19 measurement comment).
That epic is the discovery CONTEXT, not this ticket's family parent — no open orchestrator epic covers
the DIG peer-display surface today, and per CLAUDE.md §1.3 a 1:1 super-repo shadow for a trivial
repo-scoped fix would re-create the double-bookkeeping the queue split removed. This closes with its
own PR.

(Corrected: the first version of this body cited #836 as its parent. #836 is CLOSED and cannot parent
anything.)

Measured on a real machine, 2026-08-19

dig-node 0.126.2 (b92de34), installed as the OS service:

$ dign peers
dig-node peer network: running · 1 connected peer(s)
  relay wss://relay.dig.net:443 — reservation held
  peers:
    • 62ecc368ecac7ccaa599e344e228355023fbe46d06759efe8a9e5223543f2a5c  relay/outbound  [::]:0

[::]:0 reads as an address. It is the absence of one.

Context — the honest fallback already exists and is unreachable

crates/dig-node-service/src/peers.rs:215 already handles this correctly:

let addr = p["address"].as_str().unwrap_or("(no address)");

That branch fires only when the field is absent. The producer never omits it —
crates/dig-node-core/src/peer.rs:328 stringifies unconditionally:

"address": addr.to_string(),

So for a peer reached over the relay, where connected_pool_peers() has no direct address to report,
the placeholder [::]:0 is emitted and the "(no address)" branch can never run. The renderer is
correct; the producer is what needs fixing.
Guarding the display instead would leave the same
placeholder in control.peerStatus for every other consumer, including the extension.

Scope

At peer.rs:328, omit address when the socket address is unspecified or its port is 0, so the field
is genuinely absent rather than placeholder-filled. Keep the JSON shape otherwise identical — the key is
already read with .unwrap_or(..) downstream, so absence is the supported case, not a new one.

via already carries the useful truth for these peers (relay), and the relay line above prints the
reservation, so a person loses nothing by the address disappearing — they stop being told something
false.

Skill / reference of "good"

professional-ui's honesty rule and the ecosystem pattern of never implying a fact not held: a surface
must not present a placeholder that a person can mistake for real data. The same argument the dig-app
panes settled with BalanceReading's pending/known/unknown split — an unknown renders as unknown, not
as a plausible-looking zero.

§5.2 is not violated here and should not be cited: the IPv6-first ordering in peers.rs:199-200 is
correct, and is_ipv4() classifies [::]:0 as IPv6 which is technically right. The defect is
truthfulness, not address family.

Evidence

A test asserting a relay-reached peer with no direct address produces JSON without an address key,
and that the rendered line shows (no address). It must fail against today's code — which it will,
since today's code emits [::]:0.

Effort

Small. Two lines plus a test. No design fork.

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind:businessa person can DO something new, or money moves, or a shipped surface stops lying to them

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions