Skip to content

Conversation

@p4bpj
Copy link

@p4bpj p4bpj commented Aug 22, 2025

Discussion Invitation

This PR (and upcoming related PRs) is meant to spark discussion on how we can further improve the reliability and usability of Kaspa nodes at home. It is provided as a template and idea starter and does not need to be merged verbatim in its current form.

Summary

Adds automatic periodic refreshing of the external IP obtained via UPnP and propagates changes to the peer layer. The node no longer requires a restart after WAN IP changes (e.g. ISP lease renewals). When the external IP changes, outbound peers are reconnected gradually so the updated address spreads quickly.

Motivation

Previously the external (WAN) IP was fetched exactly once at startup (via UPnP) and never validated again. If the router/ISP changed the IP later, the node continued advertising a stale address until manual restart. This degraded inbound connectivity and peer discovery. The goal: make external IP tracking resilient to dynamic WAN environments with minimal overhead and no startup delays.

Key Changes

  • UPnP Extender
    • Renews port mapping as before.
    • Also fetches get_external_ip each cycle.
    • Detects IP changes and updates AddressManager.
  • AddressManager
    • Adds set_best_local_address.
    • Introduces ExternalIpChangeSink trait.
  • ConnectionManager
    • Implements ExternalIpChangeSink to trigger a staggered outbound reconnect (avoids a connection storm).
  • Config / CLI
    • Adds --disable-ipv6-interface-discovery to skip automatic IPv6 interface scanning (explicit IPv6 still honored).
  • Daemon
    • Registers ConnectionManager as an external IP change sink early in startup.
  • Logging
    • Informational / debug logs for mapping, extension, fetch results, and IP change events.

Behavior

  1. Startup: UPnP mapping established (existing flow).
  2. Each extender interval (half the lease):
    • Renew port mapping.
    • Fetch current external IP.
    • If changed: update best local address + notify sinks.
  3. ConnectionManager schedules outbound reconnects so new peers learn the updated address.
  • Sink notifications are fire-and-forget tasks

Configuration

New flag:

--disable-ipv6-interface-discovery

Use to suppress automatic IPv6 interface enumeration while still allowing explicit IPv6 configuration.

Testing / Verification

Manual scenarios:

  • Stable IP: Only renewal logs; no change events.
  • Forced WAN IP change (router reconnect): “External IP changed …” appears; outbound reconnects occur.
  • With --disable-ipv6-interface-discovery: No automatically added IPv6 addresses.

Authorship Note

This PR description was initially drafted with the assistance of an AI tool. I (p4bpj) have carefully reviewed, adjusted where necessary, and confirm that it accurately reflects the implemented changes.

p4bpj added 3 commits August 19, 2025 18:46
…utbound peers on change

Previously the external IP (via UPnP) was fetched and mapped only once at node startup; dynamic WAN IP changes (e.g. ISP 24h leases, router reconnects) were not propagated, leaving peers with a stale address until manual restart.

This change:

Adds periodic external IP refresh in the UPnP port mapping extender (re-uses the existing renew cycle to also call get_external_ip).
Detects IP changes and updates the AddressManager best local address.
Introduces ExternalIpChangeSink; ConnectionManager implements it to trigger a staggered outbound reconnect so new peers learn the updated public address sooner.
Adds set_best_local_address helper.
Adds CLI/config flag --disable-ipv6-interface-discovery to skip automatic IPv6 interface scanning while still allowing explicit IPv6 config.
Registers ConnectionManager as an external IP change sink.
- Rename init_local_addresses_with_arc -> init_local_addresses (Arc param made name redundant).
- Remove unused ConnectionManager methods trigger_outbound_reconnect_simple and reconnect_outbound_gradually (logic now handled internally elsewhere).
- Clean up stale UPnP/DynDNS setup comment in daemon.
- Minor formatting tidy in UPnP gateway search call.
Copy link
Collaborator

@coderofstuff coderofstuff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

initial comments :)

index_service.as_ref().map(|x| x.notifier()),
mining_manager,
flow_context,
flow_context.clone(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this clone necessary?

}

/// Synchronously trigger a staggered outbound reconnect (terminates peers one by one with 30s delays)
pub fn trigger_outbound_reconnect(&self) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary? When your external IP changes, wouldn't a disconnection already have happened (you disconnect from all your peers) and when you try to reconnect to your peers they would then know your new IP?


pub use stores::NetAddress;

pub trait ExternalIpChangeSink: Send + Sync {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this called Sink?

}
}

pub fn set_best_local_address(&mut self, address: NetAddress) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it's better to handle the TODO in pub fn best_local_address(&mut self) -> Option<NetAddress> { instead

@coderofstuff
Copy link
Collaborator

Also please rebase and fix the lint and test issues

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants