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 }