github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/p2p/discv5/node.go (about)

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