github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/p2p/enode/node.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:41</date>
    10  //</624450104413130752>
    11  
    12  
    13  package enode
    14  
    15  import (
    16  	"crypto/ecdsa"
    17  	"encoding/hex"
    18  	"errors"
    19  	"fmt"
    20  	"math/bits"
    21  	"math/rand"
    22  	"net"
    23  	"strings"
    24  
    25  	"github.com/ethereum/go-ethereum/p2p/enr"
    26  )
    27  
    28  //节点表示网络上的主机。
    29  type Node struct {
    30  	r  enr.Record
    31  	id ID
    32  }
    33  
    34  //New包装节点记录。根据给定的记录必须是有效的
    35  //身份方案。
    36  func New(validSchemes enr.IdentityScheme, r *enr.Record) (*Node, error) {
    37  	if err := r.VerifySignature(validSchemes); err != nil {
    38  		return nil, err
    39  	}
    40  	node := &Node{r: *r}
    41  	if n := copy(node.id[:], validSchemes.NodeAddr(&node.r)); n != len(ID{}) {
    42  		return nil, fmt.Errorf("invalid node ID length %d, need %d", n, len(ID{}))
    43  	}
    44  	return node, nil
    45  }
    46  
    47  //ID返回节点标识符。
    48  func (n *Node) ID() ID {
    49  	return n.id
    50  }
    51  
    52  //seq返回基础记录的序列号。
    53  func (n *Node) Seq() uint64 {
    54  	return n.r.Seq()
    55  }
    56  
    57  //对于没有IP地址的节点,不完整返回true。
    58  func (n *Node) Incomplete() bool {
    59  	return n.IP() == nil
    60  }
    61  
    62  //LOAD从基础记录中检索一个条目。
    63  func (n *Node) Load(k enr.Entry) error {
    64  	return n.r.Load(k)
    65  }
    66  
    67  //IP返回节点的IP地址。
    68  func (n *Node) IP() net.IP {
    69  	var ip net.IP
    70  	n.Load((*enr.IP)(&ip))
    71  	return ip
    72  }
    73  
    74  //udp返回节点的udp端口。
    75  func (n *Node) UDP() int {
    76  	var port enr.UDP
    77  	n.Load(&port)
    78  	return int(port)
    79  }
    80  
    81  //UDP返回节点的TCP端口。
    82  func (n *Node) TCP() int {
    83  	var port enr.TCP
    84  	n.Load(&port)
    85  	return int(port)
    86  }
    87  
    88  //pubkey返回节点的secp256k1公钥(如果存在)。
    89  func (n *Node) Pubkey() *ecdsa.PublicKey {
    90  	var key ecdsa.PublicKey
    91  	if n.Load((*Secp256k1)(&key)) != nil {
    92  		return nil
    93  	}
    94  	return &key
    95  }
    96  
    97  //record返回节点的记录。返回值是一个副本,可以
    98  //由调用者修改。
    99  func (n *Node) Record() *enr.Record {
   100  	cpy := n.r
   101  	return &cpy
   102  }
   103  
   104  //检查n是否为有效的完整节点。
   105  func (n *Node) ValidateComplete() error {
   106  	if n.Incomplete() {
   107  		return errors.New("incomplete node")
   108  	}
   109  	if n.UDP() == 0 {
   110  		return errors.New("missing UDP port")
   111  	}
   112  	ip := n.IP()
   113  	if ip.IsMulticast() || ip.IsUnspecified() {
   114  		return errors.New("invalid IP (multicast/unspecified)")
   115  	}
   116  //验证节点键(在曲线上等)。
   117  	var key Secp256k1
   118  	return n.Load(&key)
   119  }
   120  
   121  //节点的字符串表示形式是一个URL。
   122  //有关格式的描述,请参阅ParseNode。
   123  func (n *Node) String() string {
   124  	return n.v4URL()
   125  }
   126  
   127  //MarshalText实现Encoding.TextMarshaler。
   128  func (n *Node) MarshalText() ([]byte, error) {
   129  	return []byte(n.v4URL()), nil
   130  }
   131  
   132  //UnmarshalText实现encoding.textUnmarshaller。
   133  func (n *Node) UnmarshalText(text []byte) error {
   134  	dec, err := ParseV4(string(text))
   135  	if err == nil {
   136  		*n = *dec
   137  	}
   138  	return err
   139  }
   140  
   141  //ID是每个节点的唯一标识符。
   142  type ID [32]byte
   143  
   144  //bytes返回ID的字节片表示形式
   145  func (n ID) Bytes() []byte {
   146  	return n[:]
   147  }
   148  
   149  //ID以十六进制长数字打印。
   150  func (n ID) String() string {
   151  	return fmt.Sprintf("%x", n[:])
   152  }
   153  
   154  //ID的go语法表示是对hexid的调用。
   155  func (n ID) GoString() string {
   156  	return fmt.Sprintf("enode.HexID(\"%x\")", n[:])
   157  }
   158  
   159  //TerminalString返回用于终端日志记录的缩短的十六进制字符串。
   160  func (n ID) TerminalString() string {
   161  	return hex.EncodeToString(n[:8])
   162  }
   163  
   164  //MarshalText实现Encoding.TextMarshaler接口。
   165  func (n ID) MarshalText() ([]byte, error) {
   166  	return []byte(hex.EncodeToString(n[:])), nil
   167  }
   168  
   169  //UnmarshalText实现encoding.textUnmarshaller接口。
   170  func (n *ID) UnmarshalText(text []byte) error {
   171  	id, err := parseID(string(text))
   172  	if err != nil {
   173  		return err
   174  	}
   175  	*n = id
   176  	return nil
   177  }
   178  
   179  //hex id将十六进制字符串转换为ID。
   180  //字符串的前缀可以是0x。
   181  //如果字符串不是有效的ID,则会恐慌。
   182  func HexID(in string) ID {
   183  	id, err := parseID(in)
   184  	if err != nil {
   185  		panic(err)
   186  	}
   187  	return id
   188  }
   189  
   190  func parseID(in string) (ID, error) {
   191  	var id ID
   192  	b, err := hex.DecodeString(strings.TrimPrefix(in, "0x"))
   193  	if err != nil {
   194  		return id, err
   195  	} else if len(b) != len(id) {
   196  		return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2)
   197  	}
   198  	copy(id[:], b)
   199  	return id, nil
   200  }
   201  
   202  //distcmp比较距离a->target和b->target。
   203  //如果a接近目标返回-1,如果b接近目标返回1
   204  //如果相等,则为0。
   205  func DistCmp(target, a, b ID) int {
   206  	for i := range target {
   207  		da := a[i] ^ target[i]
   208  		db := b[i] ^ target[i]
   209  		if da > db {
   210  			return 1
   211  		} else if da < db {
   212  			return -1
   213  		}
   214  	}
   215  	return 0
   216  }
   217  
   218  //logdist返回a和b之间的对数距离,log2(a^b)。
   219  func LogDist(a, b ID) int {
   220  	lz := 0
   221  	for i := range a {
   222  		x := a[i] ^ b[i]
   223  		if x == 0 {
   224  			lz += 8
   225  		} else {
   226  			lz += bits.LeadingZeros8(x)
   227  			break
   228  		}
   229  	}
   230  	return len(a)*8 - lz
   231  }
   232  
   233  //随机返回一个随机ID B,使得logdist(a,b)=n。
   234  func RandomID(a ID, n int) (b ID) {
   235  	if n == 0 {
   236  		return a
   237  	}
   238  //在n位置翻转钻头,其余部分用随机钻头填满。
   239  	b = a
   240  	pos := len(a) - n/8 - 1
   241  	bit := byte(0x01) << (byte(n%8) - 1)
   242  	if bit == 0 {
   243  		pos++
   244  		bit = 0x80
   245  	}
   246  b[pos] = a[pos]&^bit | ^a[pos]&bit //TODO:随机结束位
   247  	for i := pos + 1; i < len(a); i++ {
   248  		b[i] = byte(rand.Intn(255))
   249  	}
   250  	return b
   251  }
   252