github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/network/kademlia.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:47</date>
    10  //</624342672412250112>
    11  
    12  
    13  package network
    14  
    15  import (
    16  	"bytes"
    17  	"fmt"
    18  	"math/rand"
    19  	"strings"
    20  	"sync"
    21  	"time"
    22  
    23  	"github.com/ethereum/go-ethereum/common"
    24  	"github.com/ethereum/go-ethereum/swarm/log"
    25  	"github.com/ethereum/go-ethereum/swarm/pot"
    26  )
    27  
    28  /*
    29  
    30  根据相对于固定点X的接近顺序,将点分类为
    31  将空间(n字节长的字节序列)放入容器中。每个项目位于
    32  最远距离X的一半是前一个箱中的项目。给出了一个
    33  均匀分布项(任意序列上的哈希函数)
    34  接近比例映射到一系列子集上,基数为负
    35  指数尺度。
    36  
    37  它还具有属于同一存储箱的任何两个项目所在的属性。
    38  最远的距离是彼此距离x的一半。
    39  
    40  如果我们把垃圾箱中的随机样本看作是网络中的连接,
    41  互联节点的相对邻近性可以作为局部
    42  当任务要在两个路径之间查找路径时,用于图形遍历的决策
    43  点。因为在每个跳跃中,有限距离的一半
    44  达到一个跳数所需的保证不变的最大跳数限制。
    45  节点。
    46  **/
    47  
    48  
    49  var pof = pot.DefaultPof(256)
    50  
    51  //kadparams保存kademlia的配置参数
    52  type KadParams struct {
    53  //可调参数
    54  MaxProxDisplay int   //表显示的行数
    55  MinProxBinSize int   //最近邻核最小基数
    56  MinBinSize     int   //一行中的最小对等数
    57  MaxBinSize     int   //修剪前一行中的最大对等数
    58  RetryInterval  int64 //对等机首次重新拨号前的初始间隔
    59  RetryExponent  int   //用指数乘以重试间隔
    60  MaxRetries     int   //重拨尝试的最大次数
    61  //制裁或阻止建议同伴的职能
    62  	Reachable func(OverlayAddr) bool
    63  }
    64  
    65  //newkadparams返回带有默认值的params结构
    66  func NewKadParams() *KadParams {
    67  	return &KadParams{
    68  		MaxProxDisplay: 16,
    69  		MinProxBinSize: 2,
    70  		MinBinSize:     2,
    71  		MaxBinSize:     4,
    72  RetryInterval:  4200000000, //4.2秒
    73  		MaxRetries:     42,
    74  		RetryExponent:  2,
    75  	}
    76  }
    77  
    78  //Kademlia是一个活动对等端表和一个已知对等端数据库(节点记录)
    79  type Kademlia struct {
    80  	lock       sync.RWMutex
    81  *KadParams          //Kademlia配置参数
    82  base       []byte   //表的不可变基址
    83  addrs      *pot.Pot //用于已知对等地址的POTS容器
    84  conns      *pot.Pot //用于实时对等连接的POTS容器
    85  depth      uint8    //存储上一个当前饱和深度
    86  nDepth     int      //存储上一个邻居深度
    87  nDepthC    chan int //由depthc函数返回,用于信号邻域深度变化
    88  addrCountC chan int //由addrcountc函数返回以指示对等计数更改
    89  }
    90  
    91  //newkademlia为基地址addr创建一个kademlia表
    92  //参数与参数相同
    93  //如果params为nil,则使用默认值
    94  func NewKademlia(addr []byte, params *KadParams) *Kademlia {
    95  	if params == nil {
    96  		params = NewKadParams()
    97  	}
    98  	return &Kademlia{
    99  		base:      addr,
   100  		KadParams: params,
   101  		addrs:     pot.NewPot(nil, 0),
   102  		conns:     pot.NewPot(nil, 0),
   103  	}
   104  }
   105  
   106  //覆盖对等接口从覆盖中捕获对等视图的公共方面
   107  //拓扑驱动程序
   108  type OverlayPeer interface {
   109  	Address() []byte
   110  }
   111  
   112  //overlayconn表示连接的对等机
   113  type OverlayConn interface {
   114  	OverlayPeer
   115  Drop(error)       //调用以指示应删除对等项
   116  Off() OverlayAddr //调用以返回Persistant OverlayAddr
   117  }
   118  
   119  //overlayAddr表示Kademlia对等记录
   120  type OverlayAddr interface {
   121  	OverlayPeer
   122  Update(OverlayAddr) OverlayAddr //返回原始版本的更新版本
   123  }
   124  
   125  //条目表示一个kademlia表条目(overlaypeer的扩展)
   126  type entry struct {
   127  	OverlayPeer
   128  	seenAt  time.Time
   129  	retries int
   130  }
   131  
   132  //NewEntry从重叠对等接口创建Kademlia对等
   133  func newEntry(p OverlayPeer) *entry {
   134  	return &entry{
   135  		OverlayPeer: p,
   136  		seenAt:      time.Now(),
   137  	}
   138  }
   139  
   140  //bin是入口地址的二进制(位向量)序列化
   141  func (e *entry) Bin() string {
   142  	return pot.ToBin(e.addr().Address())
   143  }
   144  
   145  //label是调试条目的短标记
   146  func Label(e *entry) string {
   147  	return fmt.Sprintf("%s (%d)", e.Hex()[:4], e.retries)
   148  }
   149  
   150  //十六进制是入口地址的十六进制序列化
   151  func (e *entry) Hex() string {
   152  	return fmt.Sprintf("%x", e.addr().Address())
   153  }
   154  
   155  //字符串是条目的短标记
   156  func (e *entry) String() string {
   157  	return fmt.Sprintf("%s (%d)", e.Hex()[:8], e.retries)
   158  }
   159  
   160  //addr返回条目对应的kad对等记录(overlayaddr)
   161  func (e *entry) addr() OverlayAddr {
   162  	a, _ := e.OverlayPeer.(OverlayAddr)
   163  	return a
   164  }
   165  
   166  //conn返回与条目相对应的已连接对等(overlaypeer)
   167  func (e *entry) conn() OverlayConn {
   168  	c, _ := e.OverlayPeer.(OverlayConn)
   169  	return c
   170  }
   171  
   172  //寄存器将每个overlayaddr作为kademlia对等记录输入
   173  //已知对等地址数据库
   174  func (k *Kademlia) Register(peers []OverlayAddr) error {
   175  	k.lock.Lock()
   176  	defer k.lock.Unlock()
   177  	var known, size int
   178  	for _, p := range peers {
   179  //如果自我接收错误,对等方应该知道得更好。
   180  //应该为此受到惩罚
   181  		if bytes.Equal(p.Address(), k.base) {
   182  			return fmt.Errorf("add peers: %x is self", k.base)
   183  		}
   184  		var found bool
   185  		k.addrs, _, found, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val {
   186  //如果没有找到
   187  			if v == nil {
   188  //在conn中插入新的脱机对等
   189  				return newEntry(p)
   190  			}
   191  //在已知的同龄人中发现,什么都不做
   192  			return v
   193  		})
   194  		if found {
   195  			known++
   196  		}
   197  		size++
   198  	}
   199  //仅当有新地址时才发送新地址计数值
   200  	if k.addrCountC != nil && size-known > 0 {
   201  		k.addrCountC <- k.addrs.Size()
   202  	}
   203  //log.trace(fmt.sprintf(“%x注册了%v个对等点,已知的%v个,总数:%v”,k.baseaddr()[:4],大小,已知的,k.addrs.size()))
   204  
   205  	k.sendNeighbourhoodDepthChange()
   206  	return nil
   207  }
   208  
   209  //suggestpeer返回的最低接近箱的已知对等
   210  //深度以下的最低料位计数
   211  //当然,如果有一个空行,它将返回该行的对等方
   212  func (k *Kademlia) SuggestPeer() (a OverlayAddr, o int, want bool) {
   213  	k.lock.Lock()
   214  	defer k.lock.Unlock()
   215  	minsize := k.MinBinSize
   216  	depth := k.neighbourhoodDepth()
   217  //如果当前proxbin中存在可调用邻居,请连接
   218  //这将确保最近的邻居集完全连接
   219  	var ppo int
   220  	k.addrs.EachNeighbour(k.base, pof, func(val pot.Val, po int) bool {
   221  		if po < depth {
   222  			return false
   223  		}
   224  		a = k.callable(val)
   225  		ppo = po
   226  		return a == nil
   227  	})
   228  	if a != nil {
   229  		log.Trace(fmt.Sprintf("%08x candidate nearest neighbour found: %v (%v)", k.BaseAddr()[:4], a, ppo))
   230  		return a, 0, false
   231  	}
   232  //log.trace(fmt.sprintf(“%08X没有要连接到的最近邻居(深度:%v,minproxySize:%v)%v”,k.baseAddr()[:4],深度,k.minproxyBinSize,a))。
   233  
   234  	var bpo []int
   235  	prev := -1
   236  	k.conns.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
   237  		prev++
   238  		for ; prev < po; prev++ {
   239  			bpo = append(bpo, prev)
   240  			minsize = 0
   241  		}
   242  		if size < minsize {
   243  			bpo = append(bpo, po)
   244  			minsize = size
   245  		}
   246  		return size > 0 && po < depth
   247  	})
   248  //所有桶都满了,即minSize==k.minBinSize
   249  	if len(bpo) == 0 {
   250  //log.debug(fmt.sprintf(“%08X:所有箱已饱和”,k.baseaddr()[:4]))
   251  		return nil, 0, false
   252  	}
   253  //只要我们有候选者可以联系到
   254  //不要要求新同事(want=false)
   255  //尝试选择一个候选对等
   256  //找到第一个可调用的对等
   257  	nxt := bpo[0]
   258  	k.addrs.EachBin(k.base, pof, nxt, func(po, _ int, f func(func(pot.Val, int) bool) bool) bool {
   259  //对于每个容器(直到深度),我们找到可调用的候选对等体
   260  		if po >= depth {
   261  			return false
   262  		}
   263  		return f(func(val pot.Val, _ int) bool {
   264  			a = k.callable(val)
   265  			return a == nil
   266  		})
   267  	})
   268  //找到一个候选人
   269  	if a != nil {
   270  		return a, 0, false
   271  	}
   272  //找不到候选对等,请求短箱
   273  	var changed bool
   274  	if uint8(nxt) < k.depth {
   275  		k.depth = uint8(nxt)
   276  		changed = true
   277  	}
   278  	return a, nxt, changed
   279  }
   280  
   281  //在上,将对等机作为Kademlia对等机插入活动对等机
   282  func (k *Kademlia) On(p OverlayConn) (uint8, bool) {
   283  	k.lock.Lock()
   284  	defer k.lock.Unlock()
   285  	e := newEntry(p)
   286  	var ins bool
   287  	k.conns, _, _, _ = pot.Swap(k.conns, p, pof, func(v pot.Val) pot.Val {
   288  //如果找不到现场
   289  		if v == nil {
   290  			ins = true
   291  //在conns中插入新的在线对等点
   292  			return e
   293  		}
   294  //在同龄人中找到,什么都不做
   295  		return v
   296  	})
   297  	if ins {
   298  //在加法器中插入新的在线对等点
   299  		k.addrs, _, _, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val {
   300  			return e
   301  		})
   302  //仅当插入对等端时才发送新的地址计数值
   303  		if k.addrCountC != nil {
   304  			k.addrCountC <- k.addrs.Size()
   305  		}
   306  	}
   307  	log.Trace(k.string())
   308  //计算饱和深度是否改变
   309  	depth := uint8(k.saturation(k.MinBinSize))
   310  	var changed bool
   311  	if depth != k.depth {
   312  		changed = true
   313  		k.depth = depth
   314  	}
   315  	k.sendNeighbourhoodDepthChange()
   316  	return k.depth, changed
   317  }
   318  
   319  //Neighbourhooddepthc返回发送新Kademlia的频道
   320  //每一次变化的邻里深度。
   321  //不从返回通道接收将阻塞功能
   322  //当邻近深度改变时。
   323  func (k *Kademlia) NeighbourhoodDepthC() <-chan int {
   324  	if k.nDepthC == nil {
   325  		k.nDepthC = make(chan int)
   326  	}
   327  	return k.nDepthC
   328  }
   329  
   330  //sendnieghbourhooddepthchange向k.ndepth通道发送新的邻近深度
   331  //如果已初始化。
   332  func (k *Kademlia) sendNeighbourhoodDepthChange() {
   333  //当调用neighbourhooddepthc并由其返回时,将初始化ndepthc。
   334  //它提供了邻域深度变化的信号。
   335  //如果满足这个条件,代码的这一部分将向ndepthc发送新的邻域深度。
   336  	if k.nDepthC != nil {
   337  		nDepth := k.neighbourhoodDepth()
   338  		if nDepth != k.nDepth {
   339  			k.nDepth = nDepth
   340  			k.nDepthC <- nDepth
   341  		}
   342  	}
   343  }
   344  
   345  //addrCountc返回发送新的
   346  //每次更改的地址计数值。
   347  //不从返回通道接收将阻止寄存器功能
   348  //地址计数值更改时。
   349  func (k *Kademlia) AddrCountC() <-chan int {
   350  	if k.addrCountC == nil {
   351  		k.addrCountC = make(chan int)
   352  	}
   353  	return k.addrCountC
   354  }
   355  
   356  //关闭从活动对等中删除对等
   357  func (k *Kademlia) Off(p OverlayConn) {
   358  	k.lock.Lock()
   359  	defer k.lock.Unlock()
   360  	var del bool
   361  	k.addrs, _, _, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val {
   362  //v不能为零,必须选中,否则我们将覆盖条目
   363  		if v == nil {
   364  			panic(fmt.Sprintf("connected peer not found %v", p))
   365  		}
   366  		del = true
   367  		return newEntry(p.Off())
   368  	})
   369  
   370  	if del {
   371  		k.conns, _, _, _ = pot.Swap(k.conns, p, pof, func(_ pot.Val) pot.Val {
   372  //V不能为零,但不需要检查
   373  			return nil
   374  		})
   375  //仅当对等端被删除时才发送新的地址计数值
   376  		if k.addrCountC != nil {
   377  			k.addrCountC <- k.addrs.Size()
   378  		}
   379  		k.sendNeighbourhoodDepthChange()
   380  	}
   381  }
   382  
   383  func (k *Kademlia) EachBin(base []byte, pof pot.Pof, o int, eachBinFunc func(conn OverlayConn, po int) bool) {
   384  	k.lock.RLock()
   385  	defer k.lock.RUnlock()
   386  
   387  	var startPo int
   388  	var endPo int
   389  	kadDepth := k.neighbourhoodDepth()
   390  
   391  	k.conns.EachBin(base, pof, o, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
   392  		if startPo > 0 && endPo != k.MaxProxDisplay {
   393  			startPo = endPo + 1
   394  		}
   395  		if po < kadDepth {
   396  			endPo = po
   397  		} else {
   398  			endPo = k.MaxProxDisplay
   399  		}
   400  
   401  		for bin := startPo; bin <= endPo; bin++ {
   402  			f(func(val pot.Val, _ int) bool {
   403  				return eachBinFunc(val.(*entry).conn(), bin)
   404  			})
   405  		}
   406  		return true
   407  	})
   408  }
   409  
   410  //eachconn是一个带有args(base、po、f)的迭代器,将f应用于每个活动对等端
   411  //从基地测量,接近订单为po或更低
   412  //如果基为零,则使用Kademlia基地址
   413  func (k *Kademlia) EachConn(base []byte, o int, f func(OverlayConn, int, bool) bool) {
   414  	k.lock.RLock()
   415  	defer k.lock.RUnlock()
   416  	k.eachConn(base, o, f)
   417  }
   418  
   419  func (k *Kademlia) eachConn(base []byte, o int, f func(OverlayConn, int, bool) bool) {
   420  	if len(base) == 0 {
   421  		base = k.base
   422  	}
   423  	depth := k.neighbourhoodDepth()
   424  	k.conns.EachNeighbour(base, pof, func(val pot.Val, po int) bool {
   425  		if po > o {
   426  			return true
   427  		}
   428  		return f(val.(*entry).conn(), po, po >= depth)
   429  	})
   430  }
   431  
   432  //用(base,po,f)调用的eachaddr是一个迭代器,将f应用于每个已知的对等端
   433  //从基地测量,接近订单为po或更低
   434  //如果基为零,则使用Kademlia基地址
   435  func (k *Kademlia) EachAddr(base []byte, o int, f func(OverlayAddr, int, bool) bool) {
   436  	k.lock.RLock()
   437  	defer k.lock.RUnlock()
   438  	k.eachAddr(base, o, f)
   439  }
   440  
   441  func (k *Kademlia) eachAddr(base []byte, o int, f func(OverlayAddr, int, bool) bool) {
   442  	if len(base) == 0 {
   443  		base = k.base
   444  	}
   445  	depth := k.neighbourhoodDepth()
   446  	k.addrs.EachNeighbour(base, pof, func(val pot.Val, po int) bool {
   447  		if po > o {
   448  			return true
   449  		}
   450  		return f(val.(*entry).addr(), po, po >= depth)
   451  	})
   452  }
   453  
   454  //neighbourhooddepth返回定义
   455  //基数大于等于minProxBinSize的最近邻集
   456  //如果总共小于minproxbinsize对等端,则返回0
   457  //呼叫方必须持有锁
   458  func (k *Kademlia) neighbourhoodDepth() (depth int) {
   459  	if k.conns.Size() < k.MinProxBinSize {
   460  		return 0
   461  	}
   462  	var size int
   463  	f := func(v pot.Val, i int) bool {
   464  		size++
   465  		depth = i
   466  		return size < k.MinProxBinSize
   467  	}
   468  	k.conns.EachNeighbour(k.base, pof, f)
   469  	return depth
   470  }
   471  
   472  //使用val调用时可调用,
   473  func (k *Kademlia) callable(val pot.Val) OverlayAddr {
   474  	e := val.(*entry)
   475  //如果对等方处于活动状态或超过了maxretries,则不可调用
   476  	if e.conn() != nil || e.retries > k.MaxRetries {
   477  		return nil
   478  	}
   479  //根据上次看到后经过的时间计算允许的重试次数
   480  	timeAgo := int64(time.Since(e.seenAt))
   481  	div := int64(k.RetryExponent)
   482  	div += (150000 - rand.Int63n(300000)) * div / 1000000
   483  	var retries int
   484  	for delta := timeAgo; delta > k.RetryInterval; delta /= div {
   485  		retries++
   486  	}
   487  //它从不并发调用,因此可以安全地递增
   488  //可以再次重试对等机
   489  	if retries < e.retries {
   490  		log.Trace(fmt.Sprintf("%08x: %v long time since last try (at %v) needed before retry %v, wait only warrants %v", k.BaseAddr()[:4], e, timeAgo, e.retries, retries))
   491  		return nil
   492  	}
   493  //制裁或阻止建议同伴的职能
   494  	if k.Reachable != nil && !k.Reachable(e.addr()) {
   495  		log.Trace(fmt.Sprintf("%08x: peer %v is temporarily not callable", k.BaseAddr()[:4], e))
   496  		return nil
   497  	}
   498  	e.retries++
   499  	log.Trace(fmt.Sprintf("%08x: peer %v is callable", k.BaseAddr()[:4], e))
   500  
   501  	return e.addr()
   502  }
   503  
   504  //baseaddr返回kademlia基地址
   505  func (k *Kademlia) BaseAddr() []byte {
   506  	return k.base
   507  }
   508  
   509  //字符串返回用ASCII显示的kademlia表+kaddb表
   510  func (k *Kademlia) String() string {
   511  	k.lock.RLock()
   512  	defer k.lock.RUnlock()
   513  	return k.string()
   514  }
   515  
   516  //字符串返回用ASCII显示的kademlia表+kaddb表
   517  func (k *Kademlia) string() string {
   518  	wsrow := "                          "
   519  	var rows []string
   520  
   521  	rows = append(rows, "=========================================================================")
   522  	rows = append(rows, fmt.Sprintf("%v KΛÐΞMLIΛ hive: queen's address: %x", time.Now().UTC().Format(time.UnixDate), k.BaseAddr()[:3]))
   523  	rows = append(rows, fmt.Sprintf("population: %d (%d), MinProxBinSize: %d, MinBinSize: %d, MaxBinSize: %d", k.conns.Size(), k.addrs.Size(), k.MinProxBinSize, k.MinBinSize, k.MaxBinSize))
   524  
   525  	liverows := make([]string, k.MaxProxDisplay)
   526  	peersrows := make([]string, k.MaxProxDisplay)
   527  
   528  	depth := k.neighbourhoodDepth()
   529  	rest := k.conns.Size()
   530  	k.conns.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
   531  		var rowlen int
   532  		if po >= k.MaxProxDisplay {
   533  			po = k.MaxProxDisplay - 1
   534  		}
   535  		row := []string{fmt.Sprintf("%2d", size)}
   536  		rest -= size
   537  		f(func(val pot.Val, vpo int) bool {
   538  			e := val.(*entry)
   539  			row = append(row, fmt.Sprintf("%x", e.Address()[:2]))
   540  			rowlen++
   541  			return rowlen < 4
   542  		})
   543  		r := strings.Join(row, " ")
   544  		r = r + wsrow
   545  		liverows[po] = r[:31]
   546  		return true
   547  	})
   548  
   549  	k.addrs.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
   550  		var rowlen int
   551  		if po >= k.MaxProxDisplay {
   552  			po = k.MaxProxDisplay - 1
   553  		}
   554  		if size < 0 {
   555  			panic("wtf")
   556  		}
   557  		row := []string{fmt.Sprintf("%2d", size)}
   558  //我们也在现场展示同龄人
   559  		f(func(val pot.Val, vpo int) bool {
   560  			e := val.(*entry)
   561  			row = append(row, Label(e))
   562  			rowlen++
   563  			return rowlen < 4
   564  		})
   565  		peersrows[po] = strings.Join(row, " ")
   566  		return true
   567  	})
   568  
   569  	for i := 0; i < k.MaxProxDisplay; i++ {
   570  		if i == depth {
   571  			rows = append(rows, fmt.Sprintf("============ DEPTH: %d ==========================================", i))
   572  		}
   573  		left := liverows[i]
   574  		right := peersrows[i]
   575  		if len(left) == 0 {
   576  			left = " 0                             "
   577  		}
   578  		if len(right) == 0 {
   579  			right = " 0"
   580  		}
   581  		rows = append(rows, fmt.Sprintf("%03d %v | %v", i, left, right))
   582  	}
   583  	rows = append(rows, "=========================================================================")
   584  	return "\n" + strings.Join(rows, "\n")
   585  }
   586  
   587  //Peerpot保存预期最近邻居和空箱子的信息
   588  //仅用于测试
   589  type PeerPot struct {
   590  	NNSet     [][]byte
   591  	EmptyBins []int
   592  }
   593  
   594  //newpeerpotmap用键创建overlayaddr的pot记录的映射
   595  //作为地址的十六进制表示。
   596  func NewPeerPotMap(kadMinProxSize int, addrs [][]byte) map[string]*PeerPot {
   597  //为运行状况检查创建所有节点的表
   598  	np := pot.NewPot(nil, 0)
   599  	for _, addr := range addrs {
   600  		np, _, _ = pot.Add(np, addr, pof)
   601  	}
   602  	ppmap := make(map[string]*PeerPot)
   603  
   604  	for i, a := range addrs {
   605  		pl := 256
   606  		prev := 256
   607  		var emptyBins []int
   608  		var nns [][]byte
   609  		np.EachNeighbour(addrs[i], pof, func(val pot.Val, po int) bool {
   610  			a := val.([]byte)
   611  			if po == 256 {
   612  				return true
   613  			}
   614  			if pl == 256 || pl == po {
   615  				nns = append(nns, a)
   616  			}
   617  			if pl == 256 && len(nns) >= kadMinProxSize {
   618  				pl = po
   619  				prev = po
   620  			}
   621  			if prev < pl {
   622  				for j := prev; j > po; j-- {
   623  					emptyBins = append(emptyBins, j)
   624  				}
   625  			}
   626  			prev = po - 1
   627  			return true
   628  		})
   629  		for j := prev; j >= 0; j-- {
   630  			emptyBins = append(emptyBins, j)
   631  		}
   632  		log.Trace(fmt.Sprintf("%x NNS: %s", addrs[i][:4], LogAddrs(nns)))
   633  		ppmap[common.Bytes2Hex(a)] = &PeerPot{nns, emptyBins}
   634  	}
   635  	return ppmap
   636  }
   637  
   638  //饱和返回该订单的箱的最低接近顺序
   639  //具有少于n个对等点
   640  func (k *Kademlia) saturation(n int) int {
   641  	prev := -1
   642  	k.addrs.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
   643  		prev++
   644  		return prev == po && size >= n
   645  	})
   646  	depth := k.neighbourhoodDepth()
   647  	if depth < prev {
   648  		return depth
   649  	}
   650  	return prev
   651  }
   652  
   653  //如果所有必需的容器都连接了对等方,则full返回true。
   654  //用于健康功能。
   655  func (k *Kademlia) full(emptyBins []int) (full bool) {
   656  	prev := 0
   657  	e := len(emptyBins)
   658  	ok := true
   659  	depth := k.neighbourhoodDepth()
   660  	k.conns.EachBin(k.base, pof, 0, func(po, _ int, _ func(func(val pot.Val, i int) bool) bool) bool {
   661  		if prev == depth+1 {
   662  			return true
   663  		}
   664  		for i := prev; i < po; i++ {
   665  			e--
   666  			if e < 0 {
   667  				ok = false
   668  				return false
   669  			}
   670  			if emptyBins[e] != i {
   671  				log.Trace(fmt.Sprintf("%08x po: %d, i: %d, e: %d, emptybins: %v", k.BaseAddr()[:4], po, i, e, logEmptyBins(emptyBins)))
   672  				if emptyBins[e] < i {
   673  					panic("incorrect peerpot")
   674  				}
   675  				ok = false
   676  				return false
   677  			}
   678  		}
   679  		prev = po + 1
   680  		return true
   681  	})
   682  	if !ok {
   683  		return false
   684  	}
   685  	return e == 0
   686  }
   687  
   688  func (k *Kademlia) knowNearestNeighbours(peers [][]byte) bool {
   689  	pm := make(map[string]bool)
   690  
   691  	k.eachAddr(nil, 255, func(p OverlayAddr, po int, nn bool) bool {
   692  		if !nn {
   693  			return false
   694  		}
   695  		pk := fmt.Sprintf("%x", p.Address())
   696  		pm[pk] = true
   697  		return true
   698  	})
   699  	for _, p := range peers {
   700  		pk := fmt.Sprintf("%x", p)
   701  		if !pm[pk] {
   702  			log.Trace(fmt.Sprintf("%08x: known nearest neighbour %s not found", k.BaseAddr()[:4], pk[:8]))
   703  			return false
   704  		}
   705  	}
   706  	return true
   707  }
   708  
   709  func (k *Kademlia) gotNearestNeighbours(peers [][]byte) (got bool, n int, missing [][]byte) {
   710  	pm := make(map[string]bool)
   711  
   712  	k.eachConn(nil, 255, func(p OverlayConn, po int, nn bool) bool {
   713  		if !nn {
   714  			return false
   715  		}
   716  		pk := fmt.Sprintf("%x", p.Address())
   717  		pm[pk] = true
   718  		return true
   719  	})
   720  	var gots int
   721  	var culprits [][]byte
   722  	for _, p := range peers {
   723  		pk := fmt.Sprintf("%x", p)
   724  		if pm[pk] {
   725  			gots++
   726  		} else {
   727  			log.Trace(fmt.Sprintf("%08x: ExpNN: %s not found", k.BaseAddr()[:4], pk[:8]))
   728  			culprits = append(culprits, p)
   729  		}
   730  	}
   731  	return gots == len(peers), gots, culprits
   732  }
   733  
   734  //卡德米利亚的健康状况
   735  type Health struct {
   736  KnowNN     bool     //节点是否知道所有最近的邻居
   737  GotNN      bool     //节点是否连接到其所有最近的邻居
   738  CountNN    int      //连接到的最近邻居的数量
   739  CulpritsNN [][]byte //哪些已知的nns丢失了
   740  Full       bool     //节点在每个kademlia bin中是否有一个对等点(如果有这样的对等点)
   741  	Hive       string
   742  }
   743  
   744  //健康报告Kademlia连接性的健康状态
   745  //返回健康结构
   746  func (k *Kademlia) Healthy(pp *PeerPot) *Health {
   747  	k.lock.RLock()
   748  	defer k.lock.RUnlock()
   749  	gotnn, countnn, culpritsnn := k.gotNearestNeighbours(pp.NNSet)
   750  	knownn := k.knowNearestNeighbours(pp.NNSet)
   751  	full := k.full(pp.EmptyBins)
   752  	log.Trace(fmt.Sprintf("%08x: healthy: knowNNs: %v, gotNNs: %v, full: %v\n", k.BaseAddr()[:4], knownn, gotnn, full))
   753  	return &Health{knownn, gotnn, countnn, culpritsnn, full, k.string()}
   754  }
   755  
   756  func logEmptyBins(ebs []int) string {
   757  	var ebss []string
   758  	for _, eb := range ebs {
   759  		ebss = append(ebss, fmt.Sprintf("%d", eb))
   760  	}
   761  	return strings.Join(ebss, ", ")
   762  }
   763