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