github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/network/p2p/scoring/subscription_validator.go (about)

     1  package scoring
     2  
     3  import (
     4  	"github.com/libp2p/go-libp2p/core/peer"
     5  	"github.com/rs/zerolog"
     6  
     7  	"github.com/onflow/flow-go/model/flow"
     8  	"github.com/onflow/flow-go/module/component"
     9  	"github.com/onflow/flow-go/module/irrecoverable"
    10  	"github.com/onflow/flow-go/network/p2p"
    11  	p2plogging "github.com/onflow/flow-go/network/p2p/logging"
    12  	p2putils "github.com/onflow/flow-go/network/p2p/utils"
    13  )
    14  
    15  // SubscriptionValidator validates that a peer is subscribed to topics that it is allowed to subscribe to.
    16  // It is used to penalize peers that subscribe to topics that they are not allowed to subscribe to in GossipSub.
    17  type SubscriptionValidator struct {
    18  	component.Component
    19  	logger               zerolog.Logger
    20  	subscriptionProvider p2p.SubscriptionProvider
    21  }
    22  
    23  func NewSubscriptionValidator(logger zerolog.Logger, provider p2p.SubscriptionProvider) *SubscriptionValidator {
    24  	v := &SubscriptionValidator{
    25  		logger:               logger.With().Str("component", "subscription_validator").Logger(),
    26  		subscriptionProvider: provider,
    27  	}
    28  
    29  	v.Component = component.NewComponentManagerBuilder().
    30  		AddWorker(func(ctx irrecoverable.SignalerContext, ready component.ReadyFunc) {
    31  			logger.Debug().Msg("starting subscription validator")
    32  			v.subscriptionProvider.Start(ctx)
    33  			select {
    34  			case <-ctx.Done():
    35  				logger.Debug().Msg("subscription validator is stopping")
    36  			case <-v.subscriptionProvider.Ready():
    37  				logger.Debug().Msg("subscription validator started")
    38  				ready()
    39  				logger.Debug().Msg("subscription validator is ready")
    40  			}
    41  
    42  			<-ctx.Done()
    43  			logger.Debug().Msg("subscription validator is stopping")
    44  			<-v.subscriptionProvider.Done()
    45  			logger.Debug().Msg("subscription validator stopped")
    46  		}).Build()
    47  
    48  	return v
    49  }
    50  
    51  var _ p2p.SubscriptionValidator = (*SubscriptionValidator)(nil)
    52  
    53  // CheckSubscribedToAllowedTopics checks if a peer is subscribed to topics that it is allowed to subscribe to.
    54  // Args:
    55  //
    56  //		pid: the peer ID of the peer to check
    57  //	 role: the role of the peer to check
    58  //
    59  // Returns:
    60  // error: if the peer is subscribed to topics that it is not allowed to subscribe to, an InvalidSubscriptionError is returned.
    61  // The error is benign, i.e., it does not indicate an illegal state in the execution of the code. We expect this error
    62  // when there are malicious peers in the network. But such errors should not lead to a crash of the node.
    63  func (v *SubscriptionValidator) CheckSubscribedToAllowedTopics(pid peer.ID, role flow.Role) error {
    64  	lg := v.logger.With().Str("remote_peer_id", p2plogging.PeerId(pid)).Logger()
    65  
    66  	topics := v.subscriptionProvider.GetSubscribedTopics(pid)
    67  	lg.Trace().Strs("topics", topics).Msg("checking subscription for remote peer id")
    68  
    69  	for _, topic := range topics {
    70  		if !p2putils.AllowedSubscription(role, topic) {
    71  			return p2p.NewInvalidSubscriptionError(topic)
    72  		}
    73  	}
    74  
    75  	lg.Trace().Msg("subscription is valid")
    76  	return nil
    77  }