github.com/celestiaorg/celestia-node@v0.15.0-beta.1/nodebuilder/p2p/pubsub.go (about) 1 package p2p 2 3 import ( 4 "context" 5 "fmt" 6 "net" 7 "time" 8 9 pubsub "github.com/libp2p/go-libp2p-pubsub" 10 pubsub_pb "github.com/libp2p/go-libp2p-pubsub/pb" 11 "github.com/libp2p/go-libp2p-pubsub/timecache" 12 hst "github.com/libp2p/go-libp2p/core/host" 13 "github.com/libp2p/go-libp2p/core/peer" 14 "github.com/libp2p/go-libp2p/core/protocol" 15 "go.uber.org/fx" 16 "golang.org/x/crypto/blake2b" 17 18 "github.com/celestiaorg/go-fraud" 19 "github.com/celestiaorg/go-fraud/fraudserv" 20 headp2p "github.com/celestiaorg/go-header/p2p" 21 22 "github.com/celestiaorg/celestia-node/header" 23 ) 24 25 func init() { 26 // TODO(@Wondertan): Requires deeper analysis 27 // configure larger overlay parameters 28 // the default ones are pretty conservative 29 pubsub.GossipSubD = 8 30 pubsub.GossipSubDscore = 6 31 pubsub.GossipSubDout = 3 32 pubsub.GossipSubDlo = 6 33 pubsub.GossipSubDhi = 12 34 pubsub.GossipSubDlazy = 12 35 36 pubsub.GossipSubIWantFollowupTime = 5 * time.Second 37 pubsub.GossipSubHistoryLength = 10 // cache msgs longer 38 // MutualPeers will wait for 30secs before connecting 39 pubsub.GossipSubDirectConnectInitialDelay = 30 * time.Second 40 } 41 42 // pubSub provides a constructor for PubSub protocol with GossipSub routing. 43 func pubSub(cfg Config, params pubSubParams) (*pubsub.PubSub, error) { 44 fpeers, err := cfg.mutualPeers() 45 if err != nil { 46 return nil, err 47 } 48 49 isBootstrapper := isBootstrapper() 50 51 if isBootstrapper { 52 // Turn off the mesh in bootstrappers as per: 53 // 54 // 55 //https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md#recommendations-for-network-operators 56 pubsub.GossipSubD = 0 57 pubsub.GossipSubDscore = 0 58 pubsub.GossipSubDlo = 0 59 pubsub.GossipSubDhi = 0 60 pubsub.GossipSubDout = 0 61 pubsub.GossipSubDlazy = 64 62 pubsub.GossipSubGossipFactor = 0.25 63 pubsub.GossipSubPruneBackoff = 5 * time.Minute 64 } 65 66 // TODO(@Wondertan) Validate and improve default peer scoring params 67 // Сurrent parameters are based on: 68 // * https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md#peer-scoring 69 // * lotus 70 // * prysm 71 topicScores := topicScoreParams(params) 72 peerScores, err := peerScoreParams(params.Bootstrappers, cfg) 73 if err != nil { 74 return nil, err 75 } 76 77 peerScores.Topics = topicScores 78 scoreThresholds := peerScoreThresholds() 79 80 opts := []pubsub.Option{ 81 pubsub.WithSeenMessagesStrategy(timecache.Strategy_LastSeen), 82 pubsub.WithPeerScore(peerScores, scoreThresholds), 83 pubsub.WithPeerExchange(cfg.PeerExchange || isBootstrapper), 84 pubsub.WithDirectPeers(fpeers), 85 pubsub.WithMessageIdFn(hashMsgID), 86 // specifying sub protocol helps to avoid conflicts with 87 // floodsub(because gossipsub supports floodsub protocol by default). 88 pubsub.WithGossipSubProtocols([]protocol.ID{pubsub.GossipSubID_v11}, pubsub.GossipSubDefaultFeatures), 89 } 90 91 return pubsub.NewGossipSub( 92 params.Ctx, 93 params.Host, 94 opts..., 95 ) 96 } 97 98 func hashMsgID(m *pubsub_pb.Message) string { 99 hash := blake2b.Sum256(m.Data) 100 return string(hash[:]) 101 } 102 103 type pubSubParams struct { 104 fx.In 105 106 Ctx context.Context 107 Host hst.Host 108 Bootstrappers Bootstrappers 109 Network Network 110 Unmarshaler fraud.ProofUnmarshaler[*header.ExtendedHeader] 111 } 112 113 func topicScoreParams(params pubSubParams) map[string]*pubsub.TopicScoreParams { 114 mp := map[string]*pubsub.TopicScoreParams{ 115 headp2p.PubsubTopicID(params.Network.String()): &headp2p.GossibSubScore, 116 } 117 118 for _, pt := range params.Unmarshaler.List() { 119 mp[fraudserv.PubsubTopicID(pt.String(), params.Network.String())] = &fraudserv.GossibSubScore 120 } 121 122 return mp 123 } 124 125 func peerScoreParams(bootstrappers Bootstrappers, cfg Config) (*pubsub.PeerScoreParams, error) { 126 bootstrapperSet := map[peer.ID]struct{}{} 127 for _, b := range bootstrappers { 128 bootstrapperSet[b.ID] = struct{}{} 129 } 130 131 ipColocFactWl := make([]*net.IPNet, 0, len(cfg.IPColocationWhitelist)) 132 for _, strIP := range cfg.IPColocationWhitelist { 133 _, ipNet, err := net.ParseCIDR(strIP) 134 if err != nil { 135 return nil, fmt.Errorf("error while parsing whitelist collocation CIDR string: %w", err) 136 } 137 ipColocFactWl = append(ipColocFactWl, ipNet) 138 } 139 140 // See 141 // https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md#the-score-function 142 return &pubsub.PeerScoreParams{ 143 AppSpecificScore: func(p peer.ID) float64 { 144 // return a heavy positive score for bootstrappers so that we don't unilaterally prune 145 // them and accept PX from them 146 _, ok := bootstrapperSet[p] 147 if ok { 148 return 2500 149 } 150 151 // TODO(@Wondertan): 152 // Plug the application specific score to the node itself in order 153 // to provide feedback to the pubsub system based on observed behavior 154 return 0 155 }, 156 AppSpecificWeight: 1, 157 158 // This sets the IP colocation threshold to 5 peers before we apply penalties 159 // The aim is to protect the PubSub from naive bots collocated on the same machine/datacenter 160 IPColocationFactorThreshold: 10, 161 IPColocationFactorWeight: -100, 162 IPColocationFactorWhitelist: ipColocFactWl, 163 164 BehaviourPenaltyThreshold: 6, 165 BehaviourPenaltyWeight: -10, 166 BehaviourPenaltyDecay: pubsub.ScoreParameterDecay(time.Hour), 167 168 // Scores should not only grow and this defines a decay function equal for each peer 169 DecayInterval: pubsub.DefaultDecayInterval, 170 DecayToZero: pubsub.DefaultDecayToZero, 171 172 // this retains *non-positive* scores for 6 hours 173 RetainScore: 6 * time.Hour, 174 }, nil 175 } 176 177 func peerScoreThresholds() *pubsub.PeerScoreThresholds { 178 // 179 //https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md#overview-of-new-parameters 180 return &pubsub.PeerScoreThresholds{ 181 GossipThreshold: -1000, 182 PublishThreshold: -2000, 183 GraylistThreshold: -8000, 184 AcceptPXThreshold: 1000, 185 OpportunisticGraftThreshold: 5, 186 } 187 }