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  }