scoring

package
v0.31.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 12, 2023 License: AGPL-3.0 Imports: 17 Imported by: 0

README

GossipSub App Specific Score

This package provides a scoring mechanism for peers in a GossipSub network by computing their application-specific scores. Application-specific score is part of the GossipSub scoring mechanism, which is used to determine the behavior of peers in the network from the perspective of their behavior at the application level (i.e., Flow protocol). The score is determined based on a combination of penalties and rewards related to various factors, such as spamming misbehaviors, staking status, and valid subscriptions.

Key Components

  1. GossipSubAppSpecificScoreRegistry: This struct maintains the necessary information for determining a peer's score.
  2. AppSpecificScoreFunc: This function is exposed to GossipSub and calculates the application-specific score for a peer based on penalties and rewards.
  3. stakingScore: This function computes the staking score (reward/penalty) for a peer based on their identity and role.
  4. subscriptionPenalty: This function calculates the penalty for invalid subscriptions.
  5. OnInvalidControlMessageNotification: This method updates a peer's penalty when an invalid control message misbehavior is detected, e.g., spamming on a control message.

Score Calculation

The application-specific score for a peer is calculated as the sum of the following factors:

  1. Spam Penalty: A penalty applied when a peer conducts a spamming misbehavior (e.g., GRAFT, PRUNE, iHave, or iWant misbehaviors).
  2. Staking Penalty: A penalty applied for unknown peers with invalid Flow protocol identities. This ejects them from the GossipSub network.
  3. Subscription Penalty: A penalty applied when a peer subscribes to a topic they are not allowed to, based on their role in the Flow network.
  4. Staking Reward: A reward applied to well-behaved staked peers (excluding access nodes at the moment) only if they have no penalties from spamming or invalid subscriptions.

The score is updated every time a peer misbehaves, and the spam penalties decay over time using the default decay function, which applies a geometric decay to the peer's score.

Usage

To use the scoring mechanism, create a new GossipSubAppSpecificScoreRegistry with the desired configuration, and then obtain the AppSpecificScoreFunc to be passed to the GossipSub protocol.

Example:

config := &GossipSubAppSpecificScoreRegistryConfig{
	// ... configure the required components
}
registry := NewGossipSubAppSpecificScoreRegistry(config)
appSpecificScoreFunc := registry.AppSpecificScoreFunc()

// Use appSpecificScoreFunc as the score function for GossipSub

The scoring mechanism can be easily integrated with the GossipSub protocol to ensure that well-behaved peers are prioritized, and misbehaving peers are penalized. See the ScoreOption below for more details.

Note: This package was designed specifically for the Flow network and might require adjustments if used in other contexts.

Score Option

ScoreOption is a configuration object for the peer scoring system in the Flow network. It defines several scoring parameters and thresholds that determine the behavior of the network towards its peers. This includes rewarding well-behaving peers and penalizing misbehaving ones.

Note: ScoreOption is passed to the GossipSub as a configuration option at the time of initialization.

Usage

To use the ScoreOption, you need to create a ScoreOptionConfig with the desired settings and then call NewScoreOption with that configuration.

config := NewScoreOptionConfig(logger)
config.SetProvider(identityProvider)
config.SetCacheSize(1000)
config.SetCacheMetrics(metricsCollector)

// Optional: Set custom app-specific scoring function
config.SetAppSpecificScoreFunction(customAppSpecificScoreFunction)

scoreOption := NewScoreOption(config)
Scoring Parameters

ScoreOption provides a set of default scoring parameters and thresholds that can be configured through the ScoreOptionConfig. These parameters include:

  1. AppSpecificScoreWeight: The weight of the application-specific score in the overall peer score calculation at the GossipSub.
  2. GossipThreshold: The threshold below which a peer's score will result in ignoring gossips to and from that peer.
  3. PublishThreshold: The threshold below which a peer's score will result in not propagating self-published messages to that peer.
  4. GraylistThreshold: The threshold below which a peer's score will result in ignoring incoming RPCs from that peer.
  5. AcceptPXThreshold: The threshold above which a peer's score will result in accepting PX information with a prune from that peer. PX stands for "Peer Exchange" in the context of libp2p's gossipsub protocol. When a peer sends a PRUNE control message to another peer, it can include a list of other peers as PX information. The purpose of this is to help the pruned peer find new peers to replace the ones that have been pruned from its mesh. When a node receives a PRUNE message containing PX information, it can decide whether to connect to the suggested peers based on its own criteria. In this package, the DefaultAcceptPXThreshold is used to determine if the originating peer's penalty score is good enough to accept the PX information. If the originating peer's penalty score exceeds the threshold, the node will consider connecting to the suggested peers.
  6. OpportunisticGraftThreshold: The threshold below which the median peer score in the mesh may result in selecting more peers with a higher score for opportunistic grafting.

