github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/p2p/discover/table.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:43</date>
    10  //</624342656134156288>
    11  
    12  
    13  //包发现实现了节点发现协议。
    14  //
    15  //节点发现协议提供了一种查找
    16  //可以连接到。它使用一个类似kademlia的协议来维护
    17  //所有监听的ID和端点的分布式数据库
    18  //节点。
    19  package discover
    20  
    21  import (
    22  	crand "crypto/rand"
    23  	"encoding/binary"
    24  	"fmt"
    25  	mrand "math/rand"
    26  	"net"
    27  	"sort"
    28  	"sync"
    29  	"time"
    30  
    31  	"github.com/ethereum/go-ethereum/common"
    32  	"github.com/ethereum/go-ethereum/crypto"
    33  	"github.com/ethereum/go-ethereum/log"
    34  	"github.com/ethereum/go-ethereum/p2p/netutil"
    35  )
    36  
    37  const (
    38  alpha           = 3  //Kademlia并发因子
    39  bucketSize      = 16 //卡德米利亚水桶尺寸
    40  maxReplacements = 10 //每个桶更换清单的尺寸
    41  
    42  //我们把桶放在距离的1/15以上,因为
    43  //我们不太可能遇到更近的节点。
    44  	hashBits          = len(common.Hash{}) * 8
    45  nBuckets          = hashBits / 15       //桶数
    46  bucketMinDistance = hashBits - nBuckets //最近桶的对数距离
    47  
    48  //IP地址限制。
    49  bucketIPLimit, bucketSubnet = 2, 24 //最多2个地址来自同一个/24
    50  	tableIPLimit, tableSubnet   = 10, 24
    51  
    52  maxFindnodeFailures = 5 //将删除超过此限制的节点
    53  	refreshInterval     = 30 * time.Minute
    54  	revalidateInterval  = 10 * time.Second
    55  	copyNodesInterval   = 30 * time.Second
    56  	seedMinTableTime    = 5 * time.Minute
    57  	seedCount           = 30
    58  	seedMaxAge          = 5 * 24 * time.Hour
    59  )
    60  
    61  type Table struct {
    62  mutex   sync.Mutex        //保护存储桶、存储桶内容、托儿所、兰特
    63  buckets [nBuckets]*bucket //已知节点的距离索引
    64  nursery []*Node           //引导节点
    65  rand    *mrand.Rand       //随机性来源,定期重新播种
    66  	ips     netutil.DistinctNetSet
    67  
    68  db         *nodeDB //已知节点数据库
    69  	refreshReq chan chan struct{}
    70  	initDone   chan struct{}
    71  	closeReq   chan struct{}
    72  	closed     chan struct{}
    73  
    74  nodeAddedHook func(*Node) //用于测试
    75  
    76  	net  transport
    77  self *Node //本地节点的元数据
    78  }
    79  
    80  //传输由UDP传输实现。
    81  //它是一个接口,因此我们可以在不打开大量UDP的情况下进行测试
    82  //不生成私钥的套接字。
    83  type transport interface {
    84  	ping(NodeID, *net.UDPAddr) error
    85  	findnode(toid NodeID, addr *net.UDPAddr, target NodeID) ([]*Node, error)
    86  	close()
    87  }
    88  
    89  //bucket包含按其上一个活动排序的节点。条目
    90  //最近激活的元素是条目中的第一个元素。
    91  type bucket struct {
    92  entries      []*Node //实时条目,按上次联系时间排序
    93  replacements []*Node //如果重新验证失败,则使用最近看到的节点
    94  	ips          netutil.DistinctNetSet
    95  }
    96  
    97  func newTable(t transport, ourID NodeID, ourAddr *net.UDPAddr, nodeDBPath string, bootnodes []*Node) (*Table, error) {
    98  //如果没有提供节点数据库,请使用内存中的数据库
    99  	db, err := newNodeDB(nodeDBPath, nodeDBVersion, ourID)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  	tab := &Table{
   104  		net:        t,
   105  		db:         db,
   106  		self:       NewNode(ourID, ourAddr.IP, uint16(ourAddr.Port), uint16(ourAddr.Port)),
   107  		refreshReq: make(chan chan struct{}),
   108  		initDone:   make(chan struct{}),
   109  		closeReq:   make(chan struct{}),
   110  		closed:     make(chan struct{}),
   111  		rand:       mrand.New(mrand.NewSource(0)),
   112  		ips:        netutil.DistinctNetSet{Subnet: tableSubnet, Limit: tableIPLimit},
   113  	}
   114  	if err := tab.setFallbackNodes(bootnodes); err != nil {
   115  		return nil, err
   116  	}
   117  	for i := range tab.buckets {
   118  		tab.buckets[i] = &bucket{
   119  			ips: netutil.DistinctNetSet{Subnet: bucketSubnet, Limit: bucketIPLimit},
   120  		}
   121  	}
   122  	tab.seedRand()
   123  	tab.loadSeedNodes()
   124  //加载种子后启动后台过期goroutine,以便搜索
   125  //种子节点还考虑将由
   126  //到期。
   127  	tab.db.ensureExpirer()
   128  	go tab.loop()
   129  	return tab, nil
   130  }
   131  
   132  func (tab *Table) seedRand() {
   133  	var b [8]byte
   134  	crand.Read(b[:])
   135  
   136  	tab.mutex.Lock()
   137  	tab.rand.Seed(int64(binary.BigEndian.Uint64(b[:])))
   138  	tab.mutex.Unlock()
   139  }
   140  
   141  //self返回本地节点。
   142  //调用方不应修改返回的节点。
   143  func (tab *Table) Self() *Node {
   144  	return tab.self
   145  }
   146  
   147  //readrandomnodes用来自
   148  //表。它不会多次写入同一节点。节点
   149  //切片是副本,可以由调用方修改。
   150  func (tab *Table) ReadRandomNodes(buf []*Node) (n int) {
   151  	if !tab.isInitDone() {
   152  		return 0
   153  	}
   154  	tab.mutex.Lock()
   155  	defer tab.mutex.Unlock()
   156  
   157  //找到所有非空桶,并从中获取新的部分。
   158  	var buckets [][]*Node
   159  	for _, b := range &tab.buckets {
   160  		if len(b.entries) > 0 {
   161  			buckets = append(buckets, b.entries[:])
   162  		}
   163  	}
   164  	if len(buckets) == 0 {
   165  		return 0
   166  	}
   167  //洗牌。
   168  	for i := len(buckets) - 1; i > 0; i-- {
   169  		j := tab.rand.Intn(len(buckets))
   170  		buckets[i], buckets[j] = buckets[j], buckets[i]
   171  	}
   172  //将每个桶的头部移入buf,移除变空的桶。
   173  	var i, j int
   174  	for ; i < len(buf); i, j = i+1, (j+1)%len(buckets) {
   175  		b := buckets[j]
   176  		buf[i] = &(*b[0])
   177  		buckets[j] = b[1:]
   178  		if len(b) == 1 {
   179  			buckets = append(buckets[:j], buckets[j+1:]...)
   180  		}
   181  		if len(buckets) == 0 {
   182  			break
   183  		}
   184  	}
   185  	return i + 1
   186  }
   187  
   188  //close终止网络侦听器并刷新节点数据库。
   189  func (tab *Table) Close() {
   190  	select {
   191  	case <-tab.closed:
   192  //已经关闭。
   193  	case tab.closeReq <- struct{}{}:
   194  <-tab.closed //等待RefreshLoop结束。
   195  	}
   196  }
   197  
   198  //setFallbackNodes设置初始接触点。这些节点
   199  //如果表为空,则用于连接到网络
   200  //数据库中没有已知节点。
   201  func (tab *Table) setFallbackNodes(nodes []*Node) error {
   202  	for _, n := range nodes {
   203  		if err := n.validateComplete(); err != nil {
   204  			return fmt.Errorf("bad bootstrap/fallback node %q (%v)", n, err)
   205  		}
   206  	}
   207  	tab.nursery = make([]*Node, 0, len(nodes))
   208  	for _, n := range nodes {
   209  		cpy := *n
   210  //重新计算cpy.sha,因为节点可能没有
   211  //由newnode或parsenode创建。
   212  		cpy.sha = crypto.Keccak256Hash(n.ID[:])
   213  		tab.nursery = append(tab.nursery, &cpy)
   214  	}
   215  	return nil
   216  }
   217  
   218  //IsInitDone返回表的初始种子设定过程是否已完成。
   219  func (tab *Table) isInitDone() bool {
   220  	select {
   221  	case <-tab.initDone:
   222  		return true
   223  	default:
   224  		return false
   225  	}
   226  }
   227  
   228  //解析搜索具有给定ID的特定节点。
   229  //如果找不到节点,则返回nil。
   230  func (tab *Table) Resolve(targetID NodeID) *Node {
   231  //如果节点存在于本地表中,则否
   232  //需要网络交互。
   233  	hash := crypto.Keccak256Hash(targetID[:])
   234  	tab.mutex.Lock()
   235  	cl := tab.closest(hash, 1)
   236  	tab.mutex.Unlock()
   237  	if len(cl.entries) > 0 && cl.entries[0].ID == targetID {
   238  		return cl.entries[0]
   239  	}
   240  //否则,请执行网络查找。
   241  	result := tab.Lookup(targetID)
   242  	for _, n := range result {
   243  		if n.ID == targetID {
   244  			return n
   245  		}
   246  	}
   247  	return nil
   248  }
   249  
   250  //查找对关闭的节点执行网络搜索
   251  //目标。它通过查询接近目标
   252  //在每次迭代中离它更近的节点。
   253  //给定目标不需要是实际节点
   254  //标识符。
   255  func (tab *Table) Lookup(targetID NodeID) []*Node {
   256  	return tab.lookup(targetID, true)
   257  }
   258  
   259  func (tab *Table) lookup(targetID NodeID, refreshIfEmpty bool) []*Node {
   260  	var (
   261  		target         = crypto.Keccak256Hash(targetID[:])
   262  		asked          = make(map[NodeID]bool)
   263  		seen           = make(map[NodeID]bool)
   264  		reply          = make(chan []*Node, alpha)
   265  		pendingQueries = 0
   266  		result         *nodesByDistance
   267  	)
   268  //如果我们撞到自己,不要再问了。
   269  //在实践中不太可能经常发生。
   270  	asked[tab.self.ID] = true
   271  
   272  	for {
   273  		tab.mutex.Lock()
   274  //生成初始结果集
   275  		result = tab.closest(target, bucketSize)
   276  		tab.mutex.Unlock()
   277  		if len(result.entries) > 0 || !refreshIfEmpty {
   278  			break
   279  		}
   280  //结果集为空,删除了所有节点,刷新。
   281  //我们实际上在这里等待刷新完成。非常
   282  //第一个查询将命中此情况并运行引导
   283  //逻辑。
   284  		<-tab.refresh()
   285  		refreshIfEmpty = false
   286  	}
   287  
   288  	for {
   289  //询问我们尚未询问的alpha最近的节点
   290  		for i := 0; i < len(result.entries) && pendingQueries < alpha; i++ {
   291  			n := result.entries[i]
   292  			if !asked[n.ID] {
   293  				asked[n.ID] = true
   294  				pendingQueries++
   295  				go tab.findnode(n, targetID, reply)
   296  			}
   297  		}
   298  		if pendingQueries == 0 {
   299  //我们要求所有最近的节点停止搜索
   300  			break
   301  		}
   302  //等待下一个答复
   303  		for _, n := range <-reply {
   304  			if n != nil && !seen[n.ID] {
   305  				seen[n.ID] = true
   306  				result.push(n, bucketSize)
   307  			}
   308  		}
   309  		pendingQueries--
   310  	}
   311  	return result.entries
   312  }
   313  
   314  func (tab *Table) findnode(n *Node, targetID NodeID, reply chan<- []*Node) {
   315  	fails := tab.db.findFails(n.ID)
   316  	r, err := tab.net.findnode(n.ID, n.addr(), targetID)
   317  	if err != nil || len(r) == 0 {
   318  		fails++
   319  		tab.db.updateFindFails(n.ID, fails)
   320  		log.Trace("Findnode failed", "id", n.ID, "failcount", fails, "err", err)
   321  		if fails >= maxFindnodeFailures {
   322  			log.Trace("Too many findnode failures, dropping", "id", n.ID, "failcount", fails)
   323  			tab.delete(n)
   324  		}
   325  	} else if fails > 0 {
   326  		tab.db.updateFindFails(n.ID, fails-1)
   327  	}
   328  
   329  //抓取尽可能多的节点。他们中的一些人可能已经不在了,但我们会
   330  //在重新验证期间,只需再次移除这些。
   331  	for _, n := range r {
   332  		tab.add(n)
   333  	}
   334  	reply <- r
   335  }
   336  
   337  func (tab *Table) refresh() <-chan struct{} {
   338  	done := make(chan struct{})
   339  	select {
   340  	case tab.refreshReq <- done:
   341  	case <-tab.closed:
   342  		close(done)
   343  	}
   344  	return done
   345  }
   346  
   347  //循环计划刷新、重新验证运行并协调关闭。
   348  func (tab *Table) loop() {
   349  	var (
   350  		revalidate     = time.NewTimer(tab.nextRevalidateTime())
   351  		refresh        = time.NewTicker(refreshInterval)
   352  		copyNodes      = time.NewTicker(copyNodesInterval)
   353  		revalidateDone = make(chan struct{})
   354  refreshDone    = make(chan struct{})           //Dorefresh报告完成
   355  waiting        = []chan struct{}{tab.initDone} //在DoRefresh运行时保留等待的呼叫者
   356  	)
   357  	defer refresh.Stop()
   358  	defer revalidate.Stop()
   359  	defer copyNodes.Stop()
   360  
   361  //开始初始刷新。
   362  	go tab.doRefresh(refreshDone)
   363  
   364  loop:
   365  	for {
   366  		select {
   367  		case <-refresh.C:
   368  			tab.seedRand()
   369  			if refreshDone == nil {
   370  				refreshDone = make(chan struct{})
   371  				go tab.doRefresh(refreshDone)
   372  			}
   373  		case req := <-tab.refreshReq:
   374  			waiting = append(waiting, req)
   375  			if refreshDone == nil {
   376  				refreshDone = make(chan struct{})
   377  				go tab.doRefresh(refreshDone)
   378  			}
   379  		case <-refreshDone:
   380  			for _, ch := range waiting {
   381  				close(ch)
   382  			}
   383  			waiting, refreshDone = nil, nil
   384  		case <-revalidate.C:
   385  			go tab.doRevalidate(revalidateDone)
   386  		case <-revalidateDone:
   387  			revalidate.Reset(tab.nextRevalidateTime())
   388  		case <-copyNodes.C:
   389  			go tab.copyLiveNodes()
   390  		case <-tab.closeReq:
   391  			break loop
   392  		}
   393  	}
   394  
   395  	if tab.net != nil {
   396  		tab.net.close()
   397  	}
   398  	if refreshDone != nil {
   399  		<-refreshDone
   400  	}
   401  	for _, ch := range waiting {
   402  		close(ch)
   403  	}
   404  	tab.db.close()
   405  	close(tab.closed)
   406  }
   407  
   408  //DoRefresh执行查找随机目标以保留存储桶
   409  //满的。如果表为空,则插入种子节点(初始
   410  //引导或丢弃错误对等)。
   411  func (tab *Table) doRefresh(done chan struct{}) {
   412  	defer close(done)
   413  
   414  //从数据库加载节点并插入
   415  //他们。这将产生一些以前看到的节点,
   416  //(希望)还活着。
   417  	tab.loadSeedNodes()
   418  
   419  //运行自我查找以发现新的邻居节点。
   420  	tab.lookup(tab.self.ID, false)
   421  
   422  //kademlia文件指定bucket刷新应该
   423  //在最近使用最少的存储桶中执行查找。我们不能
   424  //坚持这一点,因为findnode目标是512位值
   425  //(不是哈希大小)并且不容易生成
   426  //属于选定的桶中的sha3 preimage。
   427  //我们用随机目标执行一些查找。
   428  	for i := 0; i < 3; i++ {
   429  		var target NodeID
   430  		crand.Read(target[:])
   431  		tab.lookup(target, false)
   432  	}
   433  }
   434  
   435  func (tab *Table) loadSeedNodes() {
   436  	seeds := tab.db.querySeeds(seedCount, seedMaxAge)
   437  	seeds = append(seeds, tab.nursery...)
   438  	for i := range seeds {
   439  		seed := seeds[i]
   440  		age := log.Lazy{Fn: func() interface{} { return time.Since(tab.db.lastPongReceived(seed.ID)) }}
   441  		log.Debug("Found seed node in database", "id", seed.ID, "addr", seed.addr(), "age", age)
   442  		tab.add(seed)
   443  	}
   444  }
   445  
   446  //Dorevalidate检查随机存储桶中的最后一个节点是否仍然活动
   447  //如果没有,则替换或删除节点。
   448  func (tab *Table) doRevalidate(done chan<- struct{}) {
   449  	defer func() { done <- struct{}{} }()
   450  
   451  	last, bi := tab.nodeToRevalidate()
   452  	if last == nil {
   453  //找不到非空存储桶。
   454  		return
   455  	}
   456  
   457  //ping所选节点并等待pong。
   458  	err := tab.net.ping(last.ID, last.addr())
   459  
   460  	tab.mutex.Lock()
   461  	defer tab.mutex.Unlock()
   462  	b := tab.buckets[bi]
   463  	if err == nil {
   464  //节点响应,将其移到前面。
   465  		log.Trace("Revalidated node", "b", bi, "id", last.ID)
   466  		b.bump(last)
   467  		return
   468  	}
   469  //未收到回复,请选择替换项或删除节点(如果没有)
   470  //任何替代品。
   471  	if r := tab.replace(b, last); r != nil {
   472  		log.Trace("Replaced dead node", "b", bi, "id", last.ID, "ip", last.IP, "r", r.ID, "rip", r.IP)
   473  	} else {
   474  		log.Trace("Removed dead node", "b", bi, "id", last.ID, "ip", last.IP)
   475  	}
   476  }
   477  
   478  //nodetorefalidate返回随机非空bucket中的最后一个节点。
   479  func (tab *Table) nodeToRevalidate() (n *Node, bi int) {
   480  	tab.mutex.Lock()
   481  	defer tab.mutex.Unlock()
   482  
   483  	for _, bi = range tab.rand.Perm(len(tab.buckets)) {
   484  		b := tab.buckets[bi]
   485  		if len(b.entries) > 0 {
   486  			last := b.entries[len(b.entries)-1]
   487  			return last, bi
   488  		}
   489  	}
   490  	return nil, 0
   491  }
   492  
   493  func (tab *Table) nextRevalidateTime() time.Duration {
   494  	tab.mutex.Lock()
   495  	defer tab.mutex.Unlock()
   496  
   497  	return time.Duration(tab.rand.Int63n(int64(revalidateInterval)))
   498  }
   499  
   500  //CopyLiveNodes将表中的节点添加到数据库中(如果它们在表中)。
   501  //比Mintable时间长。
   502  func (tab *Table) copyLiveNodes() {
   503  	tab.mutex.Lock()
   504  	defer tab.mutex.Unlock()
   505  
   506  	now := time.Now()
   507  	for _, b := range &tab.buckets {
   508  		for _, n := range b.entries {
   509  			if now.Sub(n.addedAt) >= seedMinTableTime {
   510  				tab.db.updateNode(n)
   511  			}
   512  		}
   513  	}
   514  }
   515  
   516  //最近返回表中最接近
   517  //给定的ID。调用方必须保持tab.mutex。
   518  func (tab *Table) closest(target common.Hash, nresults int) *nodesByDistance {
   519  //这是一种非常浪费的查找最近节点的方法,但是
   520  //显然是正确的。我相信以树为基础的桶可以
   521  //这更容易有效地实施。
   522  	close := &nodesByDistance{target: target}
   523  	for _, b := range &tab.buckets {
   524  		for _, n := range b.entries {
   525  			close.push(n, nresults)
   526  		}
   527  	}
   528  	return close
   529  }
   530  
   531  func (tab *Table) len() (n int) {
   532  	for _, b := range &tab.buckets {
   533  		n += len(b.entries)
   534  	}
   535  	return n
   536  }
   537  
   538  //bucket返回给定节点id散列的bucket。
   539  func (tab *Table) bucket(sha common.Hash) *bucket {
   540  	d := logdist(tab.self.sha, sha)
   541  	if d <= bucketMinDistance {
   542  		return tab.buckets[0]
   543  	}
   544  	return tab.buckets[d-bucketMinDistance-1]
   545  }
   546  
   547  //添加将给定节点添加到其相应存储桶的尝试。如果桶有空间
   548  //可用,添加节点立即成功。否则,如果
   549  //bucket中最近活动的节点不响应ping数据包。
   550  //
   551  //调用方不能持有tab.mutex。
   552  func (tab *Table) add(n *Node) {
   553  	tab.mutex.Lock()
   554  	defer tab.mutex.Unlock()
   555  
   556  	b := tab.bucket(n.sha)
   557  	if !tab.bumpOrAdd(b, n) {
   558  //节点不在表中。将其添加到替换列表中。
   559  		tab.addReplacement(b, n)
   560  	}
   561  }
   562  
   563  //addthroughping将给定节点添加到表中。与平原相比
   564  //“添加”有一个附加的安全措施:如果表仍然存在
   565  //未添加初始化节点。这可以防止攻击
   566  //只需重复发送ping就可以填写表格。
   567  //
   568  //调用方不能持有tab.mutex。
   569  func (tab *Table) addThroughPing(n *Node) {
   570  	if !tab.isInitDone() {
   571  		return
   572  	}
   573  	tab.add(n)
   574  }
   575  
   576  //stufacture将表中的节点添加到相应bucket的末尾
   577  //如果桶没满。调用方不能持有tab.mutex。
   578  func (tab *Table) stuff(nodes []*Node) {
   579  	tab.mutex.Lock()
   580  	defer tab.mutex.Unlock()
   581  
   582  	for _, n := range nodes {
   583  		if n.ID == tab.self.ID {
   584  continue //不要增加自我
   585  		}
   586  		b := tab.bucket(n.sha)
   587  		if len(b.entries) < bucketSize {
   588  			tab.bumpOrAdd(b, n)
   589  		}
   590  	}
   591  }
   592  
   593  //删除从节点表中删除一个条目。用于疏散死节点。
   594  func (tab *Table) delete(node *Node) {
   595  	tab.mutex.Lock()
   596  	defer tab.mutex.Unlock()
   597  
   598  	tab.deleteInBucket(tab.bucket(node.sha), node)
   599  }
   600  
   601  func (tab *Table) addIP(b *bucket, ip net.IP) bool {
   602  	if netutil.IsLAN(ip) {
   603  		return true
   604  	}
   605  	if !tab.ips.Add(ip) {
   606  		log.Debug("IP exceeds table limit", "ip", ip)
   607  		return false
   608  	}
   609  	if !b.ips.Add(ip) {
   610  		log.Debug("IP exceeds bucket limit", "ip", ip)
   611  		tab.ips.Remove(ip)
   612  		return false
   613  	}
   614  	return true
   615  }
   616  
   617  func (tab *Table) removeIP(b *bucket, ip net.IP) {
   618  	if netutil.IsLAN(ip) {
   619  		return
   620  	}
   621  	tab.ips.Remove(ip)
   622  	b.ips.Remove(ip)
   623  }
   624  
   625  func (tab *Table) addReplacement(b *bucket, n *Node) {
   626  	for _, e := range b.replacements {
   627  		if e.ID == n.ID {
   628  return //已列入清单
   629  		}
   630  	}
   631  	if !tab.addIP(b, n.IP) {
   632  		return
   633  	}
   634  	var removed *Node
   635  	b.replacements, removed = pushNode(b.replacements, n, maxReplacements)
   636  	if removed != nil {
   637  		tab.removeIP(b, removed.IP)
   638  	}
   639  }
   640  
   641  //replace从替换列表中删除n,如果“last”是
   642  //桶中的最后一个条目。如果“last”不是最后一个条目,则它或已被替换
   643  //和别人在一起或者变得活跃起来。
   644  func (tab *Table) replace(b *bucket, last *Node) *Node {
   645  	if len(b.entries) == 0 || b.entries[len(b.entries)-1].ID != last.ID {
   646  //条目已移动,不要替换它。
   647  		return nil
   648  	}
   649  //还是最后一个条目。
   650  	if len(b.replacements) == 0 {
   651  		tab.deleteInBucket(b, last)
   652  		return nil
   653  	}
   654  	r := b.replacements[tab.rand.Intn(len(b.replacements))]
   655  	b.replacements = deleteNode(b.replacements, r)
   656  	b.entries[len(b.entries)-1] = r
   657  	tab.removeIP(b, last.IP)
   658  	return r
   659  }
   660  
   661  //bump将给定节点移动到bucket条目列表的前面
   662  //如果它包含在那个列表中。
   663  func (b *bucket) bump(n *Node) bool {
   664  	for i := range b.entries {
   665  		if b.entries[i].ID == n.ID {
   666  //把它移到前面
   667  			copy(b.entries[1:], b.entries[:i])
   668  			b.entries[0] = n
   669  			return true
   670  		}
   671  	}
   672  	return false
   673  }
   674  
   675  //bumporadd将n移动到bucket条目列表的前面,或者如果该列表不在,则将其添加。
   676  //满的。如果n在桶中,返回值为真。
   677  func (tab *Table) bumpOrAdd(b *bucket, n *Node) bool {
   678  	if b.bump(n) {
   679  		return true
   680  	}
   681  	if len(b.entries) >= bucketSize || !tab.addIP(b, n.IP) {
   682  		return false
   683  	}
   684  	b.entries, _ = pushNode(b.entries, n, bucketSize)
   685  	b.replacements = deleteNode(b.replacements, n)
   686  	n.addedAt = time.Now()
   687  	if tab.nodeAddedHook != nil {
   688  		tab.nodeAddedHook(n)
   689  	}
   690  	return true
   691  }
   692  
   693  func (tab *Table) deleteInBucket(b *bucket, n *Node) {
   694  	b.entries = deleteNode(b.entries, n)
   695  	tab.removeIP(b, n.IP)
   696  }
   697  
   698  //pushnode将n添加到列表的前面,最多保留max项。
   699  func pushNode(list []*Node, n *Node, max int) ([]*Node, *Node) {
   700  	if len(list) < max {
   701  		list = append(list, nil)
   702  	}
   703  	removed := list[len(list)-1]
   704  	copy(list[1:], list)
   705  	list[0] = n
   706  	return list, removed
   707  }
   708  
   709  //删除节点从列表中删除n。
   710  func deleteNode(list []*Node, n *Node) []*Node {
   711  	for i := range list {
   712  		if list[i].ID == n.ID {
   713  			return append(list[:i], list[i+1:]...)
   714  		}
   715  	}
   716  	return list
   717  }
   718  
   719  //nodesByDistance是节点列表,按
   720  //距离目标。
   721  type nodesByDistance struct {
   722  	entries []*Node
   723  	target  common.Hash
   724  }
   725  
   726  //push将给定节点添加到列表中,使总大小保持在maxelems以下。
   727  func (h *nodesByDistance) push(n *Node, maxElems int) {
   728  	ix := sort.Search(len(h.entries), func(i int) bool {
   729  		return distcmp(h.target, h.entries[i].sha, n.sha) > 0
   730  	})
   731  	if len(h.entries) < maxElems {
   732  		h.entries = append(h.entries, n)
   733  	}
   734  	if ix == len(h.entries) {
   735  //比我们现有的所有节点都要远。
   736  //如果有空间,那么节点现在是最后一个元素。
   737  	} else {
   738  //向下滑动现有条目以腾出空间
   739  //这将覆盖我们刚刚附加的条目。
   740  		copy(h.entries[ix+1:], h.entries[ix:])
   741  		h.entries[ix] = n
   742  	}
   743  }
   744