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