Customization

The scoring mechanism can be easily customized to suit the needs of the Flow network. This includes changing the scoring parameters, thresholds, and the scoring function itself. You can customize the scoring parameters and thresholds by using the various setter methods provided in the ScoreOptionConfig object. Additionally, you can provide a custom app-specific scoring function through the SetAppSpecificScoreFunction method.

Note: Usage of non-default app-specific scoring function is not recommended unless you are familiar with the scoring mechanism and the Flow network. It may result in routing attack vulnerabilities. It is always safer to use the default scoring function unless you know what you are doing.

Example of setting custom app-specific scoring function:

config.SetAppSpecificScoreFunction(customAppSpecificScoreFunction)

Peer Scoring System Integration

The peer scoring system is integrated with the GossipSub protocol through the ScoreOption configuration option. This option is passed to the GossipSub at the time of initialization. ScoreOption can be used to build scoring options for GossipSub protocol with the desired scoring parameters and thresholds.

flowPubSubOption := scoreOption.BuildFlowPubSubScoreOption()
gossipSubOption := scoreOption.BuildGossipSubScoreOption()

Documentation

Index

Constants

View Source
const (
	// PeerIdStatusUnknown indicates that the peer id is unknown.
	PeerIdStatusUnknown peerIdStatus = "unknown identity"
	// PeerIdStatusEjected indicates that the peer id belongs to an identity that has been ejected.
	PeerIdStatusEjected peerIdStatus = "ejected identity"
)
View Source
const (
	DefaultAppSpecificScoreWeight = 1
	MaxAppSpecificPenalty         = float64(-100)
	MinAppSpecificPenalty         = -1
	MaxAppSpecificReward          = float64(100)

	// DefaultStakedIdentityReward is the default reward for staking peers. It is applied to the peer's score when
	// the peer does not have any misbehavior record, e.g., invalid subscription, invalid message, etc.
	// The purpose is to reward the staking peers for their contribution to the network and prioritize them in neighbor selection.
	DefaultStakedIdentityReward = MaxAppSpecificReward

	// DefaultUnknownIdentityPenalty is the default penalty for unknown identity. It is applied to the peer's score when
	// the peer is not in the identity list.
	DefaultUnknownIdentityPenalty = MaxAppSpecificPenalty

	// DefaultInvalidSubscriptionPenalty is the default penalty for invalid subscription. It is applied to the peer's score when
	// the peer subscribes to a topic that it is not authorized to subscribe to.
	DefaultInvalidSubscriptionPenalty = MaxAppSpecificPenalty

	// DefaultGossipThreshold when a peer's penalty drops below this threshold,
	// no gossip is emitted towards that peer and gossip from that peer is ignored.
	//
	// Validation Constraint: GossipThreshold >= PublishThreshold && GossipThreshold < 0
	//
	// How we use it:
	// As current max penalty is -100, we set the threshold to -99 so that all gossips
	// to and from peers with penalty -100 are ignored.
	DefaultGossipThreshold = -99

	// DefaultPublishThreshold when a peer's penalty drops below this threshold,
	// self-published messages are not propagated towards this peer.
	//
	// Validation Constraint:
	// PublishThreshold >= GraylistThreshold && PublishThreshold <= GossipThreshold && PublishThreshold < 0.
	//
	// How we use it:
	// As current max penalty is -100, we set the threshold to -99 so that all penalized peers are deprived of
	// receiving any published messages.
	DefaultPublishThreshold = -99

	// DefaultGraylistThreshold when a peer's penalty drops below this threshold, the peer is graylisted, i.e.,
	// incoming RPCs from the peer are ignored.
	//
	// Validation Constraint:
	// GraylistThreshold =< PublishThreshold && GraylistThreshold =< GossipThreshold && GraylistThreshold < 0
	//
	// How we use it:
	// As current max penalty is -100, we set the threshold to -99 so that all penalized peers are graylisted.
	DefaultGraylistThreshold = -99

	// DefaultAcceptPXThreshold when a peer sends us PX information with a prune, we only accept it and connect to the supplied
	// peers if the originating peer's penalty exceeds this threshold.
	//
	// Validation Constraint: must be non-negative.
	//
	// How we use it:
	// As current max reward is 100, we set the threshold to 99 so that we only receive supplied peers from
	// well-behaved peers.
	DefaultAcceptPXThreshold = 99

	// DefaultOpportunisticGraftThreshold when the median peer penalty in the mesh drops below this value,
	// the peer may select more peers with penalty above the median to opportunistically graft on the mesh.
	//
	// Validation Constraint: must be non-negative.
	//
	// How we use it:
	// We set it to the MaxAppSpecificReward + 1 so that we only opportunistically graft peers that are not access nodes (i.e., with MinAppSpecificPenalty),
	// or penalized peers (i.e., with MaxAppSpecificPenalty).
	DefaultOpportunisticGraftThreshold = MaxAppSpecificReward + 1

	// MaxDebugLogs sets the max number of debug/trace log events per second. Logs emitted above
	// this threshold are dropped.
	MaxDebugLogs = 50
)

