github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/p2p/discovery.go (about) 1 package p2p 2 3 import ( 4 "bytes" 5 "crypto/ecdsa" 6 "net" 7 "time" 8 9 "github.com/ethereum/go-ethereum/p2p/discover" 10 "github.com/ethereum/go-ethereum/p2p/enode" 11 "github.com/ethereum/go-ethereum/p2p/enr" 12 iaddr "github.com/ipfs/go-ipfs-addr" 13 "github.com/libp2p/go-libp2p-core/network" 14 "github.com/libp2p/go-libp2p-core/peer" 15 ma "github.com/multiformats/go-multiaddr" 16 "github.com/pkg/errors" 17 "github.com/prysmaticlabs/go-bitfield" 18 "github.com/prysmaticlabs/prysm/beacon-chain/cache" 19 ) 20 21 // Listener defines the discovery V5 network interface that is used 22 // to communicate with other peers. 23 type Listener interface { 24 Self() *enode.Node 25 Close() 26 Lookup(enode.ID) []*enode.Node 27 Resolve(*enode.Node) *enode.Node 28 RandomNodes() enode.Iterator 29 Ping(*enode.Node) error 30 RequestENR(*enode.Node) (*enode.Node, error) 31 LocalNode() *enode.LocalNode 32 } 33 34 // RefreshENR uses an epoch to refresh the enr entry for our node 35 // with the tracked committee ids for the epoch, allowing our node 36 // to be dynamically discoverable by others given our tracked committee ids. 37 func (s *Service) RefreshENR() { 38 // return early if discv5 isnt running 39 if s.dv5Listener == nil { 40 return 41 } 42 bitV := bitfield.NewBitvector64() 43 committees := cache.SubnetIDs.GetAllSubnets() 44 for _, idx := range committees { 45 bitV.SetBitAt(idx, true) 46 } 47 currentBitV, err := bitvector(s.dv5Listener.Self().Record()) 48 if err != nil { 49 log.Errorf("Could not retrieve bitfield: %v", err) 50 return 51 } 52 if bytes.Equal(bitV, currentBitV) { 53 // return early if bitfield hasn't changed 54 return 55 } 56 s.updateSubnetRecordWithMetadata(bitV) 57 // ping all peers to inform them of new metadata 58 s.pingPeers() 59 } 60 61 // listen for new nodes watches for new nodes in the network and adds them to the peerstore. 62 func (s *Service) listenForNewNodes() { 63 iterator := s.dv5Listener.RandomNodes() 64 iterator = enode.Filter(iterator, s.filterPeer) 65 defer iterator.Close() 66 for { 67 // Exit if service's context is canceled 68 if s.ctx.Err() != nil { 69 break 70 } 71 if s.isPeerAtLimit(false /* inbound */) { 72 // Pause the main loop for a period to stop looking 73 // for new peers. 74 log.Trace("Not looking for peers, at peer limit") 75 time.Sleep(pollingPeriod) 76 continue 77 } 78 exists := iterator.Next() 79 if !exists { 80 break 81 } 82 node := iterator.Node() 83 peerInfo, _, err := convertToAddrInfo(node) 84 if err != nil { 85 log.WithError(err).Error("Could not convert to peer info") 86 continue 87 } 88 // Make sure that peer is not dialed too often, for each connection attempt there's a backoff period. 89 s.Peers().RandomizeBackOff(peerInfo.ID) 90 go func(info *peer.AddrInfo) { 91 if err := s.connectWithPeer(s.ctx, *info); err != nil { 92 log.WithError(err).Tracef("Could not connect with peer %s", info.String()) 93 } 94 }(peerInfo) 95 } 96 } 97 98 func (s *Service) createListener( 99 ipAddr net.IP, 100 privKey *ecdsa.PrivateKey, 101 ) (*discover.UDPv5, error) { 102 // BindIP is used to specify the ip 103 // on which we will bind our listener on 104 // by default we will listen to all interfaces. 105 var bindIP net.IP 106 switch udpVersionFromIP(ipAddr) { 107 case "udp4": 108 bindIP = net.IPv4zero 109 case "udp6": 110 bindIP = net.IPv6zero 111 default: 112 return nil, errors.New("invalid ip provided") 113 } 114 115 // If local ip is specified then use that instead. 116 if s.cfg.LocalIP != "" { 117 ipAddr = net.ParseIP(s.cfg.LocalIP) 118 if ipAddr == nil { 119 return nil, errors.New("invalid local ip provided") 120 } 121 bindIP = ipAddr 122 } 123 udpAddr := &net.UDPAddr{ 124 IP: bindIP, 125 Port: int(s.cfg.UDPPort), 126 } 127 // Listen to all network interfaces 128 // for both ip protocols. 129 networkVersion := "udp" 130 conn, err := net.ListenUDP(networkVersion, udpAddr) 131 if err != nil { 132 return nil, errors.Wrap(err, "could not listen to UDP") 133 } 134 135 localNode, err := s.createLocalNode( 136 privKey, 137 ipAddr, 138 int(s.cfg.UDPPort), 139 int(s.cfg.TCPPort), 140 ) 141 if err != nil { 142 return nil, errors.Wrap(err, "could not create local node") 143 } 144 if s.cfg.HostAddress != "" { 145 hostIP := net.ParseIP(s.cfg.HostAddress) 146 if hostIP.To4() == nil && hostIP.To16() == nil { 147 log.Errorf("Invalid host address given: %s", hostIP.String()) 148 } else { 149 localNode.SetFallbackIP(hostIP) 150 localNode.SetStaticIP(hostIP) 151 } 152 } 153 if s.cfg.HostDNS != "" { 154 host := s.cfg.HostDNS 155 ips, err := net.LookupIP(host) 156 if err != nil { 157 return nil, errors.Wrap(err, "could not resolve host address") 158 } 159 if len(ips) > 0 { 160 // Use first IP returned from the 161 // resolver. 162 firstIP := ips[0] 163 localNode.SetFallbackIP(firstIP) 164 } 165 } 166 dv5Cfg := discover.Config{ 167 PrivateKey: privKey, 168 } 169 dv5Cfg.Bootnodes = []*enode.Node{} 170 for _, addr := range s.cfg.Discv5BootStrapAddr { 171 bootNode, err := enode.Parse(enode.ValidSchemes, addr) 172 if err != nil { 173 return nil, errors.Wrap(err, "could not bootstrap addr") 174 } 175 dv5Cfg.Bootnodes = append(dv5Cfg.Bootnodes, bootNode) 176 } 177 178 listener, err := discover.ListenV5(conn, localNode, dv5Cfg) 179 if err != nil { 180 return nil, errors.Wrap(err, "could not listen to discV5") 181 } 182 return listener, nil 183 } 184 185 func (s *Service) createLocalNode( 186 privKey *ecdsa.PrivateKey, 187 ipAddr net.IP, 188 udpPort, tcpPort int, 189 ) (*enode.LocalNode, error) { 190 db, err := enode.OpenDB("") 191 if err != nil { 192 return nil, errors.Wrap(err, "could not open node's peer database") 193 } 194 localNode := enode.NewLocalNode(db, privKey) 195 196 ipEntry := enr.IP(ipAddr) 197 udpEntry := enr.UDP(udpPort) 198 tcpEntry := enr.TCP(tcpPort) 199 localNode.Set(ipEntry) 200 localNode.Set(udpEntry) 201 localNode.Set(tcpEntry) 202 localNode.SetFallbackIP(ipAddr) 203 localNode.SetFallbackUDP(udpPort) 204 205 localNode, err = addForkEntry(localNode, s.genesisTime, s.genesisValidatorsRoot) 206 if err != nil { 207 return nil, errors.Wrap(err, "could not add eth2 fork version entry to enr") 208 } 209 return intializeAttSubnets(localNode), nil 210 } 211 212 func (s *Service) startDiscoveryV5( 213 addr net.IP, 214 privKey *ecdsa.PrivateKey, 215 ) (*discover.UDPv5, error) { 216 listener, err := s.createListener(addr, privKey) 217 if err != nil { 218 return nil, errors.Wrap(err, "could not create listener") 219 } 220 record := listener.Self() 221 log.WithField("ENR", record.String()).Info("Started discovery v5") 222 return listener, nil 223 } 224 225 // filterPeer validates each node that we retrieve from our dht. We 226 // try to ascertain that the peer can be a valid protocol peer. 227 // Validity Conditions: 228 // 1) The local node is still actively looking for peers to 229 // connect to. 230 // 2) Peer has a valid IP and TCP port set in their enr. 231 // 3) Peer hasn't been marked as 'bad' 232 // 4) Peer is not currently active or connected. 233 // 5) Peer is ready to receive incoming connections. 234 // 6) Peer's fork digest in their ENR matches that of 235 // our localnodes. 236 func (s *Service) filterPeer(node *enode.Node) bool { 237 // Ignore nil node entries passed in. 238 if node == nil { 239 return false 240 } 241 // ignore nodes with no ip address stored. 242 if node.IP() == nil { 243 return false 244 } 245 // do not dial nodes with their tcp ports not set 246 if err := node.Record().Load(enr.WithEntry("tcp", new(enr.TCP))); err != nil { 247 if !enr.IsNotFound(err) { 248 log.WithError(err).Debug("Could not retrieve tcp port") 249 } 250 return false 251 } 252 peerData, multiAddr, err := convertToAddrInfo(node) 253 if err != nil { 254 log.WithError(err).Debug("Could not convert to peer data") 255 return false 256 } 257 if s.peers.IsBad(peerData.ID) { 258 return false 259 } 260 if s.peers.IsActive(peerData.ID) { 261 return false 262 } 263 if s.host.Network().Connectedness(peerData.ID) == network.Connected { 264 return false 265 } 266 if !s.peers.IsReadyToDial(peerData.ID) { 267 return false 268 } 269 nodeENR := node.Record() 270 // Decide whether or not to connect to peer that does not 271 // match the proper fork ENR data with our local node. 272 if s.genesisValidatorsRoot != nil { 273 if err := s.compareForkENR(nodeENR); err != nil { 274 log.WithError(err).Trace("Fork ENR mismatches between peer and local node") 275 return false 276 } 277 } 278 // Add peer to peer handler. 279 s.peers.Add(nodeENR, peerData.ID, multiAddr, network.DirUnknown) 280 return true 281 } 282 283 // This checks our set max peers in our config, and 284 // determines whether our currently connected and 285 // active peers are above our set max peer limit. 286 func (s *Service) isPeerAtLimit(inbound bool) bool { 287 numOfConns := len(s.host.Network().Peers()) 288 maxPeers := int(s.cfg.MaxPeers) 289 // If we are measuring the limit for inbound peers 290 // we apply the high watermark buffer. 291 if inbound { 292 maxPeers += highWatermarkBuffer 293 maxInbound := s.peers.InboundLimit() + highWatermarkBuffer 294 currInbound := len(s.peers.InboundConnected()) 295 // Exit early if we are at the inbound limit. 296 if currInbound >= maxInbound { 297 return true 298 } 299 } 300 activePeers := len(s.Peers().Active()) 301 return activePeers >= maxPeers || numOfConns >= maxPeers 302 } 303 304 func parseBootStrapAddrs(addrs []string) (discv5Nodes []string) { 305 discv5Nodes, _ = parseGenericAddrs(addrs) 306 if len(discv5Nodes) == 0 { 307 log.Warn("No bootstrap addresses supplied") 308 } 309 return discv5Nodes 310 } 311 312 func parseGenericAddrs(addrs []string) (enodeString, multiAddrString []string) { 313 for _, addr := range addrs { 314 if addr == "" { 315 // Ignore empty entries 316 continue 317 } 318 _, err := enode.Parse(enode.ValidSchemes, addr) 319 if err == nil { 320 enodeString = append(enodeString, addr) 321 continue 322 } 323 _, err = multiAddrFromString(addr) 324 if err == nil { 325 multiAddrString = append(multiAddrString, addr) 326 continue 327 } 328 log.Errorf("Invalid address of %s provided: %v", addr, err) 329 } 330 return enodeString, multiAddrString 331 } 332 333 func convertToMultiAddr(nodes []*enode.Node) []ma.Multiaddr { 334 var multiAddrs []ma.Multiaddr 335 for _, node := range nodes { 336 // ignore nodes with no ip address stored 337 if node.IP() == nil { 338 continue 339 } 340 multiAddr, err := convertToSingleMultiAddr(node) 341 if err != nil { 342 log.WithError(err).Error("Could not convert to multiAddr") 343 continue 344 } 345 multiAddrs = append(multiAddrs, multiAddr) 346 } 347 return multiAddrs 348 } 349 350 func convertToAddrInfo(node *enode.Node) (*peer.AddrInfo, ma.Multiaddr, error) { 351 multiAddr, err := convertToSingleMultiAddr(node) 352 if err != nil { 353 return nil, nil, err 354 } 355 info, err := peer.AddrInfoFromP2pAddr(multiAddr) 356 if err != nil { 357 return nil, nil, err 358 } 359 return info, multiAddr, nil 360 } 361 362 func convertToSingleMultiAddr(node *enode.Node) (ma.Multiaddr, error) { 363 pubkey := node.Pubkey() 364 assertedKey := convertToInterfacePubkey(pubkey) 365 id, err := peer.IDFromPublicKey(assertedKey) 366 if err != nil { 367 return nil, errors.Wrap(err, "could not get peer id") 368 } 369 return multiAddressBuilderWithID(node.IP().String(), "tcp", uint(node.TCP()), id) 370 } 371 372 func convertToUdpMultiAddr(node *enode.Node) ([]ma.Multiaddr, error) { 373 pubkey := node.Pubkey() 374 assertedKey := convertToInterfacePubkey(pubkey) 375 id, err := peer.IDFromPublicKey(assertedKey) 376 if err != nil { 377 return nil, errors.Wrap(err, "could not get peer id") 378 } 379 380 var addresses []ma.Multiaddr 381 var ip4 enr.IPv4 382 var ip6 enr.IPv6 383 if node.Load(&ip4) == nil { 384 address, ipErr := multiAddressBuilderWithID(net.IP(ip4).String(), "udp", uint(node.UDP()), id) 385 if ipErr != nil { 386 return nil, errors.Wrap(ipErr, "could not build IPv4 address") 387 } 388 addresses = append(addresses, address) 389 } 390 if node.Load(&ip6) == nil { 391 address, ipErr := multiAddressBuilderWithID(net.IP(ip6).String(), "udp", uint(node.UDP()), id) 392 if ipErr != nil { 393 return nil, errors.Wrap(ipErr, "could not build IPv6 address") 394 } 395 addresses = append(addresses, address) 396 } 397 398 return addresses, nil 399 } 400 401 func peersFromStringAddrs(addrs []string) ([]ma.Multiaddr, error) { 402 var allAddrs []ma.Multiaddr 403 enodeString, multiAddrString := parseGenericAddrs(addrs) 404 for _, stringAddr := range multiAddrString { 405 addr, err := multiAddrFromString(stringAddr) 406 if err != nil { 407 return nil, errors.Wrapf(err, "Could not get multiaddr from string") 408 } 409 allAddrs = append(allAddrs, addr) 410 } 411 for _, stringAddr := range enodeString { 412 enodeAddr, err := enode.Parse(enode.ValidSchemes, stringAddr) 413 if err != nil { 414 return nil, errors.Wrapf(err, "Could not get enode from string") 415 } 416 addr, err := convertToSingleMultiAddr(enodeAddr) 417 if err != nil { 418 return nil, errors.Wrapf(err, "Could not get multiaddr") 419 } 420 allAddrs = append(allAddrs, addr) 421 } 422 return allAddrs, nil 423 } 424 425 func multiAddrFromString(address string) (ma.Multiaddr, error) { 426 addr, err := iaddr.ParseString(address) 427 if err != nil { 428 return nil, err 429 } 430 return addr.Multiaddr(), nil 431 } 432 433 func udpVersionFromIP(ipAddr net.IP) string { 434 if ipAddr.To4() != nil { 435 return "udp4" 436 } 437 return "udp6" 438 }