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