github.com/waltonchain/waltonchain_gwtc_src@v1.1.4-0.20201225072101-8a298c95a819/p2p/discover/node.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-wtc library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-wtc library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package discover 18 19 import ( 20 "crypto/ecdsa" 21 "crypto/elliptic" 22 "encoding/hex" 23 "errors" 24 "fmt" 25 "math/big" 26 "math/rand" 27 "net" 28 "net/url" 29 "regexp" 30 "strconv" 31 "strings" 32 33 "github.com/wtc/go-wtc/common" 34 "github.com/wtc/go-wtc/crypto" 35 "github.com/wtc/go-wtc/crypto/secp256k1" 36 ) 37 38 const NodeIDBits = 512 39 40 // Node represents a host on the network. 41 // The fields of Node may not be modified. 42 type Node struct { 43 IP net.IP // len 4 for IPv4 or 16 for IPv6 44 UDP, TCP uint16 // port numbers 45 ID NodeID // the node's public key 46 47 // This is a cached copy of sha3(ID) which is used for node 48 // distance calculations. This is part of Node in order to make it 49 // possible to write tests that need a node at a certain distance. 50 // In those tests, the content of sha will not actually correspond 51 // with ID. 52 sha common.Hash 53 54 // whether this node is currently being pinged in order to replace 55 // it in a bucket 56 contested bool 57 } 58 59 // NewNode creates a new node. It is mostly meant to be used for 60 // testing purposes. 61 func NewNode(id NodeID, ip net.IP, udpPort, tcpPort uint16) *Node { 62 if ipv4 := ip.To4(); ipv4 != nil { 63 ip = ipv4 64 } 65 return &Node{ 66 IP: ip, 67 UDP: udpPort, 68 TCP: tcpPort, 69 ID: id, 70 sha: crypto.Keccak256Hash(id[:]), 71 } 72 } 73 74 func (n *Node) addr() *net.UDPAddr { 75 return &net.UDPAddr{IP: n.IP, Port: int(n.UDP)} 76 } 77 78 // Incomplete returns true for nodes with no IP address. 79 func (n *Node) Incomplete() bool { 80 return n.IP == nil 81 } 82 83 // checks whether n is a valid complete node. 84 func (n *Node) validateComplete() error { 85 if n.Incomplete() { 86 return errors.New("incomplete node") 87 } 88 if n.UDP == 0 { 89 return errors.New("missing UDP port") 90 } 91 if n.TCP == 0 { 92 return errors.New("missing TCP port") 93 } 94 if n.IP.IsMulticast() || n.IP.IsUnspecified() { 95 return errors.New("invalid IP (multicast/unspecified)") 96 } 97 _, err := n.ID.Pubkey() // validate the key (on curve, etc.) 98 return err 99 } 100 101 // The string representation of a Node is a URL. 102 // Please see ParseNode for a description of the format. 103 func (n *Node) String() string { 104 u := url.URL{Scheme: "enode"} 105 if n.Incomplete() { 106 u.Host = fmt.Sprintf("%x", n.ID[:]) 107 } else { 108 addr := net.TCPAddr{IP: n.IP, Port: int(n.TCP)} 109 u.User = url.User(fmt.Sprintf("%x", n.ID[:])) 110 u.Host = addr.String() 111 if n.UDP != n.TCP { 112 u.RawQuery = "discport=" + strconv.Itoa(int(n.UDP)) 113 } 114 } 115 return u.String() 116 } 117 118 var incompleteNodeURL = regexp.MustCompile("(?i)^(?:enode://)?([0-9a-f]+)$") 119 120 // ParseNode parses a node designator. 121 // 122 // There are two basic forms of node designators 123 // - incomplete nodes, which only have the public key (node ID) 124 // - complete nodes, which contain the public key and IP/Port information 125 // 126 // For incomplete nodes, the designator must look like one of these 127 // 128 // enode://<hex node id> 129 // <hex node id> 130 // 131 // For complete nodes, the node ID is encoded in the username portion 132 // of the URL, separated from the host by an @ sign. The hostname can 133 // only be given as an IP address, DNS domain names are not allowed. 134 // The port in the host name section is the TCP listening port. If the 135 // TCP and UDP (discovery) ports differ, the UDP port is specified as 136 // query parameter "discport". 137 // 138 // In the following example, the node URL describes 139 // a node with IP address 10.3.58.6, TCP listening port 10101 140 // and UDP discovery port 30301. 141 // 142 // enode://<hex node id>@10.3.58.6:10101?discport=30301 143 func ParseNode(rawurl string) (*Node, error) { 144 if m := incompleteNodeURL.FindStringSubmatch(rawurl); m != nil { 145 id, err := HexID(m[1]) 146 if err != nil { 147 return nil, fmt.Errorf("invalid node ID (%v)", err) 148 } 149 return NewNode(id, nil, 0, 0), nil 150 } 151 return parseComplete(rawurl) 152 } 153 154 func parseComplete(rawurl string) (*Node, error) { 155 var ( 156 id NodeID 157 ip net.IP 158 tcpPort, udpPort uint64 159 ) 160 u, err := url.Parse(rawurl) 161 if err != nil { 162 return nil, err 163 } 164 if u.Scheme != "enode" { 165 return nil, errors.New("invalid URL scheme, want \"enode\"") 166 } 167 // Parse the Node ID from the user portion. 168 if u.User == nil { 169 return nil, errors.New("does not contain node ID") 170 } 171 if id, err = HexID(u.User.String()); err != nil { 172 return nil, fmt.Errorf("invalid node ID (%v)", err) 173 } 174 // Parse the IP address. 175 host, port, err := net.SplitHostPort(u.Host) 176 if err != nil { 177 return nil, fmt.Errorf("invalid host: %v", err) 178 } 179 addrs, _ := net.LookupHost(host) 180 181 if len(addrs) == 0 { 182 return nil, errors.New("invalid URL address") 183 } 184 185 if len(addrs) == 1 { 186 host = addrs[0] 187 } else { 188 host = addrs[1] 189 } 190 191 if ip = net.ParseIP(host); ip == nil { 192 return nil, errors.New("invalid IP address") 193 } 194 // Ensure the IP is 4 bytes long for IPv4 addresses. 195 if ipv4 := ip.To4(); ipv4 != nil { 196 ip = ipv4 197 } 198 // Parse the port numbers. 199 if tcpPort, err = strconv.ParseUint(port, 10, 16); err != nil { 200 return nil, errors.New("invalid port") 201 } 202 udpPort = tcpPort 203 qv := u.Query() 204 if qv.Get("discport") != "" { 205 udpPort, err = strconv.ParseUint(qv.Get("discport"), 10, 16) 206 if err != nil { 207 return nil, errors.New("invalid discport in query") 208 } 209 } 210 return NewNode(id, ip, uint16(udpPort), uint16(tcpPort)), nil 211 } 212 213 // MustParseNode parses a node URL. It panics if the URL is not valid. 214 func MustParseNode(rawurl string) *Node { 215 n, err := ParseNode(rawurl) 216 if err != nil { 217 panic("invalid node URL: " + err.Error()) 218 } 219 return n 220 } 221 222 // MarshalText implements encoding.TextMarshaler. 223 func (n *Node) MarshalText() ([]byte, error) { 224 return []byte(n.String()), nil 225 } 226 227 // UnmarshalText implements encoding.TextUnmarshaler. 228 func (n *Node) UnmarshalText(text []byte) error { 229 dec, err := ParseNode(string(text)) 230 if err == nil { 231 *n = *dec 232 } 233 return err 234 } 235 236 // NodeID is a unique identifier for each node. 237 // The node identifier is a marshaled elliptic curve public key. 238 type NodeID [NodeIDBits / 8]byte 239 240 // Bytes returns a byte slice representation of the NodeID 241 func (n NodeID) Bytes() []byte { 242 return n[:] 243 } 244 245 // NodeID prints as a long hexadecimal number. 246 func (n NodeID) String() string { 247 return fmt.Sprintf("%x", n[:]) 248 } 249 250 // The Go syntax representation of a NodeID is a call to HexID. 251 func (n NodeID) GoString() string { 252 return fmt.Sprintf("discover.HexID(\"%x\")", n[:]) 253 } 254 255 // TerminalString returns a shortened hex string for terminal logging. 256 func (n NodeID) TerminalString() string { 257 return hex.EncodeToString(n[:8]) 258 } 259 260 // MarshalText implements the encoding.TextMarshaler interface. 261 func (n NodeID) MarshalText() ([]byte, error) { 262 return []byte(hex.EncodeToString(n[:])), nil 263 } 264 265 // UnmarshalText implements the encoding.TextUnmarshaler interface. 266 func (n *NodeID) UnmarshalText(text []byte) error { 267 id, err := HexID(string(text)) 268 if err != nil { 269 return err 270 } 271 *n = id 272 return nil 273 } 274 275 // BytesID converts a byte slice to a NodeID 276 func BytesID(b []byte) (NodeID, error) { 277 var id NodeID 278 if len(b) != len(id) { 279 return id, fmt.Errorf("wrong length, want %d bytes", len(id)) 280 } 281 copy(id[:], b) 282 return id, nil 283 } 284 285 // MustBytesID converts a byte slice to a NodeID. 286 // It panics if the byte slice is not a valid NodeID. 287 func MustBytesID(b []byte) NodeID { 288 id, err := BytesID(b) 289 if err != nil { 290 panic(err) 291 } 292 return id 293 } 294 295 // HexID converts a hex string to a NodeID. 296 // The string may be prefixed with 0x. 297 func HexID(in string) (NodeID, error) { 298 var id NodeID 299 b, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) 300 if err != nil { 301 return id, err 302 } else if len(b) != len(id) { 303 return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2) 304 } 305 copy(id[:], b) 306 return id, nil 307 } 308 309 // MustHexID converts a hex string to a NodeID. 310 // It panics if the string is not a valid NodeID. 311 func MustHexID(in string) NodeID { 312 id, err := HexID(in) 313 if err != nil { 314 panic(err) 315 } 316 return id 317 } 318 319 // PubkeyID returns a marshaled representation of the given public key. 320 func PubkeyID(pub *ecdsa.PublicKey) NodeID { 321 var id NodeID 322 pbytes := elliptic.Marshal(pub.Curve, pub.X, pub.Y) 323 if len(pbytes)-1 != len(id) { 324 panic(fmt.Errorf("need %d bit pubkey, got %d bits", (len(id)+1)*8, len(pbytes))) 325 } 326 copy(id[:], pbytes[1:]) 327 return id 328 } 329 330 // Pubkey returns the public key represented by the node ID. 331 // It returns an error if the ID is not a point on the curve. 332 func (id NodeID) Pubkey() (*ecdsa.PublicKey, error) { 333 p := &ecdsa.PublicKey{Curve: crypto.S256(), X: new(big.Int), Y: new(big.Int)} 334 half := len(id) / 2 335 p.X.SetBytes(id[:half]) 336 p.Y.SetBytes(id[half:]) 337 if !p.Curve.IsOnCurve(p.X, p.Y) { 338 return nil, errors.New("id is invalid secp256k1 curve point") 339 } 340 return p, nil 341 } 342 343 // recoverNodeID computes the public key used to sign the 344 // given hash from the signature. 345 func recoverNodeID(hash, sig []byte) (id NodeID, err error) { 346 pubkey, err := secp256k1.RecoverPubkey(hash, sig) 347 if err != nil { 348 return id, err 349 } 350 if len(pubkey)-1 != len(id) { 351 return id, fmt.Errorf("recovered pubkey has %d bits, want %d bits", len(pubkey)*8, (len(id)+1)*8) 352 } 353 for i := range id { 354 id[i] = pubkey[i+1] 355 } 356 return id, nil 357 } 358 359 // distcmp compares the distances a->target and b->target. 360 // Returns -1 if a is closer to target, 1 if b is closer to target 361 // and 0 if they are equal. 362 func distcmp(target, a, b common.Hash) int { 363 for i := range target { 364 da := a[i] ^ target[i] 365 db := b[i] ^ target[i] 366 if da > db { 367 return 1 368 } else if da < db { 369 return -1 370 } 371 } 372 return 0 373 } 374 375 // table of leading zero counts for bytes [0..255] 376 var lzcount = [256]int{ 377 8, 7, 6, 6, 5, 5, 5, 5, 378 4, 4, 4, 4, 4, 4, 4, 4, 379 3, 3, 3, 3, 3, 3, 3, 3, 380 3, 3, 3, 3, 3, 3, 3, 3, 381 2, 2, 2, 2, 2, 2, 2, 2, 382 2, 2, 2, 2, 2, 2, 2, 2, 383 2, 2, 2, 2, 2, 2, 2, 2, 384 2, 2, 2, 2, 2, 2, 2, 2, 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 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 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 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 } 410 411 // logdist returns the logarithmic distance between a and b, log2(a ^ b). 412 func logdist(a, b common.Hash) int { 413 lz := 0 414 for i := range a { 415 x := a[i] ^ b[i] 416 if x == 0 { 417 lz += 8 418 } else { 419 lz += lzcount[x] 420 break 421 } 422 } 423 return len(a)*8 - lz 424 } 425 426 // hashAtDistance returns a random hash such that logdist(a, b) == n 427 func hashAtDistance(a common.Hash, n int) (b common.Hash) { 428 if n == 0 { 429 return a 430 } 431 // flip bit at position n, fill the rest with random bits 432 b = a 433 pos := len(a) - n/8 - 1 434 bit := byte(0x01) << (byte(n%8) - 1) 435 if bit == 0 { 436 pos++ 437 bit = 0x80 438 } 439 b[pos] = a[pos]&^bit | ^a[pos]&bit // TODO: randomize end bits 440 for i := pos + 1; i < len(a); i++ { 441 b[i] = byte(rand.Intn(255)) 442 } 443 return b 444 }