-
Notifications
You must be signed in to change notification settings - Fork 931
/
gossip_scorer.go
110 lines (94 loc) · 3.06 KB
/
gossip_scorer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package scorers
import (
"github.com/libp2p/go-libp2p/core/peer"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p/peers/peerdata"
pbrpc "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
)
var _ Scorer = (*GossipScorer)(nil)
const (
// The boundary till which a peer's gossip score is acceptable.
gossipThreshold = -100.0
)
// GossipScorer represents scorer that evaluates peers based on their gossip performance.
// Gossip scoring metrics are periodically calculated in libp2p's internal pubsub module.
type GossipScorer struct {
config *GossipScorerConfig
store *peerdata.Store
}
// GossipScorerConfig holds configuration parameters for gossip scoring service.
type GossipScorerConfig struct{}
// newGossipScorer creates new gossip scoring service.
func newGossipScorer(store *peerdata.Store, config *GossipScorerConfig) *GossipScorer {
if config == nil {
config = &GossipScorerConfig{}
}
return &GossipScorer{
config: config,
store: store,
}
}
// Score returns calculated peer score.
func (s *GossipScorer) Score(pid peer.ID) float64 {
s.store.RLock()
defer s.store.RUnlock()
return s.score(pid)
}
// score is a lock-free version of Score.
func (s *GossipScorer) score(pid peer.ID) float64 {
peerData, ok := s.store.PeerData(pid)
if !ok {
return 0
}
return peerData.GossipScore
}
// IsBadPeer states if the peer is to be considered bad.
func (s *GossipScorer) IsBadPeer(pid peer.ID) bool {
s.store.RLock()
defer s.store.RUnlock()
return s.isBadPeer(pid)
}
// isBadPeer is lock-free version of IsBadPeer.
func (s *GossipScorer) isBadPeer(pid peer.ID) bool {
peerData, ok := s.store.PeerData(pid)
if !ok {
return false
}
return peerData.GossipScore < gossipThreshold
}
// BadPeers returns the peers that are considered bad.
func (s *GossipScorer) BadPeers() []peer.ID {
s.store.RLock()
defer s.store.RUnlock()
badPeers := make([]peer.ID, 0)
for pid := range s.store.Peers() {
if s.isBadPeer(pid) {
badPeers = append(badPeers, pid)
}
}
return badPeers
}
// SetGossipData sets the gossip related data of a peer.
func (s *GossipScorer) SetGossipData(pid peer.ID, gScore float64,
bPenalty float64, topicScores map[string]*pbrpc.TopicScoreSnapshot) {
s.store.Lock()
defer s.store.Unlock()
peerData := s.store.PeerDataGetOrCreate(pid)
peerData.GossipScore = gScore
peerData.BehaviourPenalty = bPenalty
peerData.TopicScores = topicScores
}
// GossipData gets the gossip related information of the given remote peer.
// This can return nil if there is no known gossip record the peer.
// This will error if the peer does not exist.
func (s *GossipScorer) GossipData(pid peer.ID) (float64, float64, map[string]*pbrpc.TopicScoreSnapshot, error) {
s.store.RLock()
defer s.store.RUnlock()
return s.gossipData(pid)
}
// gossipData lock-free version of GossipData.
func (s *GossipScorer) gossipData(pid peer.ID) (float64, float64, map[string]*pbrpc.TopicScoreSnapshot, error) {
if peerData, ok := s.store.PeerData(pid); ok {
return peerData.GossipScore, peerData.BehaviourPenalty, peerData.TopicScores, nil
}
return 0, 0, nil, peerdata.ErrPeerUnknown
}