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