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