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