github.com/core-coin/go-core/v2@v2.1.9/p2p/discv5/node.go (about)

     1  // Copyright 2015 by the Authors
     2  // This file is part of the go-core library.
     3  //
     4  // The go-core library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-core library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-core library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package discv5
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/hex"
    22  	"errors"
    23  	"fmt"
    24  	"math/rand"
    25  	"net"
    26  	"net/url"
    27  	"regexp"
    28  	"strconv"
    29  	"strings"
    30  
    31  	"github.com/core-coin/go-core/v2/common"
    32  	"github.com/core-coin/go-core/v2/crypto"
    33  	"github.com/core-coin/go-core/v2/log"
    34  )
    35  
    36  // Node represents a host on the network.
    37  // The public fields of Node may not be modified.
    38  type Node struct {
    39  	IP       net.IP // len 4 for IPv4 or 16 for IPv6
    40  	UDP, TCP uint16 // port numbers
    41  	ID       NodeID // the node's public key
    42  
    43  	// Network-related fields are contained in nodeNetGuts.
    44  	// These fields are not supposed to be used off the
    45  	// Network.loop goroutine.
    46  	nodeNetGuts
    47  }
    48  
    49  // NewNode creates a new node. It is mostly meant to be used for
    50  // testing purposes.
    51  func NewNode(id NodeID, ip net.IP, udpPort, tcpPort uint16) *Node {
    52  	if ipv4 := ip.To4(); ipv4 != nil {
    53  		ip = ipv4
    54  	}
    55  	return &Node{
    56  		IP:          ip,
    57  		UDP:         udpPort,
    58  		TCP:         tcpPort,
    59  		ID:          id,
    60  		nodeNetGuts: nodeNetGuts{sha: crypto.SHA3Hash(id[:])},
    61  	}
    62  }
    63  
    64  func (n *Node) addr() *net.UDPAddr {
    65  	return &net.UDPAddr{IP: n.IP, Port: int(n.UDP)}
    66  }
    67  
    68  // Incomplete returns true for nodes with no IP address.
    69  func (n *Node) Incomplete() bool {
    70  	return n.IP == nil
    71  }
    72  
    73  // checks whether n is a valid complete node.
    74  func (n *Node) validateComplete() error {
    75  	if n.Incomplete() {
    76  		return errors.New("incomplete node")
    77  	}
    78  	if n.UDP == 0 {
    79  		return errors.New("missing UDP port")
    80  	}
    81  	if n.TCP == 0 {
    82  		return errors.New("missing TCP port")
    83  	}
    84  	if n.IP.IsMulticast() || n.IP.IsUnspecified() {
    85  		return errors.New("invalid IP (multicast/unspecified)")
    86  	}
    87  	_, err := n.ID.Pubkey() // validate the key (on curve, etc.)
    88  	return err
    89  }
    90  
    91  // The string representation of a Node is a URL.
    92  // Please see ParseNode for a description of the format.
    93  func (n *Node) String() string {
    94  	u := url.URL{Scheme: "enode"}
    95  	if n.Incomplete() {
    96  		u.Host = fmt.Sprintf("%x", n.ID[:])
    97  	} else {
    98  		addr := net.TCPAddr{IP: n.IP, Port: int(n.TCP)}
    99  		u.User = url.User(fmt.Sprintf("%x", n.ID[:]))
   100  		u.Host = addr.String()
   101  		if n.UDP != n.TCP {
   102  			u.RawQuery = "discport=" + strconv.Itoa(int(n.UDP))
   103  		}
   104  	}
   105  	return u.String()
   106  }
   107  
   108  var incompleteNodeURL = regexp.MustCompile("(?i)^(?:enode://)?([0-9a-f]+)$")
   109  
   110  // ParseNode parses a node designator.
   111  //
   112  // There are two basic forms of node designators
   113  //   - incomplete nodes, which only have the public key (node ID)
   114  //   - complete nodes, which contain the public key and IP/Port information
   115  //
   116  // For incomplete nodes, the designator must look like one of these
   117  //
   118  //	enode://<hex node id>
   119  //	<hex node id>
   120  //
   121  // For complete nodes, the node ID is encoded in the username portion
   122  // of the URL, separated from the host by an @ sign. The hostname can
   123  // only be given as an IP address, DNS domain names are not allowed.
   124  // The port in the host name section is the TCP listening port. If the
   125  // TCP and UDP (discovery) ports differ, the UDP port is specified as
   126  // query parameter "discport".
   127  //
   128  // In the following example, the node URL describes
   129  // a node with IP address 10.3.58.6, TCP listening port 30300
   130  // and UDP discovery port 30330.
   131  //
   132  //	enode://<hex node id>@10.3.58.6:30300?discport=30330
   133  func ParseNode(rawurl string) (*Node, error) {
   134  	if m := incompleteNodeURL.FindStringSubmatch(rawurl); m != nil {
   135  		id, err := HexID(m[1])
   136  		if err != nil {
   137  			return nil, fmt.Errorf("invalid node ID (%v)", err)
   138  		}
   139  		return NewNode(id, nil, 0, 0), nil
   140  	}
   141  	return parseComplete(rawurl)
   142  }
   143  
   144  func parseComplete(rawurl string) (*Node, error) {
   145  	var (
   146  		id               NodeID
   147  		ip               net.IP
   148  		tcpPort, udpPort uint64
   149  	)
   150  	u, err := url.Parse(rawurl)
   151  	if err != nil {
   152  		return nil, err
   153  	}
   154  	if u.Scheme != "enode" {
   155  		return nil, errors.New("invalid URL scheme, want \"enode\"")
   156  	}
   157  	// Parse the Node ID from the user portion.
   158  	if u.User == nil {
   159  		return nil, errors.New("does not contain node ID")
   160  	}
   161  	if id, err = HexID(u.User.String()); err != nil {
   162  		return nil, fmt.Errorf("invalid node ID (%v)", err)
   163  	}
   164  	// Parse the IP address.
   165  	host, port, err := net.SplitHostPort(u.Host)
   166  	if err != nil {
   167  		return nil, fmt.Errorf("invalid host: %v", err)
   168  	}
   169  	if ip = net.ParseIP(host); ip == nil {
   170  		return nil, errors.New("invalid IP address")
   171  	}
   172  	// Ensure the IP is 4 bytes long for IPv4 addresses.
   173  	if ipv4 := ip.To4(); ipv4 != nil {
   174  		ip = ipv4
   175  	}
   176  	// Parse the port numbers.
   177  	if tcpPort, err = strconv.ParseUint(port, 10, 16); err != nil {
   178  		return nil, errors.New("invalid port")
   179  	}
   180  	udpPort = tcpPort
   181  	qv := u.Query()
   182  	if qv.Get("discport") != "" {
   183  		udpPort, err = strconv.ParseUint(qv.Get("discport"), 10, 16)
   184  		if err != nil {
   185  			return nil, errors.New("invalid discport in query")
   186  		}
   187  	}
   188  	return NewNode(id, ip, uint16(udpPort), uint16(tcpPort)), nil
   189  }
   190  
   191  // MustParseNode parses a node URL. It panics if the URL is not valid.
   192  func MustParseNode(rawurl string) *Node {
   193  	n, err := ParseNode(rawurl)
   194  	if err != nil {
   195  		log.Error("invalid node URL: " + err.Error())
   196  	}
   197  	return n
   198  }
   199  
   200  // MarshalText implements encoding.TextMarshaler.
   201  func (n *Node) MarshalText() ([]byte, error) {
   202  	return []byte(n.String()), nil
   203  }
   204  
   205  // UnmarshalText implements encoding.TextUnmarshaler.
   206  func (n *Node) UnmarshalText(text []byte) error {
   207  	dec, err := ParseNode(string(text))
   208  	if err == nil {
   209  		*n = *dec
   210  	}
   211  	return err
   212  }
   213  
   214  // type nodeQueue []*Node
   215  //
   216  // // pushNew adds n to the end if it is not present.
   217  // func (nl *nodeList) appendNew(n *Node) {
   218  // 	for _, entry := range n {
   219  // 		if entry == n {
   220  // 			return
   221  // 		}
   222  // 	}
   223  // 	*nq = append(*nq, n)
   224  // }
   225  //
   226  // // popRandom removes a random node. Nodes closer to
   227  // // to the head of the beginning of the have a slightly higher probability.
   228  // func (nl *nodeList) popRandom() *Node {
   229  // 	ix := rand.Intn(len(*nq))
   230  // 	//TODO: probability as mentioned above.
   231  // 	nl.removeIndex(ix)
   232  // }
   233  //
   234  // func (nl *nodeList) removeIndex(i int) *Node {
   235  // 	slice = *nl
   236  // 	if len(*slice) <= i {
   237  // 		return nil
   238  // 	}
   239  // 	*nl = append(slice[:i], slice[i+1:]...)
   240  // }
   241  
   242  const nodeIDBits = 456
   243  
   244  // NodeID is a unique identifier for each node.
   245  // The node identifier is a marshaled elliptic curve public key.
   246  type NodeID [nodeIDBits / 8]byte
   247  
   248  // NodeID prints as a long hexadecimal number.
   249  func (n NodeID) String() string {
   250  	return fmt.Sprintf("%x", n[:])
   251  }
   252  
   253  // The Go syntax representation of a NodeID is a call to HexID.
   254  func (n NodeID) GoString() string {
   255  	return fmt.Sprintf("discover.HexID(\"%x\")", n[:])
   256  }
   257  
   258  // TerminalString returns a shortened hex string for terminal logging.
   259  func (n NodeID) TerminalString() string {
   260  	return hex.EncodeToString(n[:8])
   261  }
   262  
   263  // HexID converts a hex string to a NodeID.
   264  // The string may be prefixed with 0x.
   265  func HexID(in string) (NodeID, error) {
   266  	var id NodeID
   267  	b, err := hex.DecodeString(strings.TrimPrefix(in, "0x"))
   268  	if err != nil {
   269  		return id, err
   270  	} else if len(b) != len(id) {
   271  		return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2)
   272  	}
   273  	copy(id[:], b)
   274  	return id, nil
   275  }
   276  
   277  // MustHexID converts a hex string to a NodeID.
   278  // It panics if the string is not a valid NodeID.
   279  func MustHexID(in string) NodeID {
   280  	id, err := HexID(in)
   281  	if err != nil {
   282  		panic(err)
   283  	}
   284  	return id
   285  }
   286  
   287  // PubkeyID returns a marshaled representation of the given public key.
   288  func PubkeyID(pub *crypto.PublicKey) NodeID {
   289  	var id NodeID
   290  	if len(pub) != len(id) {
   291  		panic("id len != pub len")
   292  	}
   293  	copy(id[:], pub[:])
   294  	return id
   295  }
   296  
   297  // Pubkey returns the public key represented by the node ID.
   298  // It returns an error if the ID is not a point on the curve.
   299  func (n NodeID) Pubkey() (*crypto.PublicKey, error) {
   300  	if bytes.Equal(n[:], (&crypto.PublicKey{})[:]) {
   301  		return nil, errors.New("invalid node id")
   302  	}
   303  	return crypto.UnmarshalPubKey(n[:])
   304  }
   305  
   306  // recoverNodeID computes the public key used to sign the
   307  // given hash from the signature.
   308  func recoverNodeID(hash, sig []byte) (id NodeID, err error) {
   309  	pubkey, err := crypto.Ecrecover(hash, sig)
   310  	if err != nil {
   311  		return id, err
   312  	}
   313  	if len(pubkey) != len(id) {
   314  		return id, fmt.Errorf("recovered pubkey has %d bits, want %d bits", len(pubkey)*8, (len(id))*8)
   315  	}
   316  	for i := range id {
   317  		id[i] = pubkey[i]
   318  	}
   319  	return id, nil
   320  }
   321  
   322  // distcmp compares the distances a->target and b->target.
   323  // Returns -1 if a is closer to target, 1 if b is closer to target
   324  // and 0 if they are equal.
   325  func distcmp(target, a, b common.Hash) int {
   326  	for i := range target {
   327  		da := a[i] ^ target[i]
   328  		db := b[i] ^ target[i]
   329  		if da > db {
   330  			return 1
   331  		} else if da < db {
   332  			return -1
   333  		}
   334  	}
   335  	return 0
   336  }
   337  
   338  // table of leading zero counts for bytes [0..255]
   339  var lzcount = [256]int{
   340  	8, 7, 6, 6, 5, 5, 5, 5,
   341  	4, 4, 4, 4, 4, 4, 4, 4,
   342  	3, 3, 3, 3, 3, 3, 3, 3,
   343  	3, 3, 3, 3, 3, 3, 3, 3,
   344  	2, 2, 2, 2, 2, 2, 2, 2,
   345  	2, 2, 2, 2, 2, 2, 2, 2,
   346  	2, 2, 2, 2, 2, 2, 2, 2,
   347  	2, 2, 2, 2, 2, 2, 2, 2,
   348  	1, 1, 1, 1, 1, 1, 1, 1,
   349  	1, 1, 1, 1, 1, 1, 1, 1,
   350  	1, 1, 1, 1, 1, 1, 1, 1,
   351  	1, 1, 1, 1, 1, 1, 1, 1,
   352  	1, 1, 1, 1, 1, 1, 1, 1,
   353  	1, 1, 1, 1, 1, 1, 1, 1,
   354  	1, 1, 1, 1, 1, 1, 1, 1,
   355  	1, 1, 1, 1, 1, 1, 1, 1,
   356  	0, 0, 0, 0, 0, 0, 0, 0,
   357  	0, 0, 0, 0, 0, 0, 0, 0,
   358  	0, 0, 0, 0, 0, 0, 0, 0,
   359  	0, 0, 0, 0, 0, 0, 0, 0,
   360  	0, 0, 0, 0, 0, 0, 0, 0,
   361  	0, 0, 0, 0, 0, 0, 0, 0,
   362  	0, 0, 0, 0, 0, 0, 0, 0,
   363  	0, 0, 0, 0, 0, 0, 0, 0,
   364  	0, 0, 0, 0, 0, 0, 0, 0,
   365  	0, 0, 0, 0, 0, 0, 0, 0,
   366  	0, 0, 0, 0, 0, 0, 0, 0,
   367  	0, 0, 0, 0, 0, 0, 0, 0,
   368  	0, 0, 0, 0, 0, 0, 0, 0,
   369  	0, 0, 0, 0, 0, 0, 0, 0,
   370  	0, 0, 0, 0, 0, 0, 0, 0,
   371  	0, 0, 0, 0, 0, 0, 0, 0,
   372  }
   373  
   374  // logdist returns the logarithmic distance between a and b, log2(a ^ b).
   375  func logdist(a, b common.Hash) int {
   376  	lz := 0
   377  	for i := range a {
   378  		x := a[i] ^ b[i]
   379  		if x == 0 {
   380  			lz += 8
   381  		} else {
   382  			lz += lzcount[x]
   383  			break
   384  		}
   385  	}
   386  	return len(a)*8 - lz
   387  }
   388  
   389  // hashAtDistance returns a random hash such that logdist(a, b) == n
   390  func hashAtDistance(a common.Hash, n int) (b common.Hash) {
   391  	if n == 0 {
   392  		return a
   393  	}
   394  	// flip bit at position n, fill the rest with random bits
   395  	b = a
   396  	pos := len(a) - n/8 - 1
   397  	bit := byte(0x01) << (byte(n%8) - 1)
   398  	if bit == 0 {
   399  		pos++
   400  		bit = 0x80
   401  	}
   402  	b[pos] = a[pos]&^bit | ^a[pos]&bit // TODO: randomize end bits
   403  	for i := pos + 1; i < len(a); i++ {
   404  		b[i] = byte(rand.Intn(255))
   405  	}
   406  	return b
   407  }