Skip to content

Commit ac16285

Browse files
fix(dot/network): move low reputation peer removal from network ConnManager to peer scoring logic (dot/peerstate) (ChainSafe#2068)
- peerset service (doWorks goroutine) sends messages to network service about peers to connect, drop, reject, disconnect etc. Some of those message were being send without a peer id and set id. This was the reason why our excess peers were not getting removed. - To save ourselves from such a problem in future, processMessage now checks if peer id is empty or not. - Also change the resultMsgCh type to peerset.Message from interface{} Fixes ChainSafe#2039
1 parent a7594a3 commit ac16285

6 files changed

Lines changed: 45 additions & 58 deletions

File tree

dot/network/connmgr.go

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ package network
55

66
import (
77
"context"
8-
"crypto/rand"
9-
"math/big"
108
"sync"
119

1210
"github.com/libp2p/go-libp2p-core/connmgr"
@@ -130,40 +128,10 @@ func (cm *ConnManager) unprotectedPeers(peers []peer.ID) []peer.ID {
130128
func (cm *ConnManager) Connected(n network.Network, c network.Conn) {
131129
logger.Tracef(
132130
"Host %s connected to peer %s", n.LocalPeer(), c.RemotePeer())
131+
133132
if cm.connectHandler != nil {
134133
cm.connectHandler(c.RemotePeer())
135134
}
136-
137-
cm.Lock()
138-
defer cm.Unlock()
139-
140-
over := len(n.Peers()) - cm.max
141-
if over <= 0 {
142-
return
143-
}
144-
145-
// TODO: peer scoring doesn't seem to prevent us from going over the max.
146-
// if over the max peer count, disconnect from (total_peers - maximum) peers
147-
// (#2039)
148-
for i := 0; i < over; i++ {
149-
unprotPeers := cm.unprotectedPeers(n.Peers())
150-
if len(unprotPeers) == 0 {
151-
return
152-
}
153-
154-
i, err := rand.Int(rand.Reader, big.NewInt(int64(len(unprotPeers))))
155-
if err != nil {
156-
logger.Errorf("error generating random number: %s", err)
157-
return
158-
}
159-
160-
up := unprotPeers[i.Int64()]
161-
logger.Tracef("Over max peer count, disconnecting from random unprotected peer %s", up)
162-
err = n.ClosePeer(up)
163-
if err != nil {
164-
logger.Tracef("failed to close connection to peer %s", up)
165-
}
166-
}
167135
}
168136

169137
// Disconnected is called when a connection closed

dot/network/service.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ package network
66
import (
77
"context"
88
"errors"
9-
"fmt"
109
"math/big"
1110
"strings"
1211
"sync"
@@ -670,6 +669,10 @@ func (s *Service) startPeerSetHandler() {
670669

671670
func (s *Service) processMessage(msg peerset.Message) {
672671
peerID := msg.PeerID
672+
if peerID == "" {
673+
logger.Errorf("found empty peer id in peerset message")
674+
return
675+
}
673676
switch msg.Status {
674677
case peerset.Connect:
675678
addrInfo := s.host.h.Peerstore().PeerInfo(peerID)
@@ -704,12 +707,7 @@ func (s *Service) startProcessingMsg() {
704707
select {
705708
case <-s.ctx.Done():
706709
return
707-
case m := <-msgCh:
708-
msg, ok := m.(peerset.Message)
709-
if !ok {
710-
logger.Error(fmt.Sprintf("failed to get message from peerSet: type is %T instead of peerset.Message", m))
711-
continue
712-
}
710+
case msg := <-msgCh:
713711
s.processMessage(msg)
714712
}
715713
}

dot/network/state.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,5 +79,5 @@ type PeerRemove interface {
7979
type Peer interface {
8080
PeerReputation(peer.ID) (peerset.Reputation, error)
8181
SortedPeers(idx int) chan peer.IDSlice
82-
Messages() chan interface{}
82+
Messages() chan peerset.Message
8383
}

dot/peerset/handler.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33

44
package peerset
55

6-
import "github.com/libp2p/go-libp2p-core/peer"
6+
import (
7+
"github.com/libp2p/go-libp2p-core/peer"
8+
)
79

810
// Handler manages peerSet.
911
type Handler struct {
@@ -88,7 +90,7 @@ func (h *Handler) Incoming(setID int, peers ...peer.ID) {
8890
}
8991

9092
// Messages return result message chan.
91-
func (h *Handler) Messages() chan interface{} {
93+
func (h *Handler) Messages() chan Message {
9294
return h.peerSet.resultMsgCh
9395
}
9496

dot/peerset/peerset.go

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ type PeerSet struct {
141141
// TODO: this will be useful for reserved only mode
142142
// this is for future purpose if reserved-only flag is enabled (#1888).
143143
isReservedOnly bool
144-
resultMsgCh chan interface{}
144+
resultMsgCh chan Message
145145
// time when the PeerSet was created.
146146
created time.Time
147147
// last time when we updated the reputations of connected nodes.
@@ -183,6 +183,8 @@ func NewConfigSet(in, out uint32, reservedOnly bool, allocTime time.Duration) *C
183183
}
184184

185185
return &ConfigSet{
186+
// Why are we using an array of config in the set, when we are
187+
// using just one config
186188
Set: []*config{set},
187189
}
188190
}
@@ -228,8 +230,8 @@ func reputationTick(reput Reputation) Reputation {
228230
return reput.sub(diff)
229231
}
230232

231-
// updateTime updates the value of latestTimeUpdate and performs all the updates that happen
232-
// over time, such as Reputation increases for staying connected.
233+
// updateTime updates the value of latestTimeUpdate and performs all the updates that
234+
// happen over time, such as Reputation increases for staying connected.
233235
func (ps *PeerSet) updateTime() error {
234236
currTime := time.Now()
235237
// identify the time difference between current time and last update time for peer reputation in seconds.
@@ -282,8 +284,8 @@ func (ps *PeerSet) updateTime() error {
282284
}
283285

284286
// reportPeer on report ReputationChange of the peer based on its behaviour,
285-
// if the updated Reputation is below BannedThresholdValue then, this node need to be disconnected
286-
// and a drop message for the peer is sent in order to disconnect.
287+
// if the updated Reputation is below BannedThresholdValue then, this node need to
288+
// be disconnected and a drop message for the peer is sent in order to disconnect.
287289
func (ps *PeerSet) reportPeer(change ReputationChange, peers ...peer.ID) error {
288290
// we want reputations to be up-to-date before adjusting them.
289291
if err := ps.updateTime(); err != nil {
@@ -516,8 +518,9 @@ func (ps *PeerSet) removePeer(setID int, peers ...peer.ID) error {
516518
return nil
517519
}
518520

519-
// incoming indicates that we have received an incoming connection. Must be answered either with
520-
// a corresponding `Accept` or `Reject`, except if we were already connected to this peer.
521+
// incoming indicates that we have received an incoming connection. Must be answered
522+
// either with a corresponding `Accept` or `Reject`, except if we were already
523+
// connected to this peer.
521524
func (ps *PeerSet) incoming(setID int, peers ...peer.ID) error {
522525
if err := ps.updateTime(); err != nil {
523526
return err
@@ -527,7 +530,11 @@ func (ps *PeerSet) incoming(setID int, peers ...peer.ID) error {
527530
for _, pid := range peers {
528531
if ps.isReservedOnly {
529532
if _, ok := ps.reservedNode[pid]; !ok {
530-
ps.resultMsgCh <- Message{Status: Reject}
533+
ps.resultMsgCh <- Message{
534+
Status: Reject,
535+
setID: uint64(setID),
536+
PeerID: pid,
537+
}
531538
continue
532539
}
533540
}
@@ -546,11 +553,24 @@ func (ps *PeerSet) incoming(setID int, peers ...peer.ID) error {
546553
p := state.nodes[pid]
547554
switch {
548555
case p.getReputation() < BannedThresholdValue:
549-
ps.resultMsgCh <- Message{Status: Reject}
556+
ps.resultMsgCh <- Message{
557+
Status: Reject,
558+
setID: uint64(setID),
559+
PeerID: pid,
560+
}
550561
case state.tryAcceptIncoming(setID, pid) != nil:
551-
ps.resultMsgCh <- Message{Status: Reject}
562+
ps.resultMsgCh <- Message{
563+
Status: Reject,
564+
setID: uint64(setID),
565+
PeerID: pid,
566+
}
552567
default:
553-
ps.resultMsgCh <- Message{Status: Accept}
568+
logger.Debugf("incoming connection accepted from peer %s", pid)
569+
ps.resultMsgCh <- Message{
570+
Status: Accept,
571+
setID: uint64(setID),
572+
PeerID: pid,
573+
}
554574
}
555575
}
556576

@@ -593,6 +613,7 @@ func (ps *PeerSet) disconnect(setIdx int, reason DropReason, peers ...peer.ID) e
593613
}
594614
ps.resultMsgCh <- Message{
595615
Status: Drop,
616+
setID: uint64(setIdx),
596617
PeerID: pid,
597618
}
598619

@@ -610,7 +631,7 @@ func (ps *PeerSet) disconnect(setIdx int, reason DropReason, peers ...peer.ID) e
610631
// start handles all the action for the peerSet.
611632
func (ps *PeerSet) start(aq chan action) {
612633
ps.actionQueue = aq
613-
ps.resultMsgCh = make(chan interface{}, msgChanSize)
634+
ps.resultMsgCh = make(chan Message, msgChanSize)
614635
go ps.doWork()
615636
}
616637

dot/peerset/peerset_test.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,7 @@ func TestAddReservedPeers(t *testing.T) {
6868
if len(ps.resultMsgCh) == 0 {
6969
break
7070
}
71-
m := <-ps.resultMsgCh
72-
msg, ok := m.(Message)
73-
require.True(t, ok)
71+
msg := <-ps.resultMsgCh
7472
require.Equal(t, expectedMsgs[i], msg)
7573
}
7674
}

0 commit comments

Comments
 (0)