github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/discover/table.go (about)

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