github.com/ebceco/ebc@v1.8.19-0.20190309150932-8cb0b9e06484/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/hex" 22 "errors" 23 "fmt" 24 "math/bits" 25 "math/rand" 26 "net" 27 "strings" 28 29 "github.com/ebceco/ebc/p2p/enr" 30 ) 31 32 // Node represents a host on the network. 33 type Node struct { 34 r enr.Record 35 id ID 36 } 37 38 // New wraps a node record. The record must be valid according to the given 39 // identity scheme. 40 func New(validSchemes enr.IdentityScheme, r *enr.Record) (*Node, error) { 41 if err := r.VerifySignature(validSchemes); err != nil { 42 return nil, err 43 } 44 node := &Node{r: *r} 45 if n := copy(node.id[:], validSchemes.NodeAddr(&node.r)); n != len(ID{}) { 46 return nil, fmt.Errorf("invalid node ID length %d, need %d", n, len(ID{})) 47 } 48 return node, nil 49 } 50 51 // ID returns the node identifier. 52 func (n *Node) ID() ID { 53 return n.id 54 } 55 56 // Seq returns the sequence number of the underlying record. 57 func (n *Node) Seq() uint64 { 58 return n.r.Seq() 59 } 60 61 // Incomplete returns true for nodes with no IP address. 62 func (n *Node) Incomplete() bool { 63 return n.IP() == nil 64 } 65 66 // Load retrieves an entry from the underlying record. 67 func (n *Node) Load(k enr.Entry) error { 68 return n.r.Load(k) 69 } 70 71 // IP returns the IP address of the node. 72 func (n *Node) IP() net.IP { 73 var ip net.IP 74 n.Load((*enr.IP)(&ip)) 75 return ip 76 } 77 78 // UDP returns the UDP port of the node. 79 func (n *Node) UDP() int { 80 var port enr.UDP 81 n.Load(&port) 82 return int(port) 83 } 84 85 // UDP returns the TCP port of the node. 86 func (n *Node) TCP() int { 87 var port enr.TCP 88 n.Load(&port) 89 return int(port) 90 } 91 92 // Pubkey returns the secp256k1 public key of the node, if present. 93 func (n *Node) Pubkey() *ecdsa.PublicKey { 94 var key ecdsa.PublicKey 95 if n.Load((*Secp256k1)(&key)) != nil { 96 return nil 97 } 98 return &key 99 } 100 101 // Record returns the node's record. The return value is a copy and may 102 // be modified by the caller. 103 func (n *Node) Record() *enr.Record { 104 cpy := n.r 105 return &cpy 106 } 107 108 // checks whether n is a valid complete node. 109 func (n *Node) ValidateComplete() error { 110 if n.Incomplete() { 111 return errors.New("incomplete node") 112 } 113 if n.UDP() == 0 { 114 return errors.New("missing UDP port") 115 } 116 ip := n.IP() 117 if ip.IsMulticast() || ip.IsUnspecified() { 118 return errors.New("invalid IP (multicast/unspecified)") 119 } 120 // Validate the node key (on curve, etc.). 121 var key Secp256k1 122 return n.Load(&key) 123 } 124 125 // The string representation of a Node is a URL. 126 // Please see ParseNode for a description of the format. 127 func (n *Node) String() string { 128 return n.v4URL() 129 } 130 131 // MarshalText implements encoding.TextMarshaler. 132 func (n *Node) MarshalText() ([]byte, error) { 133 return []byte(n.v4URL()), nil 134 } 135 136 // UnmarshalText implements encoding.TextUnmarshaler. 137 func (n *Node) UnmarshalText(text []byte) error { 138 dec, err := ParseV4(string(text)) 139 if err == nil { 140 *n = *dec 141 } 142 return err 143 } 144 145 // ID is a unique identifier for each node. 146 type ID [32]byte 147 148 // Bytes returns a byte slice representation of the ID 149 func (n ID) Bytes() []byte { 150 return n[:] 151 } 152 153 // ID prints as a long hexadecimal number. 154 func (n ID) String() string { 155 return fmt.Sprintf("%x", n[:]) 156 } 157 158 // The Go syntax representation of a ID is a call to HexID. 159 func (n ID) GoString() string { 160 return fmt.Sprintf("enode.HexID(\"%x\")", n[:]) 161 } 162 163 // TerminalString returns a shortened hex string for terminal logging. 164 func (n ID) TerminalString() string { 165 return hex.EncodeToString(n[:8]) 166 } 167 168 // MarshalText implements the encoding.TextMarshaler interface. 169 func (n ID) MarshalText() ([]byte, error) { 170 return []byte(hex.EncodeToString(n[:])), nil 171 } 172 173 // UnmarshalText implements the encoding.TextUnmarshaler interface. 174 func (n *ID) UnmarshalText(text []byte) error { 175 id, err := parseID(string(text)) 176 if err != nil { 177 return err 178 } 179 *n = id 180 return nil 181 } 182 183 // HexID converts a hex string to an ID. 184 // The string may be prefixed with 0x. 185 // It panics if the string is not a valid ID. 186 func HexID(in string) ID { 187 id, err := parseID(in) 188 if err != nil { 189 panic(err) 190 } 191 return id 192 } 193 194 func parseID(in string) (ID, error) { 195 var id ID 196 b, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) 197 if err != nil { 198 return id, err 199 } else if len(b) != len(id) { 200 return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2) 201 } 202 copy(id[:], b) 203 return id, nil 204 } 205 206 // DistCmp compares the distances a->target and b->target. 207 // Returns -1 if a is closer to target, 1 if b is closer to target 208 // and 0 if they are equal. 209 func DistCmp(target, a, b ID) int { 210 for i := range target { 211 da := a[i] ^ target[i] 212 db := b[i] ^ target[i] 213 if da > db { 214 return 1 215 } else if da < db { 216 return -1 217 } 218 } 219 return 0 220 } 221 222 // LogDist returns the logarithmic distance between a and b, log2(a ^ b). 223 func LogDist(a, b ID) int { 224 lz := 0 225 for i := range a { 226 x := a[i] ^ b[i] 227 if x == 0 { 228 lz += 8 229 } else { 230 lz += bits.LeadingZeros8(x) 231 break 232 } 233 } 234 return len(a)*8 - lz 235 } 236 237 // RandomID returns a random ID b such that logdist(a, b) == n. 238 func RandomID(a ID, n int) (b ID) { 239 if n == 0 { 240 return a 241 } 242 // flip bit at position n, fill the rest with random bits 243 b = a 244 pos := len(a) - n/8 - 1 245 bit := byte(0x01) << (byte(n%8) - 1) 246 if bit == 0 { 247 pos++ 248 bit = 0x80 249 } 250 b[pos] = a[pos]&^bit | ^a[pos]&bit // TODO: randomize end bits 251 for i := pos + 1; i < len(a); i++ { 252 b[i] = byte(rand.Intn(255)) 253 } 254 return b 255 }