github.com/waltonchain/waltonchain_gwtc_src@v1.1.4-0.20201225072101-8a298c95a819/p2p/discover/node.go (about)

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