github.com/amazechain/amc@v0.1.3/internal/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 "github.com/amazechain/amc/internal/avm/rlp" 26 "github.com/amazechain/amc/internal/p2p/enr" 27 "math/bits" 28 "net" 29 "strings" 30 ) 31 32 var errMissingPrefix = errors.New("missing 'enr:' prefix for base64-encoded record") 33 34 // Node represents a host on the network. 35 type Node struct { 36 r enr.Record 37 id ID 38 } 39 40 // New wraps a node record. The record must be valid according to the given 41 // identity scheme. 42 func New(validSchemes enr.IdentityScheme, r *enr.Record) (*Node, error) { 43 if err := r.VerifySignature(validSchemes); err != nil { 44 return nil, err 45 } 46 node := &Node{r: *r} 47 if n := copy(node.id[:], validSchemes.NodeAddr(&node.r)); n != len(ID{}) { 48 return nil, fmt.Errorf("invalid node ID length %d, need %d", n, len(ID{})) 49 } 50 return node, nil 51 } 52 53 // MustParse parses a node record or enode:// URL. It panics if the input is invalid. 54 func MustParse(rawurl string) *Node { 55 n, err := Parse(ValidSchemes, rawurl) 56 if err != nil { 57 panic("invalid node: " + err.Error()) 58 } 59 return n 60 } 61 62 // Parse decodes and verifies a base64-encoded node record. 63 func Parse(validSchemes enr.IdentityScheme, input string) (*Node, error) { 64 if strings.HasPrefix(input, "enode://") { 65 return ParseV4(input) 66 } 67 if !strings.HasPrefix(input, "enr:") { 68 return nil, errMissingPrefix 69 } 70 bin, err := base64.RawURLEncoding.DecodeString(input[4:]) 71 if err != nil { 72 return nil, err 73 } 74 var r enr.Record 75 if err := rlp.DecodeBytes(bin, &r); err != nil { 76 return nil, err 77 } 78 return New(validSchemes, &r) 79 } 80 81 // ID returns the node identifier. 82 func (n *Node) ID() ID { 83 return n.id 84 } 85 86 // Seq returns the sequence number of the underlying record. 87 func (n *Node) Seq() uint64 { 88 return n.r.Seq() 89 } 90 91 // Incomplete returns true for nodes with no IP address. 92 func (n *Node) Incomplete() bool { 93 return n.IP() == nil 94 } 95 96 // Load retrieves an entry from the underlying record. 97 func (n *Node) Load(k enr.Entry) error { 98 return n.r.Load(k) 99 } 100 101 // IP returns the IP address of the node. This prefers IPv4 addresses. 102 func (n *Node) IP() net.IP { 103 var ( 104 ip4 enr.IPv4 105 ip6 enr.IPv6 106 ) 107 if n.Load(&ip4) == nil { 108 return net.IP(ip4) 109 } 110 if n.Load(&ip6) == nil { 111 return net.IP(ip6) 112 } 113 return nil 114 } 115 116 // UDP returns the UDP port of the node. 117 func (n *Node) UDP() int { 118 var port enr.UDP 119 n.Load(&port) 120 return int(port) 121 } 122 123 // TCP returns the TCP port of the node. 124 func (n *Node) TCP() int { 125 var port enr.TCP 126 n.Load(&port) 127 return int(port) 128 } 129 130 // Pubkey returns the secp256k1 public key of the node, if present. 131 func (n *Node) Pubkey() *ecdsa.PublicKey { 132 var key ecdsa.PublicKey 133 if n.Load((*Secp256k1)(&key)) != nil { 134 return nil 135 } 136 return &key 137 } 138 139 // Record returns the node's record. The return value is a copy and may 140 // be modified by the caller. 141 func (n *Node) Record() *enr.Record { 142 cpy := n.r 143 return &cpy 144 } 145 146 // ValidateComplete checks whether n has a valid IP and UDP port. 147 // Deprecated: don't use this method. 148 func (n *Node) ValidateComplete() error { 149 if n.Incomplete() { 150 return errors.New("missing IP address") 151 } 152 if n.UDP() == 0 { 153 return errors.New("missing UDP port") 154 } 155 ip := n.IP() 156 if ip.IsMulticast() || ip.IsUnspecified() { 157 return errors.New("invalid IP (multicast/unspecified)") 158 } 159 // Validate the node key (on curve, etc.). 160 var key Secp256k1 161 return n.Load(&key) 162 } 163 164 // String returns the text representation of the record. 165 func (n *Node) String() string { 166 if isNewV4(n) { 167 return n.URLv4() // backwards-compatibility glue for NewV4 nodes 168 } 169 enc, _ := rlp.EncodeToBytes(&n.r) // always succeeds because record is valid 170 b64 := base64.RawURLEncoding.EncodeToString(enc) 171 return "enr:" + b64 172 } 173 174 // MarshalText implements encoding.TextMarshaler. 175 func (n *Node) MarshalText() ([]byte, error) { 176 return []byte(n.String()), nil 177 } 178 179 // UnmarshalText implements encoding.TextUnmarshaler. 180 func (n *Node) UnmarshalText(text []byte) error { 181 dec, err := Parse(ValidSchemes, string(text)) 182 if err == nil { 183 *n = *dec 184 } 185 return err 186 } 187 188 // ID is a unique identifier for each node. 189 type ID [32]byte 190 191 // Bytes returns a byte slice representation of the ID 192 func (n ID) Bytes() []byte { 193 return n[:] 194 } 195 196 // ID prints as a long hexadecimal number. 197 func (n ID) String() string { 198 return fmt.Sprintf("%x", n[:]) 199 } 200 201 // GoString returns the Go syntax representation of a ID is a call to HexID. 202 func (n ID) GoString() string { 203 return fmt.Sprintf("enode.HexID(\"%x\")", n[:]) 204 } 205 206 // TerminalString returns a shortened hex string for terminal logging. 207 func (n ID) TerminalString() string { 208 return hex.EncodeToString(n[:8]) 209 } 210 211 // MarshalText implements the encoding.TextMarshaler interface. 212 func (n ID) MarshalText() ([]byte, error) { 213 return []byte(hex.EncodeToString(n[:])), nil 214 } 215 216 // UnmarshalText implements the encoding.TextUnmarshaler interface. 217 func (n *ID) UnmarshalText(text []byte) error { 218 id, err := ParseID(string(text)) 219 if err != nil { 220 return err 221 } 222 *n = id 223 return nil 224 } 225 226 // HexID converts a hex string to an ID. 227 // The string may be prefixed with 0x. 228 // It panics if the string is not a valid ID. 229 func HexID(in string) ID { 230 id, err := ParseID(in) 231 if err != nil { 232 panic(err) 233 } 234 return id 235 } 236 237 func ParseID(in string) (ID, error) { 238 var id ID 239 b, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) 240 if err != nil { 241 return id, err 242 } else if len(b) != len(id) { 243 return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2) 244 } 245 copy(id[:], b) 246 return id, nil 247 } 248 249 // DistCmp compares the distances a->target and b->target. 250 // Returns -1 if a is closer to target, 1 if b is closer to target 251 // and 0 if they are equal. 252 func DistCmp(target, a, b ID) int { 253 for i := range target { 254 da := a[i] ^ target[i] 255 db := b[i] ^ target[i] 256 if da > db { 257 return 1 258 } else if da < db { 259 return -1 260 } 261 } 262 return 0 263 } 264 265 // LogDist returns the logarithmic distance between a and b, log2(a ^ b). 266 func LogDist(a, b ID) int { 267 lz := 0 268 for i := range a { 269 x := a[i] ^ b[i] 270 if x == 0 { 271 lz += 8 272 } else { 273 lz += bits.LeadingZeros8(x) 274 break 275 } 276 } 277 return len(a)*8 - lz 278 }