github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/p2p/pubsub_filter.go (about) 1 package p2p 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/libp2p/go-libp2p-core/peer" 8 pubsub "github.com/libp2p/go-libp2p-pubsub" 9 pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb" 10 "github.com/prysmaticlabs/prysm/beacon-chain/p2p/encoder" 11 ) 12 13 var _ pubsub.SubscriptionFilter = (*Service)(nil) 14 15 const pubsubSubscriptionRequestLimit = 100 16 17 // CanSubscribe returns true if the topic is of interest and we could subscribe to it. 18 func (s *Service) CanSubscribe(topic string) bool { 19 if !s.isInitialized() { 20 return false 21 } 22 parts := strings.Split(topic, "/") 23 if len(parts) != 5 { 24 return false 25 } 26 // The topic must start with a slash, which means the first part will be empty. 27 if parts[0] != "" { 28 return false 29 } 30 if parts[1] != "eth2" { 31 return false 32 } 33 fd, err := s.forkDigest() 34 if err != nil { 35 log.WithError(err).Error("Could not determine fork digest") 36 return false 37 } 38 if parts[2] != fmt.Sprintf("%x", fd) { 39 return false 40 } 41 if parts[4] != encoder.ProtocolSuffixSSZSnappy { 42 return false 43 } 44 45 // Check the incoming topic matches any topic mapping. This includes a check for part[3]. 46 for gt := range GossipTopicMappings { 47 if _, err := scanfcheck(strings.Join(parts[0:4], "/"), gt); err == nil { 48 return true 49 } 50 } 51 52 return false 53 } 54 55 // FilterIncomingSubscriptions is invoked for all RPCs containing subscription notifications. 56 // This method returns only the topics of interest and may return an error if the subscription 57 // request contains too many topics. 58 func (s *Service) FilterIncomingSubscriptions(_ peer.ID, subs []*pubsubpb.RPC_SubOpts) ([]*pubsubpb.RPC_SubOpts, error) { 59 if len(subs) > pubsubSubscriptionRequestLimit { 60 return nil, pubsub.ErrTooManySubscriptions 61 } 62 63 return pubsub.FilterSubscriptions(subs, s.CanSubscribe), nil 64 } 65 66 // scanfcheck uses fmt.Sscanf to check that a given string matches expected format. This method 67 // returns the number of formatting substitutions matched and error if the string does not match 68 // the expected format. Note: this method only accepts integer compatible formatting substitutions 69 // such as %d or %x. 70 func scanfcheck(input, format string) (int, error) { 71 var t int 72 // Sscanf requires argument pointers with the appropriate type to load the value from the input. 73 // This method only checks that the input conforms to the format, the arguments are not used and 74 // therefore we can reuse the same integer pointer. 75 var cnt = strings.Count(format, "%") 76 var args []interface{} 77 for i := 0; i < cnt; i++ { 78 args = append(args, &t) 79 } 80 return fmt.Sscanf(input, format, args...) 81 }