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