github.com/hyperion-hyn/go-ethereum@v2.4.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/hex" 22 "errors" 23 "fmt" 24 "github.com/ethereum/go-ethereum/log" 25 "math/bits" 26 "math/rand" 27 "net" 28 "strings" 29 30 "github.com/ethereum/go-ethereum/p2p/enr" 31 ) 32 33 // Node represents a host on the network. 34 type Node struct { 35 r enr.Record 36 id ID 37 } 38 39 // New wraps a node record. The record must be valid according to the given 40 // identity scheme. 41 func New(validSchemes enr.IdentityScheme, r *enr.Record) (*Node, error) { 42 if err := r.VerifySignature(validSchemes); err != nil { 43 return nil, err 44 } 45 node := &Node{r: *r} 46 if n := copy(node.id[:], validSchemes.NodeAddr(&node.r)); n != len(ID{}) { 47 return nil, fmt.Errorf("invalid node ID length %d, need %d", n, len(ID{})) 48 } 49 return node, nil 50 } 51 52 // ID returns the node identifier. 53 func (n *Node) ID() ID { 54 return n.id 55 } 56 57 // Seq returns the sequence number of the underlying record. 58 func (n *Node) Seq() uint64 { 59 return n.r.Seq() 60 } 61 62 // Incomplete returns true for nodes with no IP address. 63 func (n *Node) Incomplete() bool { 64 return n.IP() == nil 65 } 66 67 // Load retrieves an entry from the underlying record. 68 func (n *Node) Load(k enr.Entry) error { 69 return n.r.Load(k) 70 } 71 72 // IP returns the IP address of the node. 73 func (n *Node) IP() net.IP { 74 // QUORUM 75 // no host is set, so use the IP directly 76 if n.Host() == "" { 77 return n.loadIP() 78 } 79 // attempt to look up IP addresses if host is a FQDN 80 lookupIPs, err := net.LookupIP(n.Host()) 81 if err != nil { 82 log.Debug("hostname couldn't resolve, using IP instead", "hostname", n.Host(), "err", err.Error()) 83 return n.loadIP() 84 } 85 // set to first ip by default 86 return lookupIPs[0] 87 // END QUORUM 88 } 89 90 func (n *Node) loadIP() net.IP { 91 var ip net.IP 92 n.Load((*enr.IP)(&ip)) 93 return ip 94 } 95 96 // Quorum 97 func (n *Node) Host() string { 98 var hostname string 99 n.Load((*enr.Hostname)(&hostname)) 100 return hostname 101 } 102 // End-Quorum 103 104 // UDP returns the UDP port of the node. 105 func (n *Node) UDP() int { 106 var port enr.UDP 107 n.Load(&port) 108 return int(port) 109 } 110 111 // used by Quorum RAFT - returns the Raft port of the node 112 func (n *Node) RaftPort() int { 113 var port enr.RaftPort 114 err := n.Load(&port) 115 if err != nil { 116 return 0 117 } 118 return int(port) 119 } 120 121 func (n *Node) HasRaftPort() bool { 122 return n.RaftPort() > 0 123 } 124 125 // UDP returns the TCP port of the node. 126 func (n *Node) TCP() int { 127 var port enr.TCP 128 n.Load(&port) 129 return int(port) 130 } 131 132 // Pubkey returns the secp256k1 public key of the node, if present. 133 func (n *Node) Pubkey() *ecdsa.PublicKey { 134 var key ecdsa.PublicKey 135 if n.Load((*Secp256k1)(&key)) != nil { 136 return nil 137 } 138 return &key 139 } 140 141 // Record returns the node's record. The return value is a copy and may 142 // be modified by the caller. 143 func (n *Node) Record() *enr.Record { 144 cpy := n.r 145 return &cpy 146 } 147 148 // checks whether n is a valid complete node. 149 func (n *Node) ValidateComplete() error { 150 if n.Incomplete() { 151 return errors.New("incomplete node") 152 } 153 if n.UDP() == 0 { 154 return errors.New("missing UDP port") 155 } 156 ip := n.IP() 157 if ip.IsMulticast() || ip.IsUnspecified() { 158 return errors.New("invalid IP (multicast/unspecified)") 159 } 160 // Validate the node key (on curve, etc.). 161 var key Secp256k1 162 return n.Load(&key) 163 } 164 165 // The string representation of a Node is a URL. 166 // Please see ParseNode for a description of the format. 167 func (n *Node) String() string { 168 return n.v4URL() 169 } 170 171 // MarshalText implements encoding.TextMarshaler. 172 func (n *Node) MarshalText() ([]byte, error) { 173 return []byte(n.v4URL()), nil 174 } 175 176 // UnmarshalText implements encoding.TextUnmarshaler. 177 func (n *Node) UnmarshalText(text []byte) error { 178 dec, err := ParseV4(string(text)) 179 if err == nil { 180 *n = *dec 181 } 182 return err 183 } 184 185 // ID is a unique identifier for each node. 186 type ID [32]byte 187 188 // Bytes returns a byte slice representation of the ID 189 func (n ID) Bytes() []byte { 190 return n[:] 191 } 192 193 // ID prints as a long hexadecimal number. 194 func (n ID) String() string { 195 return fmt.Sprintf("%x", n[:]) 196 } 197 198 // The Go syntax representation of a ID is a call to HexID. 199 func (n ID) GoString() string { 200 return fmt.Sprintf("enode.HexID(\"%x\")", n[:]) 201 } 202 203 // TerminalString returns a shortened hex string for terminal logging. 204 func (n ID) TerminalString() string { 205 return hex.EncodeToString(n[:8]) 206 } 207 208 // MarshalText implements the encoding.TextMarshaler interface. 209 func (n ID) MarshalText() ([]byte, error) { 210 return []byte(hex.EncodeToString(n[:])), nil 211 } 212 213 // UnmarshalText implements the encoding.TextUnmarshaler interface. 214 func (n *ID) UnmarshalText(text []byte) error { 215 id, err := parseID(string(text)) 216 if err != nil { 217 return err 218 } 219 *n = id 220 return nil 221 } 222 223 // ID is a unique identifier for each node used by RAFT 224 type EnodeID [64]byte 225 226 // ID prints as a long hexadecimal number. 227 func (n EnodeID) String() string { 228 return fmt.Sprintf("%x", n[:]) 229 } 230 231 // The Go syntax representation of a ID is a call to HexID. 232 func (n EnodeID) GoString() string { 233 return fmt.Sprintf("enode.HexID(\"%x\")", n[:]) 234 } 235 236 // MarshalText implements the encoding.TextMarshaler interface. 237 func (n EnodeID) MarshalText() ([]byte, error) { 238 return []byte(hex.EncodeToString(n[:])), nil 239 } 240 241 // UnmarshalText implements the encoding.TextUnmarshaler interface. 242 func (n *EnodeID) UnmarshalText(text []byte) error { 243 id, err := RaftHexID(string(text)) 244 if err != nil { 245 return err 246 } 247 *n = id 248 return nil 249 } 250 251 // HexID converts a hex string to an ID. 252 // The string may be prefixed with 0x. 253 // It panics if the string is not a valid ID. 254 func HexID(in string) ID { 255 id, err := parseID(in) 256 if err != nil { 257 panic(err) 258 } 259 return id 260 } 261 262 // used by Quorum RAFT to derive 64 byte nodeId from 128 byte enodeID 263 func RaftHexID(in string) (EnodeID, error) { 264 var id EnodeID 265 b, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) 266 if err != nil { 267 return id, err 268 } else if len(b) != len(id) { 269 return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2) 270 } 271 272 copy(id[:], b) 273 return id, nil 274 } 275 276 func parseID(in string) (ID, error) { 277 var id ID 278 b, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) 279 if err != nil { 280 return id, err 281 } else if len(b) != len(id) { 282 return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2) 283 } 284 copy(id[:], b) 285 return id, nil 286 } 287 288 // DistCmp compares the distances a->target and b->target. 289 // Returns -1 if a is closer to target, 1 if b is closer to target 290 // and 0 if they are equal. 291 func DistCmp(target, a, b ID) int { 292 for i := range target { 293 da := a[i] ^ target[i] 294 db := b[i] ^ target[i] 295 if da > db { 296 return 1 297 } else if da < db { 298 return -1 299 } 300 } 301 return 0 302 } 303 304 // LogDist returns the logarithmic distance between a and b, log2(a ^ b). 305 func LogDist(a, b ID) int { 306 lz := 0 307 for i := range a { 308 x := a[i] ^ b[i] 309 if x == 0 { 310 lz += 8 311 } else { 312 lz += bits.LeadingZeros8(x) 313 break 314 } 315 } 316 return len(a)*8 - lz 317 } 318 319 // RandomID returns a random ID b such that logdist(a, b) == n. 320 func RandomID(a ID, n int) (b ID) { 321 if n == 0 { 322 return a 323 } 324 // flip bit at position n, fill the rest with random bits 325 b = a 326 pos := len(a) - n/8 - 1 327 bit := byte(0x01) << (byte(n%8) - 1) 328 if bit == 0 { 329 pos++ 330 bit = 0x80 331 } 332 b[pos] = a[pos]&^bit | ^a[pos]&bit // TODO: randomize end bits 333 for i := pos + 1; i < len(a); i++ { 334 b[i] = byte(rand.Intn(255)) 335 } 336 return b 337 }