mirror of
https://github.com/logos-messaging/go-libp2p-pubsub.git
synced 2026-01-02 12:53:09 +00:00
Enables non-atomic validation for peer scoring parameters (#499)
* decouples topic scoring parameters * adds skiping atomic validation for topic parameters * cleans up * adds skip atomic validation to peer score threshold * adds skip atomic validation for peer parameters * adds test for non-atomic validation * adds tests for peer score * adds tests for peer score thresholds * refactors tests
This commit is contained in:
parent
4f56e8f0a7
commit
8866ca88a1
219
score_params.go
219
score_params.go
@ -10,7 +10,10 @@ import (
|
||||
)
|
||||
|
||||
type PeerScoreThresholds struct {
|
||||
// GossipThreshold is the score threshold below which gossip propagation is supressed;
|
||||
// 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 suppressed;
|
||||
// should be negative.
|
||||
GossipThreshold float64
|
||||
|
||||
@ -18,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
|
||||
@ -32,25 +35,38 @@ 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.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.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.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.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.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.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
|
||||
}
|
||||
|
||||
type PeerScoreParams struct {
|
||||
// whether it is allowed to just set some params and not all of them.
|
||||
SkipAtomicValidation bool
|
||||
|
||||
// Score parameters per topic.
|
||||
Topics map[string]*TopicScoreParams
|
||||
|
||||
@ -99,12 +115,15 @@ type PeerScoreParams struct {
|
||||
}
|
||||
|
||||
type TopicScoreParams struct {
|
||||
// whether it is allowed to just set some params and not all of them.
|
||||
SkipAtomicValidation bool
|
||||
|
||||
// The weight of the topic.
|
||||
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
|
||||
@ -124,7 +143,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.
|
||||
@ -159,41 +178,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
|
||||
@ -207,6 +240,43 @@ 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.SkipAtomicValidation {
|
||||
// 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")
|
||||
}
|
||||
@ -220,7 +290,20 @@ 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.SkipAtomicValidation {
|
||||
// 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")
|
||||
}
|
||||
@ -231,7 +314,25 @@ 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.SkipAtomicValidation {
|
||||
// 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")
|
||||
}
|
||||
@ -251,7 +352,20 @@ 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.SkipAtomicValidation {
|
||||
// in selective mode, parameters at their zero values are dismissed from validation.
|
||||
if p.MeshFailurePenaltyDecay == 0 && p.MeshFailurePenaltyWeight == 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.MeshFailurePenaltyWeight > 0 || isInvalidNumber(p.MeshFailurePenaltyWeight) {
|
||||
return fmt.Errorf("invalid MeshFailurePenaltyWeight; must be negative (or 0 to disable) and a valid number")
|
||||
}
|
||||
@ -259,7 +373,20 @@ 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.SkipAtomicValidation {
|
||||
// in selective mode, parameters at their zero values are dismissed from validation.
|
||||
if p.InvalidMessageDeliveriesDecay == 0 && p.InvalidMessageDeliveriesWeight == 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.InvalidMessageDeliveriesWeight > 0 || isInvalidNumber(p.InvalidMessageDeliveriesWeight) {
|
||||
return fmt.Errorf("invalid InvalidMessageDeliveriesWeight; must be negative (or 0 to disable) and a valid number")
|
||||
}
|
||||
@ -281,7 +408,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)
|
||||
|
||||
@ -8,121 +8,317 @@ 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")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTopicScoreParamsValidation(t *testing.T) {
|
||||
if (&TopicScoreParams{}).validate() == nil {
|
||||
func TestTopicScoreParamsValidation_InvalidParams_AtomicValidation(t *testing.T) {
|
||||
testTopicScoreParamsValidationWithInvalidParameters(t, false)
|
||||
}
|
||||
|
||||
func TestTopicScoreParamsValidation_InvalidParams_SkipAtomicValidation(t *testing.T) {
|
||||
testTopicScoreParamsValidationWithInvalidParameters(t, true)
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
if (&TopicScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TopicWeight: -1,
|
||||
}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
|
||||
if (&TopicScoreParams{TopicWeight: -1}).validate() == nil {
|
||||
if (&TopicScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TimeInMeshWeight: -1,
|
||||
TimeInMeshQuantum: time.Second,
|
||||
}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
if (&TopicScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TimeInMeshWeight: 1,
|
||||
TimeInMeshQuantum: -1,
|
||||
}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
if (&TopicScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TimeInMeshWeight: 1,
|
||||
TimeInMeshQuantum: time.Second,
|
||||
TimeInMeshCap: -1,
|
||||
}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
|
||||
if (&TopicScoreParams{TimeInMeshWeight: -1, TimeInMeshQuantum: time.Second}).validate() == nil {
|
||||
if (&TopicScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TimeInMeshQuantum: time.Second,
|
||||
FirstMessageDeliveriesWeight: -1,
|
||||
}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
if (&TopicScoreParams{TimeInMeshWeight: 1, TimeInMeshQuantum: -1}).validate() == nil {
|
||||
if (&TopicScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TimeInMeshQuantum: time.Second,
|
||||
FirstMessageDeliveriesWeight: 1,
|
||||
FirstMessageDeliveriesDecay: -1,
|
||||
}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
if (&TopicScoreParams{TimeInMeshWeight: 1, TimeInMeshQuantum: time.Second, TimeInMeshCap: -1}).validate() == nil {
|
||||
if (&TopicScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TimeInMeshQuantum: time.Second,
|
||||
FirstMessageDeliveriesWeight: 1,
|
||||
FirstMessageDeliveriesDecay: 2,
|
||||
}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
if (&TopicScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TimeInMeshQuantum: time.Second,
|
||||
FirstMessageDeliveriesWeight: 1,
|
||||
FirstMessageDeliveriesDecay: .5,
|
||||
FirstMessageDeliveriesCap: -1,
|
||||
}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
|
||||
if (&TopicScoreParams{TimeInMeshQuantum: time.Second, FirstMessageDeliveriesWeight: -1}).validate() == nil {
|
||||
if (&TopicScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TimeInMeshQuantum: time.Second,
|
||||
MeshMessageDeliveriesWeight: 1,
|
||||
}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
if (&TopicScoreParams{TimeInMeshQuantum: time.Second, FirstMessageDeliveriesWeight: 1, FirstMessageDeliveriesDecay: -1}).validate() == nil {
|
||||
if (&TopicScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TimeInMeshQuantum: time.Second,
|
||||
MeshMessageDeliveriesWeight: -1,
|
||||
MeshMessageDeliveriesDecay: -1,
|
||||
}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
if (&TopicScoreParams{TimeInMeshQuantum: time.Second, FirstMessageDeliveriesWeight: 1, FirstMessageDeliveriesDecay: 2}).validate() == nil {
|
||||
if (&TopicScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TimeInMeshQuantum: time.Second,
|
||||
MeshMessageDeliveriesWeight: -1,
|
||||
MeshMessageDeliveriesDecay: 2}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
if (&TopicScoreParams{TimeInMeshQuantum: time.Second, FirstMessageDeliveriesWeight: 1, FirstMessageDeliveriesDecay: .5, FirstMessageDeliveriesCap: -1}).validate() == nil {
|
||||
if (&TopicScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TimeInMeshQuantum: time.Second,
|
||||
MeshMessageDeliveriesWeight: -1,
|
||||
MeshMessageDeliveriesDecay: .5,
|
||||
MeshMessageDeliveriesCap: -1,
|
||||
}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
if (&TopicScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TimeInMeshQuantum: time.Second,
|
||||
MeshMessageDeliveriesWeight: -1,
|
||||
MeshMessageDeliveriesDecay: .5,
|
||||
MeshMessageDeliveriesCap: 5,
|
||||
MeshMessageDeliveriesThreshold: -3,
|
||||
}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
if (&TopicScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TimeInMeshQuantum: time.Second,
|
||||
MeshMessageDeliveriesWeight: -1,
|
||||
MeshMessageDeliveriesDecay: .5,
|
||||
MeshMessageDeliveriesCap: 5,
|
||||
MeshMessageDeliveriesThreshold: 3,
|
||||
MeshMessageDeliveriesWindow: -1,
|
||||
}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
if (&TopicScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
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, MeshMessageDeliveriesWeight: 1}).validate() == nil {
|
||||
if (&TopicScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TimeInMeshQuantum: time.Second,
|
||||
MeshFailurePenaltyWeight: 1,
|
||||
}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
if (&TopicScoreParams{TimeInMeshQuantum: time.Second, MeshMessageDeliveriesWeight: -1, MeshMessageDeliveriesDecay: -1}).validate() == nil {
|
||||
if (&TopicScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TimeInMeshQuantum: time.Second,
|
||||
MeshFailurePenaltyWeight: -1,
|
||||
MeshFailurePenaltyDecay: -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 {
|
||||
if (&TopicScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TimeInMeshQuantum: time.Second,
|
||||
MeshFailurePenaltyWeight: -1,
|
||||
MeshFailurePenaltyDecay: 2,
|
||||
}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
|
||||
if (&TopicScoreParams{TimeInMeshQuantum: time.Second, MeshFailurePenaltyWeight: 1}).validate() == nil {
|
||||
if (&TopicScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TimeInMeshQuantum: time.Second,
|
||||
InvalidMessageDeliveriesWeight: 1,
|
||||
}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
if (&TopicScoreParams{TimeInMeshQuantum: time.Second, MeshFailurePenaltyWeight: -1, MeshFailurePenaltyDecay: -1}).validate() == nil {
|
||||
if (&TopicScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TimeInMeshQuantum: time.Second,
|
||||
InvalidMessageDeliveriesWeight: -1,
|
||||
InvalidMessageDeliveriesDecay: -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 {
|
||||
if (&TopicScoreParams{
|
||||
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!
|
||||
if (&TopicScoreParams{
|
||||
SkipAtomicValidation: false,
|
||||
TopicWeight: 1,
|
||||
TimeInMeshWeight: 0.01,
|
||||
TimeInMeshQuantum: time.Second,
|
||||
@ -145,148 +341,177 @@ func TestTopicScoreParamsValidation(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPeerScoreParamsValidation(t *testing.T) {
|
||||
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) {
|
||||
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 {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
if (&PeerScoreParams{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 {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
if (&PeerScoreParams{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 {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
if (&PeerScoreParams{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 {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
if (&PeerScoreParams{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 {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
if (&PeerScoreParams{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!
|
||||
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")
|
||||
}
|
||||
|
||||
if (&PeerScoreParams{
|
||||
TopicScoreCap: 1,
|
||||
AppSpecificScore: appScore,
|
||||
DecayInterval: time.Second,
|
||||
DecayToZero: 0.01,
|
||||
IPColocationFactorWeight: -1,
|
||||
IPColocationFactorThreshold: 1,
|
||||
Topics: map[string]*TopicScoreParams{
|
||||
"test": &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")
|
||||
}
|
||||
|
||||
// don't use these params in production!
|
||||
if (&PeerScoreParams{
|
||||
TopicScoreCap: 1,
|
||||
AppSpecificScore: appScore,
|
||||
DecayInterval: time.Second,
|
||||
DecayToZero: 0.01,
|
||||
IPColocationFactorWeight: -1,
|
||||
IPColocationFactorThreshold: 1,
|
||||
Topics: map[string]*TopicScoreParams{
|
||||
"test": &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,
|
||||
},
|
||||
},
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TopicScoreCap: -1,
|
||||
AppSpecificScore: appScore,
|
||||
DecayInterval: time.Second,
|
||||
DecayToZero: 0.01,
|
||||
}).validate() == nil {
|
||||
t.Fatal("expected validation failure")
|
||||
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{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TopicScoreCap: 1,
|
||||
AppSpecificScore: appScore,
|
||||
DecayInterval: time.Second,
|
||||
DecayToZero: 0.01,
|
||||
IPColocationFactorWeight: 1,
|
||||
}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
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{
|
||||
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{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TopicScoreCap: 1,
|
||||
AppSpecificScore: appScore,
|
||||
DecayInterval: time.Second,
|
||||
DecayToZero: -1,
|
||||
IPColocationFactorWeight: -1,
|
||||
IPColocationFactorThreshold: 1,
|
||||
}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
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{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
AppSpecificScore: appScore,
|
||||
DecayInterval: time.Second,
|
||||
DecayToZero: 0.01,
|
||||
BehaviourPenaltyWeight: 1}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
if (&PeerScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
AppSpecificScore: appScore,
|
||||
DecayInterval: time.Second,
|
||||
DecayToZero: 0.01,
|
||||
BehaviourPenaltyWeight: -1,
|
||||
}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
if (&PeerScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
AppSpecificScore: appScore,
|
||||
DecayInterval: time.Second,
|
||||
DecayToZero: 0.01,
|
||||
BehaviourPenaltyWeight: -1,
|
||||
BehaviourPenaltyDecay: 2,
|
||||
}).validate() == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
|
||||
// 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")
|
||||
}
|
||||
|
||||
if (&PeerScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TopicScoreCap: 1,
|
||||
AppSpecificScore: appScore,
|
||||
DecayInterval: time.Second,
|
||||
@ -294,7 +519,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,
|
||||
@ -318,6 +543,178 @@ func TestPeerScoreParamsValidation(t *testing.T) {
|
||||
t.Fatal("expected validation failure")
|
||||
}
|
||||
|
||||
if (&PeerScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
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")
|
||||
}
|
||||
|
||||
if (&PeerScoreParams{
|
||||
SkipAtomicValidation: skipAtomicValidation,
|
||||
TopicScoreCap: 1,
|
||||
AppSpecificScore: appScore,
|
||||
DecayInterval: time.Second,
|
||||
DecayToZero: 0.01,
|
||||
IPColocationFactorWeight: -1,
|
||||
IPColocationFactorThreshold: 1,
|
||||
Topics: map[string]*TopicScoreParams{
|
||||
"test": {
|
||||
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 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")
|
||||
}
|
||||
|
||||
if (&PeerScoreParams{
|
||||
TopicScoreCap: 1,
|
||||
AppSpecificScore: appScore,
|
||||
DecayInterval: time.Second,
|
||||
DecayToZero: 0.01,
|
||||
IPColocationFactorWeight: -1,
|
||||
IPColocationFactorThreshold: 1,
|
||||
Topics: map[string]*TopicScoreParams{
|
||||
"test": {
|
||||
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 TestPeerScoreParamsValidation_ValidParams_SkipAtomicValidation(t *testing.T) {
|
||||
appScore := func(peer.ID) float64 { return 0 }
|
||||
|
||||
// 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: 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,
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestScoreParameterDecay(t *testing.T) {
|
||||
@ -326,3 +723,17 @@ 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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user