Variables

This section is empty.

Functions

func DefaultDecayFunction added in v0.31.0

func DefaultDecayFunction() netcache.PreprocessorFunc

DefaultDecayFunction is the default decay function that is used to decay the application specific penalty of a peer. It is used if no decay function is provided in the configuration. It decays the application specific penalty of a peer if it is negative.

func GeometricDecay added in v0.31.0

func GeometricDecay(score float64, decay float64, lastUpdated time.Time) (float64, error)

GeometricDecay returns the decayed score based on the decay factor and the time since the last update.

The decayed score is calculated as follows: penalty = score * decay^t where t is the time since the last update in seconds. Args: - score: the score to be decayed. - decay: the decay factor, it should be in the range of (0, 1]. - lastUpdated: the time when the penalty was last updated. Returns:

  • the decayed score.
  • an error if the decay factor is not in the range of (0, 1] or the decayed score is NaN. it also returns an error if the last updated time is in the future (to avoid overflow). The error is considered irrecoverable (unless the parameters can be adjusted).

func HasValidFlowIdentity added in v0.28.1

func HasValidFlowIdentity(idProvider module.IdentityProvider, pid peer.ID) (*flow.Identity, error)

HasValidFlowIdentity checks if the peer has a valid Flow identity.

func InitAppScoreRecordState added in v0.31.0

func InitAppScoreRecordState() p2p.GossipSubSpamRecord

InitAppScoreRecordState initializes the gossipsub spam record state for a peer. Returns:

  • a gossipsub spam record with the default decay value and 0 penalty.

func IsInvalidPeerIDError

func IsInvalidPeerIDError(this error) bool

func NewInvalidPeerIDError

func NewInvalidPeerIDError(peerId peer.ID, status peerIdStatus) error

Types

type GossipSubAppSpecificScoreRegistry added in v0.31.0

type GossipSubAppSpecificScoreRegistry struct {
	// contains filtered or unexported fields
}

GossipSubAppSpecificScoreRegistry is the registry for the application specific score of peers in the GossipSub protocol. The application specific score is part of the overall score of a peer, and is used to determine the peer's score based on its behavior related to the application (Flow protocol). This registry holds the view of the local peer of the application specific score of other peers in the network based on what it has observed from the network. Similar to the GossipSub score, the application specific score is meant to be private to the local peer, and is not shared with other peers in the network.

func NewGossipSubAppSpecificScoreRegistry added in v0.31.0

func NewGossipSubAppSpecificScoreRegistry(config *GossipSubAppSpecificScoreRegistryConfig) *GossipSubAppSpecificScoreRegistry

NewGossipSubAppSpecificScoreRegistry returns a new GossipSubAppSpecificScoreRegistry. Args:

config: the configuration for the registry.

Returns:

a new GossipSubAppSpecificScoreRegistry.

func (*GossipSubAppSpecificScoreRegistry) AppSpecificScoreFunc added in v0.31.0

func (r *GossipSubAppSpecificScoreRegistry) AppSpecificScoreFunc() func(peer.ID) float64

AppSpecificScoreFunc returns the application specific penalty function that is called by the GossipSub protocol to determine the application specific penalty of a peer.

func (*GossipSubAppSpecificScoreRegistry) OnInvalidControlMessageNotification added in v0.31.0

