Commit 8bec48bb authored by Adrian Sutton's avatar Adrian Sutton

op-node: Add peer score diffs to increment and decay application scores

parent e8cdf4e4
......@@ -2,6 +2,7 @@ package store
import (
"errors"
"math"
"net"
"time"
......@@ -27,9 +28,59 @@ func (g GossipScores) Apply(rec *scoreRecord) {
rec.PeerScores.Gossip = g
}
type ReqRespScores struct {
ValidResponses float64 `json:"validResponses"`
ErrorResponses float64 `json:"errorResponses"`
RejectedPayloads float64 `json:"rejectedPayloads"`
}
type IncrementValidResponses struct {
Cap float64
}
func (i IncrementValidResponses) Apply(rec *scoreRecord) {
rec.PeerScores.ReqResp.ValidResponses = math.Min(rec.PeerScores.ReqResp.ValidResponses+1, i.Cap)
}
type IncrementErrorResponses struct {
Cap float64
}
func (i IncrementErrorResponses) Apply(rec *scoreRecord) {
rec.PeerScores.ReqResp.ErrorResponses = math.Min(rec.PeerScores.ReqResp.ErrorResponses+1, i.Cap)
}
type IncrementRejectedPayloads struct {
Cap float64
}
func (i IncrementRejectedPayloads) Apply(rec *scoreRecord) {
rec.PeerScores.ReqResp.RejectedPayloads = math.Min(rec.PeerScores.ReqResp.RejectedPayloads+1, i.Cap)
}
type DecayApplicationScores struct {
ValidResponseDecay float64
ErrorResponseDecay float64
RejectedPayloadDecay float64
DecayToZero float64
}
func (d *DecayApplicationScores) Apply(rec *scoreRecord) {
decay := func(value float64, decay float64) float64 {
value *= decay
if value < d.DecayToZero {
return 0
}
return value
}
rec.PeerScores.ReqResp.ValidResponses = decay(rec.PeerScores.ReqResp.ValidResponses, d.ValidResponseDecay)
rec.PeerScores.ReqResp.ErrorResponses = decay(rec.PeerScores.ReqResp.ErrorResponses, d.ErrorResponseDecay)
rec.PeerScores.ReqResp.RejectedPayloads = decay(rec.PeerScores.ReqResp.RejectedPayloads, d.RejectedPayloadDecay)
}
type PeerScores struct {
Gossip GossipScores `json:"gossip"`
ReqRespSync float64 `json:"reqRespSync"`
ReqResp ReqRespScores `json:"reqResp"`
}
// ScoreDatastore defines a type-safe API for getting and setting libp2p peer score information
......
......@@ -45,6 +45,88 @@ func TestUpdateGossipScore(t *testing.T) {
assertPeerScores(t, store, id, PeerScores{Gossip: GossipScores{Total: score}})
}
func TestIncrementValidResponses(t *testing.T) {
id := peer.ID("aaaa")
store := createMemoryStore(t)
inc := IncrementValidResponses{Cap: 2.1}
setScoreRequired(t, store, id, inc)
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{ValidResponses: 1}})
setScoreRequired(t, store, id, inc)
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{ValidResponses: 2}})
setScoreRequired(t, store, id, inc)
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{ValidResponses: 2.1}})
}
func TestIncrementErrorResponses(t *testing.T) {
id := peer.ID("aaaa")
store := createMemoryStore(t)
inc := IncrementErrorResponses{Cap: 2.1}
setScoreRequired(t, store, id, inc)
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{ErrorResponses: 1}})
setScoreRequired(t, store, id, inc)
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{ErrorResponses: 2}})
setScoreRequired(t, store, id, inc)
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{ErrorResponses: 2.1}})
}
func TestIncrementRejectedPayloads(t *testing.T) {
id := peer.ID("aaaa")
store := createMemoryStore(t)
inc := IncrementRejectedPayloads{Cap: 2.1}
setScoreRequired(t, store, id, inc)
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{RejectedPayloads: 1}})
setScoreRequired(t, store, id, inc)
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{RejectedPayloads: 2}})
setScoreRequired(t, store, id, inc)
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{RejectedPayloads: 2.1}})
}
func TestDecayApplicationScores(t *testing.T) {
id := peer.ID("aaaa")
store := createMemoryStore(t)
for i := 0; i < 10; i++ {
setScoreRequired(t, store, id, IncrementValidResponses{Cap: 100})
setScoreRequired(t, store, id, IncrementErrorResponses{Cap: 100})
setScoreRequired(t, store, id, IncrementRejectedPayloads{Cap: 100})
}
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{
ValidResponses: 10,
ErrorResponses: 10,
RejectedPayloads: 10,
}})
setScoreRequired(t, store, id, &DecayApplicationScores{
ValidResponseDecay: 0.8,
ErrorResponseDecay: 0.4,
RejectedPayloadDecay: 0.5,
DecayToZero: 0.1,
})
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{
ValidResponses: 10 * 0.8,
ErrorResponses: 10 * 0.4,
RejectedPayloads: 10 * 0.5,
}})
// Should be set to exactly zero when below DecayToZero
setScoreRequired(t, store, id, &DecayApplicationScores{
ValidResponseDecay: 0.8,
ErrorResponseDecay: 0.4,
RejectedPayloadDecay: 0.5,
DecayToZero: 5,
})
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{
ValidResponses: 10 * 0.8 * 0.8, // Not yet below 5 so preserved
ErrorResponses: 0,
RejectedPayloads: 0,
}})
}
func TestStoreScoresForMultiplePeers(t *testing.T) {
id1 := peer.ID("aaaa")
id2 := peer.ID("bbbb")
......@@ -215,7 +297,7 @@ func createPeerstoreWithBacking(t *testing.T, store *sync.MutexDatastore) Extend
return eps
}
func setScoreRequired(t *testing.T, store ScoreDatastore, id peer.ID, diff *GossipScores) {
func setScoreRequired(t *testing.T, store ScoreDatastore, id peer.ID, diff ScoreDiff) {
_, err := store.SetScore(id, diff)
require.NoError(t, err)
}
......@@ -45,7 +45,31 @@ func TestParseHistoricSerializationsV0(t *testing.T) {
IPColocationFactor: 12.34,
BehavioralPenalty: 56.78,
},
ReqRespSync: 123456,
ReqResp: ReqRespScores{},
},
LastUpdate: 1923841,
},
},
{
data: `{"peerScores":{"gossip":{"total":1234.52382,"blocks":{"timeInMesh":1234,"firstMessageDeliveries":12,"meshMessageDeliveries":34,"invalidMessageDeliveries":56},"IPColocationFactor":12.34,"behavioralPenalty":56.78},"reqResp":{"validResponses":99,"errorResponses":88,"rejectedPayloads":77}},"lastUpdate":1923841}`,
expected: scoreRecord{
PeerScores: PeerScores{
Gossip: GossipScores{
Total: 1234.52382,
Blocks: TopicScores{
TimeInMesh: 1234,
FirstMessageDeliveries: 12,
MeshMessageDeliveries: 34,
InvalidMessageDeliveries: 56,
},
IPColocationFactor: 12.34,
BehavioralPenalty: 56.78,
},
ReqResp: ReqRespScores{
ValidResponses: 99,
ErrorResponses: 88,
RejectedPayloads: 77,
},
},
LastUpdate: 1923841,
},
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment