github.com/amazechain/amc@v0.1.3/internal/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  	"github.com/amazechain/amc/internal/avm/rlp"
    26  	"github.com/amazechain/amc/internal/p2p/enr"
    27  	"math/bits"
    28  	"net"
    29  	"strings"
    30  )
    31  
    32  var errMissingPrefix = errors.New("missing 'enr:' prefix for base64-encoded record")
    33  
    34  // Node represents a host on the network.
    35  type Node struct {
    36  	r  enr.Record
    37  	id ID
    38  }
    39  
    40  // New wraps a node record. The record must be valid according to the given
    41  // identity scheme.
    42  func New(validSchemes enr.IdentityScheme, r *enr.Record) (*Node, error) {
    43  	if err := r.VerifySignature(validSchemes); err != nil {
    44  		return nil, err
    45  	}
    46  	node := &Node{r: *r}
    47  	if n := copy(node.id[:], validSchemes.NodeAddr(&node.r)); n != len(ID{}) {
    48  		return nil, fmt.Errorf("invalid node ID length %d, need %d", n, len(ID{}))
    49  	}
    50  	return node, nil
    51  }
    52  
    53  // MustParse parses a node record or enode:// URL. It panics if the input is invalid.
    54  func MustParse(rawurl string) *Node {
    55  	n, err := Parse(ValidSchemes, rawurl)
    56  	if err != nil {
    57  		panic("invalid node: " + err.Error())
    58  	}
    59  	return n
    60  }
    61  
    62  // Parse decodes and verifies a base64-encoded node record.
    63  func Parse(validSchemes enr.IdentityScheme, input string) (*Node, error) {
    64  	if strings.HasPrefix(input, "enode://") {
    65  		return ParseV4(input)
    66  	}
    67  	if !strings.HasPrefix(input, "enr:") {
    68  		return nil, errMissingPrefix
    69  	}
    70  	bin, err := base64.RawURLEncoding.DecodeString(input[4:])
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  	var r enr.Record
    75  	if err := rlp.DecodeBytes(bin, &r); err != nil {
    76  		return nil, err
    77  	}
    78  	return New(validSchemes, &r)
    79  }
    80  
    81  // ID returns the node identifier.
    82  func (n *Node) ID() ID {
    83  	return n.id
    84  }
    85  
    86  // Seq returns the sequence number of the underlying record.
    87  func (n *Node) Seq() uint64 {
    88  	return n.r.Seq()
    89  }
    90  
    91  // Incomplete returns true for nodes with no IP address.
    92  func (n *Node) Incomplete() bool {
    93  	return n.IP() == nil
    94  }
    95  
    96  // Load retrieves an entry from the underlying record.
    97  func (n *Node) Load(k enr.Entry) error {
    98  	return n.r.Load(k)
    99  }
   100  
   101  // IP returns the IP address of the node. This prefers IPv4 addresses.
   102  func (n *Node) IP() net.IP {
   103  	var (
   104  		ip4 enr.IPv4
   105  		ip6 enr.IPv6
   106  	)
   107  	if n.Load(&ip4) == nil {
   108  		return net.IP(ip4)
   109  	}
   110  	if n.Load(&ip6) == nil {
   111  		return net.IP(ip6)
   112  	}
   113  	return nil
   114  }
   115  
   116  // UDP returns the UDP port of the node.
   117  func (n *Node) UDP() int {
   118  	var port enr.UDP
   119  	n.Load(&port)
   120  	return int(port)
   121  }
   122  
   123  // TCP returns the TCP port of the node.
   124  func (n *Node) TCP() int {
   125  	var port enr.TCP
   126  	n.Load(&port)
   127  	return int(port)
   128  }
   129  
   130  // Pubkey returns the secp256k1 public key of the node, if present.
   131  func (n *Node) Pubkey() *ecdsa.PublicKey {
   132  	var key ecdsa.PublicKey
   133  	if n.Load((*Secp256k1)(&key)) != nil {
   134  		return nil
   135  	}
   136  	return &key
   137  }
   138  
   139  // Record returns the node's record. The return value is a copy and may
   140  // be modified by the caller.
   141  func (n *Node) Record() *enr.Record {
   142  	cpy := n.r
   143  	return &cpy
   144  }
   145  
   146  // ValidateComplete checks whether n has a valid IP and UDP port.
   147  // Deprecated: don't use this method.
   148  func (n *Node) ValidateComplete() error {
   149  	if n.Incomplete() {
   150  		return errors.New("missing IP address")
   151  	}
   152  	if n.UDP() == 0 {
   153  		return errors.New("missing UDP port")
   154  	}
   155  	ip := n.IP()
   156  	if ip.IsMulticast() || ip.IsUnspecified() {
   157  		return errors.New("invalid IP (multicast/unspecified)")
   158  	}
   159  	// Validate the node key (on curve, etc.).
   160  	var key Secp256k1
   161  	return n.Load(&key)
   162  }
   163  
   164  // String returns the text representation of the record.
   165  func (n *Node) String() string {
   166  	if isNewV4(n) {
   167  		return n.URLv4() // backwards-compatibility glue for NewV4 nodes
   168  	}
   169  	enc, _ := rlp.EncodeToBytes(&n.r) // always succeeds because record is valid
   170  	b64 := base64.RawURLEncoding.EncodeToString(enc)
   171  	return "enr:" + b64
   172  }
   173  
   174  // MarshalText implements encoding.TextMarshaler.
   175  func (n *Node) MarshalText() ([]byte, error) {
   176  	return []byte(n.String()), nil
   177  }
   178  
   179  // UnmarshalText implements encoding.TextUnmarshaler.
   180  func (n *Node) UnmarshalText(text []byte) error {
   181  	dec, err := Parse(ValidSchemes, string(text))
   182  	if err == nil {
   183  		*n = *dec
   184  	}
   185  	return err
   186  }
   187  
   188  // ID is a unique identifier for each node.
   189  type ID [32]byte
   190  
   191  // Bytes returns a byte slice representation of the ID
   192  func (n ID) Bytes() []byte {
   193  	return n[:]
   194  }
   195  
   196  // ID prints as a long hexadecimal number.
   197  func (n ID) String() string {
   198  	return fmt.Sprintf("%x", n[:])
   199  }
   200  
   201  // GoString returns the Go syntax representation of a ID is a call to HexID.
   202  func (n ID) GoString() string {
   203  	return fmt.Sprintf("enode.HexID(\"%x\")", n[:])
   204  }
   205  
   206  // TerminalString returns a shortened hex string for terminal logging.
   207  func (n ID) TerminalString() string {
   208  	return hex.EncodeToString(n[:8])
   209  }
   210  
   211  // MarshalText implements the encoding.TextMarshaler interface.
   212  func (n ID) MarshalText() ([]byte, error) {
   213  	return []byte(hex.EncodeToString(n[:])), nil
   214  }
   215  
   216  // UnmarshalText implements the encoding.TextUnmarshaler interface.
   217  func (n *ID) UnmarshalText(text []byte) error {
   218  	id, err := ParseID(string(text))
   219  	if err != nil {
   220  		return err
   221  	}
   222  	*n = id
   223  	return nil
   224  }
   225  
   226  // HexID converts a hex string to an ID.
   227  // The string may be prefixed with 0x.
   228  // It panics if the string is not a valid ID.
   229  func HexID(in string) ID {
   230  	id, err := ParseID(in)
   231  	if err != nil {
   232  		panic(err)
   233  	}
   234  	return id
   235  }
   236  
   237  func ParseID(in string) (ID, error) {
   238  	var id ID
   239  	b, err := hex.DecodeString(strings.TrimPrefix(in, "0x"))
   240  	if err != nil {
   241  		return id, err
   242  	} else if len(b) != len(id) {
   243  		return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2)
   244  	}
   245  	copy(id[:], b)
   246  	return id, nil
   247  }
   248  
   249  // DistCmp compares the distances a->target and b->target.
   250  // Returns -1 if a is closer to target, 1 if b is closer to target
   251  // and 0 if they are equal.
   252  func DistCmp(target, a, b ID) int {
   253  	for i := range target {
   254  		da := a[i] ^ target[i]
   255  		db := b[i] ^ target[i]
   256  		if da > db {
   257  			return 1
   258  		} else if da < db {
   259  			return -1
   260  		}
   261  	}
   262  	return 0
   263  }
   264  
   265  // LogDist returns the logarithmic distance between a and b, log2(a ^ b).
   266  func LogDist(a, b ID) int {
   267  	lz := 0
   268  	for i := range a {
   269  		x := a[i] ^ b[i]
   270  		if x == 0 {
   271  			lz += 8
   272  		} else {
   273  			lz += bits.LeadingZeros8(x)
   274  			break
   275  		}
   276  	}
   277  	return len(a)*8 - lz
   278  }