github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/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 19:16:41</date> 10 //</624450104119529472> 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, nodeDBPath string, netrestrict *netutil.Netlist) (*Network, error) { 230 realaddr := conn.LocalAddr().(*net.UDPAddr) 231 transport, err := listenUDP(priv, conn, realaddr) 232 if err != nil { 233 return nil, err 234 } 235 net, err := newNetwork(transport, priv.PublicKey, nodeDBPath, netrestrict) 236 if err != nil { 237 return nil, err 238 } 239 log.Info("UDP listener up", "net", net.tab.self) 240 transport.net = net 241 go transport.readLoop() 242 return net, nil 243 } 244 245 func listenUDP(priv *ecdsa.PrivateKey, conn conn, realaddr *net.UDPAddr) (*udp, error) { 246 return &udp{conn: conn, priv: priv, ourEndpoint: makeEndpoint(realaddr, uint16(realaddr.Port))}, nil 247 } 248 249 func (t *udp) localAddr() *net.UDPAddr { 250 return t.conn.LocalAddr().(*net.UDPAddr) 251 } 252 253 func (t *udp) Close() { 254 t.conn.Close() 255 } 256 257 func (t *udp) send(remote *Node, ptype nodeEvent, data interface{}) (hash []byte) { 258 hash, _ = t.sendPacket(remote.ID, remote.addr(), byte(ptype), data) 259 return hash 260 } 261 262 func (t *udp) sendPing(remote *Node, toaddr *net.UDPAddr, topics []Topic) (hash []byte) { 263 hash, _ = t.sendPacket(remote.ID, toaddr, byte(pingPacket), ping{ 264 Version: Version, 265 From: t.ourEndpoint, 266 To: makeEndpoint(toaddr, uint16(toaddr.Port)), //TODO:可能使用数据库中已知的TCP端口 267 Expiration: uint64(time.Now().Add(expiration).Unix()), 268 Topics: topics, 269 }) 270 return hash 271 } 272 273 func (t *udp) sendFindnode(remote *Node, target NodeID) { 274 t.sendPacket(remote.ID, remote.addr(), byte(findnodePacket), findnode{ 275 Target: target, 276 Expiration: uint64(time.Now().Add(expiration).Unix()), 277 }) 278 } 279 280 func (t *udp) sendNeighbours(remote *Node, results []*Node) { 281 //以块形式发送邻居,每个数据包最多有maxneighbors 282 //低于1280字节的限制。 283 p := neighbors{Expiration: uint64(time.Now().Add(expiration).Unix())} 284 for i, result := range results { 285 p.Nodes = append(p.Nodes, nodeToRPC(result)) 286 if len(p.Nodes) == maxNeighbors || i == len(results)-1 { 287 t.sendPacket(remote.ID, remote.addr(), byte(neighborsPacket), p) 288 p.Nodes = p.Nodes[:0] 289 } 290 } 291 } 292 293 func (t *udp) sendFindnodeHash(remote *Node, target common.Hash) { 294 t.sendPacket(remote.ID, remote.addr(), byte(findnodeHashPacket), findnodeHash{ 295 Target: target, 296 Expiration: uint64(time.Now().Add(expiration).Unix()), 297 }) 298 } 299 300 func (t *udp) sendTopicRegister(remote *Node, topics []Topic, idx int, pong []byte) { 301 t.sendPacket(remote.ID, remote.addr(), byte(topicRegisterPacket), topicRegister{ 302 Topics: topics, 303 Idx: uint(idx), 304 Pong: pong, 305 }) 306 } 307 308 func (t *udp) sendTopicNodes(remote *Node, queryHash common.Hash, nodes []*Node) { 309 p := topicNodes{Echo: queryHash} 310 var sent bool 311 for _, result := range nodes { 312 if result.IP.Equal(t.net.tab.self.IP) || netutil.CheckRelayIP(remote.IP, result.IP) == nil { 313 p.Nodes = append(p.Nodes, nodeToRPC(result)) 314 } 315 if len(p.Nodes) == maxTopicNodes { 316 t.sendPacket(remote.ID, remote.addr(), byte(topicNodesPacket), p) 317 p.Nodes = p.Nodes[:0] 318 sent = true 319 } 320 } 321 if !sent || len(p.Nodes) > 0 { 322 t.sendPacket(remote.ID, remote.addr(), byte(topicNodesPacket), p) 323 } 324 } 325 326 func (t *udp) sendPacket(toid NodeID, toaddr *net.UDPAddr, ptype byte, req interface{}) (hash []byte, err error) { 327 //fmt.println(“发送包”,nodeEvent(ptype),toaddr.string(),toid.string()) 328 packet, hash, err := encodePacket(t.priv, ptype, req) 329 if err != nil { 330 //fmt.println(错误) 331 return hash, err 332 } 333 log.Trace(fmt.Sprintf(">>> %v to %x@%v", nodeEvent(ptype), toid[:8], toaddr)) 334 if nbytes, err := t.conn.WriteToUDP(packet, toaddr); err != nil { 335 log.Trace(fmt.Sprint("UDP send failed:", err)) 336 } else { 337 egressTrafficMeter.Mark(int64(nbytes)) 338 } 339 //fmt.println(错误) 340 return hash, err 341 } 342 343 //编码包的零填充空间。 344 var headSpace = make([]byte, headSize) 345 346 func encodePacket(priv *ecdsa.PrivateKey, ptype byte, req interface{}) (p, hash []byte, err error) { 347 b := new(bytes.Buffer) 348 b.Write(headSpace) 349 b.WriteByte(ptype) 350 if err := rlp.Encode(b, req); err != nil { 351 log.Error(fmt.Sprint("error encoding packet:", err)) 352 return nil, nil, err 353 } 354 packet := b.Bytes() 355 sig, err := crypto.Sign(crypto.Keccak256(packet[headSize:]), priv) 356 if err != nil { 357 log.Error(fmt.Sprint("could not sign packet:", err)) 358 return nil, nil, err 359 } 360 copy(packet, versionPrefix) 361 copy(packet[versionPrefixSize:], sig) 362 hash = crypto.Keccak256(packet[versionPrefixSize:]) 363 return packet, hash, nil 364 } 365 366 //readloop在自己的goroutine中运行。它注入入口UDP包 367 //进入网络循环。 368 func (t *udp) readLoop() { 369 defer t.conn.Close() 370 //发现数据包被定义为不大于1280字节。 371 //大于此尺寸的包装将在末端切割并处理 372 //因为它们的哈希不匹配而无效。 373 buf := make([]byte, 1280) 374 for { 375 nbytes, from, err := t.conn.ReadFromUDP(buf) 376 ingressTrafficMeter.Mark(int64(nbytes)) 377 if netutil.IsTemporaryError(err) { 378 //忽略临时读取错误。 379 log.Debug(fmt.Sprintf("Temporary read error: %v", err)) 380 continue 381 } else if err != nil { 382 //关闭永久错误循环。 383 log.Debug(fmt.Sprintf("Read error: %v", err)) 384 return 385 } 386 t.handlePacket(from, buf[:nbytes]) 387 } 388 } 389 390 func (t *udp) handlePacket(from *net.UDPAddr, buf []byte) error { 391 pkt := ingressPacket{remoteAddr: from} 392 if err := decodePacket(buf, &pkt); err != nil { 393 log.Debug(fmt.Sprintf("Bad packet from %v: %v", from, err)) 394 //fmt.println(“坏包”,err) 395 return err 396 } 397 t.net.reqReadPacket(pkt) 398 return nil 399 } 400 401 func decodePacket(buffer []byte, pkt *ingressPacket) error { 402 if len(buffer) < headSize+1 { 403 return errPacketTooSmall 404 } 405 buf := make([]byte, len(buffer)) 406 copy(buf, buffer) 407 prefix, sig, sigdata := buf[:versionPrefixSize], buf[versionPrefixSize:headSize], buf[headSize:] 408 if !bytes.Equal(prefix, versionPrefix) { 409 return errBadPrefix 410 } 411 fromID, err := recoverNodeID(crypto.Keccak256(buf[headSize:]), sig) 412 if err != nil { 413 return err 414 } 415 pkt.rawData = buf 416 pkt.hash = crypto.Keccak256(buf[versionPrefixSize:]) 417 pkt.remoteID = fromID 418 switch pkt.ev = nodeEvent(sigdata[0]); pkt.ev { 419 case pingPacket: 420 pkt.data = new(ping) 421 case pongPacket: 422 pkt.data = new(pong) 423 case findnodePacket: 424 pkt.data = new(findnode) 425 case neighborsPacket: 426 pkt.data = new(neighbors) 427 case findnodeHashPacket: 428 pkt.data = new(findnodeHash) 429 case topicRegisterPacket: 430 pkt.data = new(topicRegister) 431 case topicQueryPacket: 432 pkt.data = new(topicQuery) 433 case topicNodesPacket: 434 pkt.data = new(topicNodes) 435 default: 436 return fmt.Errorf("unknown packet type: %d", sigdata[0]) 437 } 438 s := rlp.NewStream(bytes.NewReader(sigdata[1:]), 0) 439 err = s.Decode(pkt.data) 440 return err 441 } 442