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  }