github.com/ethereum-optimism/optimism@v1.7.2/op-node/p2p/app_scores.go (about)

     1  package p2p
     2  
     3  import (
     4  	"context"
     5  	"sync"
     6  
     7  	"github.com/ethereum-optimism/optimism/op-node/p2p/store"
     8  	"github.com/ethereum-optimism/optimism/op-service/clock"
     9  	"github.com/ethereum/go-ethereum/log"
    10  	"github.com/libp2p/go-libp2p/core/peer"
    11  )
    12  
    13  type ScoreBook interface {
    14  	GetPeerScores(id peer.ID) (store.PeerScores, error)
    15  	SetScore(id peer.ID, diff store.ScoreDiff) (store.PeerScores, error)
    16  }
    17  
    18  type ApplicationScorer interface {
    19  	ApplicationScore(id peer.ID) float64
    20  	onValidResponse(id peer.ID)
    21  	onResponseError(id peer.ID)
    22  	onRejectedPayload(id peer.ID)
    23  	start()
    24  	stop()
    25  }
    26  
    27  type peerApplicationScorer struct {
    28  	ctx            context.Context
    29  	cancelFunc     context.CancelFunc
    30  	log            log.Logger
    31  	clock          clock.Clock
    32  	params         *ApplicationScoreParams
    33  	scorebook      ScoreBook
    34  	connectedPeers func() []peer.ID
    35  
    36  	done sync.WaitGroup
    37  }
    38  
    39  var _ ApplicationScorer = (*peerApplicationScorer)(nil)
    40  
    41  func newPeerApplicationScorer(ctx context.Context, logger log.Logger, clock clock.Clock, params *ApplicationScoreParams, scorebook ScoreBook, connectedPeers func() []peer.ID) *peerApplicationScorer {
    42  	ctx, cancelFunc := context.WithCancel(ctx)
    43  	return &peerApplicationScorer{
    44  		ctx:            ctx,
    45  		cancelFunc:     cancelFunc,
    46  		log:            logger,
    47  		clock:          clock,
    48  		params:         params,
    49  		scorebook:      scorebook,
    50  		connectedPeers: connectedPeers,
    51  	}
    52  }
    53  
    54  func (s *peerApplicationScorer) ApplicationScore(id peer.ID) float64 {
    55  	scores, err := s.scorebook.GetPeerScores(id)
    56  	if err != nil {
    57  		s.log.Error("Failed to load peer scores", "peer", id, "err", err)
    58  		return 0
    59  	}
    60  	score := scores.ReqResp.ValidResponses * s.params.ValidResponseWeight
    61  	score += scores.ReqResp.ErrorResponses * s.params.ErrorResponseWeight
    62  	score += scores.ReqResp.RejectedPayloads * s.params.RejectedPayloadWeight
    63  	return score
    64  }
    65  
    66  func (s *peerApplicationScorer) onValidResponse(id peer.ID) {
    67  	_, err := s.scorebook.SetScore(id, store.IncrementValidResponses{Cap: s.params.ValidResponseCap})
    68  	if err != nil {
    69  		s.log.Error("Unable to update peer score", "peer", id, "err", err)
    70  		return
    71  	}
    72  }
    73  
    74  func (s *peerApplicationScorer) onResponseError(id peer.ID) {
    75  	_, err := s.scorebook.SetScore(id, store.IncrementErrorResponses{Cap: s.params.ErrorResponseCap})
    76  	if err != nil {
    77  		s.log.Error("Unable to update peer score", "peer", id, "err", err)
    78  		return
    79  	}
    80  }
    81  
    82  func (s *peerApplicationScorer) onRejectedPayload(id peer.ID) {
    83  	_, err := s.scorebook.SetScore(id, store.IncrementRejectedPayloads{Cap: s.params.RejectedPayloadCap})
    84  	if err != nil {
    85  		s.log.Error("Unable to update peer score", "peer", id, "err", err)
    86  		return
    87  	}
    88  }
    89  
    90  func (s *peerApplicationScorer) decayScores(id peer.ID) {
    91  	_, err := s.scorebook.SetScore(id, &store.DecayApplicationScores{
    92  		ValidResponseDecay:   s.params.ValidResponseDecay,
    93  		ErrorResponseDecay:   s.params.ErrorResponseDecay,
    94  		RejectedPayloadDecay: s.params.RejectedPayloadDecay,
    95  		DecayToZero:          s.params.DecayToZero,
    96  	})
    97  	if err != nil {
    98  		s.log.Error("Unable to decay peer score", "peer", id, "err", err)
    99  		return
   100  	}
   101  }
   102  
   103  func (s *peerApplicationScorer) decayConnectedPeerScores() {
   104  	for _, id := range s.connectedPeers() {
   105  		s.decayScores(id)
   106  	}
   107  }
   108  
   109  func (s *peerApplicationScorer) start() {
   110  	s.done.Add(1)
   111  	go func() {
   112  		defer s.done.Done()
   113  		ticker := s.clock.NewTicker(s.params.DecayInterval)
   114  		defer ticker.Stop()
   115  		for {
   116  			select {
   117  			case <-s.ctx.Done():
   118  				return
   119  			case <-ticker.Ch():
   120  				s.decayConnectedPeerScores()
   121  			}
   122  		}
   123  	}()
   124  }
   125  
   126  func (s *peerApplicationScorer) stop() {
   127  	s.cancelFunc()
   128  	s.done.Wait()
   129  }
   130  
   131  type NoopApplicationScorer struct{}
   132  
   133  func (n *NoopApplicationScorer) ApplicationScore(_ peer.ID) float64 {
   134  	return 0
   135  }
   136  
   137  func (n *NoopApplicationScorer) onValidResponse(_ peer.ID) {
   138  }
   139  
   140  func (n *NoopApplicationScorer) onResponseError(_ peer.ID) {
   141  }
   142  
   143  func (n *NoopApplicationScorer) onRejectedPayload(_ peer.ID) {
   144  }
   145  
   146  func (n *NoopApplicationScorer) start() {
   147  }
   148  
   149  func (n *NoopApplicationScorer) stop() {
   150  }
   151  
   152  var _ ApplicationScorer = (*NoopApplicationScorer)(nil)