github.com/janotchain/janota@v0.0.0-20220824112012-93ea4c5dee78/p2p/discv5/node.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum 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-ethereum 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 discv5
    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/ethereum/go-ethereum/common"
    34  	"github.com/ethereum/go-ethereum/crypto"
    35  )
    36  
    37  // Node represents a host on the network.
    38  // The public fields of Node may not be modified.
    39  type Node struct {
    40  	IP       net.IP // len 4 for IPv4 or 16 for IPv6
    41  	UDP, TCP uint16 // port numbers
    42  	ID       NodeID // the node's public key
    43  
    44  	// Network-related fields are contained in nodeNetGuts.
    45  	// These fields are not supposed to be used off the
    46  	// Network.loop goroutine.
    47  	nodeNetGuts
    48  }
    49  
    50  // NewNode creates a new node. It is mostly meant to be used for
    51  // testing purposes.
    52  func NewNode(id NodeID, ip net.IP, udpPort, tcpPort uint16) *Node {
    53  	if ipv4 := ip.To4(); ipv4 != nil {
    54  		ip = ipv4
    55  	}
    56  	return &Node{
    57  		IP:          ip,
    58  		UDP:         udpPort,
    59  		TCP:         tcpPort,
    60  		ID:          id,
    61  		nodeNetGuts: nodeNetGuts{sha: crypto.Keccak256Hash(id[:])},
    62  	}
    63  }
    64  
    65  func (n *Node) addr() *net.UDPAddr {
    66  	return &net.UDPAddr{IP: n.IP, Port: int(n.UDP)}
    67  }
    68  
    69  func (n *Node) setAddr(a *net.UDPAddr) {
    70  	n.IP = a.IP
    71  	if ipv4 := a.IP.To4(); ipv4 != nil {
    72  		n.IP = ipv4
    73  	}
    74  	n.UDP = uint16(a.Port)
    75  }
    76  
    77  // compares the given address against the stored values.
    78  func (n *Node) addrEqual(a *net.UDPAddr) bool {
    79  	ip := a.IP
    80  	if ipv4 := a.IP.To4(); ipv4 != nil {
    81  		ip = ipv4
    82  	}
    83  	return n.UDP == uint16(a.Port) && n.IP.Equal(ip)
    84  }
    85  
    86  // Incomplete returns true for nodes with no IP address.
    87  func (n *Node) Incomplete() bool {
    88  	return n.IP == nil
    89  }
    90  
    91  // checks whether n is a valid complete node.
    92  func (n *Node) validateComplete() error {
    93  	if n.Incomplete() {
    94  		return errors.New("incomplete node")
    95  	}
    96  	if n.UDP == 0 {
    97  		return errors.New("missing UDP port")
    98  	}
    99  	if n.TCP == 0 {
   100  		return errors.New("missing TCP port")
   101  	}
   102  	if n.IP.IsMulticast() || n.IP.IsUnspecified() {
   103  		return errors.New("invalid IP (multicast/unspecified)")
   104  	}
   105  	_, err := n.ID.Pubkey() // validate the key (on curve, etc.)
   106  	return err
   107  }
   108  
   109  // The string representation of a Node is a URL.
   110  // Please see ParseNode for a description of the format.
   111  func (n *Node) String() string {
   112  	u := url.URL{Scheme: "enode"}
   113  	if n.Incomplete() {
   114  		u.Host = fmt.Sprintf("%x", n.ID[:])
   115  	} else {
   116  		addr := net.TCPAddr{IP: n.IP, Port: int(n.TCP)}
   117  		u.User = url.User(fmt.Sprintf("%x", n.ID[:]))
   118  		u.Host = addr.String()
   119  		if n.UDP != n.TCP {
   120  			u.RawQuery = "discport=" + strconv.Itoa(int(n.UDP))
   121  		}
   122  	}
   123  	return u.String()
   124  }
   125  
   126  var incompleteNodeURL = regexp.MustCompile("(?i)^(?:enode://)?([0-9a-f]+)$")
   127  
   128  // ParseNode parses a node designator.
   129  //
   130  // There are two basic forms of node designators
   131  //   - incomplete nodes, which only have the public key (node ID)
   132  //   - complete nodes, which contain the public key and IP/Port information
   133  //
   134  // For incomplete nodes, the designator must look like one of these
   135  //
   136  //    enode://<hex node id>
   137  //    <hex node id>
   138  //
   139  // For complete nodes, the node ID is encoded in the username portion
   140  // of the URL, separated from the host by an @ sign. The hostname can
   141  // only be given as an IP address, DNS domain names are not allowed.
   142  // The port in the host name section is the TCP listening port. If the
   143  // TCP and UDP (discovery) ports differ, the UDP port is specified as
   144  // query parameter "discport".
   145  //
   146  // In the following example, the node URL describes
   147  // a node with IP address 10.3.58.6, TCP listening port 30303
   148  // and UDP discovery port 30301.
   149  //
   150  //    enode://<hex node id>@10.3.58.6:30303?discport=30301
   151  func ParseNode(rawurl string) (*Node, error) {
   152  	if m := incompleteNodeURL.FindStringSubmatch(rawurl); m != nil {
   153  		id, err := HexID(m[1])
   154  		if err != nil {
   155  			return nil, fmt.Errorf("invalid node ID (%v)", err)
   156  		}
   157  		return NewNode(id, nil, 0, 0), nil
   158  	}
   159  	return parseComplete(rawurl)
   160  }
   161  
   162  func parseComplete(rawurl string) (*Node, error) {
   163  	var (
   164  		id               NodeID
   165  		ip               net.IP
   166  		tcpPort, udpPort uint64
   167  	)
   168  	u, err := url.Parse(rawurl)
   169  	if err != nil {
   170  		return nil, err
   171  	}
   172  	if u.Scheme != "enode" {
   173  		return nil, errors.New("invalid URL scheme, want \"enode\"")
   174  	}
   175  	// Parse the Node ID from the user portion.
   176  	if u.User == nil {
   177  		return nil, errors.New("does not contain node ID")
   178  	}
   179  	if id, err = HexID(u.User.String()); err != nil {
   180  		return nil, fmt.Errorf("invalid node ID (%v)", err)
   181  	}
   182  	// Parse the IP address.
   183  	host, port, err := net.SplitHostPort(u.Host)
   184  	if err != nil {
   185  		return nil, fmt.Errorf("invalid host: %v", err)
   186  	}
   187  	if ip = net.ParseIP(host); ip == nil {
   188  		return nil, errors.New("invalid IP address")
   189  	}
   190  	// Ensure the IP is 4 bytes long for IPv4 addresses.
   191  	if ipv4 := ip.To4(); ipv4 != nil {
   192  		ip = ipv4
   193  	}
   194  	// Parse the port numbers.
   195  	if tcpPort, err = strconv.ParseUint(port, 10, 16); err != nil {
   196  		return nil, errors.New("invalid port")
   197  	}
   198  	udpPort = tcpPort
   199  	qv := u.Query()
   200  	if qv.Get("discport") != "" {
   201  		udpPort, err = strconv.ParseUint(qv.Get("discport"), 10, 16)
   202  		if err != nil {
   203  			return nil, errors.New("invalid discport in query")
   204  		}
   205  	}
   206  	return NewNode(id, ip, uint16(udpPort), uint16(tcpPort)), nil
   207  }
   208  
   209  // MustParseNode parses a node URL. It panics if the URL is not valid.
   210  func MustParseNode(rawurl string) *Node {
   211  	n, err := ParseNode(rawurl)
   212  	if err != nil {
   213  		panic("invalid node URL: " + err.Error())
   214  	}
   215  	return n
   216  }
   217  
   218  // MarshalText implements encoding.TextMarshaler.
   219  func (n *Node) MarshalText() ([]byte, error) {
   220  	return []byte(n.String()), nil
   221  }
   222  
   223  // UnmarshalText implements encoding.TextUnmarshaler.
   224  func (n *Node) UnmarshalText(text []byte) error {
   225  	dec, err := ParseNode(string(text))
   226  	if err == nil {
   227  		*n = *dec
   228  	}
   229  	return err
   230  }
   231  
   232  // type nodeQueue []*Node
   233  //
   234  // // pushNew adds n to the end if it is not present.
   235  // func (nl *nodeList) appendNew(n *Node) {
   236  // 	for _, entry := range n {
   237  // 		if entry == n {
   238  // 			return
   239  // 		}
   240  // 	}
   241  // 	*nq = append(*nq, n)
   242  // }
   243  //
   244  // // popRandom removes a random node. Nodes closer to
   245  // // to the head of the beginning of the have a slightly higher probability.
   246  // func (nl *nodeList) popRandom() *Node {
   247  // 	ix := rand.Intn(len(*nq))
   248  // 	//TODO: probability as mentioned above.
   249  // 	nl.removeIndex(ix)
   250  // }
   251  //
   252  // func (nl *nodeList) removeIndex(i int) *Node {
   253  // 	slice = *nl
   254  // 	if len(*slice) <= i {
   255  // 		return nil
   256  // 	}
   257  // 	*nl = append(slice[:i], slice[i+1:]...)
   258  // }
   259  
   260  const nodeIDBits = 512
   261  
   262  // NodeID is a unique identifier for each node.
   263  // The node identifier is a marshaled elliptic curve public key.
   264  type NodeID [nodeIDBits / 8]byte
   265  
   266  // NodeID prints as a long hexadecimal number.
   267  func (n NodeID) String() string {
   268  	return fmt.Sprintf("%x", n[:])
   269  }
   270  
   271  // The Go syntax representation of a NodeID is a call to HexID.
   272  func (n NodeID) GoString() string {
   273  	return fmt.Sprintf("discover.HexID(\"%x\")", n[:])
   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  }