github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/p2p/discv5/udp.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 12:09:44</date> 10 //</624342657946095616> 11 12 13 package discv5 14 15 import ( 16 "bytes" 17 "crypto/ecdsa" 18 "errors" 19 "fmt" 20 "net" 21 "time" 22 23 "github.com/ethereum/go-ethereum/common" 24 "github.com/ethereum/go-ethereum/crypto" 25 "github.com/ethereum/go-ethereum/log" 26 "github.com/ethereum/go-ethereum/p2p/nat" 27 "github.com/ethereum/go-ethereum/p2p/netutil" 28 "github.com/ethereum/go-ethereum/rlp" 29 ) 30 31 const Version = 4 32 33 //错误 34 var ( 35 errPacketTooSmall = errors.New("too small") 36 errBadPrefix = errors.New("bad prefix") 37 errTimeout = errors.New("RPC timeout") 38 ) 39 40 //超时 41 const ( 42 respTimeout = 500 * time.Millisecond 43 expiration = 20 * time.Second 44 45 driftThreshold = 10 * time.Second //警告用户前允许的时钟漂移 46 ) 47 48 //RPC请求结构 49 type ( 50 ping struct { 51 Version uint 52 From, To rpcEndpoint 53 Expiration uint64 54 55 //V5 56 Topics []Topic 57 58 //忽略其他字段(为了向前兼容)。 59 Rest []rlp.RawValue `rlp:"tail"` 60 } 61 62 //乒乓球是对乒乓球的回应。 63 pong struct { 64 //此字段应镜像UDP信封地址 65 //提供了一种发现 66 //外部地址(在NAT之后)。 67 To rpcEndpoint 68 69 ReplyTok []byte //这包含ping包的哈希。 70 Expiration uint64 //数据包失效的绝对时间戳。 71 72 //V5 73 TopicHash common.Hash 74 TicketSerial uint32 75 WaitPeriods []uint32 76 77 //忽略其他字段(为了向前兼容)。 78 Rest []rlp.RawValue `rlp:"tail"` 79 } 80 81 //findnode是对接近给定目标的节点的查询。 82 findnode struct { 83 Target NodeID //不需要是实际的公钥 84 Expiration uint64 85 //忽略其他字段(为了向前兼容)。 86 Rest []rlp.RawValue `rlp:"tail"` 87 } 88 89 //findnode是对接近给定目标的节点的查询。 90 findnodeHash struct { 91 Target common.Hash 92 Expiration uint64 93 //忽略其他字段(为了向前兼容)。 94 Rest []rlp.RawValue `rlp:"tail"` 95 } 96 97 //回复findnode 98 neighbors struct { 99 Nodes []rpcNode 100 Expiration uint64 101 //忽略其他字段(为了向前兼容)。 102 Rest []rlp.RawValue `rlp:"tail"` 103 } 104 105 topicRegister struct { 106 Topics []Topic 107 Idx uint 108 Pong []byte 109 } 110 111 topicQuery struct { 112 Topic Topic 113 Expiration uint64 114 } 115 116 //答复topicquery 117 topicNodes struct { 118 Echo common.Hash 119 Nodes []rpcNode 120 } 121 122 rpcNode struct { 123 IP net.IP //IPv4的len 4或IPv6的len 16 124 UDP uint16 //用于发现协议 125 TCP uint16 //对于RLPX协议 126 ID NodeID 127 } 128 129 rpcEndpoint struct { 130 IP net.IP //IPv4的len 4或IPv6的len 16 131 UDP uint16 //用于发现协议 132 TCP uint16 //对于RLPX协议 133 } 134 ) 135 136 var ( 137 versionPrefix = []byte("temporary discovery v5") 138 versionPrefixSize = len(versionPrefix) 139 sigSize = 520 / 8 140 headSize = versionPrefixSize + sigSize //包帧数据空间 141 ) 142 143 //邻居答复通过多个数据包发送到 144 //低于1280字节的限制。我们计算最大数 145 //通过填充一个包直到它变得太大。 146 var maxNeighbors = func() int { 147 p := neighbors{Expiration: ^uint64(0)} 148 maxSizeNode := rpcNode{IP: make(net.IP, 16), UDP: ^uint16(0), TCP: ^uint16(0)} 149 for n := 0; ; n++ { 150 p.Nodes = append(p.Nodes, maxSizeNode) 151 size, _, err := rlp.EncodeToReader(p) 152 if err != nil { 153 //如果发生这种情况,它将被单元测试捕获。 154 panic("cannot encode: " + err.Error()) 155 } 156 if headSize+size+1 >= 1280 { 157 return n 158 } 159 } 160 }() 161 162 var maxTopicNodes = func() int { 163 p := topicNodes{} 164 maxSizeNode := rpcNode{IP: make(net.IP, 16), UDP: ^uint16(0), TCP: ^uint16(0)} 165 for n := 0; ; n++ { 166 p.Nodes = append(p.Nodes, maxSizeNode) 167 size, _, err := rlp.EncodeToReader(p) 168 if err != nil { 169 //如果发生这种情况,它将被单元测试捕获。 170 panic("cannot encode: " + err.Error()) 171 } 172 if headSize+size+1 >= 1280 { 173 return n 174 } 175 } 176 }() 177 178 func makeEndpoint(addr *net.UDPAddr, tcpPort uint16) rpcEndpoint { 179 ip := addr.IP.To4() 180 if ip == nil { 181 ip = addr.IP.To16() 182 } 183 return rpcEndpoint{IP: ip, UDP: uint16(addr.Port), TCP: tcpPort} 184 } 185 186 func (e1 rpcEndpoint) equal(e2 rpcEndpoint) bool { 187 return e1.UDP == e2.UDP && e1.TCP == e2.TCP && e1.IP.Equal(e2.IP) 188 } 189 190 func nodeFromRPC(sender *net.UDPAddr, rn rpcNode) (*Node, error) { 191 if err := netutil.CheckRelayIP(sender.IP, rn.IP); err != nil { 192 return nil, err 193 } 194 n := NewNode(rn.ID, rn.IP, rn.UDP, rn.TCP) 195 err := n.validateComplete() 196 return n, err 197 } 198 199 func nodeToRPC(n *Node) rpcNode { 200 return rpcNode{ID: n.ID, IP: n.IP, UDP: n.UDP, TCP: n.TCP} 201 } 202 203 type ingressPacket struct { 204 remoteID NodeID 205 remoteAddr *net.UDPAddr 206 ev nodeEvent 207 hash []byte 208 data interface{} //rpc结构之一 209 rawData []byte 210 } 211 212 type conn interface { 213 ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) 214 WriteToUDP(b []byte, addr *net.UDPAddr) (n int, err error) 215 Close() error 216 LocalAddr() net.Addr 217 } 218 219 //UDP实现RPC协议。 220 type udp struct { 221 conn conn 222 priv *ecdsa.PrivateKey 223 ourEndpoint rpcEndpoint 224 nat nat.Interface 225 net *Network 226 } 227 228 //listenudp返回一个新表,用于侦听laddr上的udp包。 229 func ListenUDP(priv *ecdsa.PrivateKey, conn conn, realaddr *net.UDPAddr, nodeDBPath string, netrestrict *netutil.Netlist) (*Network, error) { 230 transport, err := listenUDP(priv, conn, realaddr) 231 if err != nil { 232 return nil, err 233 } 234 net, err := newNetwork(transport, priv.PublicKey, nodeDBPath, netrestrict) 235 if err != nil { 236 return nil, err 237 } 238 log.Info("UDP listener up", "net", net.tab.self) 239 transport.net = net 240 go transport.readLoop() 241 return net, nil 242 } 243 244 func listenUDP(priv *ecdsa.PrivateKey, conn conn, realaddr *net.UDPAddr) (*udp, error) { 245 return &udp{conn: conn, priv: priv, ourEndpoint: makeEndpoint(realaddr, uint16(realaddr.Port))}, nil 246 } 247 248 func (t *udp) localAddr() *net.UDPAddr { 249 return t.conn.LocalAddr().(*net.UDPAddr) 250 } 251 252 func (t *udp) Close() { 253 t.conn.Close() 254 } 255 256 func (t *udp) send(remote *Node, ptype nodeEvent, data interface{}) (hash []byte) { 257 hash, _ = t.sendPacket(remote.ID, remote.addr(), byte(ptype), data) 258 return hash 259 } 260 261 func (t *udp) sendPing(remote *Node, toaddr *net.UDPAddr, topics []Topic) (hash []byte) { 262 hash, _ = t.sendPacket(remote.ID, toaddr, byte(pingPacket), ping{ 263 Version: Version, 264 From: t.ourEndpoint, 265 To: makeEndpoint(toaddr, uint16(toaddr.Port)), //TODO:可能使用数据库中已知的TCP端口 266 Expiration: uint64(time.Now().Add(expiration).Unix()), 267 Topics: topics, 268 }) 269 return hash 270 } 271 272 func (t *udp) sendFindnode(remote *Node, target NodeID) { 273 t.sendPacket(remote.ID, remote.addr(), byte(findnodePacket), findnode{ 274 Target: target, 275 Expiration: uint64(time.Now().Add(expiration).Unix()), 276 }) 277 } 278 279 func (t *udp) sendNeighbours(remote *Node, results []*Node) { 280 //以块形式发送邻居,每个数据包最多有maxneighbors 281 //低于1280字节的限制。 282 p := neighbors{Expiration: uint64(time.Now().Add(expiration).Unix())} 283 for i, result := range results { 284 p.Nodes = append(p.Nodes, nodeToRPC(result)) 285 if len(p.Nodes) == maxNeighbors || i == len(results)-1 { 286 t.sendPacket(remote.ID, remote.addr(), byte(neighborsPacket), p) 287 p.Nodes = p.Nodes[:0] 288 } 289 } 290 } 291 292 func (t *udp) sendFindnodeHash(remote *Node, target common.Hash) { 293 t.sendPacket(remote.ID, remote.addr(), byte(findnodeHashPacket), findnodeHash{ 294 Target: target, 295 Expiration: uint64(time.Now().Add(expiration).Unix()), 296 }) 297 } 298 299 func (t *udp) sendTopicRegister(remote *Node, topics []Topic, idx int, pong []byte) { 300 t.sendPacket(remote.ID, remote.addr(), byte(topicRegisterPacket), topicRegister{ 301 Topics: topics, 302 Idx: uint(idx), 303 Pong: pong, 304 }) 305 } 306 307 func (t *udp) sendTopicNodes(remote *Node, queryHash common.Hash, nodes []*Node) { 308 p := topicNodes{Echo: queryHash} 309 var sent bool 310 for _, result := range nodes { 311 if result.IP.Equal(t.net.tab.self.IP) || netutil.CheckRelayIP(remote.IP, result.IP) == nil { 312 p.Nodes = append(p.Nodes, nodeToRPC(result)) 313 } 314 if len(p.Nodes) == maxTopicNodes { 315 t.sendPacket(remote.ID, remote.addr(), byte(topicNodesPacket), p) 316 p.Nodes = p.Nodes[:0] 317 sent = true 318 } 319 } 320 if !sent || len(p.Nodes) > 0 { 321 t.sendPacket(remote.ID, remote.addr(), byte(topicNodesPacket), p) 322 } 323 } 324 325 func (t *udp) sendPacket(toid NodeID, toaddr *net.UDPAddr, ptype byte, req interface{}) (hash []byte, err error) { 326 //fmt.println(“发送包”,nodeEvent(ptype),toaddr.string(),toid.string()) 327 packet, hash, err := encodePacket(t.priv, ptype, req) 328 if err != nil { 329 //fmt.println(错误) 330 return hash, err 331 } 332 log.Trace(fmt.Sprintf(">>> %v to %x@%v", nodeEvent(ptype), toid[:8], toaddr)) 333 if nbytes, err := t.conn.WriteToUDP(packet, toaddr); err != nil { 334 log.Trace(fmt.Sprint("UDP send failed:", err)) 335 } else { 336 egressTrafficMeter.Mark(int64(nbytes)) 337 } 338 //fmt.println(错误) 339 return hash, err 340 } 341 342 //编码包的零填充空间。 343 var headSpace = make([]byte, headSize) 344 345 func encodePacket(priv *ecdsa.PrivateKey, ptype byte, req interface{}) (p, hash []byte, err error) { 346 b := new(bytes.Buffer) 347 b.Write(headSpace) 348 b.WriteByte(ptype) 349 if err := rlp.Encode(b, req); err != nil { 350 log.Error(fmt.Sprint("error encoding packet:", err)) 351 return nil, nil, err 352 } 353 packet := b.Bytes() 354 sig, err := crypto.Sign(crypto.Keccak256(packet[headSize:]), priv) 355 if err != nil { 356 log.Error(fmt.Sprint("could not sign packet:", err)) 357 return nil, nil, err 358 } 359 copy(packet, versionPrefix) 360 copy(packet[versionPrefixSize:], sig) 361 hash = crypto.Keccak256(packet[versionPrefixSize:]) 362 return packet, hash, nil 363 } 364 365 //readloop在自己的goroutine中运行。它注入入口UDP包 366 //进入网络循环。 367 func (t *udp) readLoop() { 368 defer t.conn.Close() 369 //发现数据包被定义为不大于1280字节。 370 //大于此尺寸的包装将在末端切割并处理 371 //因为它们的哈希不匹配而无效。 372 buf := make([]byte, 1280) 373 for { 374 nbytes, from, err := t.conn.ReadFromUDP(buf) 375 ingressTrafficMeter.Mark(int64(nbytes)) 376 if netutil.IsTemporaryError(err) { 377 //忽略临时读取错误。 378 log.Debug(fmt.Sprintf("Temporary read error: %v", err)) 379 continue 380 } else if err != nil { 381 //关闭永久错误循环。 382 log.Debug(fmt.Sprintf("Read error: %v", err)) 383 return 384 } 385 t.handlePacket(from, buf[:nbytes]) 386 } 387 } 388 389 func (t *udp) handlePacket(from *net.UDPAddr, buf []byte) error { 390 pkt := ingressPacket{remoteAddr: from} 391 if err := decodePacket(buf, &pkt); err != nil { 392 log.Debug(fmt.Sprintf("Bad packet from %v: %v", from, err)) 393 //fmt.println(“坏包”,err) 394 return err 395 } 396 t.net.reqReadPacket(pkt) 397 return nil 398 } 399 400 func decodePacket(buffer []byte, pkt *ingressPacket) error { 401 if len(buffer) < headSize+1 { 402 return errPacketTooSmall 403 } 404 buf := make([]byte, len(buffer)) 405 copy(buf, buffer) 406 prefix, sig, sigdata := buf[:versionPrefixSize], buf[versionPrefixSize:headSize], buf[headSize:] 407 if !bytes.Equal(prefix, versionPrefix) { 408 return errBadPrefix 409 } 410 fromID, err := recoverNodeID(crypto.Keccak256(buf[headSize:]), sig) 411 if err != nil { 412 return err 413 } 414 pkt.rawData = buf 415 pkt.hash = crypto.Keccak256(buf[versionPrefixSize:]) 416 pkt.remoteID = fromID 417 switch pkt.ev = nodeEvent(sigdata[0]); pkt.ev { 418 case pingPacket: 419 pkt.data = new(ping) 420 case pongPacket: 421 pkt.data = new(pong) 422 case findnodePacket: 423 pkt.data = new(findnode) 424 case neighborsPacket: 425 pkt.data = new(neighbors) 426 case findnodeHashPacket: 427 pkt.data = new(findnodeHash) 428 case topicRegisterPacket: 429 pkt.data = new(topicRegister) 430 case topicQueryPacket: 431 pkt.data = new(topicQuery) 432 case topicNodesPacket: 433 pkt.data = new(topicNodes) 434 default: 435 return fmt.Errorf("unknown packet type: %d", sigdata[0]) 436 } 437 s := rlp.NewStream(bytes.NewReader(sigdata[1:]), 0) 438 err = s.Decode(pkt.data) 439 return err 440 } 441