Skip to content

fix(p2p): never ban loopback peers — stop RST of co-located reconnects (#757) - #1

Draft
frstrtr wants to merge 1 commit into
masterfrom
fix/757-loopback-reconnect-rst
Draft

fix(p2p): never ban loopback peers — stop RST of co-located reconnects (#757)#1
frstrtr wants to merge 1 commit into
masterfrom
fix/757-loopback-reconnect-rst

Conversation

@frstrtr

@frstrtr frstrtr commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Problem (issue #757)

Under connection churn, the node silently RSTs loopback reconnects from co-located peers — relevant to mixed-fleet / NAT'd deployments where processes reconnect over 127.0.0.1.

Root cause

Two ban paths added in 60d5140 (Dash Core v23+ support) write self.node.bans['127.0.0.1'] without the localhost exemption that Protocol.badPeerHappened deliberately applies (# never ban localhost):

  1. handle_version self-nonce rate-limiter (p2p.py:157) — a loopback self-connection (a node reaching its own advertised 127.0.0.1) counts toward the 3-strikes-in-10-min rule and bans 127.0.0.1 for 5 min.
  2. ClientFactory.clientConnectionFailed (p2p.py:612) — an outbound connect to a loopback peer that is momentarily down during churn (restart) bans 127.0.0.1 for 60s.

Once bans['127.0.0.1'] is set, ServerFactory.buildProtocol (p2p.py:538) returns None for every fresh incoming loopback connection → silent RST. Churn keeps refreshing the ban, so it persists.

Fix

Connection hygiene only — no share / sharechain / protocol behavior changes (consensus-neutral). Exempt loopback (127.0.0.0/8, ::1) from:

  • the self-nonce ban path (loopback self-connections are expected; drop the loop, never ban),
  • the connect-failure ban path,
  • and, as defense-in-depth, the buildProtocol ban gate, so no ban source can RST a loopback re-accept.

Adds LoopbackBanTest regression coverage in test_p2p.py.

Note (not changed here)

buildProtocol also caps incoming connections per /16 ident at 3, and all 127.x collapse to one ident — so a co-located fleet with >3 loopback peers can hit a steady-state cap independent of churn. Left as-is (avoids unbounded loopback fan-in); can be revisited if a larger co-located topology needs it.

…s (#757)

Under connection churn, co-located / loopback peers (mixed-fleet, NAT'd
deployments where c2pool and p2pool-dash reconnect over 127.0.0.1) were
silently RST'd on every fresh incoming connection.

Root cause: two ban paths added for Dash Core v23+ support wrote
self.node.bans['127.0.0.1'] without the localhost exemption that
Protocol.badPeerHappened deliberately applies:

  - handle_version self-nonce rate-limiter: a loopback self-connection
    (node reaching its own advertised 127.0.0.1) counts toward the
    3-strikes-in-10min ban -> bans 127.0.0.1 for 5 min.
  - ClientFactory.clientConnectionFailed: an outbound connect to a
    loopback peer that is momentarily down during churn (restart) bans
    127.0.0.1 for 60s.

Once bans['127.0.0.1'] is set, ServerFactory.buildProtocol returns None
for every incoming loopback connection -> silent RST. Churn keeps
refreshing the ban, so it persists.

Fix (connection hygiene only; no share/sharechain/protocol change):
exempt loopback (127.0.0.0/8, ::1) from both new ban paths, and as
defense-in-depth from the buildProtocol ban gate, so no ban source can
RST a loopback re-accept. Adds LoopbackBanTest regression coverage.

Same class as the c2pool zombie-session leak: stale admission-control
state (there a dead session, here a ban entry) not cleaned up causes new
legitimate connections to be RST'd.
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.

1 participant