diff --git a/score.go b/score.go index 2535de4..e3271ec 100644 --- a/score.go +++ b/score.go @@ -26,6 +26,9 @@ type peerStats struct { // IP tracking; store as string for easy processing ips []string + + // behavioural pattern penalties (applied by the router) + behaviourPenalty float64 } type topicStats struct { @@ -251,9 +254,30 @@ func (ps *peerScore) score(p peer.ID) float64 { } } + // P7: behavioural pattern penalty + p7 := pstats.behaviourPenalty * pstats.behaviourPenalty + score += p7 * ps.params.BehaviourPenaltyWeight + return score } +// behavioural pattern penalties +func (ps *peerScore) AddPenalty(p peer.ID, count int) { + if ps == nil { + return + } + + ps.Lock() + defer ps.Unlock() + + pstats, ok := ps.peerStats[p] + if !ok { + return + } + + pstats.behaviourPenalty += float64(count) +} + // periodic maintenance func (ps *peerScore) background(ctx context.Context) { refreshScores := time.NewTicker(ps.params.DecayInterval) @@ -366,6 +390,12 @@ func (ps *peerScore) refreshScores() { } } } + + // decay P7 counter + pstats.behaviourPenalty *= ps.params.BehaviourPenaltyDecay + if pstats.behaviourPenalty < ps.params.DecayToZero { + pstats.behaviourPenalty = 0 + } } } diff --git a/score_params.go b/score_params.go index 84f5a49..6544fc1 100644 --- a/score_params.go +++ b/score_params.go @@ -76,7 +76,8 @@ type PeerScoreParams struct { // P7: behavioural pattern penalties. // This parameter has an associated counter which tracks misbehaviour as detected by the // router. - // The value of the parameter is the counter, decaying with BehaviourPatternPenaltyDecay. + // The value of the parameter is the square of the counter, decaying with + // BehaviourPatternPenaltyDecay. // The weight of the parameter MUST be negative (or zero to disable). BehaviourPenaltyWeight, BehaviourPenaltyDecay float64 diff --git a/score_test.go b/score_test.go index 45e2356..9854e18 100644 --- a/score_test.go +++ b/score_test.go @@ -741,6 +741,42 @@ func TestScoreIPColocation(t *testing.T) { } } +func TestScoreBehaviourPenalty(t *testing.T) { + params := &PeerScoreParams{ + AppSpecificScore: func(peer.ID) float64 { return 0 }, + BehaviourPenaltyWeight: -1, + BehaviourPenaltyDecay: 0.99, + } + + peerA := peer.ID("A") + ps := newPeerScore(params) + ps.AddPeer(peerA, "myproto") + + aScore := ps.Score(peerA) + if aScore != 0 { + t.Errorf("expected peer score to be 0, got %f", aScore) + } + + ps.AddPenalty(peerA, 1) + aScore = ps.Score(peerA) + if aScore != -1 { + t.Errorf("expected peer score to be -1, got %f", aScore) + } + + ps.AddPenalty(peerA, 1) + aScore = ps.Score(peerA) + if aScore != -4 { + t.Errorf("expected peer score to be -4, got %f", aScore) + } + + ps.refreshScores() + + aScore = ps.Score(peerA) + if aScore != -3.9204 { + t.Errorf("expected peer score to be -3.9204, got %f", aScore) + } +} + func TestScoreRetention(t *testing.T) { // Create parameters with reasonable default values mytopic := "mytopic"