github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/p2p/enode/node.go (about)

     1  // Copyright 2018 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 enode
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	"encoding/base64"
    22  	"encoding/hex"
    23  	"errors"
    24  	"fmt"
    25  	"math/bits"
    26  	"net"
    27  	"strings"
    28  
    29  	"github.com/kisexp/xdchain/p2p/enr"
    30  	"github.com/kisexp/xdchain/rlp"
    31  )
    32  
    33  var errMissingPrefix = errors.New("missing 'enr:' prefix for base64-encoded record")
    34  
    35  // Node represents a host on the network.
    36  type Node struct {
    37  	r  enr.Record
    38  	id ID
    39  }
    40  
    41  // New wraps a node record. The record must be valid according to the given
    42  // identity scheme.
    43  func New(validSchemes enr.IdentityScheme, r *enr.Record) (*Node, error) {
    44  	if err := r.VerifySignature(validSchemes); err != nil {
    45  		return nil, err
    46  	}
    47  	node := &Node{r: *r}
    48  	if n := copy(node.id[:], validSchemes.NodeAddr(&node.r)); n != len(ID{}) {
    49  		return nil, fmt.Errorf("invalid node ID length %d, need %d", n, len(ID{}))
    50  	}
    51  	return node, nil
    52  }
    53  
    54  // MustParse parses a node record or enode:// URL. It panics if the input is invalid.
    55  func MustParse(rawurl string) *Node {
    56  	n, err := Parse(ValidSchemes, rawurl)
    57  	if err != nil {
    58  		panic("invalid node: " + err.Error())
    59  	}
    60  	return n
    61  }
    62  
    63  // Parse decodes and verifies a base64-encoded node record.
    64  func Parse(validSchemes enr.IdentityScheme, input string) (*Node, error) {
    65  	if strings.HasPrefix(input, "enode://") {
    66  		return ParseV4(input)
    67  	}
    68  	if !strings.HasPrefix(input, "enr:") {
    69  		return nil, errMissingPrefix
    70  	}
    71  	bin, err := base64.RawURLEncoding.DecodeString(input[4:])
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  	var r enr.Record
    76  	if err := rlp.DecodeBytes(bin, &r); err != nil {
    77  		return nil, err
    78  	}
    79  	return New(validSchemes, &r)
    80  }
    81  
    82  // ID returns the node identifier.
    83  func (n *Node) ID() ID {
    84  	return n.id
    85  }
    86  
    87  // Seq returns the sequence number of the underlying record.
    88  func (n *Node) Seq() uint64 {
    89  	return n.r.Seq()
    90  }
    91  
    92  // Quorum
    93  // Incomplete returns true for nodes with no IP address and no hostname if with raftport.
    94  func (n *Node) Incomplete() bool {
    95  	return n.IP() == nil && (!n.HasRaftPort() || (n.Host() == "" && n.HasRaftPort()))
    96  }
    97  
    98  // Load retrieves an entry from the underlying record.
    99  func (n *Node) Load(k enr.Entry) error {
   100  	return n.r.Load(k)
   101  }
   102  
   103  // IP returns the IP address of the node.
   104  //
   105  // Quorum
   106  // To support DNS lookup in node ip. The function performs hostname lookup if hostname is defined in enr.Hostname
   107  // and falls back to enr.IP value in case of failure. It also makes sure the resolved IP is in IPv4 or IPv6 format
   108  func (n *Node) IP() net.IP {
   109  	if n.Host() == "" {
   110  		// no host is set, so use the IP directly
   111  		return n.loadIP()
   112  	}
   113  	// attempt to look up IP addresses if host is a FQDN
   114  	lookupIPs, err := net.LookupIP(n.Host())
   115  	if err != nil {
   116  		return n.loadIP()
   117  	}
   118  	// set to first ip by default & as Ethereum upstream
   119  	ip := lookupIPs[0]
   120  	// Ensure the IP is 4 bytes long for IPv4 addresses.
   121  	if ipv4 := ip.To4(); ipv4 != nil {
   122  		ip = ipv4
   123  	}
   124  	return ip
   125  }
   126  
   127  func (n *Node) loadIP() net.IP {
   128  	var (
   129  		ip4 enr.IPv4
   130  		ip6 enr.IPv6
   131  	)
   132  	if n.Load(&ip4) == nil {
   133  		return net.IP(ip4)
   134  	}
   135  	if n.Load(&ip6) == nil {
   136  		return net.IP(ip6)
   137  	}
   138  	return nil
   139  }
   140  
   141  // Quorum
   142  func (n *Node) Host() string {
   143  	var hostname string
   144  	n.Load((*enr.Hostname)(&hostname))
   145  	return hostname
   146  }
   147  
   148  // End-Quorum
   149  
   150  // UDP returns the UDP port of the node.
   151  func (n *Node) UDP() int {
   152  	var port enr.UDP
   153  	n.Load(&port)
   154  	return int(port)
   155  }
   156  
   157  // used by Quorum RAFT - returns the Raft port of the node
   158  func (n *Node) RaftPort() int {
   159  	var port enr.RaftPort
   160  	err := n.Load(&port)
   161  	if err != nil {
   162  		return 0
   163  	}
   164  	return int(port)
   165  }
   166  
   167  func (n *Node) HasRaftPort() bool {
   168  	return n.RaftPort() > 0
   169  }
   170  
   171  // UDP returns the TCP port of the node.
   172  func (n *Node) TCP() int {
   173  	var port enr.TCP
   174  	n.Load(&port)
   175  	return int(port)
   176  }
   177  
   178  // Pubkey returns the secp256k1 public key of the node, if present.
   179  func (n *Node) Pubkey() *ecdsa.PublicKey {
   180  	var key ecdsa.PublicKey
   181  	if n.Load((*Secp256k1)(&key)) != nil {
   182  		return nil
   183  	}
   184  	return &key
   185  }
   186  
   187  // Record returns the node's record. The return value is a copy and may
   188  // be modified by the caller.
   189  func (n *Node) Record() *enr.Record {
   190  	cpy := n.r
   191  	return &cpy
   192  }
   193  
   194  // ValidateComplete checks whether n has a valid IP and UDP port.
   195  // Deprecated: don't use this method.
   196  func (n *Node) ValidateComplete() error {
   197  	if n.Incomplete() {
   198  		return errors.New("missing IP address")
   199  	}
   200  	if n.UDP() == 0 {
   201  		return errors.New("missing UDP port")
   202  	}
   203  	ip := n.IP()
   204  	if ip.IsMulticast() || ip.IsUnspecified() {
   205  		return errors.New("invalid IP (multicast/unspecified)")
   206  	}
   207  	// Validate the node key (on curve, etc.).
   208  	var key Secp256k1
   209  	return n.Load(&key)
   210  }
   211  
   212  // String returns the text representation of the record.
   213  func (n *Node) String() string {
   214  	if isNewV4(n) {
   215  		return n.URLv4() // backwards-compatibility glue for NewV4 nodes
   216  	}
   217  	enc, _ := rlp.EncodeToBytes(&n.r) // always succeeds because record is valid
   218  	b64 := base64.RawURLEncoding.EncodeToString(enc)
   219  	return "enr:" + b64
   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 := Parse(ValidSchemes, string(text))
   230  	if err == nil {
   231  		*n = *dec
   232  	}
   233  	return err
   234  }
   235  
   236  // ID is a unique identifier for each node.
   237  type ID [32]byte
   238  
   239  // Bytes returns a byte slice representation of the ID
   240  func (n ID) Bytes() []byte {
   241  	return n[:]
   242  }
   243  
   244  // ID prints as a long hexadecimal number.
   245  func (n ID) String() string {
   246  	return fmt.Sprintf("%x", n[:])
   247  }
   248  
   249  // The Go syntax representation of a ID is a call to HexID.
   250  func (n ID) GoString() string {
   251  	return fmt.Sprintf("enode.HexID(\"%x\")", n[:])
   252  }
   253  
   254  // TerminalString returns a shortened hex string for terminal logging.
   255  func (n ID) TerminalString() string {
   256  	return hex.EncodeToString(n[:8])
   257  }
   258  
   259  // MarshalText implements the encoding.TextMarshaler interface.
   260  func (n ID) MarshalText() ([]byte, error) {
   261  	return []byte(hex.EncodeToString(n[:])), nil
   262  }
   263  
   264  // UnmarshalText implements the encoding.TextUnmarshaler interface.
   265  func (n *ID) UnmarshalText(text []byte) error {
   266  	id, err := ParseID(string(text))
   267  	if err != nil {
   268  		return err
   269  	}
   270  	*n = id
   271  	return nil
   272  }
   273  
   274  // ID is a unique identifier for each node used by RAFT
   275  type EnodeID [64]byte
   276  
   277  // ID prints as a long hexadecimal number.
   278  func (n EnodeID) String() string {
   279  	return fmt.Sprintf("%x", n[:])
   280  }
   281  
   282  // The Go syntax representation of a ID is a call to HexID.
   283  func (n EnodeID) GoString() string {
   284  	return fmt.Sprintf("enode.HexID(\"%x\")", n[:])
   285  }
   286  
   287  // MarshalText implements the encoding.TextMarshaler interface.
   288  func (n EnodeID) MarshalText() ([]byte, error) {
   289  	return []byte(hex.EncodeToString(n[:])), nil
   290  }
   291  
   292  // UnmarshalText implements the encoding.TextUnmarshaler interface.
   293  func (n *EnodeID) UnmarshalText(text []byte) error {
   294  	id, err := RaftHexID(string(text))
   295  	if err != nil {
   296  		return err
   297  	}
   298  	*n = id
   299  	return nil
   300  }
   301  
   302  // HexID converts a hex string to an ID.
   303  // The string may be prefixed with 0x.
   304  // It panics if the string is not a valid ID.
   305  func HexID(in string) ID {
   306  	id, err := ParseID(in)
   307  	if err != nil {
   308  		panic(err)
   309  	}
   310  	return id
   311  }
   312  
   313  // used by Quorum RAFT to derive 64 byte nodeId from 128 byte enodeID
   314  func RaftHexID(in string) (EnodeID, error) {
   315  	var id EnodeID
   316  	b, err := hex.DecodeString(strings.TrimPrefix(in, "0x"))
   317  	if err != nil {
   318  		return id, err
   319  	} else if len(b) != len(id) {
   320  		return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2)
   321  	}
   322  
   323  	copy(id[:], b)
   324  	return id, nil
   325  }
   326  
   327  func ParseID(in string) (ID, error) {
   328  	var id ID
   329  	b, err := hex.DecodeString(strings.TrimPrefix(in, "0x"))
   330  	if err != nil {
   331  		return id, err
   332  	} else if len(b) != len(id) {
   333  		return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2)
   334  	}
   335  	copy(id[:], b)
   336  	return id, nil
   337  }
   338  
   339  // DistCmp compares the distances a->target and b->target.
   340  // Returns -1 if a is closer to target, 1 if b is closer to target
   341  // and 0 if they are equal.
   342  func DistCmp(target, a, b ID) int {
   343  	for i := range target {
   344  		da := a[i] ^ target[i]
   345  		db := b[i] ^ target[i]
   346  		if da > db {
   347  			return 1
   348  		} else if da < db {
   349  			return -1
   350  		}
   351  	}
   352  	return 0
   353  }
   354  
   355  // LogDist returns the logarithmic distance between a and b, log2(a ^ b).
   356  func LogDist(a, b ID) int {
   357  	lz := 0
   358  	for i := range a {
   359  		x := a[i] ^ b[i]
   360  		if x == 0 {
   361  			lz += 8
   362  		} else {
   363  			lz += bits.LeadingZeros8(x)
   364  			break
   365  		}
   366  	}
   367  	return len(a)*8 - lz
   368  }