func (r *GossipSubAppSpecificScoreRegistry) OnInvalidControlMessageNotification(notification *p2p.InvCtrlMsgNotif)

OnInvalidControlMessageNotification is called when a new invalid control message notification is distributed. Any error on consuming event must handle internally. The implementation must be concurrency safe, but can be blocking.

type GossipSubAppSpecificScoreRegistryConfig added in v0.31.0

type GossipSubAppSpecificScoreRegistryConfig struct {
	Logger zerolog.Logger

	// Validator is the subscription validator used to validate the subscriptions of peers, and determine if a peer is
	// authorized to subscribe to a topic.
	Validator p2p.SubscriptionValidator

	// Penalty encapsulates the penalty unit for each control message type misbehaviour.
	Penalty GossipSubCtrlMsgPenaltyValue

	// IdProvider is the identity provider used to translate peer ids at the networking layer to Flow identifiers (if
	// an authorized peer is found).
	IdProvider module.IdentityProvider

	// Init is a factory function that returns a new GossipSubSpamRecord. It is used to initialize the spam record of
	// a peer when the peer is first observed by the local peer.
	Init func() p2p.GossipSubSpamRecord

	// CacheFactory is a factory function that returns a new GossipSubSpamRecordCache. It is used to initialize the spamScoreCache.
	// The cache is used to store the application specific penalty of peers.
	CacheFactory func() p2p.GossipSubSpamRecordCache
}

GossipSubAppSpecificScoreRegistryConfig is the configuration for the GossipSubAppSpecificScoreRegistry. The configuration is used to initialize the registry.

type GossipSubCtrlMsgPenaltyValue added in v0.31.0

type GossipSubCtrlMsgPenaltyValue struct {
	Graft float64 // penalty value for an individual graft message misbehaviour.
	Prune float64 // penalty value for an individual prune message misbehaviour.
	IHave float64 // penalty value for an individual iHave message misbehaviour.
	IWant float64 // penalty value for an individual iWant message misbehaviour.
}

GossipSubCtrlMsgPenaltyValue is the penalty value for each control message type.

func DefaultGossipSubCtrlMsgPenaltyValue added in v0.31.0

func DefaultGossipSubCtrlMsgPenaltyValue() GossipSubCtrlMsgPenaltyValue

DefaultGossipSubCtrlMsgPenaltyValue returns the default penalty value for each control message type.

type InvalidPeerIDError

type InvalidPeerIDError struct {
	// contains filtered or unexported fields
}

InvalidPeerIDError indicates that a peer has an invalid peer id, i.e., it is not held by an authorized Flow identity.

func (InvalidPeerIDError) Error

func (e InvalidPeerIDError) Error() string

type ScoreOption

type ScoreOption struct {
	// contains filtered or unexported fields
}

ScoreOption is a functional option for configuring the peer scoring system.

func NewScoreOption

func NewScoreOption(cfg *ScoreOptionConfig) *ScoreOption

NewScoreOption creates a new penalty option with the given configuration.

func (*ScoreOption) BuildFlowPubSubScoreOption

func (s *ScoreOption) BuildFlowPubSubScoreOption() pubsub.Option

func (*ScoreOption) BuildGossipSubScoreOption added in v0.28.1

func (s *ScoreOption) BuildGossipSubScoreOption() pubsub.Option

func (*ScoreOption) SetSubscriptionProvider

func (s *ScoreOption) SetSubscriptionProvider(provider *SubscriptionProvider) error

type ScoreOptionConfig added in v0.31.0

type ScoreOptionConfig struct {
	// contains filtered or unexported fields
}

func NewScoreOptionConfig added in v0.31.0

func NewScoreOptionConfig(logger zerolog.Logger) *ScoreOptionConfig

func (*ScoreOptionConfig) SetAppSpecificScoreFunction added in v0.31.0

func (c *ScoreOptionConfig) SetAppSpecificScoreFunction(appSpecificScoreFunction func(peer.ID) float64)

SetAppSpecificScoreFunction sets the app specific penalty function for the penalty option. It is used to calculate the app specific penalty of a peer. If the app specific penalty function is not set, the default one is used. Note that it is always safer to use the default one, unless you know what you are doing. It is safe to call this method multiple times, the last call will be used.

func (*ScoreOptionConfig) SetCacheMetrics added in v0.31.0

