github.com/titbtcqash/go-ethereum@v1.9.7/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 // Incomplete returns true for nodes with no IP address. 94 func (n *Node) Incomplete() bool { 95 return n.IP() == nil 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. This prefers IPv4 addresses. 104 func (n *Node) IP() net.IP { 105 var ( 106 ip4 enr.IPv4 107 ip6 enr.IPv6 108 ) 109 if n.Load(&ip4) == nil { 110 return net.IP(ip4) 111 } 112 if n.Load(&ip6) == nil { 113 return net.IP(ip6) 114 } 115 return nil 116 } 117 118 // UDP returns the UDP port of the node. 119 func (n *Node) UDP() int { 120 var port enr.UDP 121 n.Load(&port) 122 return int(port) 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 // ValidateComplete checks whether n has a valid IP and UDP port. 149 // Deprecated: don't use this method. 150 func (n *Node) ValidateComplete() error { 151 if n.Incomplete() { 152 return errors.New("missing IP address") 153 } 154 if n.UDP() == 0 { 155 return errors.New("missing UDP port") 156 } 157 ip := n.IP() 158 if ip.IsMulticast() || ip.IsUnspecified() { 159 return errors.New("invalid IP (multicast/unspecified)") 160 } 161 // Validate the node key (on curve, etc.). 162 var key Secp256k1 163 return n.Load(&key) 164 } 165 166 // String returns the text representation of the record. 167 func (n *Node) String() string { 168 if isNewV4(n) { 169 return n.URLv4() // backwards-compatibility glue for NewV4 nodes 170 } 171 enc, _ := rlp.EncodeToBytes(&n.r) // always succeeds because record is valid 172 b64 := base64.RawURLEncoding.EncodeToString(enc) 173 return "enr:" + b64 174 } 175 176 // MarshalText implements encoding.TextMarshaler. 177 func (n *Node) MarshalText() ([]byte, error) { 178 return []byte(n.String()), nil 179 } 180 181 // UnmarshalText implements encoding.TextUnmarshaler. 182 func (n *Node) UnmarshalText(text []byte) error { 183 dec, err := Parse(ValidSchemes, string(text)) 184 if err == nil { 185 *n = *dec 186 } 187 return err 188 } 189 190 // ID is a unique identifier for each node. 191 type ID [32]byte 192 193 // Bytes returns a byte slice representation of the ID 194 func (n ID) Bytes() []byte { 195 return n[:] 196 } 197 198 // ID prints as a long hexadecimal number. 199 func (n ID) String() string { 200 return fmt.Sprintf("%x", n[:]) 201 } 202 203 // The Go syntax representation of a ID is a call to HexID. 204 func (n ID) GoString() string { 205 return fmt.Sprintf("enode.HexID(\"%x\")", n[:]) 206 } 207 208 // TerminalString returns a shortened hex string for terminal logging. 209 func (n ID) TerminalString() string { 210 return hex.EncodeToString(n[:8]) 211 } 212 213 // MarshalText implements the encoding.TextMarshaler interface. 214 func (n ID) MarshalText() ([]byte, error) { 215 return []byte(hex.EncodeToString(n[:])), nil 216 } 217 218 // UnmarshalText implements the encoding.TextUnmarshaler interface. 219 func (n *ID) UnmarshalText(text []byte) error { 220 id, err := parseID(string(text)) 221 if err != nil { 222 return err 223 } 224 *n = id 225 return nil 226 } 227 228 // HexID converts a hex string to an ID. 229 // The string may be prefixed with 0x. 230 // It panics if the string is not a valid ID. 231 func HexID(in string) ID { 232 id, err := parseID(in) 233 if err != nil { 234 panic(err) 235 } 236 return id 237 } 238 239 func parseID(in string) (ID, error) { 240 var id ID 241 b, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) 242 if err != nil { 243 return id, err 244 } else if len(b) != len(id) { 245 return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2) 246 } 247 copy(id[:], b) 248 return id, nil 249 } 250 251 // DistCmp compares the distances a->target and b->target. 252 // Returns -1 if a is closer to target, 1 if b is closer to target 253 // and 0 if they are equal. 254 func DistCmp(target, a, b ID) int { 255 for i := range target { 256 da := a[i] ^ target[i] 257 db := b[i] ^ target[i] 258 if da > db { 259 return 1 260 } else if da < db { 261 return -1 262 } 263 } 264 return 0 265 } 266 267 // LogDist returns the logarithmic distance between a and b, log2(a ^ b). 268 func LogDist(a, b ID) int { 269 lz := 0 270 for i := range a { 271 x := a[i] ^ b[i] 272 if x == 0 { 273 lz += 8 274 } else { 275 lz += bits.LeadingZeros8(x) 276 break 277 } 278 } 279 return len(a)*8 - lz 280 } 281 282 // RandomID returns a random ID b such that logdist(a, b) == n. 283 func RandomID(a ID, n int) (b ID) { 284 if n == 0 { 285 return a 286 } 287 // flip bit at position n, fill the rest with random bits 288 b = a 289 pos := len(a) - n/8 - 1 290 bit := byte(0x01) << (byte(n%8) - 1) 291 if bit == 0 { 292 pos++ 293 bit = 0x80 294 } 295 b[pos] = a[pos]&^bit | ^a[pos]&bit // TODO: randomize end bits 296 for i := pos + 1; i < len(a); i++ { 297 b[i] = byte(rand.Intn(255)) 298 } 299 return b 300 }