github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/p2p/enode/node.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // Copyright 2019 The go-aigar Authors 3 // This file is part of the go-aigar library. 4 // 5 // The go-aigar library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-aigar library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>. 17 18 package enode 19 20 import ( 21 "crypto/ecdsa" 22 "encoding/base64" 23 "encoding/hex" 24 "errors" 25 "fmt" 26 "math/bits" 27 "math/rand" 28 "net" 29 "strings" 30 31 "github.com/AigarNetwork/aigar/p2p/enr" 32 "github.com/AigarNetwork/aigar/rlp" 33 ) 34 35 var errMissingPrefix = errors.New("missing 'enr:' prefix for base64-encoded record") 36 37 // Node represents a host on the network. 38 type Node struct { 39 r enr.Record 40 id ID 41 } 42 43 // New wraps a node record. The record must be valid according to the given 44 // identity scheme. 45 func New(validSchemes enr.IdentityScheme, r *enr.Record) (*Node, error) { 46 if err := r.VerifySignature(validSchemes); err != nil { 47 return nil, err 48 } 49 node := &Node{r: *r} 50 if n := copy(node.id[:], validSchemes.NodeAddr(&node.r)); n != len(ID{}) { 51 return nil, fmt.Errorf("invalid node ID length %d, need %d", n, len(ID{})) 52 } 53 return node, nil 54 } 55 56 // MustParse parses a node record or enode:// URL. It panics if the input is invalid. 57 func MustParse(rawurl string) *Node { 58 n, err := Parse(ValidSchemes, rawurl) 59 if err != nil { 60 panic("invalid node: " + err.Error()) 61 } 62 return n 63 } 64 65 // Parse decodes and verifies a base64-encoded node record. 66 func Parse(validSchemes enr.IdentityScheme, input string) (*Node, error) { 67 if strings.HasPrefix(input, "enode://") { 68 return ParseV4(input) 69 } 70 if !strings.HasPrefix(input, "enr:") { 71 return nil, errMissingPrefix 72 } 73 bin, err := base64.RawURLEncoding.DecodeString(input[4:]) 74 if err != nil { 75 return nil, err 76 } 77 var r enr.Record 78 if err := rlp.DecodeBytes(bin, &r); err != nil { 79 return nil, err 80 } 81 return New(validSchemes, &r) 82 } 83 84 // ID returns the node identifier. 85 func (n *Node) ID() ID { 86 return n.id 87 } 88 89 // Seq returns the sequence number of the underlying record. 90 func (n *Node) Seq() uint64 { 91 return n.r.Seq() 92 } 93 94 // Incomplete returns true for nodes with no IP address. 95 func (n *Node) Incomplete() bool { 96 return n.IP() == nil 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. This prefers IPv4 addresses. 105 func (n *Node) IP() net.IP { 106 var ( 107 ip4 enr.IPv4 108 ip6 enr.IPv6 109 ) 110 if n.Load(&ip4) == nil { 111 return net.IP(ip4) 112 } 113 if n.Load(&ip6) == nil { 114 return net.IP(ip6) 115 } 116 return nil 117 } 118 119 // UDP returns the UDP port of the node. 120 func (n *Node) UDP() int { 121 var port enr.UDP 122 n.Load(&port) 123 return int(port) 124 } 125 126 // UDP returns the TCP port of the node. 127 func (n *Node) TCP() int { 128 var port enr.TCP 129 n.Load(&port) 130 return int(port) 131 } 132 133 // Pubkey returns the secp256k1 public key of the node, if present. 134 func (n *Node) Pubkey() *ecdsa.PublicKey { 135 var key ecdsa.PublicKey 136 if n.Load((*Secp256k1)(&key)) != nil { 137 return nil 138 } 139 return &key 140 } 141 142 // Record returns the node's record. The return value is a copy and may 143 // be modified by the caller. 144 func (n *Node) Record() *enr.Record { 145 cpy := n.r 146 return &cpy 147 } 148 149 // ValidateComplete checks whether n has a valid IP and UDP port. 150 // Deprecated: don't use this method. 151 func (n *Node) ValidateComplete() error { 152 if n.Incomplete() { 153 return errors.New("missing IP address") 154 } 155 if n.UDP() == 0 { 156 return errors.New("missing UDP port") 157 } 158 ip := n.IP() 159 if ip.IsMulticast() || ip.IsUnspecified() { 160 return errors.New("invalid IP (multicast/unspecified)") 161 } 162 // Validate the node key (on curve, etc.). 163 var key Secp256k1 164 return n.Load(&key) 165 } 166 167 // String returns the text representation of the record. 168 func (n *Node) String() string { 169 if isNewV4(n) { 170 return n.URLv4() // backwards-compatibility glue for NewV4 nodes 171 } 172 enc, _ := rlp.EncodeToBytes(&n.r) // always succeeds because record is valid 173 b64 := base64.RawURLEncoding.EncodeToString(enc) 174 return "enr:" + b64 175 } 176 177 // MarshalText implements encoding.TextMarshaler. 178 func (n *Node) MarshalText() ([]byte, error) { 179 return []byte(n.String()), nil 180 } 181 182 // UnmarshalText implements encoding.TextUnmarshaler. 183 func (n *Node) UnmarshalText(text []byte) error { 184 dec, err := Parse(ValidSchemes, string(text)) 185 if err == nil { 186 *n = *dec 187 } 188 return err 189 } 190 191 // ID is a unique identifier for each node. 192 type ID [32]byte 193 194 // Bytes returns a byte slice representation of the ID 195 func (n ID) Bytes() []byte { 196 return n[:] 197 } 198 199 // ID prints as a long hexadecimal number. 200 func (n ID) String() string { 201 return fmt.Sprintf("%x", n[:]) 202 } 203 204 // The Go syntax representation of a ID is a call to HexID. 205 func (n ID) GoString() string { 206 return fmt.Sprintf("enode.HexID(\"%x\")", n[:]) 207 } 208 209 // TerminalString returns a shortened hex string for terminal logging. 210 func (n ID) TerminalString() string { 211 return hex.EncodeToString(n[:8]) 212 } 213 214 // MarshalText implements the encoding.TextMarshaler interface. 215 func (n ID) MarshalText() ([]byte, error) { 216 return []byte(hex.EncodeToString(n[:])), nil 217 } 218 219 // UnmarshalText implements the encoding.TextUnmarshaler interface. 220 func (n *ID) UnmarshalText(text []byte) error { 221 id, err := parseID(string(text)) 222 if err != nil { 223 return err 224 } 225 *n = id 226 return nil 227 } 228 229 // HexID converts a hex string to an ID. 230 // The string may be prefixed with 0x. 231 // It panics if the string is not a valid ID. 232 func HexID(in string) ID { 233 id, err := parseID(in) 234 if err != nil { 235 panic(err) 236 } 237 return id 238 } 239 240 func parseID(in string) (ID, error) { 241 var id ID 242 b, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) 243 if err != nil { 244 return id, err 245 } else if len(b) != len(id) { 246 return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2) 247 } 248 copy(id[:], b) 249 return id, nil 250 } 251 252 // DistCmp compares the distances a->target and b->target. 253 // Returns -1 if a is closer to target, 1 if b is closer to target 254 // and 0 if they are equal. 255 func DistCmp(target, a, b ID) int { 256 for i := range target { 257 da := a[i] ^ target[i] 258 db := b[i] ^ target[i] 259 if da > db { 260 return 1 261 } else if da < db { 262 return -1 263 } 264 } 265 return 0 266 } 267 268 // LogDist returns the logarithmic distance between a and b, log2(a ^ b). 269 func LogDist(a, b ID) int { 270 lz := 0 271 for i := range a { 272 x := a[i] ^ b[i] 273 if x == 0 { 274 lz += 8 275 } else { 276 lz += bits.LeadingZeros8(x) 277 break 278 } 279 } 280 return len(a)*8 - lz 281 } 282 283 // RandomID returns a random ID b such that logdist(a, b) == n. 284 func RandomID(a ID, n int) (b ID) { 285 if n == 0 { 286 return a 287 } 288 // flip bit at position n, fill the rest with random bits 289 b = a 290 pos := len(a) - n/8 - 1 291 bit := byte(0x01) << (byte(n%8) - 1) 292 if bit == 0 { 293 pos++ 294 bit = 0x80 295 } 296 b[pos] = a[pos]&^bit | ^a[pos]&bit // TODO: randomize end bits 297 for i := pos + 1; i < len(a); i++ { 298 b[i] = byte(rand.Intn(255)) 299 } 300 return b 301 }