github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/p2p/enode/node.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:41</date> 10 //</624450104413130752> 11 12 13 package enode 14 15 import ( 16 "crypto/ecdsa" 17 "encoding/hex" 18 "errors" 19 "fmt" 20 "math/bits" 21 "math/rand" 22 "net" 23 "strings" 24 25 "github.com/ethereum/go-ethereum/p2p/enr" 26 ) 27 28 //节点表示网络上的主机。 29 type Node struct { 30 r enr.Record 31 id ID 32 } 33 34 //New包装节点记录。根据给定的记录必须是有效的 35 //身份方案。 36 func New(validSchemes enr.IdentityScheme, r *enr.Record) (*Node, error) { 37 if err := r.VerifySignature(validSchemes); err != nil { 38 return nil, err 39 } 40 node := &Node{r: *r} 41 if n := copy(node.id[:], validSchemes.NodeAddr(&node.r)); n != len(ID{}) { 42 return nil, fmt.Errorf("invalid node ID length %d, need %d", n, len(ID{})) 43 } 44 return node, nil 45 } 46 47 //ID返回节点标识符。 48 func (n *Node) ID() ID { 49 return n.id 50 } 51 52 //seq返回基础记录的序列号。 53 func (n *Node) Seq() uint64 { 54 return n.r.Seq() 55 } 56 57 //对于没有IP地址的节点,不完整返回true。 58 func (n *Node) Incomplete() bool { 59 return n.IP() == nil 60 } 61 62 //LOAD从基础记录中检索一个条目。 63 func (n *Node) Load(k enr.Entry) error { 64 return n.r.Load(k) 65 } 66 67 //IP返回节点的IP地址。 68 func (n *Node) IP() net.IP { 69 var ip net.IP 70 n.Load((*enr.IP)(&ip)) 71 return ip 72 } 73 74 //udp返回节点的udp端口。 75 func (n *Node) UDP() int { 76 var port enr.UDP 77 n.Load(&port) 78 return int(port) 79 } 80 81 //UDP返回节点的TCP端口。 82 func (n *Node) TCP() int { 83 var port enr.TCP 84 n.Load(&port) 85 return int(port) 86 } 87 88 //pubkey返回节点的secp256k1公钥(如果存在)。 89 func (n *Node) Pubkey() *ecdsa.PublicKey { 90 var key ecdsa.PublicKey 91 if n.Load((*Secp256k1)(&key)) != nil { 92 return nil 93 } 94 return &key 95 } 96 97 //record返回节点的记录。返回值是一个副本,可以 98 //由调用者修改。 99 func (n *Node) Record() *enr.Record { 100 cpy := n.r 101 return &cpy 102 } 103 104 //检查n是否为有效的完整节点。 105 func (n *Node) ValidateComplete() error { 106 if n.Incomplete() { 107 return errors.New("incomplete node") 108 } 109 if n.UDP() == 0 { 110 return errors.New("missing UDP port") 111 } 112 ip := n.IP() 113 if ip.IsMulticast() || ip.IsUnspecified() { 114 return errors.New("invalid IP (multicast/unspecified)") 115 } 116 //验证节点键(在曲线上等)。 117 var key Secp256k1 118 return n.Load(&key) 119 } 120 121 //节点的字符串表示形式是一个URL。 122 //有关格式的描述,请参阅ParseNode。 123 func (n *Node) String() string { 124 return n.v4URL() 125 } 126 127 //MarshalText实现Encoding.TextMarshaler。 128 func (n *Node) MarshalText() ([]byte, error) { 129 return []byte(n.v4URL()), nil 130 } 131 132 //UnmarshalText实现encoding.textUnmarshaller。 133 func (n *Node) UnmarshalText(text []byte) error { 134 dec, err := ParseV4(string(text)) 135 if err == nil { 136 *n = *dec 137 } 138 return err 139 } 140 141 //ID是每个节点的唯一标识符。 142 type ID [32]byte 143 144 //bytes返回ID的字节片表示形式 145 func (n ID) Bytes() []byte { 146 return n[:] 147 } 148 149 //ID以十六进制长数字打印。 150 func (n ID) String() string { 151 return fmt.Sprintf("%x", n[:]) 152 } 153 154 //ID的go语法表示是对hexid的调用。 155 func (n ID) GoString() string { 156 return fmt.Sprintf("enode.HexID(\"%x\")", n[:]) 157 } 158 159 //TerminalString返回用于终端日志记录的缩短的十六进制字符串。 160 func (n ID) TerminalString() string { 161 return hex.EncodeToString(n[:8]) 162 } 163 164 //MarshalText实现Encoding.TextMarshaler接口。 165 func (n ID) MarshalText() ([]byte, error) { 166 return []byte(hex.EncodeToString(n[:])), nil 167 } 168 169 //UnmarshalText实现encoding.textUnmarshaller接口。 170 func (n *ID) UnmarshalText(text []byte) error { 171 id, err := parseID(string(text)) 172 if err != nil { 173 return err 174 } 175 *n = id 176 return nil 177 } 178 179 //hex id将十六进制字符串转换为ID。 180 //字符串的前缀可以是0x。 181 //如果字符串不是有效的ID,则会恐慌。 182 func HexID(in string) ID { 183 id, err := parseID(in) 184 if err != nil { 185 panic(err) 186 } 187 return id 188 } 189 190 func parseID(in string) (ID, error) { 191 var id ID 192 b, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) 193 if err != nil { 194 return id, err 195 } else if len(b) != len(id) { 196 return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2) 197 } 198 copy(id[:], b) 199 return id, nil 200 } 201 202 //distcmp比较距离a->target和b->target。 203 //如果a接近目标返回-1,如果b接近目标返回1 204 //如果相等,则为0。 205 func DistCmp(target, a, b ID) int { 206 for i := range target { 207 da := a[i] ^ target[i] 208 db := b[i] ^ target[i] 209 if da > db { 210 return 1 211 } else if da < db { 212 return -1 213 } 214 } 215 return 0 216 } 217 218 //logdist返回a和b之间的对数距离,log2(a^b)。 219 func LogDist(a, b ID) int { 220 lz := 0 221 for i := range a { 222 x := a[i] ^ b[i] 223 if x == 0 { 224 lz += 8 225 } else { 226 lz += bits.LeadingZeros8(x) 227 break 228 } 229 } 230 return len(a)*8 - lz 231 } 232 233 //随机返回一个随机ID B,使得logdist(a,b)=n。 234 func RandomID(a ID, n int) (b ID) { 235 if n == 0 { 236 return a 237 } 238 //在n位置翻转钻头,其余部分用随机钻头填满。 239 b = a 240 pos := len(a) - n/8 - 1 241 bit := byte(0x01) << (byte(n%8) - 1) 242 if bit == 0 { 243 pos++ 244 bit = 0x80 245 } 246 b[pos] = a[pos]&^bit | ^a[pos]&bit //TODO:随机结束位 247 for i := pos + 1; i < len(a); i++ { 248 b[i] = byte(rand.Intn(255)) 249 } 250 return b 251 } 252