fix(eth): make paired peer unregister instance-aware#2351
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
This PR fixes cleanup for “paired” eth peers (two connections sharing the same peer ID) so that removing the secondary connection doesn’t accidentally remove the primary peer or leave a stale pairRw behind. It also adds regression tests to ensure paired-peer cleanup works and that header serving continues after the paired connection drops.
Changes:
- Update
ProtocolManagerpeer removal to unregister by peer instance (not just by ID), and only unregister from the downloader when removing the primary connection. - Extend
peerSetremoval logic to clear pairing state (pairRwandPairPeer) and addUnregisterPeer(*peer)to support instance-based removal. - Add regression tests for paired peer cleanup and for serving block headers after the paired connection disconnects.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
eth/peer.go |
Adds UnregisterPeer(*peer) and clears pairing state during unregister to avoid stale pairRw and incorrect removals. |
eth/handler.go |
Switches removal to instance-based (removePeer(*peer)), adds removePeerByID wrapper for downloader/fetcher callbacks. |
eth/peer_test.go |
Adds a unit test ensuring unregistering a paired instance keeps the primary and clears pair state. |
eth/handler_test.go |
Adds an integration-style test ensuring headers are still served after the paired connection drops. |
f18843c to
4926447
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
eth/peer.go:583
- Same race/tearing risk exists in this code path:
current.pairRw = nil(and the earlierexistPeer.pairRw = p.rwassignment inRegister) are not synchronized with reads inSend*methods. Even if the peerSet lock is held, send paths don’t take that lock, so this doesn’t prevent concurrent access. Consider encapsulating pair-writer access behind atomic load/store helpers or a dedicated lock onpeerto avoid data races and typed-nil panics.
if current == p {
current.pairRw = nil
delete(ps.peers, p.id)
return nil
}
if current.ClearPairPeer(p.Peer) {
p.ClearPairPeer(current.Peer)
current.pairRw = nil
return nil
4926447 to
b862d5a
Compare
b862d5a to
f3fc79e
Compare
f3fc79e to
c85eecf
Compare
92ac72a to
040bff6
Compare
cab26b8 to
029bdca
Compare
029bdca to
10d5524
Compare
cab39b2 to
f8afbf6
Compare
fc3fb61 to
b84ed74
Compare
Handle paired eth peer teardown by instance so dropping the secondary connection clears pair state without removing the primary peer from the set. Synchronize pairRw access to avoid torn interface reads during concurrent send and unregister paths, and cover the lifecycle with regression tests.
b84ed74 to
d13a123
Compare
…tized write path, close XinFinOrg#2351 XinFinOrg#2359 Replace the pair-peer dual-link write model with a single peer-owned write ingress backed by internal high/low priority queues. Preserve BFT message priority across wrapper layers, keep synchronous write errors visible to callers, and make queued versus in-flight shutdown handling deterministic. Update queue metrics and add regression coverage for priority preemption, starvation bounds, ping serialization, wrapper forwarding, and shutdown behavior.
…tized write path, close XinFinOrg#2351 XinFinOrg#2359 Replace the pair-peer dual-link write model with a single peer-owned write ingress backed by internal high/low priority queues. Preserve BFT message priority across wrapper layers, keep synchronous write errors visible to callers, and make queued versus in-flight shutdown handling deterministic. Update queue metrics and add regression coverage for priority preemption, starvation bounds, ping serialization, wrapper forwarding, and shutdown behavior.
…tized write path, close XinFinOrg#2351 XinFinOrg#2359 Replace the pair-peer dual-link write model with a single peer-owned write ingress backed by internal high/low priority queues. Preserve BFT message priority across wrapper layers, keep synchronous write errors visible to callers, and make queued versus in-flight shutdown handling deterministic. Update queue metrics and add regression coverage for priority preemption, starvation bounds, ping serialization, wrapper forwarding, and shutdown behavior.
…tized write path, close XinFinOrg#2351 XinFinOrg#2359 Replace the pair-peer dual-link write model with a single peer-owned write ingress backed by internal high/low priority queues. Preserve BFT message priority across wrapper layers, keep synchronous write errors visible to callers, and make queued versus in-flight shutdown handling deterministic. Update queue metrics and add regression coverage for priority preemption, starvation bounds, ping serialization, wrapper forwarding, and shutdown behavior.
…tized write path, close XinFinOrg#2351 XinFinOrg#2359 Replace the pair-peer dual-link write model with a single peer-owned write ingress backed by internal high/low priority queues. Preserve BFT message priority across wrapper layers, keep synchronous write errors visible to callers, and make queued versus in-flight shutdown handling deterministic. Update queue metrics and add regression coverage for priority preemption, starvation bounds, ping serialization, wrapper forwarding, and shutdown behavior.
…tized write path, close XinFinOrg#2351 XinFinOrg#2359 Replace the pair-peer dual-link write model with a single peer-owned write ingress backed by internal high/low priority queues. Preserve BFT message priority across wrapper layers, keep synchronous write errors visible to callers, and make queued versus in-flight shutdown handling deterministic. Update queue metrics and add regression coverage for priority preemption, starvation bounds, ping serialization, wrapper forwarding, and shutdown behavior.
…inFinOrg#2351 XinFinOrg#2359 XDPoSChain kept two independent RLPx/TCP connections per remote peer (a "primary" and a "pair"), a private divergence from upstream go-ethereum which allows only one connection per NodeID. This adds state-machine complexity (isPair, pairRw, PairPeer, ErrAddPairPeer, DiscPairPeerStop) without measured benefit, and the pair connection already carried both block-sync and BFT traffic, so it never isolated Vote/Timeout/SyncInfo from large BlockBodies/NodeData frames. Revert to a single connection per NodeID (upstream semantics) and route all eth messages, including the XDPoS v2 BFT messages, over that single connection using the existing upstream FIFO write scheduling. No write-priority lane is added; RLPx framing, message ids, capability strings and the handshake are unchanged, so the change is rolling-upgrade safe against legacy pair-capable nodes. Changes: - p2p/server.go: postHandshakeChecks rejects any duplicate NodeID with DiscAlreadyConnected; addPeer no longer stores a second connection. - p2p/peer.go: drop pairPeer field/methods and the DiscPairPeerStop cascade on Peer.run exit. - p2p/peer_error.go: remove ErrAddPairPeer; keep the DiscPairPeerStop enum slot (deprecated) to preserve on-the-wire numbering. - eth/peer.go: remove pairRw; all Send/Request helpers use p.rw; peerSet.Register reverts to one peer per id. - eth/handler.go: drop ErrAddPairPeer special-casing so every peer registers with the downloader and syncs transactions. Refs: XinFinOrg#2359
…FinOrg#2351 XinFinOrg#2359 XDPoSChain kept two independent RLPx/TCP connections per remote peer (a "primary" and a "pair"), a private divergence from upstream go-ethereum which allows only one connection per NodeID. This adds state-machine complexity (isPair, pairRw, PairPeer, ErrAddPairPeer, DiscPairPeerStop) without measured benefit, and the pair connection already carried both block-sync and BFT traffic, so it never isolated Vote/Timeout/SyncInfo from large BlockBodies/NodeData frames. Revert to a single connection per NodeID (upstream semantics) and route all eth messages, including the XDPoS v2 BFT messages, over that single connection using the existing upstream FIFO write scheduling. No write-priority lane is added; RLPx framing, message ids, capability strings and the handshake are unchanged, so the change is rolling-upgrade safe against legacy pair-capable nodes. Changes: - p2p/server.go: postHandshakeChecks rejects any duplicate NodeID with DiscAlreadyConnected; addPeer no longer stores a second connection. - p2p/peer.go: drop pairPeer field/methods and the DiscPairPeerStop cascade on Peer.run exit. - p2p/peer_error.go: remove ErrAddPairPeer; keep the DiscPairPeerStop enum slot (deprecated) to preserve on-the-wire numbering. - eth/peer.go: remove pairRw; all Send/Request helpers use p.rw; peerSet.Register reverts to one peer per id. - eth/handler.go: drop ErrAddPairPeer special-casing so every peer registers with the downloader and syncs transactions. Refs: XinFinOrg#2359
…Org#2351 XinFinOrg#2359 XDPoSChain kept two independent RLPx/TCP connections per remote peer (a "primary" and a "pair"), a private divergence from upstream go-ethereum which allows only one connection per NodeID. This adds state-machine complexity (isPair, pairRw, PairPeer, ErrAddPairPeer, DiscPairPeerStop) without measured benefit, and the pair connection already carried both block-sync and BFT traffic, so it never isolated Vote/Timeout/SyncInfo from large BlockBodies/NodeData frames. Revert to a single connection per NodeID (upstream semantics) and route all eth messages, including the XDPoS v2 BFT messages, over that single connection using the existing upstream FIFO write scheduling. No write-priority lane is added; RLPx framing, message ids, capability strings and the handshake are unchanged, so the change is rolling-upgrade safe against legacy pair-capable nodes. Changes: - p2p/server.go: postHandshakeChecks rejects any duplicate NodeID with DiscAlreadyConnected; addPeer no longer stores a second connection. - p2p/peer.go: drop pairPeer field/methods and the DiscPairPeerStop cascade on Peer.run exit. - p2p/peer_error.go: remove ErrAddPairPeer; keep the DiscPairPeerStop enum slot (deprecated) to preserve on-the-wire numbering. - eth/peer.go: remove pairRw; all Send/Request helpers use p.rw; peerSet.Register reverts to one peer per id. - eth/handler.go: drop ErrAddPairPeer special-casing so every peer registers with the downloader and syncs transactions. Refs: XinFinOrg#2359
…Org#2351 XinFinOrg#2359 XDPoSChain kept two independent RLPx/TCP connections per remote peer (a "primary" and a "pair"), a private divergence from upstream go-ethereum which allows only one connection per NodeID. This adds state-machine complexity (isPair, pairRw, PairPeer, ErrAddPairPeer, DiscPairPeerStop) without measured benefit, and the pair connection already carried both block-sync and BFT traffic, so it never isolated Vote/Timeout/SyncInfo from large BlockBodies/NodeData frames. Revert to a single connection per NodeID (upstream semantics) and route all eth messages, including the XDPoS v2 BFT messages, over that single connection using the existing upstream FIFO write scheduling. No write-priority lane is added; RLPx framing, message ids, capability strings and the handshake are unchanged, so the change is rolling-upgrade safe against legacy pair-capable nodes. Changes: - p2p/server.go: postHandshakeChecks rejects any duplicate NodeID with DiscAlreadyConnected; addPeer no longer stores a second connection. - p2p/peer.go: drop pairPeer field/methods and the DiscPairPeerStop cascade on Peer.run exit. - p2p/peer_error.go: remove ErrAddPairPeer; keep the DiscPairPeerStop enum slot (deprecated) to preserve on-the-wire numbering. - eth/peer.go: remove pairRw; all Send/Request helpers use p.rw; peerSet.Register reverts to one peer per id. - eth/handler.go: drop ErrAddPairPeer special-casing so every peer registers with the downloader and syncs transactions. Refs: XinFinOrg#2359
…Org#2351 XinFinOrg#2359 XDPoSChain kept two independent RLPx/TCP connections per remote peer (a "primary" and a "pair"), a private divergence from upstream go-ethereum which allows only one connection per NodeID. This adds state-machine complexity (isPair, pairRw, PairPeer, ErrAddPairPeer, DiscPairPeerStop) without measured benefit, and the pair connection already carried both block-sync and BFT traffic, so it never isolated Vote/Timeout/SyncInfo from large BlockBodies/NodeData frames. Revert to a single connection per NodeID (upstream semantics) and route all eth messages, including the XDPoS v2 BFT messages, over that single connection using the existing upstream FIFO write scheduling. No write-priority lane is added; RLPx framing, message ids, capability strings and the handshake are unchanged, so the change is rolling-upgrade safe against legacy pair-capable nodes. Changes: - p2p/server.go: postHandshakeChecks rejects any duplicate NodeID with DiscAlreadyConnected; addPeer no longer stores a second connection. - p2p/peer.go: drop pairPeer field/methods and the DiscPairPeerStop cascade on Peer.run exit. - p2p/peer_error.go: remove ErrAddPairPeer; keep the DiscPairPeerStop enum slot (deprecated) to preserve on-the-wire numbering. - eth/peer.go: remove pairRw; all Send/Request helpers use p.rw; peerSet.Register reverts to one peer per id. - eth/handler.go: drop ErrAddPairPeer special-casing so every peer registers with the downloader and syncs transactions. Refs: XinFinOrg#2359
Proposed changes
Handle paired eth peer teardown by instance so dropping the secondary connection clears pair state without removing the primary peer from the set.
Synchronize pairRw access to avoid torn interface reads during concurrent send and unregister paths, and cover the lifecycle with regression tests.
fix panic:
Types of changes
What types of changes does your code introduce to XDC network?
Put an
✅in the boxes that applyImpacted Components
Which parts of the codebase does this PR touch?
Put an
✅in the boxes that applyChecklist
Put an
✅in the boxes once you have confirmed below actions (or provide reasons on not doing so) that