github.com/oskarth/go-ethereum@v1.6.8-0.20191013093314-dac24a9d3494/swarm/network/kademlia.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package network 18 19 import ( 20 "bytes" 21 "fmt" 22 "math/rand" 23 "strings" 24 "sync" 25 "time" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/swarm/log" 29 "github.com/ethereum/go-ethereum/swarm/pot" 30 ) 31 32 /* 33 34 Taking the proximity order relative to a fix point x classifies the points in 35 the space (n byte long byte sequences) into bins. Items in each are at 36 most half as distant from x as items in the previous bin. Given a sample of 37 uniformly distributed items (a hash function over arbitrary sequence) the 38 proximity scale maps onto series of subsets with cardinalities on a negative 39 exponential scale. 40 41 It also has the property that any two item belonging to the same bin are at 42 most half as distant from each other as they are from x. 43 44 If we think of random sample of items in the bins as connections in a network of 45 interconnected nodes then relative proximity can serve as the basis for local 46 decisions for graph traversal where the task is to find a route between two 47 points. Since in every hop, the finite distance halves, there is 48 a guaranteed constant maximum limit on the number of hops needed to reach one 49 node from the other. 50 */ 51 52 var pof = pot.DefaultPof(256) 53 54 // KadParams holds the config params for Kademlia 55 type KadParams struct { 56 // adjustable parameters 57 MaxProxDisplay int // number of rows the table shows 58 MinProxBinSize int // nearest neighbour core minimum cardinality 59 MinBinSize int // minimum number of peers in a row 60 MaxBinSize int // maximum number of peers in a row before pruning 61 RetryInterval int64 // initial interval before a peer is first redialed 62 RetryExponent int // exponent to multiply retry intervals with 63 MaxRetries int // maximum number of redial attempts 64 // function to sanction or prevent suggesting a peer 65 Reachable func(*BzzAddr) bool 66 } 67 68 // NewKadParams returns a params struct with default values 69 func NewKadParams() *KadParams { 70 return &KadParams{ 71 MaxProxDisplay: 16, 72 MinProxBinSize: 2, 73 MinBinSize: 2, 74 MaxBinSize: 4, 75 RetryInterval: 4200000000, // 4.2 sec 76 MaxRetries: 42, 77 RetryExponent: 2, 78 } 79 } 80 81 // Kademlia is a table of live peers and a db of known peers (node records) 82 type Kademlia struct { 83 lock sync.RWMutex 84 *KadParams // Kademlia configuration parameters 85 base []byte // immutable baseaddress of the table 86 addrs *pot.Pot // pots container for known peer addresses 87 conns *pot.Pot // pots container for live peer connections 88 depth uint8 // stores the last current depth of saturation 89 nDepth int // stores the last neighbourhood depth 90 nDepthC chan int // returned by DepthC function to signal neighbourhood depth change 91 addrCountC chan int // returned by AddrCountC function to signal peer count change 92 } 93 94 // NewKademlia creates a Kademlia table for base address addr 95 // with parameters as in params 96 // if params is nil, it uses default values 97 func NewKademlia(addr []byte, params *KadParams) *Kademlia { 98 if params == nil { 99 params = NewKadParams() 100 } 101 return &Kademlia{ 102 base: addr, 103 KadParams: params, 104 addrs: pot.NewPot(nil, 0), 105 conns: pot.NewPot(nil, 0), 106 } 107 } 108 109 // entry represents a Kademlia table entry (an extension of BzzAddr) 110 type entry struct { 111 *BzzAddr 112 conn *Peer 113 seenAt time.Time 114 retries int 115 } 116 117 // newEntry creates a kademlia peer from a *Peer 118 func newEntry(p *BzzAddr) *entry { 119 return &entry{ 120 BzzAddr: p, 121 seenAt: time.Now(), 122 } 123 } 124 125 // Label is a short tag for the entry for debug 126 func Label(e *entry) string { 127 return fmt.Sprintf("%s (%d)", e.Hex()[:4], e.retries) 128 } 129 130 // Hex is the hexadecimal serialisation of the entry address 131 func (e *entry) Hex() string { 132 return fmt.Sprintf("%x", e.Address()) 133 } 134 135 // Register enters each address as kademlia peer record into the 136 // database of known peer addresses 137 func (k *Kademlia) Register(peers ...*BzzAddr) error { 138 k.lock.Lock() 139 defer k.lock.Unlock() 140 var known, size int 141 for _, p := range peers { 142 // error if self received, peer should know better 143 // and should be punished for this 144 if bytes.Equal(p.Address(), k.base) { 145 return fmt.Errorf("add peers: %x is self", k.base) 146 } 147 var found bool 148 k.addrs, _, found, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val { 149 // if not found 150 if v == nil { 151 // insert new offline peer into conns 152 return newEntry(p) 153 } 154 // found among known peers, do nothing 155 return v 156 }) 157 if found { 158 known++ 159 } 160 size++ 161 } 162 // send new address count value only if there are new addresses 163 if k.addrCountC != nil && size-known > 0 { 164 k.addrCountC <- k.addrs.Size() 165 } 166 167 k.sendNeighbourhoodDepthChange() 168 return nil 169 } 170 171 // SuggestPeer returns a known peer for the lowest proximity bin for the 172 // lowest bincount below depth 173 // naturally if there is an empty row it returns a peer for that 174 func (k *Kademlia) SuggestPeer() (a *BzzAddr, o int, want bool) { 175 k.lock.Lock() 176 defer k.lock.Unlock() 177 minsize := k.MinBinSize 178 depth := k.neighbourhoodDepth() 179 // if there is a callable neighbour within the current proxBin, connect 180 // this makes sure nearest neighbour set is fully connected 181 var ppo int 182 k.addrs.EachNeighbour(k.base, pof, func(val pot.Val, po int) bool { 183 if po < depth { 184 return false 185 } 186 e := val.(*entry) 187 c := k.callable(e) 188 if c { 189 a = e.BzzAddr 190 } 191 ppo = po 192 return !c 193 }) 194 if a != nil { 195 log.Trace(fmt.Sprintf("%08x candidate nearest neighbour found: %v (%v)", k.BaseAddr()[:4], a, ppo)) 196 return a, 0, false 197 } 198 199 var bpo []int 200 prev := -1 201 k.conns.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool { 202 prev++ 203 for ; prev < po; prev++ { 204 bpo = append(bpo, prev) 205 minsize = 0 206 } 207 if size < minsize { 208 bpo = append(bpo, po) 209 minsize = size 210 } 211 return size > 0 && po < depth 212 }) 213 // all buckets are full, ie., minsize == k.MinBinSize 214 if len(bpo) == 0 { 215 return nil, 0, false 216 } 217 // as long as we got candidate peers to connect to 218 // dont ask for new peers (want = false) 219 // try to select a candidate peer 220 // find the first callable peer 221 nxt := bpo[0] 222 k.addrs.EachBin(k.base, pof, nxt, func(po, _ int, f func(func(pot.Val, int) bool) bool) bool { 223 // for each bin (up until depth) we find callable candidate peers 224 if po >= depth { 225 return false 226 } 227 return f(func(val pot.Val, _ int) bool { 228 e := val.(*entry) 229 c := k.callable(e) 230 if c { 231 a = e.BzzAddr 232 } 233 return !c 234 }) 235 }) 236 // found a candidate 237 if a != nil { 238 return a, 0, false 239 } 240 // no candidate peer found, request for the short bin 241 var changed bool 242 if uint8(nxt) < k.depth { 243 k.depth = uint8(nxt) 244 changed = true 245 } 246 return a, nxt, changed 247 } 248 249 // On inserts the peer as a kademlia peer into the live peers 250 func (k *Kademlia) On(p *Peer) (uint8, bool) { 251 k.lock.Lock() 252 defer k.lock.Unlock() 253 var ins bool 254 k.conns, _, _, _ = pot.Swap(k.conns, p, pof, func(v pot.Val) pot.Val { 255 // if not found live 256 if v == nil { 257 ins = true 258 // insert new online peer into conns 259 return p 260 } 261 // found among live peers, do nothing 262 return v 263 }) 264 if ins { 265 a := newEntry(p.BzzAddr) 266 a.conn = p 267 // insert new online peer into addrs 268 k.addrs, _, _, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val { 269 return a 270 }) 271 // send new address count value only if the peer is inserted 272 if k.addrCountC != nil { 273 k.addrCountC <- k.addrs.Size() 274 } 275 } 276 log.Trace(k.string()) 277 // calculate if depth of saturation changed 278 depth := uint8(k.saturation(k.MinBinSize)) 279 var changed bool 280 if depth != k.depth { 281 changed = true 282 k.depth = depth 283 } 284 k.sendNeighbourhoodDepthChange() 285 return k.depth, changed 286 } 287 288 // NeighbourhoodDepthC returns the channel that sends a new kademlia 289 // neighbourhood depth on each change. 290 // Not receiving from the returned channel will block On function 291 // when the neighbourhood depth is changed. 292 func (k *Kademlia) NeighbourhoodDepthC() <-chan int { 293 k.lock.Lock() 294 defer k.lock.Unlock() 295 if k.nDepthC == nil { 296 k.nDepthC = make(chan int) 297 } 298 return k.nDepthC 299 } 300 301 // sendNeighbourhoodDepthChange sends new neighbourhood depth to k.nDepth channel 302 // if it is initialized. 303 func (k *Kademlia) sendNeighbourhoodDepthChange() { 304 // nDepthC is initialized when NeighbourhoodDepthC is called and returned by it. 305 // It provides signaling of neighbourhood depth change. 306 // This part of the code is sending new neighbourhood depth to nDepthC if that condition is met. 307 if k.nDepthC != nil { 308 nDepth := k.neighbourhoodDepth() 309 if nDepth != k.nDepth { 310 k.nDepth = nDepth 311 k.nDepthC <- nDepth 312 } 313 } 314 } 315 316 // AddrCountC returns the channel that sends a new 317 // address count value on each change. 318 // Not receiving from the returned channel will block Register function 319 // when address count value changes. 320 func (k *Kademlia) AddrCountC() <-chan int { 321 if k.addrCountC == nil { 322 k.addrCountC = make(chan int) 323 } 324 return k.addrCountC 325 } 326 327 // Off removes a peer from among live peers 328 func (k *Kademlia) Off(p *Peer) { 329 k.lock.Lock() 330 defer k.lock.Unlock() 331 var del bool 332 k.addrs, _, _, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val { 333 // v cannot be nil, must check otherwise we overwrite entry 334 if v == nil { 335 panic(fmt.Sprintf("connected peer not found %v", p)) 336 } 337 del = true 338 return newEntry(p.BzzAddr) 339 }) 340 341 if del { 342 k.conns, _, _, _ = pot.Swap(k.conns, p, pof, func(_ pot.Val) pot.Val { 343 // v cannot be nil, but no need to check 344 return nil 345 }) 346 // send new address count value only if the peer is deleted 347 if k.addrCountC != nil { 348 k.addrCountC <- k.addrs.Size() 349 } 350 k.sendNeighbourhoodDepthChange() 351 } 352 } 353 354 func (k *Kademlia) EachBin(base []byte, pof pot.Pof, o int, eachBinFunc func(conn *Peer, po int) bool) { 355 k.lock.RLock() 356 defer k.lock.RUnlock() 357 358 var startPo int 359 var endPo int 360 kadDepth := k.neighbourhoodDepth() 361 362 k.conns.EachBin(base, pof, o, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool { 363 if startPo > 0 && endPo != k.MaxProxDisplay { 364 startPo = endPo + 1 365 } 366 if po < kadDepth { 367 endPo = po 368 } else { 369 endPo = k.MaxProxDisplay 370 } 371 372 for bin := startPo; bin <= endPo; bin++ { 373 f(func(val pot.Val, _ int) bool { 374 return eachBinFunc(val.(*Peer), bin) 375 }) 376 } 377 return true 378 }) 379 } 380 381 // EachConn is an iterator with args (base, po, f) applies f to each live peer 382 // that has proximity order po or less as measured from the base 383 // if base is nil, kademlia base address is used 384 func (k *Kademlia) EachConn(base []byte, o int, f func(*Peer, int, bool) bool) { 385 k.lock.RLock() 386 defer k.lock.RUnlock() 387 k.eachConn(base, o, f) 388 } 389 390 func (k *Kademlia) eachConn(base []byte, o int, f func(*Peer, int, bool) bool) { 391 if len(base) == 0 { 392 base = k.base 393 } 394 depth := k.neighbourhoodDepth() 395 k.conns.EachNeighbour(base, pof, func(val pot.Val, po int) bool { 396 if po > o { 397 return true 398 } 399 return f(val.(*Peer), po, po >= depth) 400 }) 401 } 402 403 // EachAddr called with (base, po, f) is an iterator applying f to each known peer 404 // that has proximity order po or less as measured from the base 405 // if base is nil, kademlia base address is used 406 func (k *Kademlia) EachAddr(base []byte, o int, f func(*BzzAddr, int, bool) bool) { 407 k.lock.RLock() 408 defer k.lock.RUnlock() 409 k.eachAddr(base, o, f) 410 } 411 412 func (k *Kademlia) eachAddr(base []byte, o int, f func(*BzzAddr, int, bool) bool) { 413 if len(base) == 0 { 414 base = k.base 415 } 416 depth := k.neighbourhoodDepth() 417 k.addrs.EachNeighbour(base, pof, func(val pot.Val, po int) bool { 418 if po > o { 419 return true 420 } 421 return f(val.(*entry).BzzAddr, po, po >= depth) 422 }) 423 } 424 425 // neighbourhoodDepth returns the proximity order that defines the distance of 426 // the nearest neighbour set with cardinality >= MinProxBinSize 427 // if there is altogether less than MinProxBinSize peers it returns 0 428 // caller must hold the lock 429 func (k *Kademlia) neighbourhoodDepth() (depth int) { 430 if k.conns.Size() < k.MinProxBinSize { 431 return 0 432 } 433 var size int 434 f := func(v pot.Val, i int) bool { 435 size++ 436 depth = i 437 return size < k.MinProxBinSize 438 } 439 k.conns.EachNeighbour(k.base, pof, f) 440 return depth 441 } 442 443 // callable decides if an address entry represents a callable peer 444 func (k *Kademlia) callable(e *entry) bool { 445 // not callable if peer is live or exceeded maxRetries 446 if e.conn != nil || e.retries > k.MaxRetries { 447 return false 448 } 449 // calculate the allowed number of retries based on time lapsed since last seen 450 timeAgo := int64(time.Since(e.seenAt)) 451 div := int64(k.RetryExponent) 452 div += (150000 - rand.Int63n(300000)) * div / 1000000 453 var retries int 454 for delta := timeAgo; delta > k.RetryInterval; delta /= div { 455 retries++ 456 } 457 // this is never called concurrently, so safe to increment 458 // peer can be retried again 459 if retries < e.retries { 460 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)) 461 return false 462 } 463 // function to sanction or prevent suggesting a peer 464 if k.Reachable != nil && !k.Reachable(e.BzzAddr) { 465 log.Trace(fmt.Sprintf("%08x: peer %v is temporarily not callable", k.BaseAddr()[:4], e)) 466 return false 467 } 468 e.retries++ 469 log.Trace(fmt.Sprintf("%08x: peer %v is callable", k.BaseAddr()[:4], e)) 470 471 return true 472 } 473 474 // BaseAddr return the kademlia base address 475 func (k *Kademlia) BaseAddr() []byte { 476 return k.base 477 } 478 479 // String returns kademlia table + kaddb table displayed with ascii 480 func (k *Kademlia) String() string { 481 k.lock.RLock() 482 defer k.lock.RUnlock() 483 return k.string() 484 } 485 486 // string returns kademlia table + kaddb table displayed with ascii 487 // caller must hold the lock 488 func (k *Kademlia) string() string { 489 wsrow := " " 490 var rows []string 491 492 rows = append(rows, "=========================================================================") 493 rows = append(rows, fmt.Sprintf("%v KΛÐΞMLIΛ hive: queen's address: %x", time.Now().UTC().Format(time.UnixDate), k.BaseAddr()[:3])) 494 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)) 495 496 liverows := make([]string, k.MaxProxDisplay) 497 peersrows := make([]string, k.MaxProxDisplay) 498 499 depth := k.neighbourhoodDepth() 500 rest := k.conns.Size() 501 k.conns.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool { 502 var rowlen int 503 if po >= k.MaxProxDisplay { 504 po = k.MaxProxDisplay - 1 505 } 506 row := []string{fmt.Sprintf("%2d", size)} 507 rest -= size 508 f(func(val pot.Val, vpo int) bool { 509 e := val.(*Peer) 510 row = append(row, fmt.Sprintf("%x", e.Address()[:2])) 511 rowlen++ 512 return rowlen < 4 513 }) 514 r := strings.Join(row, " ") 515 r = r + wsrow 516 liverows[po] = r[:31] 517 return true 518 }) 519 520 k.addrs.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool { 521 var rowlen int 522 if po >= k.MaxProxDisplay { 523 po = k.MaxProxDisplay - 1 524 } 525 if size < 0 { 526 panic("wtf") 527 } 528 row := []string{fmt.Sprintf("%2d", size)} 529 // we are displaying live peers too 530 f(func(val pot.Val, vpo int) bool { 531 e := val.(*entry) 532 row = append(row, Label(e)) 533 rowlen++ 534 return rowlen < 4 535 }) 536 peersrows[po] = strings.Join(row, " ") 537 return true 538 }) 539 540 for i := 0; i < k.MaxProxDisplay; i++ { 541 if i == depth { 542 rows = append(rows, fmt.Sprintf("============ DEPTH: %d ==========================================", i)) 543 } 544 left := liverows[i] 545 right := peersrows[i] 546 if len(left) == 0 { 547 left = " 0 " 548 } 549 if len(right) == 0 { 550 right = " 0" 551 } 552 rows = append(rows, fmt.Sprintf("%03d %v | %v", i, left, right)) 553 } 554 rows = append(rows, "=========================================================================") 555 return "\n" + strings.Join(rows, "\n") 556 } 557 558 // PeerPot keeps info about expected nearest neighbours and empty bins 559 // used for testing only 560 type PeerPot struct { 561 NNSet [][]byte 562 EmptyBins []int 563 } 564 565 // NewPeerPotMap creates a map of pot record of *BzzAddr with keys 566 // as hexadecimal representations of the address. 567 // used for testing only 568 func NewPeerPotMap(kadMinProxSize int, addrs [][]byte) map[string]*PeerPot { 569 // create a table of all nodes for health check 570 np := pot.NewPot(nil, 0) 571 for _, addr := range addrs { 572 np, _, _ = pot.Add(np, addr, pof) 573 } 574 ppmap := make(map[string]*PeerPot) 575 576 for i, a := range addrs { 577 pl := 256 578 prev := 256 579 var emptyBins []int 580 var nns [][]byte 581 np.EachNeighbour(addrs[i], pof, func(val pot.Val, po int) bool { 582 a := val.([]byte) 583 if po == 256 { 584 return true 585 } 586 if pl == 256 || pl == po { 587 nns = append(nns, a) 588 } 589 if pl == 256 && len(nns) >= kadMinProxSize { 590 pl = po 591 prev = po 592 } 593 if prev < pl { 594 for j := prev; j > po; j-- { 595 emptyBins = append(emptyBins, j) 596 } 597 } 598 prev = po - 1 599 return true 600 }) 601 for j := prev; j >= 0; j-- { 602 emptyBins = append(emptyBins, j) 603 } 604 log.Trace(fmt.Sprintf("%x NNS: %s", addrs[i][:4], LogAddrs(nns))) 605 ppmap[common.Bytes2Hex(a)] = &PeerPot{nns, emptyBins} 606 } 607 return ppmap 608 } 609 610 // saturation returns the lowest proximity order that the bin for that order 611 // has less than n peers 612 // It is used in Healthy function for testing only 613 func (k *Kademlia) saturation(n int) int { 614 prev := -1 615 k.addrs.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool { 616 prev++ 617 return prev == po && size >= n 618 }) 619 depth := k.neighbourhoodDepth() 620 if depth < prev { 621 return depth 622 } 623 return prev 624 } 625 626 // full returns true if all required bins have connected peers. 627 // It is used in Healthy function for testing only 628 func (k *Kademlia) full(emptyBins []int) (full bool) { 629 prev := 0 630 e := len(emptyBins) 631 ok := true 632 depth := k.neighbourhoodDepth() 633 k.conns.EachBin(k.base, pof, 0, func(po, _ int, _ func(func(val pot.Val, i int) bool) bool) bool { 634 if prev == depth+1 { 635 return true 636 } 637 for i := prev; i < po; i++ { 638 e-- 639 if e < 0 { 640 ok = false 641 return false 642 } 643 if emptyBins[e] != i { 644 log.Trace(fmt.Sprintf("%08x po: %d, i: %d, e: %d, emptybins: %v", k.BaseAddr()[:4], po, i, e, logEmptyBins(emptyBins))) 645 if emptyBins[e] < i { 646 panic("incorrect peerpot") 647 } 648 ok = false 649 return false 650 } 651 } 652 prev = po + 1 653 return true 654 }) 655 if !ok { 656 return false 657 } 658 return e == 0 659 } 660 661 // knowNearestNeighbours tests if all known nearest neighbours given as arguments 662 // are found in the addressbook 663 // It is used in Healthy function for testing only 664 func (k *Kademlia) knowNearestNeighbours(peers [][]byte) bool { 665 pm := make(map[string]bool) 666 667 k.eachAddr(nil, 255, func(p *BzzAddr, po int, nn bool) bool { 668 if !nn { 669 return false 670 } 671 pk := fmt.Sprintf("%x", p.Address()) 672 pm[pk] = true 673 return true 674 }) 675 for _, p := range peers { 676 pk := fmt.Sprintf("%x", p) 677 if !pm[pk] { 678 log.Trace(fmt.Sprintf("%08x: known nearest neighbour %s not found", k.BaseAddr()[:4], pk[:8])) 679 return false 680 } 681 } 682 return true 683 } 684 685 // gotNearestNeighbours tests if all known nearest neighbours given as arguments 686 // are connected peers 687 // It is used in Healthy function for testing only 688 func (k *Kademlia) gotNearestNeighbours(peers [][]byte) (got bool, n int, missing [][]byte) { 689 pm := make(map[string]bool) 690 691 k.eachConn(nil, 255, func(p *Peer, 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 var gots int 700 var culprits [][]byte 701 for _, p := range peers { 702 pk := fmt.Sprintf("%x", p) 703 if pm[pk] { 704 gots++ 705 } else { 706 log.Trace(fmt.Sprintf("%08x: ExpNN: %s not found", k.BaseAddr()[:4], pk[:8])) 707 culprits = append(culprits, p) 708 } 709 } 710 return gots == len(peers), gots, culprits 711 } 712 713 // Health state of the Kademlia 714 // used for testing only 715 type Health struct { 716 KnowNN bool // whether node knows all its nearest neighbours 717 GotNN bool // whether node is connected to all its nearest neighbours 718 CountNN int // amount of nearest neighbors connected to 719 CulpritsNN [][]byte // which known NNs are missing 720 Full bool // whether node has a peer in each kademlia bin (where there is such a peer) 721 Hive string 722 } 723 724 // Healthy reports the health state of the kademlia connectivity 725 // returns a Health struct 726 // used for testing only 727 func (k *Kademlia) Healthy(pp *PeerPot) *Health { 728 k.lock.RLock() 729 defer k.lock.RUnlock() 730 gotnn, countnn, culpritsnn := k.gotNearestNeighbours(pp.NNSet) 731 knownn := k.knowNearestNeighbours(pp.NNSet) 732 full := k.full(pp.EmptyBins) 733 log.Trace(fmt.Sprintf("%08x: healthy: knowNNs: %v, gotNNs: %v, full: %v\n", k.BaseAddr()[:4], knownn, gotnn, full)) 734 return &Health{knownn, gotnn, countnn, culpritsnn, full, k.string()} 735 } 736 737 func logEmptyBins(ebs []int) string { 738 var ebss []string 739 for _, eb := range ebs { 740 ebss = append(ebss, fmt.Sprintf("%d", eb)) 741 } 742 return strings.Join(ebss, ", ") 743 }