Skip to content

AutoNAT v2 does not expose reachability events #3472

Description

@srene

This issue distills findings from a systematic cross-implementation evaluation of AutoNAT v2, conducted by ProbeLab. The final report of the investigation is available in the following link.

Severity:

Low — this is an API completeness / developer ergonomics gap. No runtime crash or incorrect reachability verdict; the information is tracked internally but not surfaced to applications.

Description:

What I did. Registered the autoNATv2() service on a js-libp2p Node.js node and attempted to subscribe to a reachability event from the service so the application could react to per-address REACHABLE / UNREACHABLE verdicts.

What happened. No event fires. @libp2p/autonat-v2 tracks per-address outcomes internally in a dialResults Map but does not emit any event. No dispatchEvent / safeDispatchEvent calls exist anywhere in packages/protocol-autonat-v2/.

What I expected. Per-address reachability changes surfaced as events on the service, consistent with the rest of js-libp2p, where TypedEventEmitter is used extensively:

  • Libp2p emits peer:connect, peer:disconnect, peer:discovery, connection:open/close.
  • PeerStore emits self:peer:update and peer:update.
  • Identify emits peer:identify.
  • Circuit Relay v2 emits relay:created-reservation, relay:removed, relay:found-enough-relays.

AutoNAT v2 is the outlier with no event surface. Concrete consequences: applications cannot directly observe reachability changes (they can only infer from downstream PeerStore updates, and the per-address REACHABLE/UNREACHABLE granularity is lost); for nodes behind symmetric NAT running AutoNAT v2 over QUIC, every dial-back fails, the address is silently removed via removeObservedAddr() after 8 failures, and the application sees the address disappear without ever receiving an explicit UNREACHABLE signal.

AutoNAT v2 already influences downstream behavior indirectly: observed addresses are added by Identify as unverified, and only elevated to the PeerStore entry after AutoNAT v2 calls confirmObservedAddr() on the AddressManager (client.ts:592). DHT mode switching (via self:peer:update) therefore already consumes an AutoNAT-verified address list. What is missing is only the API-level event surface for applications.

Proposal

Expose v2 probe results via TypedEventEmitter, consistent with the rest of the library:

  • Per-address event: reachability:changed { addr, state, confidence } where state is REACHABLE | UNREACHABLE | UNKNOWN.
  • Optional aggregated host-level event equivalent to go-libp2p's EvtLocalReachabilityChanged, derived from a per-address reducer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    need/triageNeeds initial labeling and prioritization

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions