github.com/rayrapetyan/go-ethereum@v1.8.21/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 NeighbourhoodSize 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 `json:"-"` 66 } 67 68 // NewKadParams returns a params struct with default values 69 func NewKadParams() *KadParams { 70 return &KadParams{ 71 MaxProxDisplay: 16, 72 NeighbourhoodSize: 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 := depthForPot(k.conns, k.NeighbourhoodSize, k.base) 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) 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) 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) 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 && !p.BzzPeer.LightNode { 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()) 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 // TODO: Why is this exported, and if it should be; why can't we have more subscribers than one? 293 func (k *Kademlia) NeighbourhoodDepthC() <-chan int { 294 k.lock.Lock() 295 defer k.lock.Unlock() 296 if k.nDepthC == nil { 297 k.nDepthC = make(chan int) 298 } 299 return k.nDepthC 300 } 301 302 // sendNeighbourhoodDepthChange sends new neighbourhood depth to k.nDepth channel 303 // if it is initialized. 304 func (k *Kademlia) sendNeighbourhoodDepthChange() { 305 // nDepthC is initialized when NeighbourhoodDepthC is called and returned by it. 306 // It provides signaling of neighbourhood depth change. 307 // This part of the code is sending new neighbourhood depth to nDepthC if that condition is met. 308 if k.nDepthC != nil { 309 nDepth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) 310 if nDepth != k.nDepth { 311 k.nDepth = nDepth 312 k.nDepthC <- nDepth 313 } 314 } 315 } 316 317 // AddrCountC returns the channel that sends a new 318 // address count value on each change. 319 // Not receiving from the returned channel will block Register function 320 // when address count value changes. 321 func (k *Kademlia) AddrCountC() <-chan int { 322 if k.addrCountC == nil { 323 k.addrCountC = make(chan int) 324 } 325 return k.addrCountC 326 } 327 328 // Off removes a peer from among live peers 329 func (k *Kademlia) Off(p *Peer) { 330 k.lock.Lock() 331 defer k.lock.Unlock() 332 var del bool 333 if !p.BzzPeer.LightNode { 334 k.addrs, _, _, _ = pot.Swap(k.addrs, p, Pof, func(v pot.Val) pot.Val { 335 // v cannot be nil, must check otherwise we overwrite entry 336 if v == nil { 337 panic(fmt.Sprintf("connected peer not found %v", p)) 338 } 339 del = true 340 return newEntry(p.BzzAddr) 341 }) 342 } else { 343 del = true 344 } 345 346 if del { 347 k.conns, _, _, _ = pot.Swap(k.conns, p, Pof, func(_ pot.Val) pot.Val { 348 // v cannot be nil, but no need to check 349 return nil 350 }) 351 // send new address count value only if the peer is deleted 352 if k.addrCountC != nil { 353 k.addrCountC <- k.addrs.Size() 354 } 355 k.sendNeighbourhoodDepthChange() 356 } 357 } 358 359 // EachConn is an iterator with args (base, po, f) applies f to each live peer 360 // that has proximity order po or less as measured from the base 361 // if base is nil, kademlia base address is used 362 func (k *Kademlia) EachConn(base []byte, o int, f func(*Peer, int) bool) { 363 k.lock.RLock() 364 defer k.lock.RUnlock() 365 k.eachConn(base, o, f) 366 } 367 368 func (k *Kademlia) eachConn(base []byte, o int, f func(*Peer, int) bool) { 369 if len(base) == 0 { 370 base = k.base 371 } 372 k.conns.EachNeighbour(base, Pof, func(val pot.Val, po int) bool { 373 if po > o { 374 return true 375 } 376 return f(val.(*Peer), po) 377 }) 378 } 379 380 // EachAddr called with (base, po, f) is an iterator applying f to each known peer 381 // that has proximity order o or less as measured from the base 382 // if base is nil, kademlia base address is used 383 func (k *Kademlia) EachAddr(base []byte, o int, f func(*BzzAddr, int) bool) { 384 k.lock.RLock() 385 defer k.lock.RUnlock() 386 k.eachAddr(base, o, f) 387 } 388 389 func (k *Kademlia) eachAddr(base []byte, o int, f func(*BzzAddr, int) bool) { 390 if len(base) == 0 { 391 base = k.base 392 } 393 k.addrs.EachNeighbour(base, Pof, func(val pot.Val, po int) bool { 394 if po > o { 395 return true 396 } 397 return f(val.(*entry).BzzAddr, po) 398 }) 399 } 400 401 func (k *Kademlia) NeighbourhoodDepth() (depth int) { 402 k.lock.RLock() 403 defer k.lock.RUnlock() 404 return depthForPot(k.conns, k.NeighbourhoodSize, k.base) 405 } 406 407 // depthForPot returns the proximity order that defines the distance of 408 // the nearest neighbour set with cardinality >= NeighbourhoodSize 409 // if there is altogether less than NeighbourhoodSize peers it returns 0 410 // caller must hold the lock 411 func depthForPot(p *pot.Pot, neighbourhoodSize int, pivotAddr []byte) (depth int) { 412 if p.Size() <= neighbourhoodSize { 413 return 0 414 } 415 416 // total number of peers in iteration 417 var size int 418 419 // determining the depth is a two-step process 420 // first we find the proximity bin of the shallowest of the NeighbourhoodSize peers 421 // the numeric value of depth cannot be higher than this 422 var maxDepth int 423 424 f := func(v pot.Val, i int) bool { 425 // po == 256 means that addr is the pivot address(self) 426 if i == 256 { 427 return true 428 } 429 size++ 430 431 // this means we have all nn-peers. 432 // depth is by default set to the bin of the farthest nn-peer 433 if size == neighbourhoodSize { 434 maxDepth = i 435 return false 436 } 437 438 return true 439 } 440 p.EachNeighbour(pivotAddr, Pof, f) 441 442 // the second step is to test for empty bins in order from shallowest to deepest 443 // if an empty bin is found, this will be the actual depth 444 // we stop iterating if we hit the maxDepth determined in the first step 445 p.EachBin(pivotAddr, Pof, 0, func(po int, _ int, f func(func(pot.Val) bool) bool) bool { 446 if po == depth { 447 if maxDepth == depth { 448 return false 449 } 450 depth++ 451 return true 452 } 453 return false 454 }) 455 456 return depth 457 } 458 459 // callable decides if an address entry represents a callable peer 460 func (k *Kademlia) callable(e *entry) bool { 461 // not callable if peer is live or exceeded maxRetries 462 if e.conn != nil || e.retries > k.MaxRetries { 463 return false 464 } 465 // calculate the allowed number of retries based on time lapsed since last seen 466 timeAgo := int64(time.Since(e.seenAt)) 467 div := int64(k.RetryExponent) 468 div += (150000 - rand.Int63n(300000)) * div / 1000000 469 var retries int 470 for delta := timeAgo; delta > k.RetryInterval; delta /= div { 471 retries++ 472 } 473 // this is never called concurrently, so safe to increment 474 // peer can be retried again 475 if retries < e.retries { 476 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)) 477 return false 478 } 479 // function to sanction or prevent suggesting a peer 480 if k.Reachable != nil && !k.Reachable(e.BzzAddr) { 481 log.Trace(fmt.Sprintf("%08x: peer %v is temporarily not callable", k.BaseAddr()[:4], e)) 482 return false 483 } 484 e.retries++ 485 log.Trace(fmt.Sprintf("%08x: peer %v is callable", k.BaseAddr()[:4], e)) 486 487 return true 488 } 489 490 // BaseAddr return the kademlia base address 491 func (k *Kademlia) BaseAddr() []byte { 492 return k.base 493 } 494 495 // String returns kademlia table + kaddb table displayed with ascii 496 func (k *Kademlia) String() string { 497 k.lock.RLock() 498 defer k.lock.RUnlock() 499 return k.string() 500 } 501 502 // string returns kademlia table + kaddb table displayed with ascii 503 // caller must hold the lock 504 func (k *Kademlia) string() string { 505 wsrow := " " 506 var rows []string 507 508 rows = append(rows, "=========================================================================") 509 rows = append(rows, fmt.Sprintf("%v KΛÐΞMLIΛ hive: queen's address: %x", time.Now().UTC().Format(time.UnixDate), k.BaseAddr()[:3])) 510 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)) 511 512 liverows := make([]string, k.MaxProxDisplay) 513 peersrows := make([]string, k.MaxProxDisplay) 514 515 depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) 516 rest := k.conns.Size() 517 k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { 518 var rowlen int 519 if po >= k.MaxProxDisplay { 520 po = k.MaxProxDisplay - 1 521 } 522 row := []string{fmt.Sprintf("%2d", size)} 523 rest -= size 524 f(func(val pot.Val) bool { 525 e := val.(*Peer) 526 row = append(row, fmt.Sprintf("%x", e.Address()[:2])) 527 rowlen++ 528 return rowlen < 4 529 }) 530 r := strings.Join(row, " ") 531 r = r + wsrow 532 liverows[po] = r[:31] 533 return true 534 }) 535 536 k.addrs.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { 537 var rowlen int 538 if po >= k.MaxProxDisplay { 539 po = k.MaxProxDisplay - 1 540 } 541 if size < 0 { 542 panic("wtf") 543 } 544 row := []string{fmt.Sprintf("%2d", size)} 545 // we are displaying live peers too 546 f(func(val pot.Val) bool { 547 e := val.(*entry) 548 row = append(row, Label(e)) 549 rowlen++ 550 return rowlen < 4 551 }) 552 peersrows[po] = strings.Join(row, " ") 553 return true 554 }) 555 556 for i := 0; i < k.MaxProxDisplay; i++ { 557 if i == depth { 558 rows = append(rows, fmt.Sprintf("============ DEPTH: %d ==========================================", i)) 559 } 560 left := liverows[i] 561 right := peersrows[i] 562 if len(left) == 0 { 563 left = " 0 " 564 } 565 if len(right) == 0 { 566 right = " 0" 567 } 568 rows = append(rows, fmt.Sprintf("%03d %v | %v", i, left, right)) 569 } 570 rows = append(rows, "=========================================================================") 571 return "\n" + strings.Join(rows, "\n") 572 } 573 574 // PeerPot keeps info about expected nearest neighbours 575 // used for testing only 576 // TODO move to separate testing tools file 577 type PeerPot struct { 578 NNSet [][]byte 579 } 580 581 // NewPeerPotMap creates a map of pot record of *BzzAddr with keys 582 // as hexadecimal representations of the address. 583 // the NeighbourhoodSize of the passed kademlia is used 584 // used for testing only 585 // TODO move to separate testing tools file 586 func NewPeerPotMap(neighbourhoodSize int, addrs [][]byte) map[string]*PeerPot { 587 588 // create a table of all nodes for health check 589 np := pot.NewPot(nil, 0) 590 for _, addr := range addrs { 591 np, _, _ = pot.Add(np, addr, Pof) 592 } 593 ppmap := make(map[string]*PeerPot) 594 595 // generate an allknowing source of truth for connections 596 // for every kademlia passed 597 for i, a := range addrs { 598 599 // actual kademlia depth 600 depth := depthForPot(np, neighbourhoodSize, a) 601 602 // all nn-peers 603 var nns [][]byte 604 605 // iterate through the neighbours, going from the deepest to the shallowest 606 np.EachNeighbour(a, Pof, func(val pot.Val, po int) bool { 607 addr := val.([]byte) 608 // po == 256 means that addr is the pivot address(self) 609 // we do not include self in the map 610 if po == 256 { 611 return true 612 } 613 // append any neighbors found 614 // a neighbor is any peer in or deeper than the depth 615 if po >= depth { 616 nns = append(nns, addr) 617 return true 618 } 619 return false 620 }) 621 622 log.Trace(fmt.Sprintf("%x PeerPotMap NNS: %s", addrs[i][:4], LogAddrs(nns))) 623 ppmap[common.Bytes2Hex(a)] = &PeerPot{ 624 NNSet: nns, 625 } 626 } 627 return ppmap 628 } 629 630 // saturation iterates through all peers and 631 // returns the smallest po value in which the node has less than n peers 632 // if the iterator reaches depth, then value for depth is returned 633 // TODO move to separate testing tools file 634 // TODO this function will stop at the first bin with less than MinBinSize peers, even if there are empty bins between that bin and the depth. This may not be correct behavior 635 func (k *Kademlia) saturation() int { 636 prev := -1 637 k.addrs.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { 638 prev++ 639 return prev == po && size >= k.MinBinSize 640 }) 641 // TODO evaluate whether this check cannot just as well be done within the eachbin 642 depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) 643 if depth < prev { 644 return depth 645 } 646 return prev 647 } 648 649 // knowNeighbours tests if all neighbours in the peerpot 650 // are found among the peers known to the kademlia 651 // It is used in Healthy function for testing only 652 // TODO move to separate testing tools file 653 func (k *Kademlia) knowNeighbours(addrs [][]byte) (got bool, n int, missing [][]byte) { 654 pm := make(map[string]bool) 655 depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) 656 // create a map with all peers at depth and deeper known in the kademlia 657 k.eachAddr(nil, 255, func(p *BzzAddr, po int) bool { 658 // in order deepest to shallowest compared to the kademlia base address 659 // all bins (except self) are included (0 <= bin <= 255) 660 if po < depth { 661 return false 662 } 663 pk := common.Bytes2Hex(p.Address()) 664 pm[pk] = true 665 return true 666 }) 667 668 // iterate through nearest neighbors in the peerpot map 669 // if we can't find the neighbor in the map we created above 670 // then we don't know all our neighbors 671 // (which sadly is all too common in modern society) 672 var gots int 673 var culprits [][]byte 674 for _, p := range addrs { 675 pk := common.Bytes2Hex(p) 676 if pm[pk] { 677 gots++ 678 } else { 679 log.Trace(fmt.Sprintf("%08x: known nearest neighbour %s not found", k.base, pk)) 680 culprits = append(culprits, p) 681 } 682 } 683 return gots == len(addrs), gots, culprits 684 } 685 686 // connectedNeighbours tests if all neighbours in the peerpot 687 // are currently connected in the kademlia 688 // It is used in Healthy function for testing only 689 func (k *Kademlia) connectedNeighbours(peers [][]byte) (got bool, n int, missing [][]byte) { 690 pm := make(map[string]bool) 691 692 // create a map with all peers at depth and deeper that are connected in the kademlia 693 // in order deepest to shallowest compared to the kademlia base address 694 // all bins (except self) are included (0 <= bin <= 255) 695 depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) 696 k.eachConn(nil, 255, func(p *Peer, po int) bool { 697 if po < depth { 698 return false 699 } 700 pk := common.Bytes2Hex(p.Address()) 701 pm[pk] = true 702 return true 703 }) 704 705 // iterate through nearest neighbors in the peerpot map 706 // if we can't find the neighbor in the map we created above 707 // then we don't know all our neighbors 708 var gots int 709 var culprits [][]byte 710 for _, p := range peers { 711 pk := common.Bytes2Hex(p) 712 if pm[pk] { 713 gots++ 714 } else { 715 log.Trace(fmt.Sprintf("%08x: ExpNN: %s not found", k.base, pk)) 716 culprits = append(culprits, p) 717 } 718 } 719 return gots == len(peers), gots, culprits 720 } 721 722 // Health state of the Kademlia 723 // used for testing only 724 type Health struct { 725 KnowNN bool // whether node knows all its neighbours 726 CountKnowNN int // amount of neighbors known 727 MissingKnowNN [][]byte // which neighbours we should have known but we don't 728 ConnectNN bool // whether node is connected to all its neighbours 729 CountConnectNN int // amount of neighbours connected to 730 MissingConnectNN [][]byte // which neighbours we should have been connected to but we're not 731 Saturated bool // whether we are connected to all the peers we would have liked to 732 Hive string 733 } 734 735 // Healthy reports the health state of the kademlia connectivity 736 // 737 // The PeerPot argument provides an all-knowing view of the network 738 // The resulting Health object is a result of comparisons between 739 // what is the actual composition of the kademlia in question (the receiver), and 740 // what SHOULD it have been when we take all we know about the network into consideration. 741 // 742 // used for testing only 743 func (k *Kademlia) Healthy(pp *PeerPot) *Health { 744 k.lock.RLock() 745 defer k.lock.RUnlock() 746 gotnn, countgotnn, culpritsgotnn := k.connectedNeighbours(pp.NNSet) 747 knownn, countknownn, culpritsknownn := k.knowNeighbours(pp.NNSet) 748 depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) 749 saturated := k.saturation() < depth 750 log.Trace(fmt.Sprintf("%08x: healthy: knowNNs: %v, gotNNs: %v, saturated: %v\n", k.base, knownn, gotnn, saturated)) 751 return &Health{ 752 KnowNN: knownn, 753 CountKnowNN: countknownn, 754 MissingKnowNN: culpritsknownn, 755 ConnectNN: gotnn, 756 CountConnectNN: countgotnn, 757 MissingConnectNN: culpritsgotnn, 758 Saturated: saturated, 759 Hive: k.string(), 760 } 761 }