github.com/Night-mk/quorum@v21.1.0+incompatible/p2p/enode/node.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum 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-ethereum 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 enode 18 19 import ( 20 "crypto/ecdsa" 21 "encoding/base64" 22 "encoding/hex" 23 "errors" 24 "fmt" 25 "math/bits" 26 "math/rand" 27 "net" 28 "strings" 29 30 "github.com/ethereum/go-ethereum/p2p/enr" 31 "github.com/ethereum/go-ethereum/rlp" 32 ) 33 34 var errMissingPrefix = errors.New("missing 'enr:' prefix for base64-encoded record") 35 36 // Node represents a host on the network. 37 type Node struct { 38 r enr.Record 39 id ID 40 } 41 42 // New wraps a node record. The record must be valid according to the given 43 // identity scheme. 44 func New(validSchemes enr.IdentityScheme, r *enr.Record) (*Node, error) { 45 if err := r.VerifySignature(validSchemes); err != nil { 46 return nil, err 47 } 48 node := &Node{r: *r} 49 if n := copy(node.id[:], validSchemes.NodeAddr(&node.r)); n != len(ID{}) { 50 return nil, fmt.Errorf("invalid node ID length %d, need %d", n, len(ID{})) 51 } 52 return node, nil 53 } 54 55 // MustParse parses a node record or enode:// URL. It panics if the input is invalid. 56 func MustParse(rawurl string) *Node { 57 n, err := Parse(ValidSchemes, rawurl) 58 if err != nil { 59 panic("invalid node: " + err.Error()) 60 } 61 return n 62 } 63 64 // Parse decodes and verifies a base64-encoded node record. 65 func Parse(validSchemes enr.IdentityScheme, input string) (*Node, error) { 66 if strings.HasPrefix(input, "enode://") { 67 return ParseV4(input) 68 } 69 if !strings.HasPrefix(input, "enr:") { 70 return nil, errMissingPrefix 71 } 72 bin, err := base64.RawURLEncoding.DecodeString(input[4:]) 73 if err != nil { 74 return nil, err 75 } 76 var r enr.Record 77 if err := rlp.DecodeBytes(bin, &r); err != nil { 78 return nil, err 79 } 80 return New(validSchemes, &r) 81 } 82 83 // ID returns the node identifier. 84 func (n *Node) ID() ID { 85 return n.id 86 } 87 88 // Seq returns the sequence number of the underlying record. 89 func (n *Node) Seq() uint64 { 90 return n.r.Seq() 91 } 92 93 // Quorum 94 // Incomplete returns true for nodes with no IP address and no hostname if with raftport. 95 func (n *Node) Incomplete() bool { 96 return n.IP() == nil && (!n.HasRaftPort() || (n.Host() == "" && n.HasRaftPort())) 97 } 98 99 // Load retrieves an entry from the underlying record. 100 func (n *Node) Load(k enr.Entry) error { 101 return n.r.Load(k) 102 } 103 104 // IP returns the IP address of the node. 105 // 106 // Quorum 107 // To support DNS lookup in node ip. The function performs hostname lookup if hostname is defined in enr.Hostname 108 // and falls back to enr.IP value in case of failure. It also makes sure the resolved IP is in IPv4 or IPv6 format 109 func (n *Node) IP() net.IP { 110 if n.Host() == "" { 111 // no host is set, so use the IP directly 112 return n.loadIP() 113 } 114 // attempt to look up IP addresses if host is a FQDN 115 lookupIPs, err := net.LookupIP(n.Host()) 116 if err != nil { 117 return n.loadIP() 118 } 119 // set to first ip by default & as Ethereum upstream 120 ip := lookupIPs[0] 121 // Ensure the IP is 4 bytes long for IPv4 addresses. 122 if ipv4 := ip.To4(); ipv4 != nil { 123 ip = ipv4 124 } 125 return ip 126 } 127 128 func (n *Node) loadIP() net.IP { 129 var ( 130 ip4 enr.IPv4 131 ip6 enr.IPv6 132 ) 133 if n.Load(&ip4) == nil { 134 return net.IP(ip4) 135 } 136 if n.Load(&ip6) == nil { 137 return net.IP(ip6) 138 } 139 return nil 140 } 141 142 // Quorum 143 func (n *Node) Host() string { 144 var hostname string 145 n.Load((*enr.Hostname)(&hostname)) 146 return hostname 147 } 148 149 // End-Quorum 150 151 // UDP returns the UDP port of the node. 152 func (n *Node) UDP() int { 153 var port enr.UDP 154 n.Load(&port) 155 return int(port) 156 } 157 158 // used by Quorum RAFT - returns the Raft port of the node 159 func (n *Node) RaftPort() int { 160 var port enr.RaftPort 161 err := n.Load(&port) 162 if err != nil { 163 return 0 164 } 165 return int(port) 166 } 167 168 func (n *Node) HasRaftPort() bool { 169 return n.RaftPort() > 0 170 } 171 172 // UDP returns the TCP port of the node. 173 func (n *Node) TCP() int { 174 var port enr.TCP 175 n.Load(&port) 176 return int(port) 177 } 178 179 // Pubkey returns the secp256k1 public key of the node, if present. 180 func (n *Node) Pubkey() *ecdsa.PublicKey { 181 var key ecdsa.PublicKey 182 if n.Load((*Secp256k1)(&key)) != nil { 183 return nil 184 } 185 return &key 186 } 187 188 // Record returns the node's record. The return value is a copy and may 189 // be modified by the caller. 190 func (n *Node) Record() *enr.Record { 191 cpy := n.r 192 return &cpy 193 } 194 195 // ValidateComplete checks whether n has a valid IP and UDP port. 196 // Deprecated: don't use this method. 197 func (n *Node) ValidateComplete() error { 198 if n.Incomplete() { 199 return errors.New("missing IP address") 200 } 201 if n.UDP() == 0 { 202 return errors.New("missing UDP port") 203 } 204 ip := n.IP() 205 if ip.IsMulticast() || ip.IsUnspecified() { 206 return errors.New("invalid IP (multicast/unspecified)") 207 } 208 // Validate the node key (on curve, etc.). 209 var key Secp256k1 210 return n.Load(&key) 211 } 212 213 // String returns the text representation of the record. 214 func (n *Node) String() string { 215 if isNewV4(n) { 216 return n.URLv4() // backwards-compatibility glue for NewV4 nodes 217 } 218 enc, _ := rlp.EncodeToBytes(&n.r) // always succeeds because record is valid 219 b64 := base64.RawURLEncoding.EncodeToString(enc) 220 return "enr:" + b64 221 } 222 223 // MarshalText implements encoding.TextMarshaler. 224 func (n *Node) MarshalText() ([]byte, error) { 225 return []byte(n.String()), nil 226 } 227 228 // UnmarshalText implements encoding.TextUnmarshaler. 229 func (n *Node) UnmarshalText(text []byte) error { 230 dec, err := Parse(ValidSchemes, string(text)) 231 if err == nil { 232 *n = *dec 233 } 234 return err 235 } 236 237 // ID is a unique identifier for each node. 238 type ID [32]byte 239 240 // Bytes returns a byte slice representation of the ID 241 func (n ID) Bytes() []byte { 242 return n[:] 243 } 244 245 // ID prints as a long hexadecimal number. 246 func (n ID) String() string { 247 return fmt.Sprintf("%x", n[:]) 248 } 249 250 // The Go syntax representation of a ID is a call to HexID. 251 func (n ID) GoString() string { 252 return fmt.Sprintf("enode.HexID(\"%x\")", n[:]) 253 } 254 255 // TerminalString returns a shortened hex string for terminal logging. 256 func (n ID) TerminalString() string { 257 return hex.EncodeToString(n[:8]) 258 } 259 260 // MarshalText implements the encoding.TextMarshaler interface. 261 func (n ID) MarshalText() ([]byte, error) { 262 return []byte(hex.EncodeToString(n[:])), nil 263 } 264 265 // UnmarshalText implements the encoding.TextUnmarshaler interface. 266 func (n *ID) UnmarshalText(text []byte) error { 267 id, err := parseID(string(text)) 268 if err != nil { 269 return err 270 } 271 *n = id 272 return nil 273 } 274 275 // ID is a unique identifier for each node used by RAFT 276 type EnodeID [64]byte 277 278 // ID prints as a long hexadecimal number. 279 func (n EnodeID) String() string { 280 return fmt.Sprintf("%x", n[:]) 281 } 282 283 // The Go syntax representation of a ID is a call to HexID. 284 func (n EnodeID) GoString() string { 285 return fmt.Sprintf("enode.HexID(\"%x\")", n[:]) 286 } 287 288 // MarshalText implements the encoding.TextMarshaler interface. 289 func (n EnodeID) MarshalText() ([]byte, error) { 290 return []byte(hex.EncodeToString(n[:])), nil 291 } 292 293 // UnmarshalText implements the encoding.TextUnmarshaler interface. 294 func (n *EnodeID) UnmarshalText(text []byte) error { 295 id, err := RaftHexID(string(text)) 296 if err != nil { 297 return err 298 } 299 *n = id 300 return nil 301 } 302 303 // HexID converts a hex string to an ID. 304 // The string may be prefixed with 0x. 305 // It panics if the string is not a valid ID. 306 func HexID(in string) ID { 307 id, err := parseID(in) 308 if err != nil { 309 panic(err) 310 } 311 return id 312 } 313 314 // used by Quorum RAFT to derive 64 byte nodeId from 128 byte enodeID 315 func RaftHexID(in string) (EnodeID, error) { 316 var id EnodeID 317 b, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) 318 if err != nil { 319 return id, err 320 } else if len(b) != len(id) { 321 return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2) 322 } 323 324 copy(id[:], b) 325 return id, nil 326 } 327 328 func parseID(in string) (ID, error) { 329 var id ID 330 b, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) 331 if err != nil { 332 return id, err 333 } else if len(b) != len(id) { 334 return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2) 335 } 336 copy(id[:], b) 337 return id, nil 338 } 339 340 // DistCmp compares the distances a->target and b->target. 341 // Returns -1 if a is closer to target, 1 if b is closer to target 342 // and 0 if they are equal. 343 func DistCmp(target, a, b ID) int { 344 for i := range target { 345 da := a[i] ^ target[i] 346 db := b[i] ^ target[i] 347 if da > db { 348 return 1 349 } else if da < db { 350 return -1 351 } 352 } 353 return 0 354 } 355 356 // LogDist returns the logarithmic distance between a and b, log2(a ^ b). 357 func LogDist(a, b ID) int { 358 lz := 0 359 for i := range a { 360 x := a[i] ^ b[i] 361 if x == 0 { 362 lz += 8 363 } else { 364 lz += bits.LeadingZeros8(x) 365 break 366 } 367 } 368 return len(a)*8 - lz 369 } 370 371 // RandomID returns a random ID b such that logdist(a, b) == n. 372 func RandomID(a ID, n int) (b ID) { 373 if n == 0 { 374 return a 375 } 376 // flip bit at position n, fill the rest with random bits 377 b = a 378 pos := len(a) - n/8 - 1 379 bit := byte(0x01) << (byte(n%8) - 1) 380 if bit == 0 { 381 pos++ 382 bit = 0x80 383 } 384 b[pos] = a[pos]&^bit | ^a[pos]&bit // TODO: randomize end bits 385 for i := pos + 1; i < len(a); i++ { 386 b[i] = byte(rand.Intn(255)) 387 } 388 return b 389 }