Skip to content

Commit e43fbf0

Browse files
committed
[release-v2.1] p2p: Handle peer ID wraparound
When wraparound of the uint64 peer ID counter occurs, take care to never conflict (sharing a peer ID) with existing peers who are still connected with the same ID. While here, continue to skip the zero ID (remote peer IDs always start at one) so zero can be reserved for local peer usage. Backport of 54a9b82.
1 parent 99ca177 commit e43fbf0

1 file changed

Lines changed: 18 additions & 14 deletions

File tree

p2p/peering.go

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@ type RemotePeer struct {
144144
// messages with remote peers on the network.
145145
type LocalPeer struct {
146146
mask atomic.Uint64
147-
peerIDCounter atomic.Uint64
148147
requireHeight atomic.Int32
149148

150149
dial DialFunc
@@ -160,8 +159,9 @@ type LocalPeer struct {
160159
chainParams *chaincfg.Params
161160
disableRelayTx bool
162161

163-
rpByID map[uint64]*RemotePeer
164-
rpMu sync.Mutex
162+
rpByID map[uint64]*RemotePeer
163+
rpIDCounter uint64
164+
rpMu sync.Mutex
165165
}
166166

167167
// NewLocalPeer creates a LocalPeer that is externally reachable to remote peers
@@ -257,9 +257,6 @@ func (lp *LocalPeer) ConnectOutbound(ctx context.Context, addr string, reqSvcs w
257257

258258
log.Debugf("Attempting connection to peer %v", addr)
259259

260-
// Generate a unique ID for this peer and add the initial connection state.
261-
id := lp.peerIDCounter.Add(1)
262-
263260
tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
264261
if err != nil {
265262
return nil, err
@@ -269,7 +266,7 @@ func (lp *LocalPeer) ConnectOutbound(ctx context.Context, addr string, reqSvcs w
269266
na := addrmgr.NewNetAddressFromIPPort(tcpAddr.IP, uint16(tcpAddr.Port), wire.SFNodeNetwork)
270267
na.Timestamp = time.Now()
271268

272-
rp, err := lp.connectOutbound(ctx, id, addr, na)
269+
rp, err := lp.connectOutbound(ctx, addr, na)
273270
if err != nil {
274271
op := errors.Opf(opf, addr)
275272
return nil, errors.E(op, err)
@@ -544,11 +541,11 @@ func (rp *RemotePeer) sendWaitingInventory(ctx context.Context) error {
544541
return nil
545542
}
546543

547-
func handshake(ctx context.Context, lp *LocalPeer, id uint64, na *addrmgr.NetAddress, c net.Conn) (*RemotePeer, error) {
544+
func handshake(ctx context.Context, lp *LocalPeer, na *addrmgr.NetAddress, c net.Conn) (*RemotePeer, error) {
548545
const op errors.Op = "p2p.handshake"
549546

550547
rp := &RemotePeer{
551-
id: id,
548+
id: 0, // Set after handshake completes
552549
lp: lp,
553550
ua: "",
554551
services: 0,
@@ -618,9 +615,7 @@ func handshake(ctx context.Context, lp *LocalPeer, id uint64, na *addrmgr.NetAdd
618615
return rp, nil
619616
}
620617

621-
func (lp *LocalPeer) connectOutbound(ctx context.Context, id uint64, addr string,
622-
na *addrmgr.NetAddress) (*RemotePeer, error) {
623-
618+
func (lp *LocalPeer) connectOutbound(ctx context.Context, addr string, na *addrmgr.NetAddress) (*RemotePeer, error) {
624619
// Mark the connection attempt.
625620
lp.amgr.Attempt(na)
626621

@@ -636,15 +631,24 @@ func (lp *LocalPeer) connectOutbound(ctx context.Context, id uint64, addr string
636631

637632
// Handshake with a timeout of 5s.
638633
handshakeCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
639-
rp, err := handshake(handshakeCtx, lp, id, na, c)
634+
rp, err := handshake(handshakeCtx, lp, na, c)
640635
cancel()
641636
if err != nil {
642637
return nil, err
643638
}
644639

645640
// Associate connected rp with local peer.
646641
lp.rpMu.Lock()
647-
lp.rpByID[rp.id] = rp
642+
for {
643+
// Generate a unique ID for this peer and add the initial connection state.
644+
lp.rpIDCounter++
645+
id := lp.rpIDCounter
646+
if _, ok := lp.rpByID[id]; !ok && id != 0 {
647+
rp.id = id
648+
lp.rpByID[id] = rp
649+
break
650+
}
651+
}
648652
lp.rpMu.Unlock()
649653

650654
// The real services of the net address are now known.

0 commit comments

Comments
 (0)