Brother blockchain getting started tutorial ETH source code analysis p2p-udp.go source code analysis ()
The Network Discovery Protocol of P2P uses the kademlia protocol to process node discovery of the network. Node search and node update. Kademlia protocol uses UDP protocol for network communication.
Read this part of the code. We recommend that you first look at the introduction of the kademlia protocol in references to see what the kademlia protocol is.
First, let's look at the data structure. Four types of data packets are transmitted over the network (UDP is a packet-based protocol. One data packet is transmitted), which is
Ping, Pong, findnode, and neighbors. The following defines four message formats. // RPC packet types const (pingpacket = iota + 1 // zero is 'reserved' pongpacket findnodepacket neighborspacket) // RPC Request structures type (Ping struct {version uint // Protocol version from, to rpcendpoint // the destination IP address expiration uint64 // timeout // ignore additional fields (for forward compatibility ). // ignore fields. To forward compatibility with rest [] RLP. rawvalue 'rlp: "tail" '} ''// Pong is the reply to ping. // ping packet response Pong struct {// This field shocould mirror the UDP envelope address // Of the ping packet, which provides a way to discover the // The external address (after Nat ). // The destination IP address to rpcendpoint // indicates that the pong packet responds to the ping packet. Contains the ping packet's hash value replytok [] Byte // This contains the hash of the ping packet. // The absolute timeout time of the packet. If the packet received exceeds this time, the packet is deemed to have timed out. Expiration uint64 // absolute timestamp at which the packet becomes invalid. // ignore additional fields (for forward compatibility ). rest [] RLP. rawvalue 'rlp: "tail" '} // findnode is used to query nodes that are relatively close to the target. // findnode is a query for nodes close to the given target. findnode struct {// target node nodeid // doesn't need to be an actual public key expiration uint64 // ignore additional fields (for forwa Rd compatibility ). rest [] RLP. rawvalue 'rlp: "tail" '} // reply to findnode // node value near the target in response to the neighbors struct. Nodes [] rpcnode expiration uint64 // ignore additional fields (for forward compatibility ). rest [] RLP. rawvalue 'rlp: "tail" '} rpcnode struct {IP net. IP // Len 4 for IPv4 or 16 for IPv6 UDP uint16 // For Discovery protocol TCP uint16 // For rlpx protocol id nodeid} rpcendpoint struct {IP net. IP // Len 4 for IPv4 or 16 for IPv6 UDP uint16 // For Discovery protocol TCP uint16 // For rlpx Protocol }) Two interface types are defined. The packet interface type should be to assign different handle methods to four different types of packages. The conn interface defines a UDP connection function. Type Packet interface {handle (T * UDP, from * Net. udpaddr, fromid nodeid, Mac [] Byte) Error name () string} type conn interface {readfromudp (B [] Byte) (N int, ADDR * Net. udpaddr, err error) writetoudp (B [] Byte, ADDR * Net. udpaddr) (N int, err error) Close () Error localaddr () net. ADDR} UDP structure. Note that the last field * Table is an anonymous field in go. That is to say, UDP can directly call the table method of the anonymous field. // UDP implements the RPC protocol. type UDP struct {conn // network connection netrestrict * netutil. netlist priv * ECDSA. privatekey // private key, which is used to generate your own ID. Ourendpoint rpcendpoint addpending chan * Pending // used to apply for a pending gotreply Chan reply // used to obtain the response queue closing Chan struct {} // used to disable the NAT Nat of the queue. interface * Table} pending and reply structures. The structure for communication between the two structures of the Go routine. // Pending represents a pending reply. // some implementations of the Protocol wish to send more than one // reply packet to findnode. in general, any neighbors packet cannot // be matched up with a specific findnode packet. // Our implementation handles this by storing a callback function for // each pending reply. incoming packets from a node are dispatched // to all the callback functions for T The hat node. // pending structure means waiting for a reply. // you can store a callback for each pending reply to implement this function. All data packets from a node are allocated to the corresponding callback of the node. Type pending struct {// these fields must match in the reply. from nodeid ptype byte // time when the request must complete deadline time. time // callback is called when a matching reply arrives. if it returns // true, the callback is removed from the pending reply queue. // if it returns false, the reply is considered incomplete and // The callback will be invoked again for the next matching rep Ly. // If the returned value is true. Then callback will be removed from the queue. If false is returned, reply is considered to have not been completed, and the next reply will continue. callback func (RESP interface {}) (done bool) // ERRC when es nil when the callback indicates completion or an // error if no further reply is already ed within the timeout. ERRC Chan <-error} type reply struct {from nodeid ptype byte data interface {} // loop indicates whether there was // a matching request by sending on this channel. // send a message to the channel to indicate Matches a request. Matched Chan <-bool} UDP creation // listenudp returns a new table that listens for UDP packets on laddr. func listenudp (priv * ECDSA. privatekey, laddr string, NATM Nat. interface, nodedbpath string, netrestrict * netutil. netlist) (* Table, error) {ADDR, err: = net. resolveudpaddr ("UDP", laddr) If Err! = Nil {return nil, err} Conn, err: = net. listenudp ("UDP", ADDR) If Err! = Nil {return nil, err} tab, _, err: = newudp (priv, Conn, NATM, nodedbpath, netrestrict) If Err! = Nil {return nil, err} log. info ("UDP listener up", "self", Tab. self) return tab, nil} func newudp (priv * ECDSA. privatekey, C Conn, NATM Nat. interface, nodedbpath string, netrestrict * netutil. netlist) (* Table, * UDP, error) {UDP: = & UDP {Conn: C, priv: priv, netrestrict: netrestrict, closing: Make (Chan struct {}), gotreply: Make (Chan reply), addpending: Make (chan * pending),} realaddr: = C. localad Dr (). (* Net. udpaddr) If NATM! = Nil {// NATM Nat mapping is used to obtain the Internet address if! Realaddr. IP. isloopback () {// if the address is a local loopback address go Nat. map (NATM, UDP. closing, "UDP", realaddr. port, realaddr. port, "ethereum discovery")} // todo: react to external IP changes over time. if Ext, err: = NATM. externalip (); err = nil {realaddr = & net. udpaddr {IP: EXT, Port: realaddr. port }}// todo: separate TCP port UDP. ourendpoint = makeendpoint (realaddr, uint16 (realaddr. port) // create a table. The main logic of kademlia is implemented in this class. Tab, err: = newtable (UDP, pubkeyid (& priv. publickey), realaddr, nodedbpath) If Err! = Nil {return nil, nil, err} UDP. table = tab // anonymous field value assignment go UDP. loop () // go routine go UDP. readloop () // read network data. Return UDP. Table, UDP, nil}
Brother blockchain getting started tutorial ETH source code analysis p2p-udp.go source code analysis ()