github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/p2p/discover/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 12:09:43</date>
    10  //</624342655907663872>
    11  
    12  
    13  package discover
    14  
    15  import (
    16  	"crypto/ecdsa"
    17  	"crypto/elliptic"
    18  	"encoding/hex"
    19  	"errors"
    20  	"fmt"
    21  	"math/big"
    22  	"math/rand"
    23  	"net"
    24  	"net/url"
    25  	"regexp"
    26  	"strconv"
    27  	"strings"
    28  	"time"
    29  
    30  	"github.com/ethereum/go-ethereum/common"
    31  	"github.com/ethereum/go-ethereum/crypto"
    32  	"github.com/ethereum/go-ethereum/crypto/secp256k1"
    33  )
    34  
    35  const NodeIDBits = 512
    36  
    37  //节点表示网络上的主机。
    38  //不能修改节点的字段。
    39  type Node struct {
    40  IP       net.IP //IPv4的len 4或IPv6的len 16
    41  UDP, TCP uint16 //端口号
    42  ID       NodeID //节点的公钥
    43  
    44  //这是用于节点的sha3(id)的缓存副本
    45  //距离计算。这是节点的一部分,以便
    46  //可以编写在一定距离需要节点的测试。
    47  //在这些测试中,sha的内容实际上并不对应
    48  //和ID.
    49  	sha common.Hash
    50  
    51  //将节点添加到表中的时间。
    52  	addedAt time.Time
    53  }
    54  
    55  //new node创建新节点。它主要用于
    56  //测试目的。
    57  func NewNode(id NodeID, ip net.IP, udpPort, tcpPort uint16) *Node {
    58  	if ipv4 := ip.To4(); ipv4 != nil {
    59  		ip = ipv4
    60  	}
    61  	return &Node{
    62  		IP:  ip,
    63  		UDP: udpPort,
    64  		TCP: tcpPort,
    65  		ID:  id,
    66  		sha: crypto.Keccak256Hash(id[:]),
    67  	}
    68  }
    69  
    70  func (n *Node) addr() *net.UDPAddr {
    71  	return &net.UDPAddr{IP: n.IP, Port: int(n.UDP)}
    72  }
    73  
    74  //对于没有IP地址的节点,不完整返回true。
    75  func (n *Node) Incomplete() bool {
    76  	return n.IP == nil
    77  }
    78  
    79  //检查n是否为有效的完整节点。
    80  func (n *Node) validateComplete() error {
    81  	if n.Incomplete() {
    82  		return errors.New("incomplete node")
    83  	}
    84  	if n.UDP == 0 {
    85  		return errors.New("missing UDP port")
    86  	}
    87  	if n.TCP == 0 {
    88  		return errors.New("missing TCP port")
    89  	}
    90  	if n.IP.IsMulticast() || n.IP.IsUnspecified() {
    91  		return errors.New("invalid IP (multicast/unspecified)")
    92  	}
    93  _, err := n.ID.Pubkey() //验证密钥(在曲线上等)
    94  	return err
    95  }
    96  
    97  //节点的字符串表示形式是一个URL。
    98  //有关格式的描述,请参阅ParseNode。
    99  func (n *Node) String() string {
   100  	u := url.URL{Scheme: "enode"}
   101  	if n.Incomplete() {
   102  		u.Host = fmt.Sprintf("%x", n.ID[:])
   103  	} else {
   104  		addr := net.TCPAddr{IP: n.IP, Port: int(n.TCP)}
   105  		u.User = url.User(fmt.Sprintf("%x", n.ID[:]))
   106  		u.Host = addr.String()
   107  		if n.UDP != n.TCP {
   108  			u.RawQuery = "discport=" + strconv.Itoa(int(n.UDP))
   109  		}
   110  	}
   111  	return u.String()
   112  }
   113  
   114  var incompleteNodeURL = regexp.MustCompile("(?i)^(?:enode://)?([09a- f] +)$
   115  
   116  //ParseNode解析节点指示符。
   117  //
   118  //节点指示符有两种基本形式
   119  //-节点不完整,只有公钥(节点ID)
   120  //-包含公钥和IP/端口信息的完整节点
   121  //
   122  //对于不完整的节点,指示器必须类似于
   123  //
   124  //enode://<hex node id>
   125  //<十六进制节点ID >
   126  //
   127  //对于完整的节点,节点ID编码在用户名部分
   128  //以@符号与主机分隔的URL。主机名可以
   129  //仅作为IP地址提供,不允许使用DNS域名。
   130  //主机名部分中的端口是TCP侦听端口。如果
   131  //TCP和UDP(发现)端口不同,UDP端口指定为
   132  //查询参数“discport”。
   133  //
   134  //在下面的示例中,节点URL描述了
   135  //IP地址为10.3.58.6、TCP侦听端口为30303的节点。
   136  //和UDP发现端口30301。
   137  //
   138  //enode://<hex node id>@10.3.58.6:30303?磁盘端口=30301
   139  func ParseNode(rawurl string) (*Node, error) {
   140  	if m := incompleteNodeURL.FindStringSubmatch(rawurl); m != nil {
   141  		id, err := HexID(m[1])
   142  		if err != nil {
   143  			return nil, fmt.Errorf("invalid node ID (%v)", err)
   144  		}
   145  		return NewNode(id, nil, 0, 0), nil
   146  	}
   147  	return parseComplete(rawurl)
   148  }
   149  
   150  func parseComplete(rawurl string) (*Node, error) {
   151  	var (
   152  		id               NodeID
   153  		ip               net.IP
   154  		tcpPort, udpPort uint64
   155  	)
   156  	u, err := url.Parse(rawurl)
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  	if u.Scheme != "enode" {
   161  		return nil, errors.New("invalid URL scheme, want \"enode\"")
   162  	}
   163  //从用户部分分析节点ID。
   164  	if u.User == nil {
   165  		return nil, errors.New("does not contain node ID")
   166  	}
   167  	if id, err = HexID(u.User.String()); err != nil {
   168  		return nil, fmt.Errorf("invalid node ID (%v)", err)
   169  	}
   170  //分析IP地址。
   171  	host, port, err := net.SplitHostPort(u.Host)
   172  	if err != nil {
   173  		return nil, fmt.Errorf("invalid host: %v", err)
   174  	}
   175  	if ip = net.ParseIP(host); ip == nil {
   176  		return nil, errors.New("invalid IP address")
   177  	}
   178  //确保IPv4地址的IP长度为4字节。
   179  	if ipv4 := ip.To4(); ipv4 != nil {
   180  		ip = ipv4
   181  	}
   182  //分析端口号。
   183  	if tcpPort, err = strconv.ParseUint(port, 10, 16); err != nil {
   184  		return nil, errors.New("invalid port")
   185  	}
   186  	udpPort = tcpPort
   187  	qv := u.Query()
   188  	if qv.Get("discport") != "" {
   189  		udpPort, err = strconv.ParseUint(qv.Get("discport"), 10, 16)
   190  		if err != nil {
   191  			return nil, errors.New("invalid discport in query")
   192  		}
   193  	}
   194  	return NewNode(id, ip, uint16(udpPort), uint16(tcpPort)), nil
   195  }
   196  
   197  //mustParseNode解析节点URL。如果URL无效,它会恐慌。
   198  func MustParseNode(rawurl string) *Node {
   199  	n, err := ParseNode(rawurl)
   200  	if err != nil {
   201  		panic("invalid node URL: " + err.Error())
   202  	}
   203  	return n
   204  }
   205  
   206  //MarshalText实现Encoding.TextMarshaler。
   207  func (n *Node) MarshalText() ([]byte, error) {
   208  	return []byte(n.String()), nil
   209  }
   210  
   211  //UnmarshalText实现encoding.textUnmarshaller。
   212  func (n *Node) UnmarshalText(text []byte) error {
   213  	dec, err := ParseNode(string(text))
   214  	if err == nil {
   215  		*n = *dec
   216  	}
   217  	return err
   218  }
   219  
   220  //nodeid是每个节点的唯一标识符。
   221  //节点标识符是一个封送椭圆曲线公钥。
   222  type NodeID [NodeIDBits / 8]byte
   223  
   224  //bytes返回nodeid的字节片表示形式
   225  func (n NodeID) Bytes() []byte {
   226  	return n[:]
   227  }
   228  
   229  //nodeid以十六进制长数字打印。
   230  func (n NodeID) String() string {
   231  	return fmt.Sprintf("%x", n[:])
   232  }
   233  
   234  //nodeid的go语法表示是对hexid的调用。
   235  func (n NodeID) GoString() string {
   236  	return fmt.Sprintf("discover.HexID(\"%x\")", n[:])
   237  }
   238  
   239  //TerminalString返回用于终端日志记录的缩短的十六进制字符串。
   240  func (n NodeID) TerminalString() string {
   241  	return hex.EncodeToString(n[:8])
   242  }
   243  
   244  //MarshalText实现Encoding.TextMarshaler接口。
   245  func (n NodeID) MarshalText() ([]byte, error) {
   246  	return []byte(hex.EncodeToString(n[:])), nil
   247  }
   248  
   249  //UnmarshalText实现encoding.textUnmarshaller接口。
   250  func (n *NodeID) UnmarshalText(text []byte) error {
   251  	id, err := HexID(string(text))
   252  	if err != nil {
   253  		return err
   254  	}
   255  	*n = id
   256  	return nil
   257  }
   258  
   259  //bytesid将字节片转换为nodeid
   260  func BytesID(b []byte) (NodeID, error) {
   261  	var id NodeID
   262  	if len(b) != len(id) {
   263  		return id, fmt.Errorf("wrong length, want %d bytes", len(id))
   264  	}
   265  	copy(id[:], b)
   266  	return id, nil
   267  }
   268  
   269  //mustbytesid将字节片转换为nodeid。
   270  //如果字节片不是有效的nodeid,它会恐慌。
   271  func MustBytesID(b []byte) NodeID {
   272  	id, err := BytesID(b)
   273  	if err != nil {
   274  		panic(err)
   275  	}
   276  	return id
   277  }
   278  
   279  //hexid将十六进制字符串转换为nodeid。
   280  //字符串的前缀可以是0x。
   281  func HexID(in string) (NodeID, error) {
   282  	var id NodeID
   283  	b, err := hex.DecodeString(strings.TrimPrefix(in, "0x"))
   284  	if err != nil {
   285  		return id, err
   286  	} else if len(b) != len(id) {
   287  		return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2)
   288  	}
   289  	copy(id[:], b)
   290  	return id, nil
   291  }
   292  
   293  //musthexid将十六进制字符串转换为nodeid。
   294  //如果字符串不是有效的nodeid,它会恐慌。
   295  func MustHexID(in string) NodeID {
   296  	id, err := HexID(in)
   297  	if err != nil {
   298  		panic(err)
   299  	}
   300  	return id
   301  }
   302  
   303  //pubkeyid返回给定公钥的封送表示形式。
   304  func PubkeyID(pub *ecdsa.PublicKey) NodeID {
   305  	var id NodeID
   306  	pbytes := elliptic.Marshal(pub.Curve, pub.X, pub.Y)
   307  	if len(pbytes)-1 != len(id) {
   308  		panic(fmt.Errorf("need %d bit pubkey, got %d bits", (len(id)+1)*8, len(pbytes)))
   309  	}
   310  	copy(id[:], pbytes[1:])
   311  	return id
   312  }
   313  
   314  //pubkey返回由节点ID表示的公钥。
   315  //如果ID不是曲线上的点,则返回错误。
   316  func (id NodeID) Pubkey() (*ecdsa.PublicKey, error) {
   317  	p := &ecdsa.PublicKey{Curve: crypto.S256(), X: new(big.Int), Y: new(big.Int)}
   318  	half := len(id) / 2
   319  	p.X.SetBytes(id[:half])
   320  	p.Y.SetBytes(id[half:])
   321  	if !p.Curve.IsOnCurve(p.X, p.Y) {
   322  		return nil, errors.New("id is invalid secp256k1 curve point")
   323  	}
   324  	return p, nil
   325  }
   326  
   327  //recovernodeid计算用于签名的公钥
   328  //从签名中给定哈希。
   329  func recoverNodeID(hash, sig []byte) (id NodeID, err error) {
   330  	pubkey, err := secp256k1.RecoverPubkey(hash, sig)
   331  	if err != nil {
   332  		return id, err
   333  	}
   334  	if len(pubkey)-1 != len(id) {
   335  		return id, fmt.Errorf("recovered pubkey has %d bits, want %d bits", len(pubkey)*8, (len(id)+1)*8)
   336  	}
   337  	for i := range id {
   338  		id[i] = pubkey[i+1]
   339  	}
   340  	return id, nil
   341  }
   342  
   343  //distcmp比较距离a->target和b->target。
   344  //如果a接近目标返回-1,如果b接近目标返回1
   345  //如果相等,则为0。
   346  func distcmp(target, a, b common.Hash) int {
   347  	for i := range target {
   348  		da := a[i] ^ target[i]
   349  		db := b[i] ^ target[i]
   350  		if da > db {
   351  			return 1
   352  		} else if da < db {
   353  			return -1
   354  		}
   355  	}
   356  	return 0
   357  }
   358  
   359  //字节[0..255]的前导零计数表
   360  var lzcount = [256]int{
   361  	8, 7, 6, 6, 5, 5, 5, 5,
   362  	4, 4, 4, 4, 4, 4, 4, 4,
   363  	3, 3, 3, 3, 3, 3, 3, 3,
   364  	3, 3, 3, 3, 3, 3, 3, 3,
   365  	2, 2, 2, 2, 2, 2, 2, 2,
   366  	2, 2, 2, 2, 2, 2, 2, 2,
   367  	2, 2, 2, 2, 2, 2, 2, 2,
   368  	2, 2, 2, 2, 2, 2, 2, 2,
   369  	1, 1, 1, 1, 1, 1, 1, 1,
   370  	1, 1, 1, 1, 1, 1, 1, 1,
   371  	1, 1, 1, 1, 1, 1, 1, 1,
   372  	1, 1, 1, 1, 1, 1, 1, 1,
   373  	1, 1, 1, 1, 1, 1, 1, 1,
   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  	0, 0, 0, 0, 0, 0, 0, 0,
   378  	0, 0, 0, 0, 0, 0, 0, 0,
   379  	0, 0, 0, 0, 0, 0, 0, 0,
   380  	0, 0, 0, 0, 0, 0, 0, 0,
   381  	0, 0, 0, 0, 0, 0, 0, 0,
   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  }
   394  
   395  //logdist返回a和b之间的对数距离,log2(a^b)。
   396  func logdist(a, b common.Hash) int {
   397  	lz := 0
   398  	for i := range a {
   399  		x := a[i] ^ b[i]
   400  		if x == 0 {
   401  			lz += 8
   402  		} else {
   403  			lz += lzcount[x]
   404  			break
   405  		}
   406  	}
   407  	return len(a)*8 - lz
   408  }
   409  
   410  //hashatDistance返回一个随机哈希,使logDist(a,b)=n
   411  func hashAtDistance(a common.Hash, n int) (b common.Hash) {
   412  	if n == 0 {
   413  		return a
   414  	}
   415  //在n位置翻转钻头,其余部分用随机钻头填满。
   416  	b = a
   417  	pos := len(a) - n/8 - 1
   418  	bit := byte(0x01) << (byte(n%8) - 1)
   419  	if bit == 0 {
   420  		pos++
   421  		bit = 0x80
   422  	}
   423  b[pos] = a[pos]&^bit | ^a[pos]&bit //TODO:随机结束位
   424  	for i := pos + 1; i < len(a); i++ {
   425  		b[i] = byte(rand.Intn(255))
   426  	}
   427  	return b
   428  }
   429