github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/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/unicornultrafoundation/go-u2u/p2p/enr" 30 "github.com/unicornultrafoundation/go-u2u/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 func ParseNodes(s string) ([]*Node, error) { 83 ws := strings.NewReplacer(" ", "", "\n", "", "\t", "") 84 urls := strings.Split(ws.Replace(s), ",") 85 nodes := make([]*Node, 0) 86 for _, url := range urls { 87 if url == "" { 88 continue 89 } 90 node, err := Parse(ValidSchemes, url) 91 if err != nil { 92 return nil, fmt.Errorf("couldn't parse enode %v: %v", url, err) 93 } 94 nodes = append(nodes, node) 95 } 96 return nodes, nil 97 } 98 99 // ID returns the node identifier. 100 func (n *Node) ID() ID { 101 return n.id 102 } 103 104 // Seq returns the sequence number of the underlying record. 105 func (n *Node) Seq() uint64 { 106 return n.r.Seq() 107 } 108 109 // Incomplete returns true for nodes with no IP address. 110 func (n *Node) Incomplete() bool { 111 return n.IP() == nil 112 } 113 114 // Load retrieves an entry from the underlying record. 115 func (n *Node) Load(k enr.Entry) error { 116 return n.r.Load(k) 117 } 118 119 // IP returns the IP address of the node. This prefers IPv4 addresses. 120 func (n *Node) IP() net.IP { 121 var ( 122 ip4 enr.IPv4 123 ip6 enr.IPv6 124 ) 125 if n.Load(&ip4) == nil { 126 return net.IP(ip4) 127 } 128 if n.Load(&ip6) == nil { 129 return net.IP(ip6) 130 } 131 return nil 132 } 133 134 // UDP returns the UDP port of the node. 135 func (n *Node) UDP() int { 136 var port enr.UDP 137 n.Load(&port) 138 return int(port) 139 } 140 141 // TCP returns the TCP port of the node. 142 func (n *Node) TCP() int { 143 var port enr.TCP 144 n.Load(&port) 145 return int(port) 146 } 147 148 // Pubkey returns the secp256k1 public key of the node, if present. 149 func (n *Node) Pubkey() *ecdsa.PublicKey { 150 var key ecdsa.PublicKey 151 if n.Load((*Secp256k1)(&key)) != nil { 152 return nil 153 } 154 return &key 155 } 156 157 // Record returns the node's record. The return value is a copy and may 158 // be modified by the caller. 159 func (n *Node) Record() *enr.Record { 160 cpy := n.r 161 return &cpy 162 } 163 164 // ValidateComplete checks whether n has a valid IP and UDP port. 165 // Deprecated: don't use this method. 166 func (n *Node) ValidateComplete() error { 167 if n.Incomplete() { 168 return errors.New("missing IP address") 169 } 170 if n.UDP() == 0 { 171 return errors.New("missing UDP port") 172 } 173 ip := n.IP() 174 if ip.IsMulticast() || ip.IsUnspecified() { 175 return errors.New("invalid IP (multicast/unspecified)") 176 } 177 // Validate the node key (on curve, etc.). 178 var key Secp256k1 179 return n.Load(&key) 180 } 181 182 // String returns the text representation of the record. 183 func (n *Node) String() string { 184 if isNewV4(n) { 185 return n.URLv4() // backwards-compatibility glue for NewV4 nodes 186 } 187 enc, _ := rlp.EncodeToBytes(&n.r) // always succeeds because record is valid 188 b64 := base64.RawURLEncoding.EncodeToString(enc) 189 return "enr:" + b64 190 } 191 192 // MarshalText implements encoding.TextMarshaler. 193 func (n *Node) MarshalText() ([]byte, error) { 194 return []byte(n.String()), nil 195 } 196 197 // UnmarshalText implements encoding.TextUnmarshaler. 198 func (n *Node) UnmarshalText(text []byte) error { 199 dec, err := Parse(ValidSchemes, string(text)) 200 if err == nil { 201 *n = *dec 202 } 203 return err 204 } 205 206 // ID is a unique identifier for each node. 207 type ID [32]byte 208 209 // Bytes returns a byte slice representation of the ID 210 func (n ID) Bytes() []byte { 211 return n[:] 212 } 213 214 // ID prints as a long hexadecimal number. 215 func (n ID) String() string { 216 return fmt.Sprintf("%x", n[:]) 217 } 218 219 // The Go syntax representation of a ID is a call to HexID. 220 func (n ID) GoString() string { 221 return fmt.Sprintf("enode.HexID(\"%x\")", n[:]) 222 } 223 224 // TerminalString returns a shortened hex string for terminal logging. 225 func (n ID) TerminalString() string { 226 return hex.EncodeToString(n[:8]) 227 } 228 229 // MarshalText implements the encoding.TextMarshaler interface. 230 func (n ID) MarshalText() ([]byte, error) { 231 return []byte(hex.EncodeToString(n[:])), nil 232 } 233 234 // UnmarshalText implements the encoding.TextUnmarshaler interface. 235 func (n *ID) UnmarshalText(text []byte) error { 236 id, err := ParseID(string(text)) 237 if err != nil { 238 return err 239 } 240 *n = id 241 return nil 242 } 243 244 // HexID converts a hex string to an ID. 245 // The string may be prefixed with 0x. 246 // It panics if the string is not a valid ID. 247 func HexID(in string) ID { 248 id, err := ParseID(in) 249 if err != nil { 250 panic(err) 251 } 252 return id 253 } 254 255 func ParseID(in string) (ID, error) { 256 var id ID 257 b, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) 258 if err != nil { 259 return id, err 260 } else if len(b) != len(id) { 261 return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2) 262 } 263 copy(id[:], b) 264 return id, nil 265 } 266 267 // DistCmp compares the distances a->target and b->target. 268 // Returns -1 if a is closer to target, 1 if b is closer to target 269 // and 0 if they are equal. 270 func DistCmp(target, a, b ID) int { 271 for i := range target { 272 da := a[i] ^ target[i] 273 db := b[i] ^ target[i] 274 if da > db { 275 return 1 276 } else if da < db { 277 return -1 278 } 279 } 280 return 0 281 } 282 283 // LogDist returns the logarithmic distance between a and b, log2(a ^ b). 284 func LogDist(a, b ID) int { 285 lz := 0 286 for i := range a { 287 x := a[i] ^ b[i] 288 if x == 0 { 289 lz += 8 290 } else { 291 lz += bits.LeadingZeros8(x) 292 break 293 } 294 } 295 return len(a)*8 - lz 296 }