github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/p2p/discover/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  //</624450103171616768>
    11  
    12  
    13  package discover
    14  
    15  import (
    16  	"bytes"
    17  	"container/list"
    18  	"crypto/ecdsa"
    19  	"errors"
    20  	"fmt"
    21  	"net"
    22  	"sync"
    23  	"time"
    24  
    25  	"github.com/ethereum/go-ethereum/crypto"
    26  	"github.com/ethereum/go-ethereum/log"
    27  	"github.com/ethereum/go-ethereum/p2p/enode"
    28  	"github.com/ethereum/go-ethereum/p2p/netutil"
    29  	"github.com/ethereum/go-ethereum/rlp"
    30  )
    31  
    32  //错误
    33  var (
    34  	errPacketTooSmall   = errors.New("too small")
    35  	errBadHash          = errors.New("bad hash")
    36  	errExpired          = errors.New("expired")
    37  	errUnsolicitedReply = errors.New("unsolicited reply")
    38  	errUnknownNode      = errors.New("unknown node")
    39  	errTimeout          = errors.New("RPC timeout")
    40  	errClockWarp        = errors.New("reply deadline too far in the future")
    41  	errClosed           = errors.New("socket closed")
    42  )
    43  
    44  //超时
    45  const (
    46  	respTimeout    = 500 * time.Millisecond
    47  	expiration     = 20 * time.Second
    48  	bondExpiration = 24 * time.Hour
    49  
    50  ntpFailureThreshold = 32               //连续超时,之后检查NTP
    51  ntpWarningCooldown  = 10 * time.Minute //重复NTP警告之前要经过的最短时间
    52  driftThreshold      = 10 * time.Second //警告用户前允许的时钟漂移
    53  )
    54  
    55  //RPC数据包类型
    56  const (
    57  pingPacket = iota + 1 //零为“保留”
    58  	pongPacket
    59  	findnodePacket
    60  	neighborsPacket
    61  )
    62  
    63  //RPC请求结构
    64  type (
    65  	ping struct {
    66  		Version    uint
    67  		From, To   rpcEndpoint
    68  		Expiration uint64
    69  //忽略其他字段(为了向前兼容)。
    70  		Rest []rlp.RawValue `rlp:"tail"`
    71  	}
    72  
    73  //乒乓球是对乒乓球的回应。
    74  	pong struct {
    75  //此字段应镜像UDP信封地址
    76  //提供了一种发现
    77  //外部地址(在NAT之后)。
    78  		To rpcEndpoint
    79  
    80  ReplyTok   []byte //这包含ping包的哈希。
    81  Expiration uint64 //数据包失效的绝对时间戳。
    82  //忽略其他字段(为了向前兼容)。
    83  		Rest []rlp.RawValue `rlp:"tail"`
    84  	}
    85  
    86  //findnode是对接近给定目标的节点的查询。
    87  	findnode struct {
    88  		Target     encPubkey
    89  		Expiration uint64
    90  //忽略其他字段(为了向前兼容)。
    91  		Rest []rlp.RawValue `rlp:"tail"`
    92  	}
    93  
    94  //回复findnode
    95  	neighbors struct {
    96  		Nodes      []rpcNode
    97  		Expiration uint64
    98  //忽略其他字段(为了向前兼容)。
    99  		Rest []rlp.RawValue `rlp:"tail"`
   100  	}
   101  
   102  	rpcNode struct {
   103  IP  net.IP //IPv4的len 4或IPv6的len 16
   104  UDP uint16 //用于发现协议
   105  TCP uint16 //对于RLPX协议
   106  		ID  encPubkey
   107  	}
   108  
   109  	rpcEndpoint struct {
   110  IP  net.IP //IPv4的len 4或IPv6的len 16
   111  UDP uint16 //用于发现协议
   112  TCP uint16 //对于RLPX协议
   113  	}
   114  )
   115  
   116  func makeEndpoint(addr *net.UDPAddr, tcpPort uint16) rpcEndpoint {
   117  	ip := net.IP{}
   118  	if ip4 := addr.IP.To4(); ip4 != nil {
   119  		ip = ip4
   120  	} else if ip6 := addr.IP.To16(); ip6 != nil {
   121  		ip = ip6
   122  	}
   123  	return rpcEndpoint{IP: ip, UDP: uint16(addr.Port), TCP: tcpPort}
   124  }
   125  
   126  func (t *udp) nodeFromRPC(sender *net.UDPAddr, rn rpcNode) (*node, error) {
   127  	if rn.UDP <= 1024 {
   128  		return nil, errors.New("low port")
   129  	}
   130  	if err := netutil.CheckRelayIP(sender.IP, rn.IP); err != nil {
   131  		return nil, err
   132  	}
   133  	if t.netrestrict != nil && !t.netrestrict.Contains(rn.IP) {
   134  		return nil, errors.New("not contained in netrestrict whitelist")
   135  	}
   136  	key, err := decodePubkey(rn.ID)
   137  	if err != nil {
   138  		return nil, err
   139  	}
   140  	n := wrapNode(enode.NewV4(key, rn.IP, int(rn.TCP), int(rn.UDP)))
   141  	err = n.ValidateComplete()
   142  	return n, err
   143  }
   144  
   145  func nodeToRPC(n *node) rpcNode {
   146  	var key ecdsa.PublicKey
   147  	var ekey encPubkey
   148  	if err := n.Load((*enode.Secp256k1)(&key)); err == nil {
   149  		ekey = encodePubkey(&key)
   150  	}
   151  	return rpcNode{ID: ekey, IP: n.IP(), UDP: uint16(n.UDP()), TCP: uint16(n.TCP())}
   152  }
   153  
   154  type packet interface {
   155  	handle(t *udp, from *net.UDPAddr, fromKey encPubkey, mac []byte) error
   156  	name() string
   157  }
   158  
   159  type conn interface {
   160  	ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error)
   161  	WriteToUDP(b []byte, addr *net.UDPAddr) (n int, err error)
   162  	Close() error
   163  	LocalAddr() net.Addr
   164  }
   165  
   166  //UDP实现Discovery v4 UDP有线协议。
   167  type udp struct {
   168  	conn        conn
   169  	netrestrict *netutil.Netlist
   170  	priv        *ecdsa.PrivateKey
   171  	localNode   *enode.LocalNode
   172  	db          *enode.DB
   173  	tab         *Table
   174  	wg          sync.WaitGroup
   175  
   176  	addpending chan *pending
   177  	gotreply   chan reply
   178  	closing    chan struct{}
   179  }
   180  
   181  //挂起表示挂起的答复。
   182  //
   183  //协议的某些实现希望发送多个
   184  //将数据包回复到findnode。一般来说,任何邻居包都不能
   185  //与特定的findnode包匹配。
   186  //
   187  //我们的实现通过存储
   188  //每个等待答复。来自节点的传入数据包被调度
   189  //到该节点的所有回调函数。
   190  type pending struct {
   191  //这些字段必须在答复中匹配。
   192  	from  enode.ID
   193  	ptype byte
   194  
   195  //请求必须完成的时间
   196  	deadline time.Time
   197  
   198  //当匹配的答复到达时调用回调。如果它回来
   199  //如果为true,则从挂起的答复队列中删除回调。
   200  //如果返回错误,则认为答复不完整,并且
   201  //将为下一个匹配的答复再次调用回调。
   202  	callback func(resp interface{}) (done bool)
   203  
   204  //当回调指示完成或
   205  //如果在超时时间内没有收到进一步的答复,则出错。
   206  	errc chan<- error
   207  }
   208  
   209  type reply struct {
   210  	from  enode.ID
   211  	ptype byte
   212  	data  interface{}
   213  //循环指示是否存在
   214  //通过此频道发送的匹配请求。
   215  	matched chan<- bool
   216  }
   217  
   218  //无法处理readpacket时,会将其发送到未处理的通道。
   219  type ReadPacket struct {
   220  	Data []byte
   221  	Addr *net.UDPAddr
   222  }
   223  
   224  //配置保存与表相关的设置。
   225  type Config struct {
   226  //需要这些设置并配置UDP侦听器:
   227  	PrivateKey *ecdsa.PrivateKey
   228  
   229  //这些设置是可选的:
   230  NetRestrict *netutil.Netlist  //网络白名单
   231  Bootnodes   []*enode.Node     //引导程序节点列表
   232  Unhandled   chan<- ReadPacket //在此通道上发送未处理的数据包
   233  }
   234  
   235  //listenudp返回一个新表,用于侦听laddr上的udp包。
   236  func ListenUDP(c conn, ln *enode.LocalNode, cfg Config) (*Table, error) {
   237  	tab, _, err := newUDP(c, ln, cfg)
   238  	if err != nil {
   239  		return nil, err
   240  	}
   241  	return tab, nil
   242  }
   243  
   244  func newUDP(c conn, ln *enode.LocalNode, cfg Config) (*Table, *udp, error) {
   245  	udp := &udp{
   246  		conn:        c,
   247  		priv:        cfg.PrivateKey,
   248  		netrestrict: cfg.NetRestrict,
   249  		localNode:   ln,
   250  		db:          ln.Database(),
   251  		closing:     make(chan struct{}),
   252  		gotreply:    make(chan reply),
   253  		addpending:  make(chan *pending),
   254  	}
   255  	tab, err := newTable(udp, ln.Database(), cfg.Bootnodes)
   256  	if err != nil {
   257  		return nil, nil, err
   258  	}
   259  	udp.tab = tab
   260  
   261  	udp.wg.Add(2)
   262  	go udp.loop()
   263  	go udp.readLoop(cfg.Unhandled)
   264  	return udp.tab, udp, nil
   265  }
   266  
   267  func (t *udp) self() *enode.Node {
   268  	return t.localNode.Node()
   269  }
   270  
   271  func (t *udp) close() {
   272  	close(t.closing)
   273  	t.conn.Close()
   274  	t.wg.Wait()
   275  }
   276  
   277  func (t *udp) ourEndpoint() rpcEndpoint {
   278  	n := t.self()
   279  	a := &net.UDPAddr{IP: n.IP(), Port: n.UDP()}
   280  	return makeEndpoint(a, uint16(n.TCP()))
   281  }
   282  
   283  //ping向给定节点发送ping消息并等待答复。
   284  func (t *udp) ping(toid enode.ID, toaddr *net.UDPAddr) error {
   285  	return <-t.sendPing(toid, toaddr, nil)
   286  }
   287  
   288  //发送ping向给定节点发送ping消息并调用回调
   289  //当回复到达时。
   290  func (t *udp) sendPing(toid enode.ID, toaddr *net.UDPAddr, callback func()) <-chan error {
   291  	req := &ping{
   292  		Version:    4,
   293  		From:       t.ourEndpoint(),
   294  To:         makeEndpoint(toaddr, 0), //TODO:可能使用数据库中已知的TCP端口
   295  		Expiration: uint64(time.Now().Add(expiration).Unix()),
   296  	}
   297  	packet, hash, err := encodePacket(t.priv, pingPacket, req)
   298  	if err != nil {
   299  		errc := make(chan error, 1)
   300  		errc <- err
   301  		return errc
   302  	}
   303  	errc := t.pending(toid, pongPacket, func(p interface{}) bool {
   304  		ok := bytes.Equal(p.(*pong).ReplyTok, hash)
   305  		if ok && callback != nil {
   306  			callback()
   307  		}
   308  		return ok
   309  	})
   310  	t.localNode.UDPContact(toaddr)
   311  	t.write(toaddr, req.name(), packet)
   312  	return errc
   313  }
   314  
   315  func (t *udp) waitping(from enode.ID) error {
   316  	return <-t.pending(from, pingPacket, func(interface{}) bool { return true })
   317  }
   318  
   319  //findnode向给定节点发送findnode请求,并等待直到
   320  //节点已发送到k个邻居。
   321  func (t *udp) findnode(toid enode.ID, toaddr *net.UDPAddr, target encPubkey) ([]*node, error) {
   322  //如果我们有一段时间没有看到目标节点的ping,它将不会记得
   323  //我们的端点证明和拒绝findnode。先打个乒乓球。
   324  	if time.Since(t.db.LastPingReceived(toid)) > bondExpiration {
   325  		t.ping(toid, toaddr)
   326  		t.waitping(toid)
   327  	}
   328  
   329  	nodes := make([]*node, 0, bucketSize)
   330  	nreceived := 0
   331  	errc := t.pending(toid, neighborsPacket, func(r interface{}) bool {
   332  		reply := r.(*neighbors)
   333  		for _, rn := range reply.Nodes {
   334  			nreceived++
   335  			n, err := t.nodeFromRPC(toaddr, rn)
   336  			if err != nil {
   337  				log.Trace("Invalid neighbor node received", "ip", rn.IP, "addr", toaddr, "err", err)
   338  				continue
   339  			}
   340  			nodes = append(nodes, n)
   341  		}
   342  		return nreceived >= bucketSize
   343  	})
   344  	t.send(toaddr, findnodePacket, &findnode{
   345  		Target:     target,
   346  		Expiration: uint64(time.Now().Add(expiration).Unix()),
   347  	})
   348  	return nodes, <-errc
   349  }
   350  
   351  //挂起向挂起的答复队列添加答复回调。
   352  //有关详细说明,请参阅“挂起”类型的文档。
   353  func (t *udp) pending(id enode.ID, ptype byte, callback func(interface{}) bool) <-chan error {
   354  	ch := make(chan error, 1)
   355  	p := &pending{from: id, ptype: ptype, callback: callback, errc: ch}
   356  	select {
   357  	case t.addpending <- p:
   358  //循环将处理它
   359  	case <-t.closing:
   360  		ch <- errClosed
   361  	}
   362  	return ch
   363  }
   364  
   365  func (t *udp) handleReply(from enode.ID, ptype byte, req packet) bool {
   366  	matched := make(chan bool, 1)
   367  	select {
   368  	case t.gotreply <- reply{from, ptype, req, matched}:
   369  //循环将处理它
   370  		return <-matched
   371  	case <-t.closing:
   372  		return false
   373  	}
   374  }
   375  
   376  //循环在自己的Goroutine中运行。它跟踪
   377  //刷新计时器和挂起的答复队列。
   378  func (t *udp) loop() {
   379  	defer t.wg.Done()
   380  
   381  	var (
   382  		plist        = list.New()
   383  		timeout      = time.NewTimer(0)
   384  nextTimeout  *pending //上次重置超时时的plist头
   385  contTimeouts = 0      //要执行NTP检查的连续超时数
   386  		ntpWarnTime  = time.Unix(0, 0)
   387  	)
   388  <-timeout.C //忽略第一次超时
   389  	defer timeout.Stop()
   390  
   391  	resetTimeout := func() {
   392  		if plist.Front() == nil || nextTimeout == plist.Front().Value {
   393  			return
   394  		}
   395  //启动计时器,以便在下一个挂起的答复过期时触发。
   396  		now := time.Now()
   397  		for el := plist.Front(); el != nil; el = el.Next() {
   398  			nextTimeout = el.Value.(*pending)
   399  			if dist := nextTimeout.deadline.Sub(now); dist < 2*respTimeout {
   400  				timeout.Reset(dist)
   401  				return
   402  			}
   403  //删除截止时间太长的挂起答复
   404  //未来。如果系统时钟跳变,就会发生这种情况。
   405  //在最后期限被分配后向后。
   406  			nextTimeout.errc <- errClockWarp
   407  			plist.Remove(el)
   408  		}
   409  		nextTimeout = nil
   410  		timeout.Stop()
   411  	}
   412  
   413  	for {
   414  		resetTimeout()
   415  
   416  		select {
   417  		case <-t.closing:
   418  			for el := plist.Front(); el != nil; el = el.Next() {
   419  				el.Value.(*pending).errc <- errClosed
   420  			}
   421  			return
   422  
   423  		case p := <-t.addpending:
   424  			p.deadline = time.Now().Add(respTimeout)
   425  			plist.PushBack(p)
   426  
   427  		case r := <-t.gotreply:
   428  			var matched bool
   429  			for el := plist.Front(); el != nil; el = el.Next() {
   430  				p := el.Value.(*pending)
   431  				if p.from == r.from && p.ptype == r.ptype {
   432  					matched = true
   433  //如果Matcher的回调指示
   434  //所有答复都已收到。这是
   435  //需要多个数据包类型
   436  //应答包。
   437  					if p.callback(r.data) {
   438  						p.errc <- nil
   439  						plist.Remove(el)
   440  					}
   441  //重置连续超时计数器(时间漂移检测)
   442  					contTimeouts = 0
   443  				}
   444  			}
   445  			r.matched <- matched
   446  
   447  		case now := <-timeout.C:
   448  			nextTimeout = nil
   449  
   450  //通知并删除期限已过的回调。
   451  			for el := plist.Front(); el != nil; el = el.Next() {
   452  				p := el.Value.(*pending)
   453  				if now.After(p.deadline) || now.Equal(p.deadline) {
   454  					p.errc <- errTimeout
   455  					plist.Remove(el)
   456  					contTimeouts++
   457  				}
   458  			}
   459  //如果我们累积了太多超时,请执行NTP时间同步检查
   460  			if contTimeouts > ntpFailureThreshold {
   461  				if time.Since(ntpWarnTime) >= ntpWarningCooldown {
   462  					ntpWarnTime = time.Now()
   463  					go checkClockDrift()
   464  				}
   465  				contTimeouts = 0
   466  			}
   467  		}
   468  	}
   469  }
   470  
   471  const (
   472  	macSize  = 256 / 8
   473  	sigSize  = 520 / 8
   474  headSize = macSize + sigSize //包帧数据空间
   475  )
   476  
   477  var (
   478  	headSpace = make([]byte, headSize)
   479  
   480  //邻居答复通过多个数据包发送到
   481  //低于1280字节的限制。我们计算最大数
   482  //通过填充一个包直到它变得太大。
   483  	maxNeighbors int
   484  )
   485  
   486  func init() {
   487  	p := neighbors{Expiration: ^uint64(0)}
   488  	maxSizeNode := rpcNode{IP: make(net.IP, 16), UDP: ^uint16(0), TCP: ^uint16(0)}
   489  	for n := 0; ; n++ {
   490  		p.Nodes = append(p.Nodes, maxSizeNode)
   491  		size, _, err := rlp.EncodeToReader(p)
   492  		if err != nil {
   493  //如果发生这种情况,它将被单元测试捕获。
   494  			panic("cannot encode: " + err.Error())
   495  		}
   496  		if headSize+size+1 >= 1280 {
   497  			maxNeighbors = n
   498  			break
   499  		}
   500  	}
   501  }
   502  
   503  func (t *udp) send(toaddr *net.UDPAddr, ptype byte, req packet) ([]byte, error) {
   504  	packet, hash, err := encodePacket(t.priv, ptype, req)
   505  	if err != nil {
   506  		return hash, err
   507  	}
   508  	return hash, t.write(toaddr, req.name(), packet)
   509  }
   510  
   511  func (t *udp) write(toaddr *net.UDPAddr, what string, packet []byte) error {
   512  	_, err := t.conn.WriteToUDP(packet, toaddr)
   513  	log.Trace(">> "+what, "addr", toaddr, "err", err)
   514  	return err
   515  }
   516  
   517  func encodePacket(priv *ecdsa.PrivateKey, ptype byte, req interface{}) (packet, hash []byte, err error) {
   518  	b := new(bytes.Buffer)
   519  	b.Write(headSpace)
   520  	b.WriteByte(ptype)
   521  	if err := rlp.Encode(b, req); err != nil {
   522  		log.Error("Can't encode discv4 packet", "err", err)
   523  		return nil, nil, err
   524  	}
   525  	packet = b.Bytes()
   526  	sig, err := crypto.Sign(crypto.Keccak256(packet[headSize:]), priv)
   527  	if err != nil {
   528  		log.Error("Can't sign discv4 packet", "err", err)
   529  		return nil, nil, err
   530  	}
   531  	copy(packet[macSize:], sig)
   532  //将哈希添加到前面。注意:这不保护
   533  //以任何方式打包。我们的公钥将是这个哈希的一部分
   534  //未来。
   535  	hash = crypto.Keccak256(packet[macSize:])
   536  	copy(packet, hash)
   537  	return packet, hash, nil
   538  }
   539  
   540  //readloop在自己的goroutine中运行。它处理传入的UDP数据包。
   541  func (t *udp) readLoop(unhandled chan<- ReadPacket) {
   542  	defer t.wg.Done()
   543  	if unhandled != nil {
   544  		defer close(unhandled)
   545  	}
   546  
   547  //发现数据包被定义为不大于1280字节。
   548  //大于此尺寸的包装将在末端切割并处理
   549  //因为它们的哈希不匹配而无效。
   550  	buf := make([]byte, 1280)
   551  	for {
   552  		nbytes, from, err := t.conn.ReadFromUDP(buf)
   553  		if netutil.IsTemporaryError(err) {
   554  //忽略临时读取错误。
   555  			log.Debug("Temporary UDP read error", "err", err)
   556  			continue
   557  		} else if err != nil {
   558  //关闭永久错误循环。
   559  			log.Debug("UDP read error", "err", err)
   560  			return
   561  		}
   562  		if t.handlePacket(from, buf[:nbytes]) != nil && unhandled != nil {
   563  			select {
   564  			case unhandled <- ReadPacket{buf[:nbytes], from}:
   565  			default:
   566  			}
   567  		}
   568  	}
   569  }
   570  
   571  func (t *udp) handlePacket(from *net.UDPAddr, buf []byte) error {
   572  	packet, fromID, hash, err := decodePacket(buf)
   573  	if err != nil {
   574  		log.Debug("Bad discv4 packet", "addr", from, "err", err)
   575  		return err
   576  	}
   577  	err = packet.handle(t, from, fromID, hash)
   578  	log.Trace("<< "+packet.name(), "addr", from, "err", err)
   579  	return err
   580  }
   581  
   582  func decodePacket(buf []byte) (packet, encPubkey, []byte, error) {
   583  	if len(buf) < headSize+1 {
   584  		return nil, encPubkey{}, nil, errPacketTooSmall
   585  	}
   586  	hash, sig, sigdata := buf[:macSize], buf[macSize:headSize], buf[headSize:]
   587  	shouldhash := crypto.Keccak256(buf[macSize:])
   588  	if !bytes.Equal(hash, shouldhash) {
   589  		return nil, encPubkey{}, nil, errBadHash
   590  	}
   591  	fromKey, err := recoverNodeKey(crypto.Keccak256(buf[headSize:]), sig)
   592  	if err != nil {
   593  		return nil, fromKey, hash, err
   594  	}
   595  
   596  	var req packet
   597  	switch ptype := sigdata[0]; ptype {
   598  	case pingPacket:
   599  		req = new(ping)
   600  	case pongPacket:
   601  		req = new(pong)
   602  	case findnodePacket:
   603  		req = new(findnode)
   604  	case neighborsPacket:
   605  		req = new(neighbors)
   606  	default:
   607  		return nil, fromKey, hash, fmt.Errorf("unknown type: %d", ptype)
   608  	}
   609  	s := rlp.NewStream(bytes.NewReader(sigdata[1:]), 0)
   610  	err = s.Decode(req)
   611  	return req, fromKey, hash, err
   612  }
   613  
   614  func (req *ping) handle(t *udp, from *net.UDPAddr, fromKey encPubkey, mac []byte) error {
   615  	if expired(req.Expiration) {
   616  		return errExpired
   617  	}
   618  	key, err := decodePubkey(fromKey)
   619  	if err != nil {
   620  		return fmt.Errorf("invalid public key: %v", err)
   621  	}
   622  	t.send(from, pongPacket, &pong{
   623  		To:         makeEndpoint(from, req.From.TCP),
   624  		ReplyTok:   mac,
   625  		Expiration: uint64(time.Now().Add(expiration).Unix()),
   626  	})
   627  	n := wrapNode(enode.NewV4(key, from.IP, int(req.From.TCP), from.Port))
   628  	t.handleReply(n.ID(), pingPacket, req)
   629  	if time.Since(t.db.LastPongReceived(n.ID())) > bondExpiration {
   630  		t.sendPing(n.ID(), from, func() { t.tab.addThroughPing(n) })
   631  	} else {
   632  		t.tab.addThroughPing(n)
   633  	}
   634  	t.localNode.UDPEndpointStatement(from, &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)})
   635  	t.db.UpdateLastPingReceived(n.ID(), time.Now())
   636  	return nil
   637  }
   638  
   639  func (req *ping) name() string { return "PING/v4" }
   640  
   641  func (req *pong) handle(t *udp, from *net.UDPAddr, fromKey encPubkey, mac []byte) error {
   642  	if expired(req.Expiration) {
   643  		return errExpired
   644  	}
   645  	fromID := fromKey.id()
   646  	if !t.handleReply(fromID, pongPacket, req) {
   647  		return errUnsolicitedReply
   648  	}
   649  	t.localNode.UDPEndpointStatement(from, &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)})
   650  	t.db.UpdateLastPongReceived(fromID, time.Now())
   651  	return nil
   652  }
   653  
   654  func (req *pong) name() string { return "PONG/v4" }
   655  
   656  func (req *findnode) handle(t *udp, from *net.UDPAddr, fromKey encPubkey, mac []byte) error {
   657  	if expired(req.Expiration) {
   658  		return errExpired
   659  	}
   660  	fromID := fromKey.id()
   661  	if time.Since(t.db.LastPongReceived(fromID)) > bondExpiration {
   662  //不存在端点验证pong,我们不处理数据包。这可以防止
   663  //攻击向量,发现协议可用于放大
   664  //DDoS攻击。恶意参与者将使用IP地址发送findnode请求
   665  //目标的UDP端口作为源地址。findnode的接收者
   666  //然后,包将发送一个邻居包(比
   667  //找到受害者。
   668  		return errUnknownNode
   669  	}
   670  	target := enode.ID(crypto.Keccak256Hash(req.Target[:]))
   671  	t.tab.mutex.Lock()
   672  	closest := t.tab.closest(target, bucketSize).entries
   673  	t.tab.mutex.Unlock()
   674  
   675  	p := neighbors{Expiration: uint64(time.Now().Add(expiration).Unix())}
   676  	var sent bool
   677  //以块形式发送邻居,每个数据包最多有maxneighbors
   678  //低于1280字节的限制。
   679  	for _, n := range closest {
   680  		if netutil.CheckRelayIP(from.IP, n.IP()) == nil {
   681  			p.Nodes = append(p.Nodes, nodeToRPC(n))
   682  		}
   683  		if len(p.Nodes) == maxNeighbors {
   684  			t.send(from, neighborsPacket, &p)
   685  			p.Nodes = p.Nodes[:0]
   686  			sent = true
   687  		}
   688  	}
   689  	if len(p.Nodes) > 0 || !sent {
   690  		t.send(from, neighborsPacket, &p)
   691  	}
   692  	return nil
   693  }
   694  
   695  func (req *findnode) name() string { return "FINDNODE/v4" }
   696  
   697  func (req *neighbors) handle(t *udp, from *net.UDPAddr, fromKey encPubkey, mac []byte) error {
   698  	if expired(req.Expiration) {
   699  		return errExpired
   700  	}
   701  	if !t.handleReply(fromKey.id(), neighborsPacket, req) {
   702  		return errUnsolicitedReply
   703  	}
   704  	return nil
   705  }
   706  
   707  func (req *neighbors) name() string { return "NEIGHBORS/v4" }
   708  
   709  func expired(ts uint64) bool {
   710  	return time.Unix(int64(ts), 0).Before(time.Now())
   711  }
   712