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)