github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/discover/node.go (about)

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