github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/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 19:16:43</date>
    10  //</624450113812566016>
    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  NeighbourhoodSize int   //最近邻核最小基数
    56  MinBinSize        int   //一行中的最小对等数
    57  MaxBinSize        int   //修剪前一行中的最大对等数
    58  RetryInterval     int64 //对等机首次重新拨号前的初始间隔
    59  RetryExponent     int   //用指数乘以重试间隔
    60  MaxRetries        int   //重拨尝试的最大次数
    61  //制裁或阻止建议同伴的职能
    62  	Reachable func(*BzzAddr) bool `json:"-"`
    63  }
    64  
    65  //newkadparams返回带有默认值的params结构
    66  func NewKadParams() *KadParams {
    67  	return &KadParams{
    68  		MaxProxDisplay:    16,
    69  		NeighbourhoodSize: 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  //条目表示一个kademlia表条目(bzzaddr的扩展)
   107  type entry struct {
   108  	*BzzAddr
   109  	conn    *Peer
   110  	seenAt  time.Time
   111  	retries int
   112  }
   113  
   114  //NewEntry从*对等创建一个Kademlia对等
   115  func newEntry(p *BzzAddr) *entry {
   116  	return &entry{
   117  		BzzAddr: p,
   118  		seenAt:  time.Now(),
   119  	}
   120  }
   121  
   122  //label是调试条目的短标记
   123  func Label(e *entry) string {
   124  	return fmt.Sprintf("%s (%d)", e.Hex()[:4], e.retries)
   125  }
   126  
   127  //十六进制是入口地址的十六进制序列化
   128  func (e *entry) Hex() string {
   129  	return fmt.Sprintf("%x", e.Address())
   130  }
   131  
   132  //寄存器将每个地址作为kademlia对等记录输入
   133  //已知对等地址数据库
   134  func (k *Kademlia) Register(peers ...*BzzAddr) error {
   135  	k.lock.Lock()
   136  	defer k.lock.Unlock()
   137  	var known, size int
   138  	for _, p := range peers {
   139  //如果自我接收错误,对等方应该知道得更好。
   140  //应该为此受到惩罚
   141  		if bytes.Equal(p.Address(), k.base) {
   142  			return fmt.Errorf("add peers: %x is self", k.base)
   143  		}
   144  		var found bool
   145  		k.addrs, _, found, _ = pot.Swap(k.addrs, p, Pof, func(v pot.Val) pot.Val {
   146  //如果没有找到
   147  			if v == nil {
   148  //在conn中插入新的脱机对等
   149  				return newEntry(p)
   150  			}
   151  //在已知的同龄人中发现,什么都不做
   152  			return v
   153  		})
   154  		if found {
   155  			known++
   156  		}
   157  		size++
   158  	}
   159  //仅当有新地址时才发送新地址计数值
   160  	if k.addrCountC != nil && size-known > 0 {
   161  		k.addrCountC <- k.addrs.Size()
   162  	}
   163  
   164  	k.sendNeighbourhoodDepthChange()
   165  	return nil
   166  }
   167  
   168  //SuggestPeer返回未连接的对等地址作为连接的对等建议
   169  func (k *Kademlia) SuggestPeer() (suggestedPeer *BzzAddr, saturationDepth int, changed bool) {
   170  	k.lock.Lock()
   171  	defer k.lock.Unlock()
   172  	radius := neighbourhoodRadiusForPot(k.conns, k.NeighbourhoodSize, k.base)
   173  //按连接对等数的升序收集未饱和的垃圾箱
   174  //从浅到深(po的升序)
   175  //将它们插入bin数组的映射中,并用连接的对等方的数量进行键控
   176  	saturation := make(map[int][]int)
   177  var lastPO int       //迭代中最后一个非空的po bin
   178  saturationDepth = -1 //最深的Po,所有较浅的箱子都有大于等于k.minbinsizepeer的箱子。
   179  var pastDepth bool   //迭代的po是否大于等于深度
   180  	k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool {
   181  //处理跳过的空容器
   182  		for ; lastPO < po; lastPO++ {
   183  //找到最低的不饱和料仓
   184  			if saturationDepth == -1 {
   185  				saturationDepth = lastPO
   186  			}
   187  //如果有空的垃圾桶,深度肯定会过去。
   188  			pastDepth = true
   189  			saturation[0] = append(saturation[0], lastPO)
   190  		}
   191  		lastPO = po + 1
   192  //通过半径,深度肯定通过
   193  		if po >= radius {
   194  			pastDepth = true
   195  		}
   196  //超出深度后,即使尺寸大于等于K.MinBinSize,料仓也被视为不饱和。
   197  //为了实现与所有邻居的完全连接
   198  		if pastDepth && size >= k.MinBinSize {
   199  			size = k.MinBinSize - 1
   200  		}
   201  //处理非空不饱和料仓
   202  		if size < k.MinBinSize {
   203  //找到最低的不饱和料仓
   204  			if saturationDepth == -1 {
   205  				saturationDepth = po
   206  			}
   207  			saturation[size] = append(saturation[size], po)
   208  		}
   209  		return true
   210  	})
   211  //触发比最近连接更近的对等请求,包括
   212  //从最近连接到最近地址的所有箱子都是不饱和的。
   213  	var nearestAddrAt int
   214  	k.addrs.EachNeighbour(k.base, Pof, func(_ pot.Val, po int) bool {
   215  		nearestAddrAt = po
   216  		return false
   217  	})
   218  //包含大小为0的容器会影响请求连接
   219  //优先于非空的浅仓
   220  	for ; lastPO <= nearestAddrAt; lastPO++ {
   221  		saturation[0] = append(saturation[0], lastPO)
   222  	}
   223  //所有的po箱都是饱和的,即minsize>=k.minbinSize,不建议同行使用。
   224  	if len(saturation) == 0 {
   225  		return nil, 0, false
   226  	}
   227  //在通讯簿中查找第一个可调用的对等点
   228  //从最小尺寸的箱子开始,从浅到深
   229  //对于每个垃圾箱(直到邻里半径),我们可以找到可调用的候选对等物。
   230  	for size := 0; size < k.MinBinSize && suggestedPeer == nil; size++ {
   231  		bins, ok := saturation[size]
   232  		if !ok {
   233  //没有这种尺寸的箱子
   234  			continue
   235  		}
   236  		cur := 0
   237  		curPO := bins[0]
   238  		k.addrs.EachBin(k.base, Pof, curPO, func(po, _ int, f func(func(pot.Val) bool) bool) bool {
   239  			curPO = bins[cur]
   240  //查找下一个大小为的纸盒
   241  			if curPO == po {
   242  				cur++
   243  			} else {
   244  //跳过没有地址的存储箱
   245  				for ; cur < len(bins) && curPO < po; cur++ {
   246  					curPO = bins[cur]
   247  				}
   248  				if po < curPO {
   249  					cur--
   250  					return true
   251  				}
   252  //没有地址时停止
   253  				if curPO < po {
   254  					return false
   255  				}
   256  			}
   257  //科普发现
   258  //从未饱和的bin中的地址中找到一个可调用的对等方
   259  //如果发现停止
   260  			f(func(val pot.Val) bool {
   261  				e := val.(*entry)
   262  				if k.callable(e) {
   263  					suggestedPeer = e.BzzAddr
   264  					return false
   265  				}
   266  				return true
   267  			})
   268  			return cur < len(bins) && suggestedPeer == nil
   269  		})
   270  	}
   271  
   272  	if uint8(saturationDepth) < k.depth {
   273  		k.depth = uint8(saturationDepth)
   274  		return suggestedPeer, saturationDepth, true
   275  	}
   276  	return suggestedPeer, 0, false
   277  }
   278  
   279  //在上,将对等机作为Kademlia对等机插入活动对等机
   280  func (k *Kademlia) On(p *Peer) (uint8, bool) {
   281  	k.lock.Lock()
   282  	defer k.lock.Unlock()
   283  	var ins bool
   284  	k.conns, _, _, _ = pot.Swap(k.conns, p, Pof, func(v pot.Val) pot.Val {
   285  //如果找不到现场
   286  		if v == nil {
   287  			ins = true
   288  //在conns中插入新的在线对等点
   289  			return p
   290  		}
   291  //在同龄人中找到,什么都不做
   292  		return v
   293  	})
   294  	if ins && !p.BzzPeer.LightNode {
   295  		a := newEntry(p.BzzAddr)
   296  		a.conn = p
   297  //在加法器中插入新的在线对等点
   298  		k.addrs, _, _, _ = pot.Swap(k.addrs, p, Pof, func(v pot.Val) pot.Val {
   299  			return a
   300  		})
   301  //仅当插入对等端时才发送新的地址计数值
   302  		if k.addrCountC != nil {
   303  			k.addrCountC <- k.addrs.Size()
   304  		}
   305  	}
   306  	log.Trace(k.string())
   307  //计算饱和深度是否改变
   308  	depth := uint8(k.saturation())
   309  	var changed bool
   310  	if depth != k.depth {
   311  		changed = true
   312  		k.depth = depth
   313  	}
   314  	k.sendNeighbourhoodDepthChange()
   315  	return k.depth, changed
   316  }
   317  
   318  //Neighbourhooddepthc返回发送新Kademlia的频道
   319  //每一次变化的邻里深度。
   320  //不从返回通道接收将阻塞功能
   321  //当邻近深度改变时。
   322  //托多:为什么要导出它,如果应该的话;为什么我们不能有多个订户?
   323  func (k *Kademlia) NeighbourhoodDepthC() <-chan int {
   324  	k.lock.Lock()
   325  	defer k.lock.Unlock()
   326  	if k.nDepthC == nil {
   327  		k.nDepthC = make(chan int)
   328  	}
   329  	return k.nDepthC
   330  }
   331  
   332  //sendnieghbourhooddepthchange向k.ndepth通道发送新的邻近深度
   333  //如果已初始化。
   334  func (k *Kademlia) sendNeighbourhoodDepthChange() {
   335  //当调用neighbourhooddepthc并由其返回时,将初始化ndepthc。
   336  //它提供了邻域深度变化的信号。
   337  //如果满足这个条件,代码的这一部分将向ndepthc发送新的邻域深度。
   338  	if k.nDepthC != nil {
   339  		nDepth := depthForPot(k.conns, k.NeighbourhoodSize, k.base)
   340  		if nDepth != k.nDepth {
   341  			k.nDepth = nDepth
   342  			k.nDepthC <- nDepth
   343  		}
   344  	}
   345  }
   346  
   347  //addrCountc返回发送新的
   348  //每次更改的地址计数值。
   349  //不从返回通道接收将阻止寄存器功能
   350  //地址计数值更改时。
   351  func (k *Kademlia) AddrCountC() <-chan int {
   352  	if k.addrCountC == nil {
   353  		k.addrCountC = make(chan int)
   354  	}
   355  	return k.addrCountC
   356  }
   357  
   358  //关闭从活动对等中删除对等
   359  func (k *Kademlia) Off(p *Peer) {
   360  	k.lock.Lock()
   361  	defer k.lock.Unlock()
   362  	var del bool
   363  	if !p.BzzPeer.LightNode {
   364  		k.addrs, _, _, _ = pot.Swap(k.addrs, p, Pof, func(v pot.Val) pot.Val {
   365  //v不能为零,必须选中,否则我们将覆盖条目
   366  			if v == nil {
   367  				panic(fmt.Sprintf("connected peer not found %v", p))
   368  			}
   369  			del = true
   370  			return newEntry(p.BzzAddr)
   371  		})
   372  	} else {
   373  		del = true
   374  	}
   375  
   376  	if del {
   377  		k.conns, _, _, _ = pot.Swap(k.conns, p, Pof, func(_ pot.Val) pot.Val {
   378  //V不能为零,但不需要检查
   379  			return nil
   380  		})
   381  //仅当对等端被删除时才发送新的地址计数值
   382  		if k.addrCountC != nil {
   383  			k.addrCountC <- k.addrs.Size()
   384  		}
   385  		k.sendNeighbourhoodDepthChange()
   386  	}
   387  }
   388  
   389  //eachconn是一个带有args(base、po、f)的迭代器,将f应用于每个活动对等端
   390  //从基地测量,接近订单为po或更低
   391  //如果基为零,则使用Kademlia基地址
   392  func (k *Kademlia) EachConn(base []byte, o int, f func(*Peer, int) bool) {
   393  	k.lock.RLock()
   394  	defer k.lock.RUnlock()
   395  	k.eachConn(base, o, f)
   396  }
   397  
   398  func (k *Kademlia) eachConn(base []byte, o int, f func(*Peer, int) bool) {
   399  	if len(base) == 0 {
   400  		base = k.base
   401  	}
   402  	k.conns.EachNeighbour(base, Pof, func(val pot.Val, po int) bool {
   403  		if po > o {
   404  			return true
   405  		}
   406  		return f(val.(*Peer), po)
   407  	})
   408  }
   409  
   410  //用(base,po,f)调用的eachaddr是一个迭代器,将f应用于每个已知的对等端
   411  //从底部测量,接近顺序为O或更低
   412  //如果基为零,则使用Kademlia基地址
   413  func (k *Kademlia) EachAddr(base []byte, o int, f func(*BzzAddr, int) bool) {
   414  	k.lock.RLock()
   415  	defer k.lock.RUnlock()
   416  	k.eachAddr(base, o, f)
   417  }
   418  
   419  func (k *Kademlia) eachAddr(base []byte, o int, f func(*BzzAddr, int) bool) {
   420  	if len(base) == 0 {
   421  		base = k.base
   422  	}
   423  	k.addrs.EachNeighbour(base, Pof, func(val pot.Val, po int) bool {
   424  		if po > o {
   425  			return true
   426  		}
   427  		return f(val.(*entry).BzzAddr, po)
   428  	})
   429  }
   430  
   431  //Neighbourhooddepth返回壶的深度,请参见壶的深度
   432  func (k *Kademlia) NeighbourhoodDepth() (depth int) {
   433  	k.lock.RLock()
   434  	defer k.lock.RUnlock()
   435  	return depthForPot(k.conns, k.NeighbourhoodSize, k.base)
   436  }
   437  
   438  //邻里公路返回卡德米利亚的邻里半径。
   439  //邻域半径包含大小大于等于neighbourhood size的最近邻域集
   440  //也就是说,邻里半径是最深的,这样所有的垃圾箱就不会全部变浅。
   441  //至少包含邻居大小连接的对等点
   442  //如果连接的邻居大小的对等点总数少于,则返回0
   443  //呼叫方必须持有锁
   444  func neighbourhoodRadiusForPot(p *pot.Pot, neighbourhoodSize int, pivotAddr []byte) (depth int) {
   445  	if p.Size() <= neighbourhoodSize {
   446  		return 0
   447  	}
   448  //迭代中的对等方总数
   449  	var size int
   450  	f := func(v pot.Val, i int) bool {
   451  //po==256表示addr是透视地址(self)
   452  		if i == 256 {
   453  			return true
   454  		}
   455  		size++
   456  
   457  //这意味着我们都有NN同龄人。
   458  //默认情况下,深度设置为最远nn对等端的bin。
   459  		if size == neighbourhoodSize {
   460  			depth = i
   461  			return false
   462  		}
   463  
   464  		return true
   465  	}
   466  	p.EachNeighbour(pivotAddr, Pof, f)
   467  	return depth
   468  }
   469  
   470  //depth for pot返回pot的深度
   471  //深度是最近邻区最小延伸半径
   472  //包括所有空的采购订单仓。也就是说,深度是最深的Po,因此
   473  //-深度不超过邻里半径
   474  //-所有比深度浅的箱子都不是空的。
   475  //呼叫方必须持有锁
   476  func depthForPot(p *pot.Pot, neighbourhoodSize int, pivotAddr []byte) (depth int) {
   477  	if p.Size() <= neighbourhoodSize {
   478  		return 0
   479  	}
   480  //确定深度是一个两步过程
   481  //首先,我们找到邻近地区最浅的同类的近距离垃圾箱。
   482  //深度的数值不能高于此值
   483  	maxDepth := neighbourhoodRadiusForPot(p, neighbourhoodSize, pivotAddr)
   484  
   485  //第二步是从最浅到最深依次测试空仓。
   486  //如果发现空的垃圾箱,这将是实际深度
   487  //如果达到第一步确定的最大深度,则停止迭代
   488  	p.EachBin(pivotAddr, Pof, 0, func(po int, _ int, f func(func(pot.Val) bool) bool) bool {
   489  		if po == depth {
   490  			if maxDepth == depth {
   491  				return false
   492  			}
   493  			depth++
   494  			return true
   495  		}
   496  		return false
   497  	})
   498  
   499  	return depth
   500  }
   501  
   502  //Callable决定地址条目是否表示可调用对等
   503  func (k *Kademlia) callable(e *entry) bool {
   504  //如果对等方处于活动状态或超过了maxretries,则不可调用
   505  	if e.conn != nil || e.retries > k.MaxRetries {
   506  		return false
   507  	}
   508  //根据上次看到后经过的时间计算允许的重试次数
   509  	timeAgo := int64(time.Since(e.seenAt))
   510  	div := int64(k.RetryExponent)
   511  	div += (150000 - rand.Int63n(300000)) * div / 1000000
   512  	var retries int
   513  	for delta := timeAgo; delta > k.RetryInterval; delta /= div {
   514  		retries++
   515  	}
   516  //它从不并发调用,因此可以安全地递增
   517  //可以再次重试对等机
   518  	if retries < e.retries {
   519  		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))
   520  		return false
   521  	}
   522  //制裁或阻止建议同伴的职能
   523  	if k.Reachable != nil && !k.Reachable(e.BzzAddr) {
   524  		log.Trace(fmt.Sprintf("%08x: peer %v is temporarily not callable", k.BaseAddr()[:4], e))
   525  		return false
   526  	}
   527  	e.retries++
   528  	log.Trace(fmt.Sprintf("%08x: peer %v is callable", k.BaseAddr()[:4], e))
   529  
   530  	return true
   531  }
   532  
   533  //baseaddr返回kademlia基地址
   534  func (k *Kademlia) BaseAddr() []byte {
   535  	return k.base
   536  }
   537  
   538  //字符串返回用ASCII显示的kademlia表+kaddb表
   539  func (k *Kademlia) String() string {
   540  	k.lock.RLock()
   541  	defer k.lock.RUnlock()
   542  	return k.string()
   543  }
   544  
   545  //字符串返回用ASCII显示的kademlia表+kaddb表
   546  //呼叫方必须持有锁
   547  func (k *Kademlia) string() string {
   548  	wsrow := "                          "
   549  	var rows []string
   550  
   551  	rows = append(rows, "=========================================================================")
   552  	rows = append(rows, fmt.Sprintf("%v KΛÐΞMLIΛ hive: queen's address: %x", time.Now().UTC().Format(time.UnixDate), k.BaseAddr()[:3]))
   553  	rows = append(rows, fmt.Sprintf("population: %d (%d), NeighbourhoodSize: %d, MinBinSize: %d, MaxBinSize: %d", k.conns.Size(), k.addrs.Size(), k.NeighbourhoodSize, k.MinBinSize, k.MaxBinSize))
   554  
   555  	liverows := make([]string, k.MaxProxDisplay)
   556  	peersrows := make([]string, k.MaxProxDisplay)
   557  
   558  	depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base)
   559  	rest := k.conns.Size()
   560  	k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool {
   561  		var rowlen int
   562  		if po >= k.MaxProxDisplay {
   563  			po = k.MaxProxDisplay - 1
   564  		}
   565  		row := []string{fmt.Sprintf("%2d", size)}
   566  		rest -= size
   567  		f(func(val pot.Val) bool {
   568  			e := val.(*Peer)
   569  			row = append(row, fmt.Sprintf("%x", e.Address()[:2]))
   570  			rowlen++
   571  			return rowlen < 4
   572  		})
   573  		r := strings.Join(row, " ")
   574  		r = r + wsrow
   575  		liverows[po] = r[:31]
   576  		return true
   577  	})
   578  
   579  	k.addrs.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool {
   580  		var rowlen int
   581  		if po >= k.MaxProxDisplay {
   582  			po = k.MaxProxDisplay - 1
   583  		}
   584  		if size < 0 {
   585  			panic("wtf")
   586  		}
   587  		row := []string{fmt.Sprintf("%2d", size)}
   588  //我们也在现场展示同龄人
   589  		f(func(val pot.Val) bool {
   590  			e := val.(*entry)
   591  			row = append(row, Label(e))
   592  			rowlen++
   593  			return rowlen < 4
   594  		})
   595  		peersrows[po] = strings.Join(row, " ")
   596  		return true
   597  	})
   598  
   599  	for i := 0; i < k.MaxProxDisplay; i++ {
   600  		if i == depth {
   601  			rows = append(rows, fmt.Sprintf("============ DEPTH: %d ==========================================", i))
   602  		}
   603  		left := liverows[i]
   604  		right := peersrows[i]
   605  		if len(left) == 0 {
   606  			left = " 0                             "
   607  		}
   608  		if len(right) == 0 {
   609  			right = " 0"
   610  		}
   611  		rows = append(rows, fmt.Sprintf("%03d %v | %v", i, left, right))
   612  	}
   613  	rows = append(rows, "=========================================================================")
   614  	return "\n" + strings.Join(rows, "\n")
   615  }
   616  
   617  //Peerpot保存有关预期最近邻居的信息
   618  //仅用于测试
   619  //TODO移动到单独的测试工具文件
   620  type PeerPot struct {
   621  	NNSet [][]byte
   622  }
   623  
   624  //newpeerpotmap用键创建一个pot记录的映射*bzzaddr
   625  //作为地址的十六进制表示。
   626  //使用通过的卡德米利亚的邻里大小
   627  //仅用于测试
   628  //TODO移动到单独的测试工具文件
   629  func NewPeerPotMap(neighbourhoodSize int, addrs [][]byte) map[string]*PeerPot {
   630  
   631  //为运行状况检查创建所有节点的表
   632  	np := pot.NewPot(nil, 0)
   633  	for _, addr := range addrs {
   634  		np, _, _ = pot.Add(np, addr, Pof)
   635  	}
   636  	ppmap := make(map[string]*PeerPot)
   637  
   638  //为连接生成一个通晓真相的来源
   639  //每经过一个卡德米利亚
   640  	for i, a := range addrs {
   641  
   642  //实际Kademlia深度
   643  		depth := depthForPot(np, neighbourhoodSize, a)
   644  
   645  //全神经网络节点
   646  		var nns [][]byte
   647  
   648  //从最深的地方到最浅的地方
   649  		np.EachNeighbour(a, Pof, func(val pot.Val, po int) bool {
   650  			addr := val.([]byte)
   651  //po==256表示addr是透视地址(self)
   652  //我们在地图上不包括自己
   653  			if po == 256 {
   654  				return true
   655  			}
   656  //附加找到的任何邻居
   657  //邻居是指深度内或深度之外的任何对等体。
   658  			if po >= depth {
   659  				nns = append(nns, addr)
   660  				return true
   661  			}
   662  			return false
   663  		})
   664  
   665  		log.Trace(fmt.Sprintf("%x PeerPotMap NNS: %s", addrs[i][:4], LogAddrs(nns)))
   666  		ppmap[common.Bytes2Hex(a)] = &PeerPot{
   667  			NNSet: nns,
   668  		}
   669  	}
   670  	return ppmap
   671  }
   672  
   673  //饱和返回节点具有小于minbinsize对等点的最小采购订单值。
   674  //如果迭代器达到邻域半径,则返回最后一个bin+1
   675  func (k *Kademlia) saturation() int {
   676  	prev := -1
   677  	radius := neighbourhoodRadiusForPot(k.conns, k.NeighbourhoodSize, k.base)
   678  	k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool {
   679  		prev++
   680  		if po >= radius {
   681  			return false
   682  		}
   683  		return prev == po && size >= k.MinBinSize
   684  	})
   685  	if prev < 0 {
   686  		return 0
   687  	}
   688  	return prev
   689  }
   690  
   691  //知道的邻居测试是否所有邻居都在同一个地方
   692  //在卡德米利亚已知的同龄人中发现
   693  //它仅用于健康功能的测试
   694  //TODO移动到单独的测试工具文件
   695  func (k *Kademlia) knowNeighbours(addrs [][]byte) (got bool, n int, missing [][]byte) {
   696  	pm := make(map[string]bool)
   697  	depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base)
   698  //创建一张地图,让所有同行深入了解卡德米利亚。
   699  	k.eachAddr(nil, 255, func(p *BzzAddr, po int) bool {
   700  //与卡德米利亚基地地址相比,从最深到最浅
   701  //包括所有料仓(自身除外)(0<=料仓<=255)
   702  		if po < depth {
   703  			return false
   704  		}
   705  		pk := common.Bytes2Hex(p.Address())
   706  		pm[pk] = true
   707  		return true
   708  	})
   709  
   710  //遍历Peerpot地图中最近的邻居
   711  //如果我们在上面创建的地图中找不到邻居
   712  //那我们就不了解所有的邻居了
   713  //(可悲的是,这在现代社会太普遍了)
   714  	var gots int
   715  	var culprits [][]byte
   716  	for _, p := range addrs {
   717  		pk := common.Bytes2Hex(p)
   718  		if pm[pk] {
   719  			gots++
   720  		} else {
   721  			log.Trace(fmt.Sprintf("%08x: known nearest neighbour %s not found", k.base, pk))
   722  			culprits = append(culprits, p)
   723  		}
   724  	}
   725  	return gots == len(addrs), gots, culprits
   726  }
   727  
   728  //连接的邻居测试Peerpot中的所有邻居
   729  //目前连接在卡德米利亚
   730  //它仅用于健康功能的测试
   731  func (k *Kademlia) connectedNeighbours(peers [][]byte) (got bool, n int, missing [][]byte) {
   732  	pm := make(map[string]bool)
   733  
   734  //创建一个地图,所有深度和深度的对等点都连接在Kademlia中。
   735  //与卡德米利亚基地地址相比,从最深到最浅
   736  //包括所有料仓(自身除外)(0<=料仓<=255)
   737  	depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base)
   738  	k.eachConn(nil, 255, func(p *Peer, po int) bool {
   739  		if po < depth {
   740  			return false
   741  		}
   742  		pk := common.Bytes2Hex(p.Address())
   743  		pm[pk] = true
   744  		return true
   745  	})
   746  
   747  //遍历Peerpot地图中最近的邻居
   748  //如果我们在上面创建的地图中找不到邻居
   749  //那我们就不了解所有的邻居了
   750  	var gots int
   751  	var culprits [][]byte
   752  	for _, p := range peers {
   753  		pk := common.Bytes2Hex(p)
   754  		if pm[pk] {
   755  			gots++
   756  		} else {
   757  			log.Trace(fmt.Sprintf("%08x: ExpNN: %s not found", k.base, pk))
   758  			culprits = append(culprits, p)
   759  		}
   760  	}
   761  	return gots == len(peers), gots, culprits
   762  }
   763  
   764  //卡德米利亚的健康状况
   765  //仅用于测试
   766  type Health struct {
   767  KnowNN           bool     //节点是否知道其所有邻居
   768  CountKnowNN      int      //已知邻居数量
   769  MissingKnowNN    [][]byte //我们应该知道哪些邻居,但我们不知道
   770  ConnectNN        bool     //节点是否连接到其所有邻居
   771  CountConnectNN   int      //连接到的邻居数量
   772  MissingConnectNN [][]byte //我们应该和哪个邻居有联系,但我们没有
   773  Saturated        bool     //我们是否与所有我们想联系的同龄人建立了联系
   774  	Hive             string
   775  }
   776  
   777  //健康报告Kademlia连接性的健康状态
   778  //
   779  //peerpot参数提供了网络的全知视图
   780  //结果健康对象是
   781  //问题中的卡德米利亚(接受者)的实际组成是什么,以及
   782  //当我们考虑到我们对网络的所有了解时,应该是什么情况呢?
   783  //
   784  //仅用于测试
   785  func (k *Kademlia) Healthy(pp *PeerPot) *Health {
   786  	k.lock.RLock()
   787  	defer k.lock.RUnlock()
   788  	if len(pp.NNSet) < k.NeighbourhoodSize {
   789  		log.Warn("peerpot NNSet < NeighbourhoodSize")
   790  	}
   791  	gotnn, countgotnn, culpritsgotnn := k.connectedNeighbours(pp.NNSet)
   792  	knownn, countknownn, culpritsknownn := k.knowNeighbours(pp.NNSet)
   793  	depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base)
   794  	saturated := k.saturation() < depth
   795  	log.Trace(fmt.Sprintf("%08x: healthy: knowNNs: %v, gotNNs: %v, saturated: %v\n", k.base, knownn, gotnn, saturated))
   796  	return &Health{
   797  		KnowNN:           knownn,
   798  		CountKnowNN:      countknownn,
   799  		MissingKnowNN:    culpritsknownn,
   800  		ConnectNN:        gotnn,
   801  		CountConnectNN:   countgotnn,
   802  		MissingConnectNN: culpritsgotnn,
   803  		Saturated:        saturated,
   804  		Hive:             k.string(),
   805  	}
   806  }
   807