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