forked from ethereum-optimism/optimism
-
Notifications
You must be signed in to change notification settings - Fork 0
/
peer_scorer.go
93 lines (81 loc) · 3.13 KB
/
peer_scorer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package p2p
import (
"time"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/p2p/store"
log "github.com/ethereum/go-ethereum/log"
pubsub "github.com/libp2p/go-libp2p-pubsub"
peer "github.com/libp2p/go-libp2p/core/peer"
)
type scorer struct {
peerStore Peerstore
metricer ScoreMetrics
appScorer ApplicationScorer
log log.Logger
cfg *rollup.Config
}
// Peerstore is a subset of the libp2p peerstore.Peerstore interface.
//
//go:generate mockery --name Peerstore --output mocks/
type Peerstore interface {
// PeerInfo returns a peer.PeerInfo struct for given peer.ID.
// This is a small slice of the information Peerstore has on
// that peer, useful to other services.
PeerInfo(peer.ID) peer.AddrInfo
// Peers returns all of the peer IDs stored across all inner stores.
Peers() peer.IDSlice
SetScore(id peer.ID, diff store.ScoreDiff) (store.PeerScores, error)
}
// Scorer is a peer scorer that scores peers based on application-specific metrics.
type Scorer interface {
SnapshotHook() pubsub.ExtendedPeerScoreInspectFn
ApplicationScore(peer.ID) float64
}
//go:generate mockery --name ScoreMetrics --output mocks/
type ScoreMetrics interface {
SetPeerScores([]store.PeerScores)
}
// NewScorer returns a new peer scorer.
func NewScorer(cfg *rollup.Config, peerStore Peerstore, metricer ScoreMetrics, appScorer ApplicationScorer, log log.Logger) Scorer {
return &scorer{
peerStore: peerStore,
metricer: metricer,
appScorer: appScorer,
log: log,
cfg: cfg,
}
}
// SnapshotHook returns a function that is called periodically by the pubsub library to inspect the gossip peer scores.
// It is passed into the pubsub library as a [pubsub.ExtendedPeerScoreInspectFn] in the [pubsub.WithPeerScoreInspect] option.
// The returned [pubsub.ExtendedPeerScoreInspectFn] is called with a mapping of peer IDs to peer score snapshots.
// The incoming peer score snapshots only contain gossip-score components.
func (s *scorer) SnapshotHook() pubsub.ExtendedPeerScoreInspectFn {
blocksTopicName := blocksTopicV1(s.cfg)
return func(m map[peer.ID]*pubsub.PeerScoreSnapshot) {
allScores := make([]store.PeerScores, 0, len(m))
// Now set the new scores.
for id, snap := range m {
diff := store.GossipScores{
Total: snap.Score,
Blocks: store.TopicScores{},
IPColocationFactor: snap.IPColocationFactor,
BehavioralPenalty: snap.BehaviourPenalty,
}
if topSnap, ok := snap.Topics[blocksTopicName]; ok {
diff.Blocks.TimeInMesh = float64(topSnap.TimeInMesh) / float64(time.Second)
diff.Blocks.MeshMessageDeliveries = topSnap.MeshMessageDeliveries
diff.Blocks.FirstMessageDeliveries = topSnap.FirstMessageDeliveries
diff.Blocks.InvalidMessageDeliveries = topSnap.InvalidMessageDeliveries
}
if peerScores, err := s.peerStore.SetScore(id, &diff); err != nil {
s.log.Warn("Unable to update peer gossip score", "err", err)
} else {
allScores = append(allScores, peerScores)
}
}
s.metricer.SetPeerScores(allScores)
}
}
func (s *scorer) ApplicationScore(id peer.ID) float64 {
return s.appScorer.ApplicationScore(id)
}