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  }