github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/p2p/enode/node.go (about)

     1  //  Copyright 2018 The go-ethereum Authors
     2  //  Copyright 2019 The go-aigar Authors
     3  //  This file is part of the go-aigar library.
     4  //
     5  //  The go-aigar library is free software: you can redistribute it and/or modify
     6  //  it under the terms of the GNU Lesser General Public License as published by
     7  //  the Free Software Foundation, either version 3 of the License, or
     8  //  (at your option) any later version.
     9  //
    10  //  The go-aigar library is distributed in the hope that it will be useful,
    11  //  but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  //  GNU Lesser General Public License for more details.
    14  //
    15  //  You should have received a copy of the GNU Lesser General Public License
    16  //  along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package enode
    19  
    20  import (
    21  	"crypto/ecdsa"
    22  	"encoding/base64"
    23  	"encoding/hex"
    24  	"errors"
    25  	"fmt"
    26  	"math/bits"
    27  	"math/rand"
    28  	"net"
    29  	"strings"
    30  
    31  	"github.com/AigarNetwork/aigar/p2p/enr"
    32  	"github.com/AigarNetwork/aigar/rlp"
    33  )
    34  
    35  var errMissingPrefix = errors.New("missing 'enr:' prefix for base64-encoded record")
    36  
    37  // Node represents a host on the network.
    38  type Node struct {
    39  	r  enr.Record
    40  	id ID
    41  }
    42  
    43  // New wraps a node record. The record must be valid according to the given
    44  // identity scheme.
    45  func New(validSchemes enr.IdentityScheme, r *enr.Record) (*Node, error) {
    46  	if err := r.VerifySignature(validSchemes); err != nil {
    47  		return nil, err
    48  	}
    49  	node := &Node{r: *r}
    50  	if n := copy(node.id[:], validSchemes.NodeAddr(&node.r)); n != len(ID{}) {
    51  		return nil, fmt.Errorf("invalid node ID length %d, need %d", n, len(ID{}))
    52  	}
    53  	return node, nil
    54  }
    55  
    56  // MustParse parses a node record or enode:// URL. It panics if the input is invalid.
    57  func MustParse(rawurl string) *Node {
    58  	n, err := Parse(ValidSchemes, rawurl)
    59  	if err != nil {
    60  		panic("invalid node: " + err.Error())
    61  	}
    62  	return n
    63  }
    64  
    65  // Parse decodes and verifies a base64-encoded node record.
    66  func Parse(validSchemes enr.IdentityScheme, input string) (*Node, error) {
    67  	if strings.HasPrefix(input, "enode://") {
    68  		return ParseV4(input)
    69  	}
    70  	if !strings.HasPrefix(input, "enr:") {
    71  		return nil, errMissingPrefix
    72  	}
    73  	bin, err := base64.RawURLEncoding.DecodeString(input[4:])
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  	var r enr.Record
    78  	if err := rlp.DecodeBytes(bin, &r); err != nil {
    79  		return nil, err
    80  	}
    81  	return New(validSchemes, &r)
    82  }
    83  
    84  // ID returns the node identifier.
    85  func (n *Node) ID() ID {
    86  	return n.id
    87  }
    88  
    89  // Seq returns the sequence number of the underlying record.
    90  func (n *Node) Seq() uint64 {
    91  	return n.r.Seq()
    92  }
    93  
    94  // Incomplete returns true for nodes with no IP address.
    95  func (n *Node) Incomplete() bool {
    96  	return n.IP() == nil
    97  }
    98  
    99  // Load retrieves an entry from the underlying record.
   100  func (n *Node) Load(k enr.Entry) error {
   101  	return n.r.Load(k)
   102  }
   103  
   104  // IP returns the IP address of the node. This prefers IPv4 addresses.
   105  func (n *Node) IP() net.IP {
   106  	var (
   107  		ip4 enr.IPv4
   108  		ip6 enr.IPv6
   109  	)
   110  	if n.Load(&ip4) == nil {
   111  		return net.IP(ip4)
   112  	}
   113  	if n.Load(&ip6) == nil {
   114  		return net.IP(ip6)
   115  	}
   116  	return nil
   117  }
   118  
   119  // UDP returns the UDP port of the node.
   120  func (n *Node) UDP() int {
   121  	var port enr.UDP
   122  	n.Load(&port)
   123  	return int(port)
   124  }
   125  
   126  // UDP returns the TCP port of the node.
   127  func (n *Node) TCP() int {
   128  	var port enr.TCP
   129  	n.Load(&port)
   130  	return int(port)
   131  }
   132  
   133  // Pubkey returns the secp256k1 public key of the node, if present.
   134  func (n *Node) Pubkey() *ecdsa.PublicKey {
   135  	var key ecdsa.PublicKey
   136  	if n.Load((*Secp256k1)(&key)) != nil {
   137  		return nil
   138  	}
   139  	return &key
   140  }
   141  
   142  // Record returns the node's record. The return value is a copy and may
   143  // be modified by the caller.
   144  func (n *Node) Record() *enr.Record {
   145  	cpy := n.r
   146  	return &cpy
   147  }
   148  
   149  // ValidateComplete checks whether n has a valid IP and UDP port.
   150  // Deprecated: don't use this method.
   151  func (n *Node) ValidateComplete() error {
   152  	if n.Incomplete() {
   153  		return errors.New("missing IP address")
   154  	}
   155  	if n.UDP() == 0 {
   156  		return errors.New("missing UDP port")
   157  	}
   158  	ip := n.IP()
   159  	if ip.IsMulticast() || ip.IsUnspecified() {
   160  		return errors.New("invalid IP (multicast/unspecified)")
   161  	}
   162  	// Validate the node key (on curve, etc.).
   163  	var key Secp256k1
   164  	return n.Load(&key)
   165  }
   166  
   167  // String returns the text representation of the record.
   168  func (n *Node) String() string {
   169  	if isNewV4(n) {
   170  		return n.URLv4() // backwards-compatibility glue for NewV4 nodes
   171  	}
   172  	enc, _ := rlp.EncodeToBytes(&n.r) // always succeeds because record is valid
   173  	b64 := base64.RawURLEncoding.EncodeToString(enc)
   174  	return "enr:" + b64
   175  }
   176  
   177  // MarshalText implements encoding.TextMarshaler.
   178  func (n *Node) MarshalText() ([]byte, error) {
   179  	return []byte(n.String()), nil
   180  }
   181  
   182  // UnmarshalText implements encoding.TextUnmarshaler.
   183  func (n *Node) UnmarshalText(text []byte) error {
   184  	dec, err := Parse(ValidSchemes, string(text))
   185  	if err == nil {
   186  		*n = *dec
   187  	}
   188  	return err
   189  }
   190  
   191  // ID is a unique identifier for each node.
   192  type ID [32]byte
   193  
   194  // Bytes returns a byte slice representation of the ID
   195  func (n ID) Bytes() []byte {
   196  	return n[:]
   197  }
   198  
   199  // ID prints as a long hexadecimal number.
   200  func (n ID) String() string {
   201  	return fmt.Sprintf("%x", n[:])
   202  }
   203  
   204  // The Go syntax representation of a ID is a call to HexID.
   205  func (n ID) GoString() string {
   206  	return fmt.Sprintf("enode.HexID(\"%x\")", n[:])
   207  }
   208  
   209  // TerminalString returns a shortened hex string for terminal logging.
   210  func (n ID) TerminalString() string {
   211  	return hex.EncodeToString(n[:8])
   212  }
   213  
   214  // MarshalText implements the encoding.TextMarshaler interface.
   215  func (n ID) MarshalText() ([]byte, error) {
   216  	return []byte(hex.EncodeToString(n[:])), nil
   217  }
   218  
   219  // UnmarshalText implements the encoding.TextUnmarshaler interface.
   220  func (n *ID) UnmarshalText(text []byte) error {
   221  	id, err := parseID(string(text))
   222  	if err != nil {
   223  		return err
   224  	}
   225  	*n = id
   226  	return nil
   227  }
   228  
   229  // HexID converts a hex string to an ID.
   230  // The string may be prefixed with 0x.
   231  // It panics if the string is not a valid ID.
   232  func HexID(in string) ID {
   233  	id, err := parseID(in)
   234  	if err != nil {
   235  		panic(err)
   236  	}
   237  	return id
   238  }
   239  
   240  func parseID(in string) (ID, error) {
   241  	var id ID
   242  	b, err := hex.DecodeString(strings.TrimPrefix(in, "0x"))
   243  	if err != nil {
   244  		return id, err
   245  	} else if len(b) != len(id) {
   246  		return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2)
   247  	}
   248  	copy(id[:], b)
   249  	return id, nil
   250  }
   251  
   252  // DistCmp compares the distances a->target and b->target.
   253  // Returns -1 if a is closer to target, 1 if b is closer to target
   254  // and 0 if they are equal.
   255  func DistCmp(target, a, b ID) int {
   256  	for i := range target {
   257  		da := a[i] ^ target[i]
   258  		db := b[i] ^ target[i]
   259  		if da > db {
   260  			return 1
   261  		} else if da < db {
   262  			return -1
   263  		}
   264  	}
   265  	return 0
   266  }
   267  
   268  // LogDist returns the logarithmic distance between a and b, log2(a ^ b).
   269  func LogDist(a, b ID) int {
   270  	lz := 0
   271  	for i := range a {
   272  		x := a[i] ^ b[i]
   273  		if x == 0 {
   274  			lz += 8
   275  		} else {
   276  			lz += bits.LeadingZeros8(x)
   277  			break
   278  		}
   279  	}
   280  	return len(a)*8 - lz
   281  }
   282  
   283  // RandomID returns a random ID b such that logdist(a, b) == n.
   284  func RandomID(a ID, n int) (b ID) {
   285  	if n == 0 {
   286  		return a
   287  	}
   288  	// flip bit at position n, fill the rest with random bits
   289  	b = a
   290  	pos := len(a) - n/8 - 1
   291  	bit := byte(0x01) << (byte(n%8) - 1)
   292  	if bit == 0 {
   293  		pos++
   294  		bit = 0x80
   295  	}
   296  	b[pos] = a[pos]&^bit | ^a[pos]&bit // TODO: randomize end bits
   297  	for i := pos + 1; i < len(a); i++ {
   298  		b[i] = byte(rand.Intn(255))
   299  	}
   300  	return b
   301  }