github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/p2p/enode/node.go (about) 1 // Copyright 2018 The go-simplechain Authors 2 // This file is part of the go-simplechain library. 3 // 4 // The go-simplechain 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-simplechain 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-simplechain 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 "github.com/bigzoro/my_simplechain/crypto" 26 "math/bits" 27 "math/rand" 28 "net" 29 "strings" 30 31 "github.com/bigzoro/my_simplechain/p2p/enr" 32 "github.com/bigzoro/my_simplechain/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 // used by Quorum RAFT - to derive enodeID 90 func (n *Node) EnodeID() string { 91 var ( 92 scheme enr.ID 93 nodeid string 94 key ecdsa.PublicKey 95 ) 96 n.Load(&scheme) 97 n.Load((*Secp256k1)(&key)) 98 switch { 99 case scheme == "v4" || key != ecdsa.PublicKey{}: 100 nodeid = fmt.Sprintf("%x", crypto.FromECDSAPub(&key)[1:]) 101 default: 102 nodeid = fmt.Sprintf("%s.%x", scheme, n.id[:]) 103 } 104 return nodeid 105 } 106 107 // used by RAFT - returns the Raft port of the node 108 func (n *Node) RaftPort() int { 109 var port enr.RaftPort 110 err := n.Load(&port) 111 if err != nil { 112 return 0 113 } 114 return int(port) 115 } 116 117 func (n *Node) HasRaftPort() bool { 118 return n.RaftPort() > 0 119 } 120 121 // Seq returns the sequence number of the underlying record. 122 func (n *Node) Seq() uint64 { 123 return n.r.Seq() 124 } 125 126 // Incomplete returns true for nodes with no IP address. 127 func (n *Node) Incomplete() bool { 128 return n.IP() == nil 129 } 130 131 // Load retrieves an entry from the underlying record. 132 func (n *Node) Load(k enr.Entry) error { 133 return n.r.Load(k) 134 } 135 136 // IP returns the IP address of the node. This prefers IPv4 addresses. 137 func (n *Node) IP() net.IP { 138 var ( 139 ip4 enr.IPv4 140 ip6 enr.IPv6 141 ) 142 if n.Load(&ip4) == nil { 143 return net.IP(ip4) 144 } 145 if n.Load(&ip6) == nil { 146 return net.IP(ip6) 147 } 148 return nil 149 } 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 // UDP returns the TCP port of the node. 159 func (n *Node) TCP() int { 160 var port enr.TCP 161 n.Load(&port) 162 return int(port) 163 } 164 165 // Pubkey returns the secp256k1 public key of the node, if present. 166 func (n *Node) Pubkey() *ecdsa.PublicKey { 167 var key ecdsa.PublicKey 168 if n.Load((*Secp256k1)(&key)) != nil { 169 return nil 170 } 171 return &key 172 } 173 174 // Record returns the node's record. The return value is a copy and may 175 // be modified by the caller. 176 func (n *Node) Record() *enr.Record { 177 cpy := n.r 178 return &cpy 179 } 180 181 // ValidateComplete checks whether n has a valid IP and UDP port. 182 // Deprecated: don't use this method. 183 func (n *Node) ValidateComplete() error { 184 if n.Incomplete() { 185 return errors.New("missing IP address") 186 } 187 if n.UDP() == 0 { 188 return errors.New("missing UDP port") 189 } 190 ip := n.IP() 191 if ip.IsMulticast() || ip.IsUnspecified() { 192 return errors.New("invalid IP (multicast/unspecified)") 193 } 194 // Validate the node key (on curve, etc.). 195 var key Secp256k1 196 return n.Load(&key) 197 } 198 199 // String returns the text representation of the record. 200 func (n *Node) String() string { 201 if isNewV4(n) { 202 return n.URLv4() // backwards-compatibility glue for NewV4 nodes 203 } 204 enc, _ := rlp.EncodeToBytes(&n.r) // always succeeds because record is valid 205 b64 := base64.RawURLEncoding.EncodeToString(enc) 206 return "enr:" + b64 207 } 208 209 // MarshalText implements encoding.TextMarshaler. 210 func (n *Node) MarshalText() ([]byte, error) { 211 return []byte(n.String()), nil 212 } 213 214 // UnmarshalText implements encoding.TextUnmarshaler. 215 func (n *Node) UnmarshalText(text []byte) error { 216 dec, err := Parse(ValidSchemes, string(text)) 217 if err == nil { 218 *n = *dec 219 } 220 return err 221 } 222 223 // ID is a unique identifier for each node. 224 type ID [32]byte 225 226 // Bytes returns a byte slice representation of the ID 227 func (n ID) Bytes() []byte { 228 return n[:] 229 } 230 231 // ID prints as a long hexadecimal number. 232 func (n ID) String() string { 233 return fmt.Sprintf("%x", n[:]) 234 } 235 236 // The Go syntax representation of a ID is a call to HexID. 237 func (n ID) GoString() string { 238 return fmt.Sprintf("enode.HexID(\"%x\")", n[:]) 239 } 240 241 // TerminalString returns a shortened hex string for terminal logging. 242 func (n ID) TerminalString() string { 243 return hex.EncodeToString(n[:8]) 244 } 245 246 // MarshalText implements the encoding.TextMarshaler interface. 247 func (n ID) MarshalText() ([]byte, error) { 248 return []byte(hex.EncodeToString(n[:])), nil 249 } 250 251 // UnmarshalText implements the encoding.TextUnmarshaler interface. 252 func (n *ID) UnmarshalText(text []byte) error { 253 id, err := parseID(string(text)) 254 if err != nil { 255 return err 256 } 257 *n = id 258 return nil 259 } 260 261 // used by Quorum RAFT to derive 64 byte nodeId from 128 byte enodeID 262 func RaftHexID(in string) (EnodeID, error) { 263 var id EnodeID 264 b, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) 265 if err != nil { 266 return id, err 267 } else if len(b) != len(id) { 268 return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2) 269 } 270 271 copy(id[:], b) 272 return id, 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 // HexID converts a hex string to an ID. 289 // The string may be prefixed with 0x. 290 // It panics if the string is not a valid ID. 291 func HexID(in string) ID { 292 id, err := parseID(in) 293 if err != nil { 294 panic(err) 295 } 296 return id 297 } 298 299 func parseID(in string) (ID, error) { 300 var id ID 301 b, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) 302 if err != nil { 303 return id, err 304 } else if len(b) != len(id) { 305 return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2) 306 } 307 copy(id[:], b) 308 return id, nil 309 } 310 311 // DistCmp compares the distances a->target and b->target. 312 // Returns -1 if a is closer to target, 1 if b is closer to target 313 // and 0 if they are equal. 314 func DistCmp(target, a, b ID) int { 315 for i := range target { 316 da := a[i] ^ target[i] 317 db := b[i] ^ target[i] 318 if da > db { 319 return 1 320 } else if da < db { 321 return -1 322 } 323 } 324 return 0 325 } 326 327 // LogDist returns the logarithmic distance between a and b, log2(a ^ b). 328 func LogDist(a, b ID) int { 329 lz := 0 330 for i := range a { 331 x := a[i] ^ b[i] 332 if x == 0 { 333 lz += 8 334 } else { 335 lz += bits.LeadingZeros8(x) 336 break 337 } 338 } 339 return len(a)*8 - lz 340 } 341 342 // RandomID returns a random ID b such that logdist(a, b) == n. 343 func RandomID(a ID, n int) (b ID) { 344 if n == 0 { 345 return a 346 } 347 // flip bit at position n, fill the rest with random bits 348 b = a 349 pos := len(a) - n/8 - 1 350 bit := byte(0x01) << (byte(n%8) - 1) 351 if bit == 0 { 352 pos++ 353 bit = 0x80 354 } 355 b[pos] = a[pos]&^bit | ^a[pos]&bit // TODO: randomize end bits 356 for i := pos + 1; i < len(a); i++ { 357 b[i] = byte(rand.Intn(255)) 358 } 359 return b 360 }