github.com/simplechain-org/go-simplechain@v1.0.6/p2p/discv5/node.go (about) 1 // Copyright 2015 The go-simplechain Authors 2 // This file is part of the go-simplechain library. 3 // 4 // The go-simplechain 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-simplechain 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-simplechain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package discv5 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/simplechain-org/go-simplechain/common" 34 "github.com/simplechain-org/go-simplechain/crypto" 35 ) 36 37 // Node represents a host on the network. 38 // The public fields of Node may not be modified. 39 type Node struct { 40 IP net.IP // len 4 for IPv4 or 16 for IPv6 41 UDP, TCP uint16 // port numbers 42 ID NodeID // the node's public key 43 44 // Network-related fields are contained in nodeNetGuts. 45 // These fields are not supposed to be used off the 46 // Network.loop goroutine. 47 nodeNetGuts 48 } 49 50 // NewNode creates a new node. It is mostly meant to be used for 51 // testing purposes. 52 func NewNode(id NodeID, ip net.IP, udpPort, tcpPort uint16) *Node { 53 if ipv4 := ip.To4(); ipv4 != nil { 54 ip = ipv4 55 } 56 return &Node{ 57 IP: ip, 58 UDP: udpPort, 59 TCP: tcpPort, 60 ID: id, 61 nodeNetGuts: nodeNetGuts{sha: crypto.Keccak256Hash(id[:])}, 62 } 63 } 64 65 func (n *Node) addr() *net.UDPAddr { 66 return &net.UDPAddr{IP: n.IP, Port: int(n.UDP)} 67 } 68 69 // Incomplete returns true for nodes with no IP address. 70 func (n *Node) Incomplete() bool { 71 return n.IP == nil 72 } 73 74 // checks whether n is a valid complete node. 75 func (n *Node) validateComplete() error { 76 if n.Incomplete() { 77 return errors.New("incomplete node") 78 } 79 if n.UDP == 0 { 80 return errors.New("missing UDP port") 81 } 82 if n.TCP == 0 { 83 return errors.New("missing TCP port") 84 } 85 if n.IP.IsMulticast() || n.IP.IsUnspecified() { 86 return errors.New("invalid IP (multicast/unspecified)") 87 } 88 _, err := n.ID.Pubkey() // validate the key (on curve, etc.) 89 return err 90 } 91 92 // The string representation of a Node is a URL. 93 // Please see ParseNode for a description of the format. 94 func (n *Node) String() string { 95 u := url.URL{Scheme: "enode"} 96 if n.Incomplete() { 97 u.Host = fmt.Sprintf("%x", n.ID[:]) 98 } else { 99 addr := net.TCPAddr{IP: n.IP, Port: int(n.TCP)} 100 u.User = url.User(fmt.Sprintf("%x", n.ID[:])) 101 u.Host = addr.String() 102 if n.UDP != n.TCP { 103 u.RawQuery = "discport=" + strconv.Itoa(int(n.UDP)) 104 } 105 } 106 return u.String() 107 } 108 109 var incompleteNodeURL = regexp.MustCompile("(?i)^(?:enode://)?([0-9a-f]+)$") 110 111 // ParseNode parses a node designator. 112 // 113 // There are two basic forms of node designators 114 // - incomplete nodes, which only have the public key (node ID) 115 // - complete nodes, which contain the public key and IP/Port information 116 // 117 // For incomplete nodes, the designator must look like one of these 118 // 119 // enode://<hex node id> 120 // <hex node id> 121 // 122 // For complete nodes, the node ID is encoded in the username portion 123 // of the URL, separated from the host by an @ sign. The hostname can 124 // only be given as an IP address, DNS domain names are not allowed. 125 // The port in the host name section is the TCP listening port. If the 126 // TCP and UDP (discovery) ports differ, the UDP port is specified as 127 // query parameter "discport". 128 // 129 // In the following example, the node URL describes 130 // a node with IP address 10.3.58.6, TCP listening port 30303 131 // and UDP discovery port 30301. 132 // 133 // enode://<hex node id>@10.3.58.6:30303?discport=30301 134 func ParseNode(rawurl string) (*Node, error) { 135 if m := incompleteNodeURL.FindStringSubmatch(rawurl); m != nil { 136 id, err := HexID(m[1]) 137 if err != nil { 138 return nil, fmt.Errorf("invalid node ID (%v)", err) 139 } 140 return NewNode(id, nil, 0, 0), nil 141 } 142 return parseComplete(rawurl) 143 } 144 145 func parseComplete(rawurl string) (*Node, error) { 146 var ( 147 id NodeID 148 ip net.IP 149 tcpPort, udpPort uint64 150 ) 151 u, err := url.Parse(rawurl) 152 if err != nil { 153 return nil, err 154 } 155 if u.Scheme != "enode" { 156 return nil, errors.New("invalid URL scheme, want \"enode\"") 157 } 158 // Parse the Node ID from the user portion. 159 if u.User == nil { 160 return nil, errors.New("does not contain node ID") 161 } 162 if id, err = HexID(u.User.String()); err != nil { 163 return nil, fmt.Errorf("invalid node ID (%v)", err) 164 } 165 // Parse the IP address. 166 host, port, err := net.SplitHostPort(u.Host) 167 if err != nil { 168 return nil, fmt.Errorf("invalid host: %v", err) 169 } 170 if ip = net.ParseIP(host); ip == nil { 171 return nil, errors.New("invalid IP address") 172 } 173 // Ensure the IP is 4 bytes long for IPv4 addresses. 174 if ipv4 := ip.To4(); ipv4 != nil { 175 ip = ipv4 176 } 177 // Parse the port numbers. 178 if tcpPort, err = strconv.ParseUint(port, 10, 16); err != nil { 179 return nil, errors.New("invalid port") 180 } 181 udpPort = tcpPort 182 qv := u.Query() 183 if qv.Get("discport") != "" { 184 udpPort, err = strconv.ParseUint(qv.Get("discport"), 10, 16) 185 if err != nil { 186 return nil, errors.New("invalid discport in query") 187 } 188 } 189 return NewNode(id, ip, uint16(udpPort), uint16(tcpPort)), nil 190 } 191 192 // MustParseNode parses a node URL. It panics if the URL is not valid. 193 func MustParseNode(rawurl string) *Node { 194 n, err := ParseNode(rawurl) 195 if err != nil { 196 panic("invalid node URL: " + err.Error()) 197 } 198 return n 199 } 200 201 // MarshalText implements encoding.TextMarshaler. 202 func (n *Node) MarshalText() ([]byte, error) { 203 return []byte(n.String()), nil 204 } 205 206 // UnmarshalText implements encoding.TextUnmarshaler. 207 func (n *Node) UnmarshalText(text []byte) error { 208 dec, err := ParseNode(string(text)) 209 if err == nil { 210 *n = *dec 211 } 212 return err 213 } 214 215 // type nodeQueue []*Node 216 // 217 // // pushNew adds n to the end if it is not present. 218 // func (nl *nodeList) appendNew(n *Node) { 219 // for _, entry := range n { 220 // if entry == n { 221 // return 222 // } 223 // } 224 // *nq = append(*nq, n) 225 // } 226 // 227 // // popRandom removes a random node. Nodes closer to 228 // // to the head of the beginning of the have a slightly higher probability. 229 // func (nl *nodeList) popRandom() *Node { 230 // ix := rand.Intn(len(*nq)) 231 // //TODO: probability as mentioned above. 232 // nl.removeIndex(ix) 233 // } 234 // 235 // func (nl *nodeList) removeIndex(i int) *Node { 236 // slice = *nl 237 // if len(*slice) <= i { 238 // return nil 239 // } 240 // *nl = append(slice[:i], slice[i+1:]...) 241 // } 242 243 const nodeIDBits = 512 244 245 // NodeID is a unique identifier for each node. 246 // The node identifier is a marshaled elliptic curve public key. 247 type NodeID [nodeIDBits / 8]byte 248 249 // NodeID prints as a long hexadecimal number. 250 func (n NodeID) String() string { 251 return fmt.Sprintf("%x", n[:]) 252 } 253 254 // The Go syntax representation of a NodeID is a call to HexID. 255 func (n NodeID) GoString() string { 256 return fmt.Sprintf("discover.HexID(\"%x\")", n[:]) 257 } 258 259 // TerminalString returns a shortened hex string for terminal logging. 260 func (n NodeID) TerminalString() string { 261 return hex.EncodeToString(n[:8]) 262 } 263 264 // HexID converts a hex string to a NodeID. 265 // The string may be prefixed with 0x. 266 func HexID(in string) (NodeID, error) { 267 var id NodeID 268 b, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) 269 if err != nil { 270 return id, err 271 } else if len(b) != len(id) { 272 return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2) 273 } 274 copy(id[:], b) 275 return id, nil 276 } 277 278 // MustHexID converts a hex string to a NodeID. 279 // It panics if the string is not a valid NodeID. 280 func MustHexID(in string) NodeID { 281 id, err := HexID(in) 282 if err != nil { 283 panic(err) 284 } 285 return id 286 } 287 288 // PubkeyID returns a marshaled representation of the given public key. 289 func PubkeyID(pub *ecdsa.PublicKey) NodeID { 290 var id NodeID 291 pbytes := elliptic.Marshal(pub.Curve, pub.X, pub.Y) 292 if len(pbytes)-1 != len(id) { 293 panic(fmt.Errorf("need %d bit pubkey, got %d bits", (len(id)+1)*8, len(pbytes))) 294 } 295 copy(id[:], pbytes[1:]) 296 return id 297 } 298 299 // Pubkey returns the public key represented by the node ID. 300 // It returns an error if the ID is not a point on the curve. 301 func (n NodeID) Pubkey() (*ecdsa.PublicKey, error) { 302 p := &ecdsa.PublicKey{Curve: crypto.S256(), X: new(big.Int), Y: new(big.Int)} 303 half := len(n) / 2 304 p.X.SetBytes(n[:half]) 305 p.Y.SetBytes(n[half:]) 306 if !p.Curve.IsOnCurve(p.X, p.Y) { 307 return nil, errors.New("id is invalid secp256k1 curve point") 308 } 309 return p, nil 310 } 311 312 // recoverNodeID computes the public key used to sign the 313 // given hash from the signature. 314 func recoverNodeID(hash, sig []byte) (id NodeID, err error) { 315 pubkey, err := crypto.Ecrecover(hash, sig) 316 if err != nil { 317 return id, err 318 } 319 if len(pubkey)-1 != len(id) { 320 return id, fmt.Errorf("recovered pubkey has %d bits, want %d bits", len(pubkey)*8, (len(id)+1)*8) 321 } 322 for i := range id { 323 id[i] = pubkey[i+1] 324 } 325 return id, nil 326 } 327 328 // distcmp compares the distances a->target and b->target. 329 // Returns -1 if a is closer to target, 1 if b is closer to target 330 // and 0 if they are equal. 331 func distcmp(target, a, b common.Hash) int { 332 for i := range target { 333 da := a[i] ^ target[i] 334 db := b[i] ^ target[i] 335 if da > db { 336 return 1 337 } else if da < db { 338 return -1 339 } 340 } 341 return 0 342 } 343 344 // table of leading zero counts for bytes [0..255] 345 var lzcount = [256]int{ 346 8, 7, 6, 6, 5, 5, 5, 5, 347 4, 4, 4, 4, 4, 4, 4, 4, 348 3, 3, 3, 3, 3, 3, 3, 3, 349 3, 3, 3, 3, 3, 3, 3, 3, 350 2, 2, 2, 2, 2, 2, 2, 2, 351 2, 2, 2, 2, 2, 2, 2, 2, 352 2, 2, 2, 2, 2, 2, 2, 2, 353 2, 2, 2, 2, 2, 2, 2, 2, 354 1, 1, 1, 1, 1, 1, 1, 1, 355 1, 1, 1, 1, 1, 1, 1, 1, 356 1, 1, 1, 1, 1, 1, 1, 1, 357 1, 1, 1, 1, 1, 1, 1, 1, 358 1, 1, 1, 1, 1, 1, 1, 1, 359 1, 1, 1, 1, 1, 1, 1, 1, 360 1, 1, 1, 1, 1, 1, 1, 1, 361 1, 1, 1, 1, 1, 1, 1, 1, 362 0, 0, 0, 0, 0, 0, 0, 0, 363 0, 0, 0, 0, 0, 0, 0, 0, 364 0, 0, 0, 0, 0, 0, 0, 0, 365 0, 0, 0, 0, 0, 0, 0, 0, 366 0, 0, 0, 0, 0, 0, 0, 0, 367 0, 0, 0, 0, 0, 0, 0, 0, 368 0, 0, 0, 0, 0, 0, 0, 0, 369 0, 0, 0, 0, 0, 0, 0, 0, 370 0, 0, 0, 0, 0, 0, 0, 0, 371 0, 0, 0, 0, 0, 0, 0, 0, 372 0, 0, 0, 0, 0, 0, 0, 0, 373 0, 0, 0, 0, 0, 0, 0, 0, 374 0, 0, 0, 0, 0, 0, 0, 0, 375 0, 0, 0, 0, 0, 0, 0, 0, 376 0, 0, 0, 0, 0, 0, 0, 0, 377 0, 0, 0, 0, 0, 0, 0, 0, 378 } 379 380 // logdist returns the logarithmic distance between a and b, log2(a ^ b). 381 func logdist(a, b common.Hash) int { 382 lz := 0 383 for i := range a { 384 x := a[i] ^ b[i] 385 if x == 0 { 386 lz += 8 387 } else { 388 lz += lzcount[x] 389 break 390 } 391 } 392 return len(a)*8 - lz 393 } 394 395 // hashAtDistance returns a random hash such that logdist(a, b) == n 396 func hashAtDistance(a common.Hash, n int) (b common.Hash) { 397 if n == 0 { 398 return a 399 } 400 // flip bit at position n, fill the rest with random bits 401 b = a 402 pos := len(a) - n/8 - 1 403 bit := byte(0x01) << (byte(n%8) - 1) 404 if bit == 0 { 405 pos++ 406 bit = 0x80 407 } 408 b[pos] = a[pos]&^bit | ^a[pos]&bit // TODO: randomize end bits 409 for i := pos + 1; i < len(a); i++ { 410 b[i] = byte(rand.Intn(255)) 411 } 412 return b 413 }