github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/p2p/peers/scorers/gossip_scorer.go (about)

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