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