func (c *ScoreOptionConfig) SetCacheMetrics(metrics module.HeroCacheMetrics)

SetCacheMetrics sets the cache metrics collector for the penalty option. It is used to collect metrics for the app specific penalty cache. If the cache metrics collector is not set, a no-op collector will be used. It is safe to call this method multiple times, the last call will be used.

func (*ScoreOptionConfig) SetCacheSize added in v0.31.0

func (c *ScoreOptionConfig) SetCacheSize(size uint32)

SetCacheSize sets the size of the cache used to store the app specific penalty of peers. If the cache size is not set, the default value will be used. It is safe to call this method multiple times, the last call will be used.

func (*ScoreOptionConfig) SetProvider added in v0.31.0

func (c *ScoreOptionConfig) SetProvider(provider module.IdentityProvider)

SetProvider sets the identity provider for the penalty option. It is used to retrieve the identity of a peer when calculating the app specific penalty. If the provider is not set, the penalty registry will crash. This is a required field. It is safe to call this method multiple times, the last call will be used.

func (*ScoreOptionConfig) SetRegisterNotificationConsumerFunc added in v0.31.0

func (c *ScoreOptionConfig) SetRegisterNotificationConsumerFunc(f func(p2p.GossipSubInvCtrlMsgNotifConsumer))

SetRegisterNotificationConsumerFunc sets the function to register the notification consumer for the penalty option. ScoreOption uses this function to register the notification consumer for the pubsub system so that it can receive notifications of invalid control messages.

func (*ScoreOptionConfig) SetTopicScoreParams added in v0.31.0

func (c *ScoreOptionConfig) SetTopicScoreParams(topic channels.Topic, topicScoreParams *pubsub.TopicScoreParams)

SetTopicScoreParams adds the topic penalty parameters to the peer penalty parameters. It is used to configure the topic penalty parameters for the pubsub system. If there is already a topic penalty parameter for the given topic, the last call will be used.

type SubscriptionProvider

type SubscriptionProvider struct {
	// contains filtered or unexported fields
}

SubscriptionProvider provides a list of topics a peer is subscribed to.

func NewSubscriptionProvider

func NewSubscriptionProvider(logger zerolog.Logger, tp p2p.TopicProvider) *SubscriptionProvider

func (*SubscriptionProvider) GetSubscribedTopics

func (s *SubscriptionProvider) GetSubscribedTopics(pid peer.ID) []string

GetSubscribedTopics returns all the subscriptions of a peer within the pubsub network. Note that the current node can only see peer subscriptions to topics that it has also subscribed to e.g., if current node has subscribed to topics A and B, and peer1 has subscribed to topics A, B, and C, then GetSubscribedTopics(peer1) will return A and B. Since this node has not subscribed to topic C, it will not be able to query for other peers subscribed to topic C.

type SubscriptionValidator

type SubscriptionValidator struct {
	// contains filtered or unexported fields
}

SubscriptionValidator validates that a peer is subscribed to topics that it is allowed to subscribe to. It is used to penalize peers that subscribe to topics that they are not allowed to subscribe to in GossipSub.

func NewSubscriptionValidator

func NewSubscriptionValidator() *SubscriptionValidator

func (*SubscriptionValidator) CheckSubscribedToAllowedTopics

func (v *SubscriptionValidator) CheckSubscribedToAllowedTopics(pid peer.ID, role flow.Role) error

CheckSubscribedToAllowedTopics checks if a peer is subscribed to topics that it is allowed to subscribe to. Args:

	pid: the peer ID of the peer to check
 role: the role of the peer to check

Returns: error: if the peer is subscribed to topics that it is not allowed to subscribe to, an InvalidSubscriptionError is returned. The error is benign, i.e., it does not indicate an illegal state in the execution of the code. We expect this error when there are malicious peers in the network. But such errors should not lead to a crash of the node.

func (*SubscriptionValidator) RegisterSubscriptionProvider

func (v *SubscriptionValidator) RegisterSubscriptionProvider(provider p2p.SubscriptionProvider) error

RegisterSubscriptionProvider registers the subscription provider with the subscription validator. This follows a dependency injection pattern. Args:

provider: the subscription provider

Returns:

		error: if the subscription provider is nil, an error is returned. The error is irrecoverable, i.e.,
     it indicates an illegal state in the execution of the code. We expect this error only when there is a bug in the code.
     Such errors should lead to a crash of the node.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL