From a530ef846e6d7613d0d52505d1c43ab7641917c7 Mon Sep 17 00:00:00 2001 From: Yahya Hassanzadeh Date: Thu, 1 Sep 2022 14:18:16 -0700 Subject: [PATCH 1/9] decouples topic scoring parameters --- score_params.go | 55 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/score_params.go b/score_params.go index 827f0456..987ba1f4 100644 --- a/score_params.go +++ b/score_params.go @@ -51,6 +51,9 @@ func (p *PeerScoreThresholds) validate() error { } type PeerScoreParams struct { + // whether it is allowed to just set some params and not all of them. + SelectiveParams bool + // Score parameters per topic. Topics map[string]*TopicScoreParams @@ -99,6 +102,9 @@ type PeerScoreParams struct { } type TopicScoreParams struct { + // whether it is allowed to just set some params and not all of them. + SelectiveParams bool + // The weight of the topic. TopicWeight float64 @@ -207,6 +213,33 @@ func (p *TopicScoreParams) validate() error { } // check P1 + if err := p.validateTimeInMeshParams(); err != nil { + return err + } + + // check P2 + if err := p.validateMessageDeliveryParams(); err != nil { + return err + } + // check P3 + if err := p.validateMeshMessageDeliveryParams(); err != nil { + return err + } + + // check P3b + if err := p.validateMessageFailurePenaltyParams(); err != nil { + return err + } + + // check P4 + if err := p.validateInvalidMessageDeliveryParams(); err != nil { + return err + } + + return nil +} + +func (p *TopicScoreParams) validateTimeInMeshParams() error { if p.TimeInMeshQuantum == 0 { return fmt.Errorf("invalid TimeInMeshQuantum; must be non zero") } @@ -220,7 +253,10 @@ func (p *TopicScoreParams) validate() error { return fmt.Errorf("invalid TimeInMeshCap; must be positive and a valid number") } - // check P2 + return nil +} + +func (p *TopicScoreParams) validateMessageDeliveryParams() error { if p.FirstMessageDeliveriesWeight < 0 || isInvalidNumber(p.FirstMessageDeliveriesWeight) { return fmt.Errorf("invallid FirstMessageDeliveriesWeight; must be positive (or 0 to disable) and a valid number") } @@ -231,7 +267,10 @@ func (p *TopicScoreParams) validate() error { return fmt.Errorf("invalid FirstMessageDeliveriesCap; must be positive and a valid number") } - // check P3 + return nil +} + +func (p *TopicScoreParams) validateMeshMessageDeliveryParams() error { if p.MeshMessageDeliveriesWeight > 0 || isInvalidNumber(p.MeshMessageDeliveriesWeight) { return fmt.Errorf("invalid MeshMessageDeliveriesWeight; must be negative (or 0 to disable) and a valid number") } @@ -251,7 +290,10 @@ func (p *TopicScoreParams) validate() error { return fmt.Errorf("invalid MeshMessageDeliveriesActivation; must be at least 1s") } - // check P3b + return nil +} + +func (p *TopicScoreParams) validateMessageFailurePenaltyParams() error { if p.MeshFailurePenaltyWeight > 0 || isInvalidNumber(p.MeshFailurePenaltyWeight) { return fmt.Errorf("invalid MeshFailurePenaltyWeight; must be negative (or 0 to disable) and a valid number") } @@ -259,7 +301,10 @@ func (p *TopicScoreParams) validate() error { return fmt.Errorf("invalid MeshFailurePenaltyDecay; must be between 0 and 1") } - // check P4 + return nil +} + +func (p *TopicScoreParams) validateInvalidMessageDeliveryParams() error { if p.InvalidMessageDeliveriesWeight > 0 || isInvalidNumber(p.InvalidMessageDeliveriesWeight) { return fmt.Errorf("invalid InvalidMessageDeliveriesWeight; must be negative (or 0 to disable) and a valid number") } @@ -281,7 +326,7 @@ func ScoreParameterDecay(decay time.Duration) float64 { return ScoreParameterDecayWithBase(decay, DefaultDecayInterval, DefaultDecayToZero) } -// ScoreParameterDecay computes the decay factor for a parameter using base as the DecayInterval +// ScoreParameterDecayWithBase computes the decay factor for a parameter using base as the DecayInterval func ScoreParameterDecayWithBase(decay time.Duration, base time.Duration, decayToZero float64) float64 { // the decay is linear, so after n ticks the value is factor^n // so factor^n = decayToZero => factor = decayToZero^(1/n) From aeb247a444062b31e3a8c2333a5a13d96b334a2a Mon Sep 17 00:00:00 2001 From: Yahya Hassanzadeh Date: Thu, 1 Sep 2022 15:51:23 -0700 Subject: [PATCH 2/9] adds skiping atomic validation for topic parameters --- score_params.go | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/score_params.go b/score_params.go index 987ba1f4..afcb9dd3 100644 --- a/score_params.go +++ b/score_params.go @@ -52,7 +52,7 @@ func (p *PeerScoreThresholds) validate() error { type PeerScoreParams struct { // whether it is allowed to just set some params and not all of them. - SelectiveParams bool + SkipAtomicValidation bool // Score parameters per topic. Topics map[string]*TopicScoreParams @@ -103,7 +103,7 @@ type PeerScoreParams struct { type TopicScoreParams struct { // whether it is allowed to just set some params and not all of them. - SelectiveParams bool + SkipAtomicValidation bool // The weight of the topic. TopicWeight float64 @@ -240,6 +240,13 @@ func (p *TopicScoreParams) validate() error { } func (p *TopicScoreParams) validateTimeInMeshParams() error { + if p.SkipAtomicValidation { + // in selective mode, parameters at their zero values are dismissed from validation. + if p.TimeInMeshQuantum == 0 && p.TimeInMeshCap == 0 { + return nil + } + } + if p.TimeInMeshQuantum == 0 { return fmt.Errorf("invalid TimeInMeshQuantum; must be non zero") } @@ -257,6 +264,13 @@ func (p *TopicScoreParams) validateTimeInMeshParams() error { } func (p *TopicScoreParams) validateMessageDeliveryParams() error { + if p.SkipAtomicValidation { + // in selective mode, parameters at their zero values are dismissed from validation. + if p.FirstMessageDeliveriesCap == 0 && p.MeshMessageDeliveriesDecay == 0 { + return nil + } + } + if p.FirstMessageDeliveriesWeight < 0 || isInvalidNumber(p.FirstMessageDeliveriesWeight) { return fmt.Errorf("invallid FirstMessageDeliveriesWeight; must be positive (or 0 to disable) and a valid number") } @@ -271,6 +285,13 @@ func (p *TopicScoreParams) validateMessageDeliveryParams() error { } func (p *TopicScoreParams) validateMeshMessageDeliveryParams() error { + if p.SkipAtomicValidation { + // in selective mode, parameters at their zero values are dismissed from validation. + if p.FirstMessageDeliveriesCap == 0 && p.MeshMessageDeliveriesDecay == 0 { + return nil + } + } + if p.MeshMessageDeliveriesWeight > 0 || isInvalidNumber(p.MeshMessageDeliveriesWeight) { return fmt.Errorf("invalid MeshMessageDeliveriesWeight; must be negative (or 0 to disable) and a valid number") } @@ -294,6 +315,13 @@ func (p *TopicScoreParams) validateMeshMessageDeliveryParams() error { } func (p *TopicScoreParams) validateMessageFailurePenaltyParams() error { + if p.SkipAtomicValidation { + // in selective mode, parameters at their zero values are dismissed from validation. + if p.MeshFailurePenaltyDecay == 0 { + return nil + } + } + if p.MeshFailurePenaltyWeight > 0 || isInvalidNumber(p.MeshFailurePenaltyWeight) { return fmt.Errorf("invalid MeshFailurePenaltyWeight; must be negative (or 0 to disable) and a valid number") } @@ -305,6 +333,13 @@ func (p *TopicScoreParams) validateMessageFailurePenaltyParams() error { } func (p *TopicScoreParams) validateInvalidMessageDeliveryParams() error { + if p.SkipAtomicValidation { + // in selective mode, parameters at their zero values are dismissed from validation. + if p.InvalidMessageDeliveriesDecay == 0 { + return nil + } + } + if p.InvalidMessageDeliveriesWeight > 0 || isInvalidNumber(p.InvalidMessageDeliveriesWeight) { return fmt.Errorf("invalid InvalidMessageDeliveriesWeight; must be negative (or 0 to disable) and a valid number") } From 7207b06f4eee3623afa33e1252b6831716e12718 Mon Sep 17 00:00:00 2001 From: Yahya Hassanzadeh Date: Thu, 1 Sep 2022 16:53:26 -0700 Subject: [PATCH 3/9] cleans up --- score_params.go | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/score_params.go b/score_params.go index afcb9dd3..7ac911d2 100644 --- a/score_params.go +++ b/score_params.go @@ -109,8 +109,8 @@ type TopicScoreParams struct { TopicWeight float64 // P1: time in the mesh - // This is the time the peer has ben grafted in the mesh. - // The value of of the parameter is the time/TimeInMeshQuantum, capped by TimeInMeshCap + // This is the time the peer has been grafted in the mesh. + // The value of the parameter is the time/TimeInMeshQuantum, capped by TimeInMeshCap. // The weight of the parameter MUST be positive (or zero to disable). TimeInMeshWeight float64 TimeInMeshQuantum time.Duration @@ -130,7 +130,7 @@ type TopicScoreParams struct { // when validation succeeds. // This window accounts for the minimum time before a hostile mesh peer trying to game the score // could replay back a valid message we just sent them. - // It effectively tracks first and near-first deliveries, ie a message seen from a mesh peer + // It effectively tracks first and near-first deliveries, i.e., a message seen from a mesh peer // before we have forwarded it to them. // The parameter has an associated counter, decaying with MeshMessageDeliveriesDecay. // If the counter exceeds the threshold, its value is 0. @@ -241,12 +241,15 @@ func (p *TopicScoreParams) validate() error { func (p *TopicScoreParams) validateTimeInMeshParams() error { if p.SkipAtomicValidation { - // in selective mode, parameters at their zero values are dismissed from validation. - if p.TimeInMeshQuantum == 0 && p.TimeInMeshCap == 0 { + // in non-atomic mode, parameters at their zero values are dismissed from validation. + if p.TimeInMeshWeight == 0 && p.TimeInMeshQuantum == 0 && p.TimeInMeshCap == 0 { return nil } } + // either atomic validation mode, or some parameters have been set a value, + // hence, proceed with normal validation of all related parameters in this context. + if p.TimeInMeshQuantum == 0 { return fmt.Errorf("invalid TimeInMeshQuantum; must be non zero") } @@ -265,12 +268,15 @@ func (p *TopicScoreParams) validateTimeInMeshParams() error { func (p *TopicScoreParams) validateMessageDeliveryParams() error { if p.SkipAtomicValidation { - // in selective mode, parameters at their zero values are dismissed from validation. - if p.FirstMessageDeliveriesCap == 0 && p.MeshMessageDeliveriesDecay == 0 { + // in non-atomic mode, parameters at their zero values are dismissed from validation. + if p.FirstMessageDeliveriesWeight == 0 && p.FirstMessageDeliveriesCap == 0 && p.FirstMessageDeliveriesDecay == 0 { return nil } } + // either atomic validation mode, or some parameters have been set a value, + // hence, proceed with normal validation of all related parameters in this context. + if p.FirstMessageDeliveriesWeight < 0 || isInvalidNumber(p.FirstMessageDeliveriesWeight) { return fmt.Errorf("invallid FirstMessageDeliveriesWeight; must be positive (or 0 to disable) and a valid number") } @@ -286,12 +292,20 @@ func (p *TopicScoreParams) validateMessageDeliveryParams() error { func (p *TopicScoreParams) validateMeshMessageDeliveryParams() error { if p.SkipAtomicValidation { - // in selective mode, parameters at their zero values are dismissed from validation. - if p.FirstMessageDeliveriesCap == 0 && p.MeshMessageDeliveriesDecay == 0 { + // in non-atomic mode, parameters at their zero values are dismissed from validation. + if p.MeshMessageDeliveriesWeight == 0 && + p.MeshMessageDeliveriesCap == 0 && + p.MeshMessageDeliveriesDecay == 0 && + p.MeshMessageDeliveriesThreshold == 0 && + p.MeshMessageDeliveriesWindow == 0 && + p.MeshMessageDeliveriesActivation == 0 { return nil } } + // either atomic validation mode, or some parameters have been set a value, + // hence, proceed with normal validation of all related parameters in this context. + if p.MeshMessageDeliveriesWeight > 0 || isInvalidNumber(p.MeshMessageDeliveriesWeight) { return fmt.Errorf("invalid MeshMessageDeliveriesWeight; must be negative (or 0 to disable) and a valid number") } @@ -322,6 +336,9 @@ func (p *TopicScoreParams) validateMessageFailurePenaltyParams() error { } } + // either atomic validation mode, or some parameters have been set a value, + // hence, proceed with normal validation of all related parameters in this context. + if p.MeshFailurePenaltyWeight > 0 || isInvalidNumber(p.MeshFailurePenaltyWeight) { return fmt.Errorf("invalid MeshFailurePenaltyWeight; must be negative (or 0 to disable) and a valid number") } @@ -340,6 +357,9 @@ func (p *TopicScoreParams) validateInvalidMessageDeliveryParams() error { } } + // either atomic validation mode, or some parameters have been set a value, + // hence, proceed with normal validation of all related parameters in this context. + if p.InvalidMessageDeliveriesWeight > 0 || isInvalidNumber(p.InvalidMessageDeliveriesWeight) { return fmt.Errorf("invalid InvalidMessageDeliveriesWeight; must be negative (or 0 to disable) and a valid number") } From ce2b69f3b9235bed47713a304d9d40733271ead9 Mon Sep 17 00:00:00 2001 From: Yahya Hassanzadeh Date: Thu, 1 Sep 2022 17:00:12 -0700 Subject: [PATCH 4/9] adds skip atomic validation to peer score threshold --- score_params.go | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/score_params.go b/score_params.go index 7ac911d2..3c2e240f 100644 --- a/score_params.go +++ b/score_params.go @@ -10,6 +10,9 @@ import ( ) type PeerScoreThresholds struct { + // whether it is allowed to just set some params and not all of them. + SkipAtomicValidation bool + // GossipThreshold is the score threshold below which gossip propagation is supressed; // should be negative. GossipThreshold float64 @@ -32,21 +35,36 @@ type PeerScoreThresholds struct { } func (p *PeerScoreThresholds) validate() error { - if p.GossipThreshold > 0 || isInvalidNumber(p.GossipThreshold) { - return fmt.Errorf("invalid gossip threshold; it must be <= 0 and a valid number") + if !p.SkipAtomicValidation || p.GossipThreshold != 0 { + if p.GossipThreshold > 0 || isInvalidNumber(p.GossipThreshold) { + return fmt.Errorf("invalid gossip threshold; it must be <= 0 and a valid number") + } } - if p.PublishThreshold > 0 || p.PublishThreshold > p.GossipThreshold || isInvalidNumber(p.PublishThreshold) { - return fmt.Errorf("invalid publish threshold; it must be <= 0 and <= gossip threshold and a valid number") + + if !p.SkipAtomicValidation || p.PublishThreshold != 0 { + if p.PublishThreshold > 0 || p.PublishThreshold > p.GossipThreshold || isInvalidNumber(p.PublishThreshold) { + return fmt.Errorf("invalid publish threshold; it must be <= 0 and <= gossip threshold and a valid number") + } } - if p.GraylistThreshold > 0 || p.GraylistThreshold > p.PublishThreshold || isInvalidNumber(p.GraylistThreshold) { - return fmt.Errorf("invalid graylist threshold; it must be <= 0 and <= publish threshold and a valid number") + + if !p.SkipAtomicValidation || p.GraylistThreshold != 0 { + if p.GraylistThreshold > 0 || p.GraylistThreshold > p.PublishThreshold || isInvalidNumber(p.GraylistThreshold) { + return fmt.Errorf("invalid graylist threshold; it must be <= 0 and <= publish threshold and a valid number") + } } - if p.AcceptPXThreshold < 0 || isInvalidNumber(p.AcceptPXThreshold) { - return fmt.Errorf("invalid accept PX threshold; it must be >= 0 and a valid number") + + if !p.SkipAtomicValidation || p.AcceptPXThreshold != 0 { + if p.AcceptPXThreshold < 0 || isInvalidNumber(p.AcceptPXThreshold) { + return fmt.Errorf("invalid accept PX threshold; it must be >= 0 and a valid number") + } } - if p.OpportunisticGraftThreshold < 0 || isInvalidNumber(p.OpportunisticGraftThreshold) { - return fmt.Errorf("invalid opportunistic grafting threshold; it must be >= 0 and a valid number") + + if !p.SkipAtomicValidation || p.OpportunisticGraftThreshold != 0 { + if p.OpportunisticGraftThreshold < 0 || isInvalidNumber(p.OpportunisticGraftThreshold) { + return fmt.Errorf("invalid opportunistic grafting threshold; it must be >= 0 and a valid number") + } } + return nil } From a714f091d344e8e15e006e9b0dad73d60f0d15d7 Mon Sep 17 00:00:00 2001 From: Yahya Hassanzadeh Date: Thu, 1 Sep 2022 17:12:16 -0700 Subject: [PATCH 5/9] adds skip atomic validation for peer parameters --- score_params.go | 60 ++++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/score_params.go b/score_params.go index 3c2e240f..479848d9 100644 --- a/score_params.go +++ b/score_params.go @@ -183,41 +183,55 @@ func (p *PeerScoreParams) validate() error { } } - // check that the topic score is 0 or something positive - if p.TopicScoreCap < 0 || isInvalidNumber(p.TopicScoreCap) { - return fmt.Errorf("invalid topic score cap; must be positive (or 0 for no cap) and a valid number") + if !p.SkipAtomicValidation || p.TopicScoreCap != 0 { + // check that the topic score is 0 or something positive + if p.TopicScoreCap < 0 || isInvalidNumber(p.TopicScoreCap) { + return fmt.Errorf("invalid topic score cap; must be positive (or 0 for no cap) and a valid number") + } } // check that we have an app specific score; the weight can be anything (but expected positive) if p.AppSpecificScore == nil { - return fmt.Errorf("missing application specific score function") + if p.SkipAtomicValidation { + p.AppSpecificScore = func(p peer.ID) float64 { + return 0 + } + } else { + return fmt.Errorf("missing application specific score function") + } } - // check the IP colocation factor - if p.IPColocationFactorWeight > 0 || isInvalidNumber(p.IPColocationFactorWeight) { - return fmt.Errorf("invalid IPColocationFactorWeight; must be negative (or 0 to disable) and a valid number") - } - if p.IPColocationFactorWeight != 0 && p.IPColocationFactorThreshold < 1 { - return fmt.Errorf("invalid IPColocationFactorThreshold; must be at least 1") + if !p.SkipAtomicValidation || p.IPColocationFactorWeight != 0 { + // check the IP collocation factor + if p.IPColocationFactorWeight > 0 || isInvalidNumber(p.IPColocationFactorWeight) { + return fmt.Errorf("invalid IPColocationFactorWeight; must be negative (or 0 to disable) and a valid number") + } + if p.IPColocationFactorWeight != 0 && p.IPColocationFactorThreshold < 1 { + return fmt.Errorf("invalid IPColocationFactorThreshold; must be at least 1") + } } // check the behaviour penalty - if p.BehaviourPenaltyWeight > 0 || isInvalidNumber(p.BehaviourPenaltyWeight) { - return fmt.Errorf("invalid BehaviourPenaltyWeight; must be negative (or 0 to disable) and a valid number") - } - if p.BehaviourPenaltyWeight != 0 && (p.BehaviourPenaltyDecay <= 0 || p.BehaviourPenaltyDecay >= 1 || isInvalidNumber(p.BehaviourPenaltyDecay)) { - return fmt.Errorf("invalid BehaviourPenaltyDecay; must be between 0 and 1") - } - if p.BehaviourPenaltyThreshold < 0 || isInvalidNumber(p.BehaviourPenaltyThreshold) { - return fmt.Errorf("invalid BehaviourPenaltyThreshold; must be >= 0 and a valid number") + if !p.SkipAtomicValidation || p.BehaviourPenaltyWeight != 0 || p.BehaviourPenaltyThreshold != 0 { + if p.BehaviourPenaltyWeight > 0 || isInvalidNumber(p.BehaviourPenaltyWeight) { + return fmt.Errorf("invalid BehaviourPenaltyWeight; must be negative (or 0 to disable) and a valid number") + } + if p.BehaviourPenaltyWeight != 0 && (p.BehaviourPenaltyDecay <= 0 || p.BehaviourPenaltyDecay >= 1 || isInvalidNumber(p.BehaviourPenaltyDecay)) { + return fmt.Errorf("invalid BehaviourPenaltyDecay; must be between 0 and 1") + } + if p.BehaviourPenaltyThreshold < 0 || isInvalidNumber(p.BehaviourPenaltyThreshold) { + return fmt.Errorf("invalid BehaviourPenaltyThreshold; must be >= 0 and a valid number") + } } // check the decay parameters - if p.DecayInterval < time.Second { - return fmt.Errorf("invalid DecayInterval; must be at least 1s") - } - if p.DecayToZero <= 0 || p.DecayToZero >= 1 || isInvalidNumber(p.DecayToZero) { - return fmt.Errorf("invalid DecayToZero; must be between 0 and 1") + if !p.SkipAtomicValidation || p.DecayInterval != 0 || p.DecayToZero != 0 { + if p.DecayInterval < time.Second { + return fmt.Errorf("invalid DecayInterval; must be at least 1s") + } + if p.DecayToZero <= 0 || p.DecayToZero >= 1 || isInvalidNumber(p.DecayToZero) { + return fmt.Errorf("invalid DecayToZero; must be between 0 and 1") + } } // no need to check the score retention; a value of 0 means that we don't retain scores From bf07620fb0237bb9be3b63c8273a53c2f9d9ba5f Mon Sep 17 00:00:00 2001 From: Yahya Hassanzadeh Date: Tue, 6 Sep 2022 10:45:52 -0700 Subject: [PATCH 6/9] adds test for non-atomic validation --- score_params.go | 4 +- score_params_test.go | 243 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 241 insertions(+), 6 deletions(-) diff --git a/score_params.go b/score_params.go index 479848d9..6d09e0b5 100644 --- a/score_params.go +++ b/score_params.go @@ -363,7 +363,7 @@ func (p *TopicScoreParams) validateMeshMessageDeliveryParams() error { func (p *TopicScoreParams) validateMessageFailurePenaltyParams() error { if p.SkipAtomicValidation { // in selective mode, parameters at their zero values are dismissed from validation. - if p.MeshFailurePenaltyDecay == 0 { + if p.MeshFailurePenaltyDecay == 0 && p.MeshFailurePenaltyWeight == 0 { return nil } } @@ -384,7 +384,7 @@ func (p *TopicScoreParams) validateMessageFailurePenaltyParams() error { func (p *TopicScoreParams) validateInvalidMessageDeliveryParams() error { if p.SkipAtomicValidation { // in selective mode, parameters at their zero values are dismissed from validation. - if p.InvalidMessageDeliveriesDecay == 0 { + if p.InvalidMessageDeliveriesDecay == 0 && p.InvalidMessageDeliveriesWeight == 0 { return nil } } diff --git a/score_params_test.go b/score_params_test.go index e91a6832..004cc4f9 100644 --- a/score_params_test.go +++ b/score_params_test.go @@ -47,7 +47,7 @@ func TestPeerScoreThresholdsValidation(t *testing.T) { } } -func TestTopicScoreParamsValidation(t *testing.T) { +func TestTopicScoreParamsValidation_AtomicValidation(t *testing.T) { if (&TopicScoreParams{}).validate() == nil { t.Fatal("expected validation error") } @@ -145,6 +145,241 @@ func TestTopicScoreParamsValidation(t *testing.T) { } } +func TestTopicScoreParamsValidation_NonAtomicValidation(t *testing.T) { + if (&TopicScoreParams{SkipAtomicValidation: true}).validate() != nil { + t.Fatal("expected no validation error in non-atomic mode") + } + + // Following tests evaluate that even when we skip atomic validation, those parameters that are set with a value are + // going through validation. + if (&TopicScoreParams{ + SkipAtomicValidation: true, + TopicWeight: -1, + }). + validate() == nil { + t.Fatalf("expected validation error") + } + + if (&TopicScoreParams{ + SkipAtomicValidation: true, + TimeInMeshWeight: -1, + TimeInMeshQuantum: time.Second, + }).validate() == nil { + t.Fatalf("expected validation error") + } + + if (&TopicScoreParams{ + SkipAtomicValidation: true, + TimeInMeshWeight: 1, + TimeInMeshQuantum: time.Second, + TimeInMeshCap: -1, + }).validate() == nil { + t.Fatal("expected validation error") + } + + if (&TopicScoreParams{ + SkipAtomicValidation: true, + TimeInMeshQuantum: time.Second, + FirstMessageDeliveriesWeight: -1, + }).validate() == nil { + t.Fatal("expected validation error") + } + if (&TopicScoreParams{ + SkipAtomicValidation: true, + TimeInMeshQuantum: time.Second, + FirstMessageDeliveriesWeight: 1, + FirstMessageDeliveriesDecay: -1, + }).validate() == nil { + t.Fatal("expected validation error") + } + if (&TopicScoreParams{ + SkipAtomicValidation: true, + TimeInMeshQuantum: time.Second, + FirstMessageDeliveriesWeight: 1, + FirstMessageDeliveriesDecay: 2, + }).validate() == nil { + t.Fatal("expected validation error") + } + if (&TopicScoreParams{ + SkipAtomicValidation: true, + TimeInMeshQuantum: time.Second, + FirstMessageDeliveriesWeight: 1, + FirstMessageDeliveriesDecay: .5, + FirstMessageDeliveriesCap: -1, + }).validate() == nil { + t.Fatal("expected validation error") + } + + if (&TopicScoreParams{ + SkipAtomicValidation: true, + TimeInMeshQuantum: time.Second, + MeshMessageDeliveriesWeight: 1, + }).validate() == nil { + t.Fatal("expected validation error") + } + if (&TopicScoreParams{SkipAtomicValidation: true, + TimeInMeshQuantum: time.Second, + MeshMessageDeliveriesWeight: -1, + MeshMessageDeliveriesDecay: -1, + }).validate() == nil { + t.Fatal("expected validation error") + } + if (&TopicScoreParams{ + SkipAtomicValidation: true, + TimeInMeshQuantum: time.Second, + MeshMessageDeliveriesWeight: -1, + MeshMessageDeliveriesDecay: 2, + }).validate() == nil { + t.Fatal("expected validation error") + } + if (&TopicScoreParams{ + SkipAtomicValidation: true, + TimeInMeshQuantum: time.Second, + MeshMessageDeliveriesWeight: -1, + MeshMessageDeliveriesDecay: .5, + MeshMessageDeliveriesCap: -1, + }).validate() == nil { + t.Fatal("expected validation error") + } + if (&TopicScoreParams{ + SkipAtomicValidation: true, + TimeInMeshQuantum: time.Second, + MeshMessageDeliveriesWeight: -1, + MeshMessageDeliveriesDecay: .5, + MeshMessageDeliveriesCap: 5, + MeshMessageDeliveriesThreshold: -3, + }).validate() == nil { + t.Fatal("expected validation error") + } + if (&TopicScoreParams{ + SkipAtomicValidation: true, + TimeInMeshQuantum: time.Second, + MeshMessageDeliveriesWeight: -1, + MeshMessageDeliveriesDecay: .5, + MeshMessageDeliveriesCap: 5, + MeshMessageDeliveriesThreshold: 3, + MeshMessageDeliveriesWindow: -1, + }).validate() == nil { + t.Fatal("expected validation error") + } + if (&TopicScoreParams{ + SkipAtomicValidation: true, + TimeInMeshQuantum: time.Second, + MeshMessageDeliveriesWeight: -1, + MeshMessageDeliveriesDecay: .5, + MeshMessageDeliveriesCap: 5, + MeshMessageDeliveriesThreshold: 3, + MeshMessageDeliveriesWindow: time.Millisecond, + MeshMessageDeliveriesActivation: time.Millisecond, + }).validate() == nil { + t.Fatal("expected validation error") + } + + if (&TopicScoreParams{ + SkipAtomicValidation: true, + TimeInMeshQuantum: time.Second, + MeshFailurePenaltyWeight: 1, + }).validate() == nil { + t.Fatal("expected validation error") + } + if (&TopicScoreParams{ + SkipAtomicValidation: true, + TimeInMeshQuantum: time.Second, + MeshFailurePenaltyWeight: -1, + MeshFailurePenaltyDecay: -1, + }).validate() == nil { + t.Fatal("expected validation error") + } + if (&TopicScoreParams{ + SkipAtomicValidation: true, + TimeInMeshQuantum: time.Second, + MeshFailurePenaltyWeight: -1, + MeshFailurePenaltyDecay: 2, + }).validate() == nil { + t.Fatal("expected validation error") + } + + if (&TopicScoreParams{ + SkipAtomicValidation: true, + TimeInMeshQuantum: time.Second, + InvalidMessageDeliveriesWeight: 1, + }).validate() == nil { + t.Fatal("expected validation error") + } + if (&TopicScoreParams{ + SkipAtomicValidation: true, + TimeInMeshQuantum: time.Second, + InvalidMessageDeliveriesWeight: -1, + InvalidMessageDeliveriesDecay: -1, + }).validate() == nil { + t.Fatal("expected validation error") + } + if (&TopicScoreParams{ + SkipAtomicValidation: true, + TimeInMeshQuantum: time.Second, + InvalidMessageDeliveriesWeight: -1, + InvalidMessageDeliveriesDecay: 2, + }).validate() == nil { + t.Fatal("expected validation error") + } + + // Don't use these params in production! + // In non-atomic (selective) validation mode, the subset of parameters passes + // validation if the individual parameters values pass validation. + p := TopicScoreParams{SkipAtomicValidation: true} + + if err := p.validate(); err != nil { + t.Fatalf("expected validation success, got: %s", err) + } + + // including topic weight + p.TopicWeight = 1 + if err := p.validate(); err != nil { + t.Fatalf("expected validation success, got: %s", err) + } + + // including time in mesh parameters + p.TimeInMeshWeight = 0.01 + p.TimeInMeshQuantum = time.Second + p.TimeInMeshCap = 10 + if err := p.validate(); err != nil { + t.Fatalf("expected validation success, got: %s", err) + } + + // including first message delivery parameters + p.FirstMessageDeliveriesWeight = 1 + p.FirstMessageDeliveriesDecay = 0.5 + p.FirstMessageDeliveriesCap = 10 + if err := p.validate(); err != nil { + t.Fatalf("expected validation success, got: %s", err) + } + + // including mesh message delivery parameters + p.MeshMessageDeliveriesWeight = -1 + p.MeshMessageDeliveriesDecay = 0.05 + p.MeshMessageDeliveriesCap = 10 + p.MeshMessageDeliveriesThreshold = 5 + p.MeshMessageDeliveriesWindow = time.Millisecond + p.MeshMessageDeliveriesActivation = time.Second + if err := p.validate(); err != nil { + t.Fatalf("expected validation success, got: %s", err) + } + + // including mesh failure penalty parameters + p.MeshFailurePenaltyWeight = -1 + p.MeshFailurePenaltyDecay = 0.5 + if err := p.validate(); err != nil { + t.Fatalf("expected validation success, got: %s", err) + } + + // including invalid message delivery parameters + p.InvalidMessageDeliveriesWeight = -1 + p.InvalidMessageDeliveriesDecay = 0.5 + if err := p.validate(); err != nil { + t.Fatalf("expected validation success, got: %s", err) + } +} + func TestPeerScoreParamsValidation(t *testing.T) { appScore := func(peer.ID) float64 { return 0 } @@ -213,7 +448,7 @@ func TestPeerScoreParamsValidation(t *testing.T) { IPColocationFactorWeight: -1, IPColocationFactorThreshold: 1, Topics: map[string]*TopicScoreParams{ - "test": &TopicScoreParams{ + "test": { TopicWeight: 1, TimeInMeshWeight: 0.01, TimeInMeshQuantum: time.Second, @@ -246,7 +481,7 @@ func TestPeerScoreParamsValidation(t *testing.T) { IPColocationFactorWeight: -1, IPColocationFactorThreshold: 1, Topics: map[string]*TopicScoreParams{ - "test": &TopicScoreParams{ + "test": { TopicWeight: -1, TimeInMeshWeight: 0.01, TimeInMeshQuantum: time.Second, @@ -294,7 +529,7 @@ func TestPeerScoreParamsValidation(t *testing.T) { IPColocationFactorWeight: -1, IPColocationFactorThreshold: 1, Topics: map[string]*TopicScoreParams{ - "test": &TopicScoreParams{ + "test": { TopicWeight: math.Inf(0), TimeInMeshWeight: math.NaN(), TimeInMeshQuantum: time.Second, From fa1076d76588278d1ef33428e3392db8b9e703c9 Mon Sep 17 00:00:00 2001 From: Yahya Hassanzadeh Date: Tue, 6 Sep 2022 16:39:22 -0700 Subject: [PATCH 7/9] adds tests for peer score --- score_params_test.go | 295 +++++++++++++++++++++++++++++++++---------- 1 file changed, 229 insertions(+), 66 deletions(-) diff --git a/score_params_test.go b/score_params_test.go index 004cc4f9..c20a3561 100644 --- a/score_params_test.go +++ b/score_params_test.go @@ -380,67 +380,178 @@ func TestTopicScoreParamsValidation_NonAtomicValidation(t *testing.T) { } } -func TestPeerScoreParamsValidation(t *testing.T) { +func TestPeerScoreParamsValidation_InvalidParams_AtomicValidation(t *testing.T) { + testPeerScoreParamsValidationWithInvalidParams(t, false) +} + +func TestPeerScoreParamsValidation_InvalidParams_SkipAtomicValidation(t *testing.T) { + testPeerScoreParamsValidationWithInvalidParams(t, true) +} + +func testPeerScoreParamsValidationWithInvalidParams(t *testing.T, skipAtomicValidation bool) { appScore := func(peer.ID) float64 { return 0 } - if (&PeerScoreParams{TopicScoreCap: -1, AppSpecificScore: appScore, DecayInterval: time.Second, DecayToZero: 0.01}).validate() == nil { + if (&PeerScoreParams{ + SkipAtomicValidation: skipAtomicValidation, + TopicScoreCap: -1, + AppSpecificScore: appScore, + DecayInterval: time.Second, + DecayToZero: 0.01, + }).validate() == nil { t.Fatal("expected validation error") } - if (&PeerScoreParams{TopicScoreCap: 1, DecayInterval: time.Second, DecayToZero: 0.01}).validate() == nil { - t.Fatal("expected validation error") + + if skipAtomicValidation { + if (&PeerScoreParams{ + SkipAtomicValidation: skipAtomicValidation, + TopicScoreCap: 1, + DecayInterval: time.Second, + DecayToZero: 0.01, + }).validate() != nil { + t.Fatal("expected validation success") + } + } else { + if (&PeerScoreParams{ + SkipAtomicValidation: skipAtomicValidation, + TopicScoreCap: 1, + DecayInterval: time.Second, + DecayToZero: 0.01, + }).validate() == nil { + t.Fatal("expected validation error") + } } - if (&PeerScoreParams{TopicScoreCap: 1, AppSpecificScore: appScore, DecayInterval: time.Second, DecayToZero: 0.01, IPColocationFactorWeight: 1}).validate() == nil { + + if (&PeerScoreParams{ + SkipAtomicValidation: skipAtomicValidation, + TopicScoreCap: 1, + AppSpecificScore: appScore, + DecayInterval: time.Second, + DecayToZero: 0.01, + IPColocationFactorWeight: 1, + }).validate() == nil { t.Fatal("expected validation error") } - if (&PeerScoreParams{TopicScoreCap: 1, AppSpecificScore: appScore, DecayInterval: time.Second, DecayToZero: 0.01, IPColocationFactorWeight: -1, IPColocationFactorThreshold: -1}).validate() == nil { + if (&PeerScoreParams{ + SkipAtomicValidation: skipAtomicValidation, + TopicScoreCap: 1, + AppSpecificScore: appScore, + DecayInterval: time.Second, + DecayToZero: 0.01, + IPColocationFactorWeight: -1, + IPColocationFactorThreshold: -1}).validate() == nil { t.Fatal("expected validation error") } - if (&PeerScoreParams{TopicScoreCap: 1, AppSpecificScore: appScore, DecayInterval: time.Millisecond, DecayToZero: 0.01, IPColocationFactorWeight: -1, IPColocationFactorThreshold: 1}).validate() == nil { + if (&PeerScoreParams{ + SkipAtomicValidation: skipAtomicValidation, + TopicScoreCap: 1, + AppSpecificScore: appScore, + DecayInterval: time.Millisecond, + DecayToZero: 0.01, + IPColocationFactorWeight: -1, + IPColocationFactorThreshold: 1, + }).validate() == nil { t.Fatal("expected validation error") } - if (&PeerScoreParams{TopicScoreCap: 1, AppSpecificScore: appScore, DecayInterval: time.Second, DecayToZero: -1, IPColocationFactorWeight: -1, IPColocationFactorThreshold: 1}).validate() == nil { + if (&PeerScoreParams{ + SkipAtomicValidation: skipAtomicValidation, + TopicScoreCap: 1, + AppSpecificScore: appScore, + DecayInterval: time.Second, + DecayToZero: -1, + IPColocationFactorWeight: -1, + IPColocationFactorThreshold: 1, + }).validate() == nil { t.Fatal("expected validation error") } - if (&PeerScoreParams{TopicScoreCap: 1, AppSpecificScore: appScore, DecayInterval: time.Second, DecayToZero: 2, IPColocationFactorWeight: -1, IPColocationFactorThreshold: 1}).validate() == nil { + if (&PeerScoreParams{ + SkipAtomicValidation: skipAtomicValidation, + TopicScoreCap: 1, + AppSpecificScore: appScore, + DecayInterval: time.Second, + DecayToZero: 2, + IPColocationFactorWeight: -1, + IPColocationFactorThreshold: 1, + }).validate() == nil { t.Fatal("expected validation error") } - if (&PeerScoreParams{AppSpecificScore: appScore, DecayInterval: time.Second, DecayToZero: 0.01, BehaviourPenaltyWeight: 1}).validate() == nil { + if (&PeerScoreParams{ + SkipAtomicValidation: skipAtomicValidation, + AppSpecificScore: appScore, + DecayInterval: time.Second, + DecayToZero: 0.01, + BehaviourPenaltyWeight: 1}).validate() == nil { t.Fatal("expected validation error") } - if (&PeerScoreParams{AppSpecificScore: appScore, DecayInterval: time.Second, DecayToZero: 0.01, BehaviourPenaltyWeight: -1}).validate() == nil { + if (&PeerScoreParams{ + SkipAtomicValidation: skipAtomicValidation, + AppSpecificScore: appScore, + DecayInterval: time.Second, + DecayToZero: 0.01, + BehaviourPenaltyWeight: -1, + }).validate() == nil { t.Fatal("expected validation error") } - if (&PeerScoreParams{AppSpecificScore: appScore, DecayInterval: time.Second, DecayToZero: 0.01, BehaviourPenaltyWeight: -1, BehaviourPenaltyDecay: 2}).validate() == nil { + if (&PeerScoreParams{ + SkipAtomicValidation: skipAtomicValidation, + AppSpecificScore: appScore, + DecayInterval: time.Second, + DecayToZero: 0.01, + BehaviourPenaltyWeight: -1, + BehaviourPenaltyDecay: 2, + }).validate() == nil { t.Fatal("expected validation error") } - // don't use these params in production! + // Checks the topic parameters for invalid values such as infinite and + // NaN numbers. if (&PeerScoreParams{ + SkipAtomicValidation: skipAtomicValidation, + TopicScoreCap: 1, AppSpecificScore: appScore, DecayInterval: time.Second, DecayToZero: 0.01, IPColocationFactorWeight: -1, IPColocationFactorThreshold: 1, - BehaviourPenaltyWeight: -1, - BehaviourPenaltyDecay: 0.999, - }).validate() != nil { - t.Fatal("expected validation success") + Topics: map[string]*TopicScoreParams{ + "test": { + TopicWeight: math.Inf(0), + TimeInMeshWeight: math.NaN(), + TimeInMeshQuantum: time.Second, + TimeInMeshCap: 10, + FirstMessageDeliveriesWeight: math.Inf(1), + FirstMessageDeliveriesDecay: 0.5, + FirstMessageDeliveriesCap: 10, + MeshMessageDeliveriesWeight: math.Inf(-1), + MeshMessageDeliveriesDecay: math.NaN(), + MeshMessageDeliveriesCap: math.Inf(0), + MeshMessageDeliveriesThreshold: 5, + MeshMessageDeliveriesWindow: time.Millisecond, + MeshMessageDeliveriesActivation: time.Second, + MeshFailurePenaltyWeight: -1, + MeshFailurePenaltyDecay: math.NaN(), + InvalidMessageDeliveriesWeight: math.Inf(0), + InvalidMessageDeliveriesDecay: math.NaN(), + }, + }, + }).validate() == nil { + t.Fatal("expected validation failure") } if (&PeerScoreParams{ - TopicScoreCap: 1, + SkipAtomicValidation: skipAtomicValidation, AppSpecificScore: appScore, DecayInterval: time.Second, - DecayToZero: 0.01, - IPColocationFactorWeight: -1, + DecayToZero: math.Inf(0), + IPColocationFactorWeight: math.Inf(-1), IPColocationFactorThreshold: 1, - BehaviourPenaltyWeight: -1, - BehaviourPenaltyDecay: 0.999, - }).validate() != nil { - t.Fatal("expected validation success") + BehaviourPenaltyWeight: math.Inf(0), + BehaviourPenaltyDecay: math.NaN(), + }).validate() == nil { + t.Fatal("expected validation failure") } if (&PeerScoreParams{ + SkipAtomicValidation: skipAtomicValidation, TopicScoreCap: 1, AppSpecificScore: appScore, DecayInterval: time.Second, @@ -449,7 +560,7 @@ func TestPeerScoreParamsValidation(t *testing.T) { IPColocationFactorThreshold: 1, Topics: map[string]*TopicScoreParams{ "test": { - TopicWeight: 1, + TopicWeight: -1, TimeInMeshWeight: 0.01, TimeInMeshQuantum: time.Second, TimeInMeshCap: 10, @@ -468,11 +579,40 @@ func TestPeerScoreParamsValidation(t *testing.T) { InvalidMessageDeliveriesDecay: 0.5, }, }, + }).validate() == nil { + t.Fatal("expected validation failure") + } +} + +func TestPeerScoreParamsValidation_ValidParams_AtomicValidation(t *testing.T) { + appScore := func(peer.ID) float64 { return 0 } + + // don't use these params in production! + if (&PeerScoreParams{ + AppSpecificScore: appScore, + DecayInterval: time.Second, + DecayToZero: 0.01, + IPColocationFactorWeight: -1, + IPColocationFactorThreshold: 1, + BehaviourPenaltyWeight: -1, + BehaviourPenaltyDecay: 0.999, + }).validate() != nil { + t.Fatal("expected validation success") + } + + if (&PeerScoreParams{ + TopicScoreCap: 1, + AppSpecificScore: appScore, + DecayInterval: time.Second, + DecayToZero: 0.01, + IPColocationFactorWeight: -1, + IPColocationFactorThreshold: 1, + BehaviourPenaltyWeight: -1, + BehaviourPenaltyDecay: 0.999, }).validate() != nil { t.Fatal("expected validation success") } - // don't use these params in production! if (&PeerScoreParams{ TopicScoreCap: 1, AppSpecificScore: appScore, @@ -482,7 +622,7 @@ func TestPeerScoreParamsValidation(t *testing.T) { IPColocationFactorThreshold: 1, Topics: map[string]*TopicScoreParams{ "test": { - TopicWeight: -1, + TopicWeight: 1, TimeInMeshWeight: 0.01, TimeInMeshQuantum: time.Second, TimeInMeshCap: 10, @@ -501,58 +641,74 @@ func TestPeerScoreParamsValidation(t *testing.T) { InvalidMessageDeliveriesDecay: 0.5, }, }, - }).validate() == nil { - t.Fatal("expected validation failure") + }).validate() != nil { + t.Fatal("expected validation success") } +} - // Checks the topic parameters for invalid values such as infinite and - // NaN numbers. - - // Don't use these params in production! - if (&PeerScoreParams{ - AppSpecificScore: appScore, - DecayInterval: time.Second, - DecayToZero: math.Inf(0), - IPColocationFactorWeight: math.Inf(-1), - IPColocationFactorThreshold: 1, - BehaviourPenaltyWeight: math.Inf(0), - BehaviourPenaltyDecay: math.NaN(), - }).validate() == nil { - t.Fatal("expected validation failure") - } +func TestPeerScoreParamsValidation_ValidParams_SkipAtomicValidation(t *testing.T) { + appScore := func(peer.ID) float64 { return 0 } - if (&PeerScoreParams{ - TopicScoreCap: 1, - AppSpecificScore: appScore, - DecayInterval: time.Second, - DecayToZero: 0.01, - IPColocationFactorWeight: -1, - IPColocationFactorThreshold: 1, - Topics: map[string]*TopicScoreParams{ + // don't use these params in production! + p := &PeerScoreParams{} + setParamAndValidate(t, p, func(params *PeerScoreParams) { + params.SkipAtomicValidation = true + }) + setParamAndValidate(t, p, func(params *PeerScoreParams) { + params.AppSpecificScore = appScore + }) + setParamAndValidate(t, p, func(params *PeerScoreParams) { + params.DecayInterval = time.Second + params.DecayToZero = 0.01 + }) + setParamAndValidate(t, p, func(params *PeerScoreParams) { + params.IPColocationFactorWeight = -1 + params.IPColocationFactorThreshold = 1 + }) + setParamAndValidate(t, p, func(params *PeerScoreParams) { + params.BehaviourPenaltyWeight = -1 + params.BehaviourPenaltyDecay = 0.999 + }) + + p = &PeerScoreParams{SkipAtomicValidation: true, AppSpecificScore: appScore} + setParamAndValidate(t, p, func(params *PeerScoreParams) { + params.TopicScoreCap = 1 + }) + setParamAndValidate(t, p, func(params *PeerScoreParams) { + params.DecayInterval = time.Second + params.DecayToZero = 0.01 + }) + setParamAndValidate(t, p, func(params *PeerScoreParams) { + params.IPColocationFactorWeight = -1 + params.IPColocationFactorThreshold = 1 + }) + setParamAndValidate(t, p, func(params *PeerScoreParams) { + params.BehaviourPenaltyWeight = -1 + params.BehaviourPenaltyDecay = 0.999 + }) + setParamAndValidate(t, p, func(params *PeerScoreParams) { + params.Topics = map[string]*TopicScoreParams{ "test": { - TopicWeight: math.Inf(0), - TimeInMeshWeight: math.NaN(), + TopicWeight: 1, + TimeInMeshWeight: 0.01, TimeInMeshQuantum: time.Second, TimeInMeshCap: 10, - FirstMessageDeliveriesWeight: math.Inf(1), + FirstMessageDeliveriesWeight: 1, FirstMessageDeliveriesDecay: 0.5, FirstMessageDeliveriesCap: 10, - MeshMessageDeliveriesWeight: math.Inf(-1), - MeshMessageDeliveriesDecay: math.NaN(), - MeshMessageDeliveriesCap: math.Inf(0), + MeshMessageDeliveriesWeight: -1, + MeshMessageDeliveriesDecay: 0.5, + MeshMessageDeliveriesCap: 10, MeshMessageDeliveriesThreshold: 5, MeshMessageDeliveriesWindow: time.Millisecond, MeshMessageDeliveriesActivation: time.Second, MeshFailurePenaltyWeight: -1, - MeshFailurePenaltyDecay: math.NaN(), - InvalidMessageDeliveriesWeight: math.Inf(0), - InvalidMessageDeliveriesDecay: math.NaN(), + MeshFailurePenaltyDecay: 0.5, + InvalidMessageDeliveriesWeight: -1, + InvalidMessageDeliveriesDecay: 0.5, }, - }, - }).validate() == nil { - t.Fatal("expected validation failure") - } - + } + }) } func TestScoreParameterDecay(t *testing.T) { @@ -561,3 +717,10 @@ func TestScoreParameterDecay(t *testing.T) { t.Fatalf("expected .9987216039048303, got %f", decay1hr) } } + +func setParamAndValidate(t *testing.T, params *PeerScoreParams, set func(*PeerScoreParams)) { + set(params) + if err := params.validate(); err != nil { + t.Fatalf("expected validation success, got: %s", err) + } +} From e4fceaa6b49efb5ef83d2c568b2112fcb0b60b15 Mon Sep 17 00:00:00 2001 From: Yahya Hassanzadeh Date: Tue, 6 Sep 2022 16:59:08 -0700 Subject: [PATCH 8/9] adds tests for peer score thresholds --- score_params.go | 15 +++---- score_params_test.go | 97 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 89 insertions(+), 23 deletions(-) diff --git a/score_params.go b/score_params.go index 6d09e0b5..99c9526d 100644 --- a/score_params.go +++ b/score_params.go @@ -13,7 +13,7 @@ type PeerScoreThresholds struct { // whether it is allowed to just set some params and not all of them. SkipAtomicValidation bool - // GossipThreshold is the score threshold below which gossip propagation is supressed; + // GossipThreshold is the score threshold below which gossip propagation is suppressed; // should be negative. GossipThreshold float64 @@ -21,8 +21,8 @@ type PeerScoreThresholds struct { // publishing (also applies to fanout and floodsub peers); should be negative and <= GossipThreshold. PublishThreshold float64 - // GraylistThreshold is the score threshold below which message processing is supressed altogether, - // implementing an effective graylist according to peer score; should be negative and <= PublisThreshold. + // GraylistThreshold is the score threshold below which message processing is suppressed altogether, + // implementing an effective gray list according to peer score; should be negative and <= PublishThreshold. GraylistThreshold float64 // AcceptPXThreshold is the score threshold below which PX will be ignored; this should be positive @@ -35,19 +35,14 @@ type PeerScoreThresholds struct { } func (p *PeerScoreThresholds) validate() error { - if !p.SkipAtomicValidation || p.GossipThreshold != 0 { + + if !p.SkipAtomicValidation || p.PublishThreshold != 0 || p.GossipThreshold != 0 || p.GraylistThreshold != 0 { if p.GossipThreshold > 0 || isInvalidNumber(p.GossipThreshold) { return fmt.Errorf("invalid gossip threshold; it must be <= 0 and a valid number") } - } - - if !p.SkipAtomicValidation || p.PublishThreshold != 0 { if p.PublishThreshold > 0 || p.PublishThreshold > p.GossipThreshold || isInvalidNumber(p.PublishThreshold) { return fmt.Errorf("invalid publish threshold; it must be <= 0 and <= gossip threshold and a valid number") } - } - - if !p.SkipAtomicValidation || p.GraylistThreshold != 0 { if p.GraylistThreshold > 0 || p.GraylistThreshold > p.PublishThreshold || isInvalidNumber(p.GraylistThreshold) { return fmt.Errorf("invalid graylist threshold; it must be <= 0 and <= publish threshold and a valid number") } diff --git a/score_params_test.go b/score_params_test.go index c20a3561..b5d0ede9 100644 --- a/score_params_test.go +++ b/score_params_test.go @@ -8,41 +8,112 @@ import ( "github.com/libp2p/go-libp2p/core/peer" ) -func TestPeerScoreThresholdsValidation(t *testing.T) { - if (&PeerScoreThresholds{GossipThreshold: 1}).validate() == nil { +func TestPeerScoreThreshold_AtomicValidation(t *testing.T) { + testPeerScoreThresholdsValidation(t, false) +} + +func TestPeerScoreThreshold_SkipAtomicValidation(t *testing.T) { + testPeerScoreThresholdsValidation(t, true) +} + +func testPeerScoreThresholdsValidation(t *testing.T, skipAtomicValidation bool) { + if (&PeerScoreThresholds{ + SkipAtomicValidation: skipAtomicValidation, + GossipThreshold: 1, + }).validate() == nil { t.Fatal("expected validation error") } - if (&PeerScoreThresholds{PublishThreshold: 1}).validate() == nil { + if (&PeerScoreThresholds{ + SkipAtomicValidation: skipAtomicValidation, + PublishThreshold: 1, + }).validate() == nil { t.Fatal("expected validation error") } - if (&PeerScoreThresholds{GossipThreshold: -1, PublishThreshold: 0}).validate() == nil { + + if (&PeerScoreThresholds{ + SkipAtomicValidation: skipAtomicValidation, + GossipThreshold: -1, + PublishThreshold: 0, + }).validate() == nil { t.Fatal("expected validation error") } - if (&PeerScoreThresholds{GossipThreshold: -1, PublishThreshold: -2, GraylistThreshold: 0}).validate() == nil { + if (&PeerScoreThresholds{ + SkipAtomicValidation: skipAtomicValidation, + GossipThreshold: -1, + PublishThreshold: -2, + GraylistThreshold: 0, + }).validate() == nil { t.Fatal("expected validation error") } - if (&PeerScoreThresholds{AcceptPXThreshold: -1}).validate() == nil { + if (&PeerScoreThresholds{ + SkipAtomicValidation: skipAtomicValidation, + AcceptPXThreshold: -1, + }).validate() == nil { t.Fatal("expected validation error") } - if (&PeerScoreThresholds{OpportunisticGraftThreshold: -1}).validate() == nil { + if (&PeerScoreThresholds{ + SkipAtomicValidation: skipAtomicValidation, + OpportunisticGraftThreshold: -1, + }).validate() == nil { t.Fatal("expected validation error") } - if (&PeerScoreThresholds{GossipThreshold: -1, PublishThreshold: -2, GraylistThreshold: -3, AcceptPXThreshold: 1, OpportunisticGraftThreshold: 2}).validate() != nil { + if (&PeerScoreThresholds{ + SkipAtomicValidation: skipAtomicValidation, + GossipThreshold: -1, + PublishThreshold: -2, + GraylistThreshold: -3, + AcceptPXThreshold: 1, + OpportunisticGraftThreshold: 2}).validate() != nil { t.Fatal("expected validation success") } - if (&PeerScoreThresholds{GossipThreshold: math.Inf(-1), PublishThreshold: -2, GraylistThreshold: -3, AcceptPXThreshold: 1, OpportunisticGraftThreshold: 2}).validate() == nil { + if (&PeerScoreThresholds{ + SkipAtomicValidation: skipAtomicValidation, + GossipThreshold: math.Inf(-1), + PublishThreshold: -2, + GraylistThreshold: -3, + AcceptPXThreshold: 1, + OpportunisticGraftThreshold: 2, + }).validate() == nil { t.Fatal("expected validation error") } - if (&PeerScoreThresholds{GossipThreshold: -1, PublishThreshold: math.Inf(-1), GraylistThreshold: -3, AcceptPXThreshold: 1, OpportunisticGraftThreshold: 2}).validate() == nil { + if (&PeerScoreThresholds{ + SkipAtomicValidation: skipAtomicValidation, + GossipThreshold: -1, + PublishThreshold: math.Inf(-1), + GraylistThreshold: -3, + AcceptPXThreshold: 1, + OpportunisticGraftThreshold: 2, + }).validate() == nil { t.Fatal("expected validation error") } - if (&PeerScoreThresholds{GossipThreshold: -1, PublishThreshold: -2, GraylistThreshold: math.Inf(-1), AcceptPXThreshold: 1, OpportunisticGraftThreshold: 2}).validate() == nil { + if (&PeerScoreThresholds{ + SkipAtomicValidation: skipAtomicValidation, + GossipThreshold: -1, + PublishThreshold: -2, + GraylistThreshold: math.Inf(-1), + AcceptPXThreshold: 1, + OpportunisticGraftThreshold: 2, + }).validate() == nil { t.Fatal("expected validation error") } - if (&PeerScoreThresholds{GossipThreshold: -1, PublishThreshold: -2, GraylistThreshold: -3, AcceptPXThreshold: math.NaN(), OpportunisticGraftThreshold: 2}).validate() == nil { + if (&PeerScoreThresholds{ + SkipAtomicValidation: skipAtomicValidation, + GossipThreshold: -1, + PublishThreshold: -2, + GraylistThreshold: -3, + AcceptPXThreshold: math.NaN(), + OpportunisticGraftThreshold: 2, + }).validate() == nil { t.Fatal("expected validation error") } - if (&PeerScoreThresholds{GossipThreshold: -1, PublishThreshold: -2, GraylistThreshold: -3, AcceptPXThreshold: 1, OpportunisticGraftThreshold: math.Inf(0)}).validate() == nil { + if (&PeerScoreThresholds{ + SkipAtomicValidation: skipAtomicValidation, + GossipThreshold: -1, + PublishThreshold: -2, + GraylistThreshold: -3, + AcceptPXThreshold: 1, + OpportunisticGraftThreshold: math.Inf(0), + }).validate() == nil { t.Fatal("expected validation error") } } From eda34497f9e28d43b0e71bfce9e4600d6c8f12d8 Mon Sep 17 00:00:00 2001 From: Yahya Hassanzadeh Date: Wed, 7 Sep 2022 15:26:51 -0700 Subject: [PATCH 9/9] refactors tests --- score_params_test.go | 304 +++++++++++++++++-------------------------- 1 file changed, 123 insertions(+), 181 deletions(-) diff --git a/score_params_test.go b/score_params_test.go index b5d0ede9..89f216e1 100644 --- a/score_params_test.go +++ b/score_params_test.go @@ -118,129 +118,50 @@ func testPeerScoreThresholdsValidation(t *testing.T, skipAtomicValidation bool) } } -func TestTopicScoreParamsValidation_AtomicValidation(t *testing.T) { - if (&TopicScoreParams{}).validate() == nil { - t.Fatal("expected validation error") - } - - if (&TopicScoreParams{TopicWeight: -1}).validate() == nil { - t.Fatal("expected validation error") - } - - if (&TopicScoreParams{TimeInMeshWeight: -1, TimeInMeshQuantum: time.Second}).validate() == nil { - t.Fatal("expected validation error") - } - if (&TopicScoreParams{TimeInMeshWeight: 1, TimeInMeshQuantum: -1}).validate() == nil { - t.Fatal("expected validation error") - } - if (&TopicScoreParams{TimeInMeshWeight: 1, TimeInMeshQuantum: time.Second, TimeInMeshCap: -1}).validate() == nil { - t.Fatal("expected validation error") - } - - if (&TopicScoreParams{TimeInMeshQuantum: time.Second, FirstMessageDeliveriesWeight: -1}).validate() == nil { - t.Fatal("expected validation error") - } - if (&TopicScoreParams{TimeInMeshQuantum: time.Second, FirstMessageDeliveriesWeight: 1, FirstMessageDeliveriesDecay: -1}).validate() == nil { - t.Fatal("expected validation error") - } - if (&TopicScoreParams{TimeInMeshQuantum: time.Second, FirstMessageDeliveriesWeight: 1, FirstMessageDeliveriesDecay: 2}).validate() == nil { - t.Fatal("expected validation error") - } - if (&TopicScoreParams{TimeInMeshQuantum: time.Second, FirstMessageDeliveriesWeight: 1, FirstMessageDeliveriesDecay: .5, FirstMessageDeliveriesCap: -1}).validate() == nil { - t.Fatal("expected validation error") - } - - if (&TopicScoreParams{TimeInMeshQuantum: time.Second, MeshMessageDeliveriesWeight: 1}).validate() == nil { - t.Fatal("expected validation error") - } - if (&TopicScoreParams{TimeInMeshQuantum: time.Second, MeshMessageDeliveriesWeight: -1, MeshMessageDeliveriesDecay: -1}).validate() == nil { - t.Fatal("expected validation error") - } - if (&TopicScoreParams{TimeInMeshQuantum: time.Second, MeshMessageDeliveriesWeight: -1, MeshMessageDeliveriesDecay: 2}).validate() == nil { - t.Fatal("expected validation error") - } - if (&TopicScoreParams{TimeInMeshQuantum: time.Second, MeshMessageDeliveriesWeight: -1, MeshMessageDeliveriesDecay: .5, MeshMessageDeliveriesCap: -1}).validate() == nil { - t.Fatal("expected validation error") - } - if (&TopicScoreParams{TimeInMeshQuantum: time.Second, MeshMessageDeliveriesWeight: -1, MeshMessageDeliveriesDecay: .5, MeshMessageDeliveriesCap: 5, MeshMessageDeliveriesThreshold: -3}).validate() == nil { - t.Fatal("expected validation error") - } - if (&TopicScoreParams{TimeInMeshQuantum: time.Second, MeshMessageDeliveriesWeight: -1, MeshMessageDeliveriesDecay: .5, MeshMessageDeliveriesCap: 5, MeshMessageDeliveriesThreshold: 3, MeshMessageDeliveriesWindow: -1}).validate() == nil { - t.Fatal("expected validation error") - } - if (&TopicScoreParams{TimeInMeshQuantum: time.Second, MeshMessageDeliveriesWeight: -1, MeshMessageDeliveriesDecay: .5, MeshMessageDeliveriesCap: 5, MeshMessageDeliveriesThreshold: 3, MeshMessageDeliveriesWindow: time.Millisecond, MeshMessageDeliveriesActivation: time.Millisecond}).validate() == nil { - t.Fatal("expected validation error") - } - - if (&TopicScoreParams{TimeInMeshQuantum: time.Second, MeshFailurePenaltyWeight: 1}).validate() == nil { - t.Fatal("expected validation error") - } - if (&TopicScoreParams{TimeInMeshQuantum: time.Second, MeshFailurePenaltyWeight: -1, MeshFailurePenaltyDecay: -1}).validate() == nil { - t.Fatal("expected validation error") - } - if (&TopicScoreParams{TimeInMeshQuantum: time.Second, MeshFailurePenaltyWeight: -1, MeshFailurePenaltyDecay: 2}).validate() == nil { - t.Fatal("expected validation error") - } - - if (&TopicScoreParams{TimeInMeshQuantum: time.Second, InvalidMessageDeliveriesWeight: 1}).validate() == nil { - t.Fatal("expected validation error") - } - if (&TopicScoreParams{TimeInMeshQuantum: time.Second, InvalidMessageDeliveriesWeight: -1, InvalidMessageDeliveriesDecay: -1}).validate() == nil { - t.Fatal("expected validation error") - } - if (&TopicScoreParams{TimeInMeshQuantum: time.Second, InvalidMessageDeliveriesWeight: -1, InvalidMessageDeliveriesDecay: 2}).validate() == nil { - t.Fatal("expected validation error") - } +func TestTopicScoreParamsValidation_InvalidParams_AtomicValidation(t *testing.T) { + testTopicScoreParamsValidationWithInvalidParameters(t, false) +} - // Don't use these params in production! - if (&TopicScoreParams{ - TopicWeight: 1, - TimeInMeshWeight: 0.01, - TimeInMeshQuantum: time.Second, - TimeInMeshCap: 10, - FirstMessageDeliveriesWeight: 1, - FirstMessageDeliveriesDecay: 0.5, - FirstMessageDeliveriesCap: 10, - MeshMessageDeliveriesWeight: -1, - MeshMessageDeliveriesDecay: 0.5, - MeshMessageDeliveriesCap: 10, - MeshMessageDeliveriesThreshold: 5, - MeshMessageDeliveriesWindow: time.Millisecond, - MeshMessageDeliveriesActivation: time.Second, - MeshFailurePenaltyWeight: -1, - MeshFailurePenaltyDecay: 0.5, - InvalidMessageDeliveriesWeight: -1, - InvalidMessageDeliveriesDecay: 0.5, - }).validate() != nil { - t.Fatal("expected validation success") - } +func TestTopicScoreParamsValidation_InvalidParams_SkipAtomicValidation(t *testing.T) { + testTopicScoreParamsValidationWithInvalidParameters(t, true) } -func TestTopicScoreParamsValidation_NonAtomicValidation(t *testing.T) { - if (&TopicScoreParams{SkipAtomicValidation: true}).validate() != nil { - t.Fatal("expected no validation error in non-atomic mode") +func testTopicScoreParamsValidationWithInvalidParameters(t *testing.T, skipAtomicValidation bool) { + + if skipAtomicValidation { + if (&TopicScoreParams{ + SkipAtomicValidation: true}).validate() != nil { + t.Fatal("expected validation success") + } + } else { + if (&TopicScoreParams{}).validate() == nil { + t.Fatal("expected validation failure") + } } - // Following tests evaluate that even when we skip atomic validation, those parameters that are set with a value are - // going through validation. if (&TopicScoreParams{ - SkipAtomicValidation: true, + SkipAtomicValidation: skipAtomicValidation, TopicWeight: -1, - }). - validate() == nil { - t.Fatalf("expected validation error") + }).validate() == nil { + t.Fatal("expected validation error") } if (&TopicScoreParams{ - SkipAtomicValidation: true, + SkipAtomicValidation: skipAtomicValidation, TimeInMeshWeight: -1, TimeInMeshQuantum: time.Second, }).validate() == nil { - t.Fatalf("expected validation error") + t.Fatal("expected validation error") } - if (&TopicScoreParams{ - SkipAtomicValidation: true, + SkipAtomicValidation: skipAtomicValidation, + TimeInMeshWeight: 1, + TimeInMeshQuantum: -1, + }).validate() == nil { + t.Fatal("expected validation error") + } + if (&TopicScoreParams{ + SkipAtomicValidation: skipAtomicValidation, TimeInMeshWeight: 1, TimeInMeshQuantum: time.Second, TimeInMeshCap: -1, @@ -249,14 +170,14 @@ func TestTopicScoreParamsValidation_NonAtomicValidation(t *testing.T) { } if (&TopicScoreParams{ - SkipAtomicValidation: true, + SkipAtomicValidation: skipAtomicValidation, TimeInMeshQuantum: time.Second, FirstMessageDeliveriesWeight: -1, }).validate() == nil { t.Fatal("expected validation error") } if (&TopicScoreParams{ - SkipAtomicValidation: true, + SkipAtomicValidation: skipAtomicValidation, TimeInMeshQuantum: time.Second, FirstMessageDeliveriesWeight: 1, FirstMessageDeliveriesDecay: -1, @@ -264,7 +185,7 @@ func TestTopicScoreParamsValidation_NonAtomicValidation(t *testing.T) { t.Fatal("expected validation error") } if (&TopicScoreParams{ - SkipAtomicValidation: true, + SkipAtomicValidation: skipAtomicValidation, TimeInMeshQuantum: time.Second, FirstMessageDeliveriesWeight: 1, FirstMessageDeliveriesDecay: 2, @@ -272,7 +193,7 @@ func TestTopicScoreParamsValidation_NonAtomicValidation(t *testing.T) { t.Fatal("expected validation error") } if (&TopicScoreParams{ - SkipAtomicValidation: true, + SkipAtomicValidation: skipAtomicValidation, TimeInMeshQuantum: time.Second, FirstMessageDeliveriesWeight: 1, FirstMessageDeliveriesDecay: .5, @@ -282,13 +203,14 @@ func TestTopicScoreParamsValidation_NonAtomicValidation(t *testing.T) { } if (&TopicScoreParams{ - SkipAtomicValidation: true, + SkipAtomicValidation: skipAtomicValidation, TimeInMeshQuantum: time.Second, MeshMessageDeliveriesWeight: 1, }).validate() == nil { t.Fatal("expected validation error") } - if (&TopicScoreParams{SkipAtomicValidation: true, + if (&TopicScoreParams{ + SkipAtomicValidation: skipAtomicValidation, TimeInMeshQuantum: time.Second, MeshMessageDeliveriesWeight: -1, MeshMessageDeliveriesDecay: -1, @@ -296,15 +218,14 @@ func TestTopicScoreParamsValidation_NonAtomicValidation(t *testing.T) { t.Fatal("expected validation error") } if (&TopicScoreParams{ - SkipAtomicValidation: true, + SkipAtomicValidation: skipAtomicValidation, TimeInMeshQuantum: time.Second, MeshMessageDeliveriesWeight: -1, - MeshMessageDeliveriesDecay: 2, - }).validate() == nil { + MeshMessageDeliveriesDecay: 2}).validate() == nil { t.Fatal("expected validation error") } if (&TopicScoreParams{ - SkipAtomicValidation: true, + SkipAtomicValidation: skipAtomicValidation, TimeInMeshQuantum: time.Second, MeshMessageDeliveriesWeight: -1, MeshMessageDeliveriesDecay: .5, @@ -313,7 +234,7 @@ func TestTopicScoreParamsValidation_NonAtomicValidation(t *testing.T) { t.Fatal("expected validation error") } if (&TopicScoreParams{ - SkipAtomicValidation: true, + SkipAtomicValidation: skipAtomicValidation, TimeInMeshQuantum: time.Second, MeshMessageDeliveriesWeight: -1, MeshMessageDeliveriesDecay: .5, @@ -323,7 +244,7 @@ func TestTopicScoreParamsValidation_NonAtomicValidation(t *testing.T) { t.Fatal("expected validation error") } if (&TopicScoreParams{ - SkipAtomicValidation: true, + SkipAtomicValidation: skipAtomicValidation, TimeInMeshQuantum: time.Second, MeshMessageDeliveriesWeight: -1, MeshMessageDeliveriesDecay: .5, @@ -334,27 +255,26 @@ func TestTopicScoreParamsValidation_NonAtomicValidation(t *testing.T) { t.Fatal("expected validation error") } if (&TopicScoreParams{ - SkipAtomicValidation: true, + SkipAtomicValidation: skipAtomicValidation, TimeInMeshQuantum: time.Second, MeshMessageDeliveriesWeight: -1, MeshMessageDeliveriesDecay: .5, MeshMessageDeliveriesCap: 5, MeshMessageDeliveriesThreshold: 3, MeshMessageDeliveriesWindow: time.Millisecond, - MeshMessageDeliveriesActivation: time.Millisecond, - }).validate() == nil { + MeshMessageDeliveriesActivation: time.Millisecond}).validate() == nil { t.Fatal("expected validation error") } if (&TopicScoreParams{ - SkipAtomicValidation: true, + SkipAtomicValidation: skipAtomicValidation, TimeInMeshQuantum: time.Second, MeshFailurePenaltyWeight: 1, }).validate() == nil { t.Fatal("expected validation error") } if (&TopicScoreParams{ - SkipAtomicValidation: true, + SkipAtomicValidation: skipAtomicValidation, TimeInMeshQuantum: time.Second, MeshFailurePenaltyWeight: -1, MeshFailurePenaltyDecay: -1, @@ -362,7 +282,7 @@ func TestTopicScoreParamsValidation_NonAtomicValidation(t *testing.T) { t.Fatal("expected validation error") } if (&TopicScoreParams{ - SkipAtomicValidation: true, + SkipAtomicValidation: skipAtomicValidation, TimeInMeshQuantum: time.Second, MeshFailurePenaltyWeight: -1, MeshFailurePenaltyDecay: 2, @@ -371,14 +291,14 @@ func TestTopicScoreParamsValidation_NonAtomicValidation(t *testing.T) { } if (&TopicScoreParams{ - SkipAtomicValidation: true, + SkipAtomicValidation: skipAtomicValidation, TimeInMeshQuantum: time.Second, InvalidMessageDeliveriesWeight: 1, }).validate() == nil { t.Fatal("expected validation error") } if (&TopicScoreParams{ - SkipAtomicValidation: true, + SkipAtomicValidation: skipAtomicValidation, TimeInMeshQuantum: time.Second, InvalidMessageDeliveriesWeight: -1, InvalidMessageDeliveriesDecay: -1, @@ -386,69 +306,84 @@ func TestTopicScoreParamsValidation_NonAtomicValidation(t *testing.T) { t.Fatal("expected validation error") } if (&TopicScoreParams{ - SkipAtomicValidation: true, + SkipAtomicValidation: skipAtomicValidation, TimeInMeshQuantum: time.Second, InvalidMessageDeliveriesWeight: -1, InvalidMessageDeliveriesDecay: 2, }).validate() == nil { t.Fatal("expected validation error") } +} +func TestTopicScoreParamsValidation_ValidParams_AtomicValidation(t *testing.T) { // Don't use these params in production! - // In non-atomic (selective) validation mode, the subset of parameters passes - // validation if the individual parameters values pass validation. - p := TopicScoreParams{SkipAtomicValidation: true} - - if err := p.validate(); err != nil { - t.Fatalf("expected validation success, got: %s", err) - } - - // including topic weight - p.TopicWeight = 1 - if err := p.validate(); err != nil { - t.Fatalf("expected validation success, got: %s", err) - } - - // including time in mesh parameters - p.TimeInMeshWeight = 0.01 - p.TimeInMeshQuantum = time.Second - p.TimeInMeshCap = 10 - if err := p.validate(); err != nil { - t.Fatalf("expected validation success, got: %s", err) - } - - // including first message delivery parameters - p.FirstMessageDeliveriesWeight = 1 - p.FirstMessageDeliveriesDecay = 0.5 - p.FirstMessageDeliveriesCap = 10 - if err := p.validate(); err != nil { - t.Fatalf("expected validation success, got: %s", err) - } - - // including mesh message delivery parameters - p.MeshMessageDeliveriesWeight = -1 - p.MeshMessageDeliveriesDecay = 0.05 - p.MeshMessageDeliveriesCap = 10 - p.MeshMessageDeliveriesThreshold = 5 - p.MeshMessageDeliveriesWindow = time.Millisecond - p.MeshMessageDeliveriesActivation = time.Second - if err := p.validate(); err != nil { - t.Fatalf("expected validation success, got: %s", err) - } - - // including mesh failure penalty parameters - p.MeshFailurePenaltyWeight = -1 - p.MeshFailurePenaltyDecay = 0.5 - if err := p.validate(); err != nil { - t.Fatalf("expected validation success, got: %s", err) + if (&TopicScoreParams{ + SkipAtomicValidation: false, + TopicWeight: 1, + TimeInMeshWeight: 0.01, + TimeInMeshQuantum: time.Second, + TimeInMeshCap: 10, + FirstMessageDeliveriesWeight: 1, + FirstMessageDeliveriesDecay: 0.5, + FirstMessageDeliveriesCap: 10, + MeshMessageDeliveriesWeight: -1, + MeshMessageDeliveriesDecay: 0.5, + MeshMessageDeliveriesCap: 10, + MeshMessageDeliveriesThreshold: 5, + MeshMessageDeliveriesWindow: time.Millisecond, + MeshMessageDeliveriesActivation: time.Second, + MeshFailurePenaltyWeight: -1, + MeshFailurePenaltyDecay: 0.5, + InvalidMessageDeliveriesWeight: -1, + InvalidMessageDeliveriesDecay: 0.5, + }).validate() != nil { + t.Fatal("expected validation success") } +} - // including invalid message delivery parameters - p.InvalidMessageDeliveriesWeight = -1 - p.InvalidMessageDeliveriesDecay = 0.5 - if err := p.validate(); err != nil { - t.Fatalf("expected validation success, got: %s", err) - } +func TestTopicScoreParamsValidation_NonAtomicValidation(t *testing.T) { + // Don't use these params in production! + // In non-atomic (selective) validation mode, the subset of parameters passes + // validation if the individual parameters values pass validation. + p := &TopicScoreParams{} + setTopicParamAndValidate(t, p, func(params *TopicScoreParams) { + params.SkipAtomicValidation = true + }) + // including topic weight. + setTopicParamAndValidate(t, p, func(params *TopicScoreParams) { + params.TopicWeight = 1 + }) + // including time in mesh parameters. + setTopicParamAndValidate(t, p, func(params *TopicScoreParams) { + params.TimeInMeshWeight = 0.01 + params.TimeInMeshQuantum = time.Second + params.TimeInMeshCap = 10 + }) + // including first message delivery parameters. + setTopicParamAndValidate(t, p, func(params *TopicScoreParams) { + params.FirstMessageDeliveriesWeight = 1 + params.FirstMessageDeliveriesDecay = 0.5 + params.FirstMessageDeliveriesCap = 10 + }) + // including mesh message delivery parameters. + setTopicParamAndValidate(t, p, func(params *TopicScoreParams) { + params.MeshMessageDeliveriesWeight = -1 + params.MeshMessageDeliveriesDecay = 0.5 + params.MeshMessageDeliveriesCap = 10 + params.MeshMessageDeliveriesThreshold = 5 + params.MeshMessageDeliveriesWindow = time.Millisecond + params.MeshMessageDeliveriesActivation = time.Second + }) + // including mesh failure penalty parameters. + setTopicParamAndValidate(t, p, func(params *TopicScoreParams) { + params.MeshFailurePenaltyWeight = -1 + params.MeshFailurePenaltyDecay = 0.5 + }) + // including invalid message delivery parameters. + setTopicParamAndValidate(t, p, func(params *TopicScoreParams) { + params.InvalidMessageDeliveriesWeight = -1 + params.InvalidMessageDeliveriesDecay = 0.5 + }) } func TestPeerScoreParamsValidation_InvalidParams_AtomicValidation(t *testing.T) { @@ -795,3 +730,10 @@ func setParamAndValidate(t *testing.T, params *PeerScoreParams, set func(*PeerSc t.Fatalf("expected validation success, got: %s", err) } } + +func setTopicParamAndValidate(t *testing.T, params *TopicScoreParams, set func(topic *TopicScoreParams)) { + set(params) + if err := params.validate(); err != nil { + t.Fatalf("expected validation success, got: %s", err) + } +}