github.com/aaa256/atlantis@v0.0.0-20210707112435-42ee889287a2/swarm/network/kademlia.go (about) 1 // Copyright 2017 The go-athereum Authors 2 // This file is part of the go-athereum library. 3 // 4 // The go-athereum 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-athereum 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-athereum 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/athereum/go-athereum/common" 28 "github.com/athereum/go-athereum/swarm/log" 29 "github.com/athereum/go-athereum/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(OverlayAddr) 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 // OverlayPeer interface captures the common aspect of view of a peer from the Overlay 110 // topology driver 111 type OverlayPeer interface { 112 Address() []byte 113 } 114 115 // OverlayConn represents a connected peer 116 type OverlayConn interface { 117 OverlayPeer 118 Drop(error) // call to indicate a peer should be expunged 119 Off() OverlayAddr // call to return a persitent OverlayAddr 120 } 121 122 // OverlayAddr represents a kademlia peer record 123 type OverlayAddr interface { 124 OverlayPeer 125 Update(OverlayAddr) OverlayAddr // returns the updated version of the original 126 } 127 128 // entry represents a Kademlia table entry (an extension of OverlayPeer) 129 type entry struct { 130 OverlayPeer 131 seenAt time.Time 132 retries int 133 } 134 135 // newEntry creates a kademlia peer from an OverlayPeer interface 136 func newEntry(p OverlayPeer) *entry { 137 return &entry{ 138 OverlayPeer: p, 139 seenAt: time.Now(), 140 } 141 } 142 143 // Bin is the binary (bitvector) serialisation of the entry address 144 func (e *entry) Bin() string { 145 return pot.ToBin(e.addr().Address()) 146 } 147 148 // Label is a short tag for the entry for debug 149 func Label(e *entry) string { 150 return fmt.Sprintf("%s (%d)", e.Hex()[:4], e.retries) 151 } 152 153 // Hex is the hexadecimal serialisation of the entry address 154 func (e *entry) Hex() string { 155 return fmt.Sprintf("%x", e.addr().Address()) 156 } 157 158 // String is the short tag for the entry 159 func (e *entry) String() string { 160 return fmt.Sprintf("%s (%d)", e.Hex()[:8], e.retries) 161 } 162 163 // addr returns the kad peer record (OverlayAddr) corresponding to the entry 164 func (e *entry) addr() OverlayAddr { 165 a, _ := e.OverlayPeer.(OverlayAddr) 166 return a 167 } 168 169 // conn returns the connected peer (OverlayPeer) corresponding to the entry 170 func (e *entry) conn() OverlayConn { 171 c, _ := e.OverlayPeer.(OverlayConn) 172 return c 173 } 174 175 // Register enters each OverlayAddr as kademlia peer record into the 176 // database of known peer addresses 177 func (k *Kademlia) Register(peers []OverlayAddr) error { 178 k.lock.Lock() 179 defer k.lock.Unlock() 180 var known, size int 181 for _, p := range peers { 182 // error if self received, peer should know better 183 // and should be punished for this 184 if bytes.Equal(p.Address(), k.base) { 185 return fmt.Errorf("add peers: %x is self", k.base) 186 } 187 var found bool 188 k.addrs, _, found, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val { 189 // if not found 190 if v == nil { 191 // insert new offline peer into conns 192 return newEntry(p) 193 } 194 // found among known peers, do nothing 195 return v 196 }) 197 if found { 198 known++ 199 } 200 size++ 201 } 202 // send new address count value only if there are new addresses 203 if k.addrCountC != nil && size-known > 0 { 204 k.addrCountC <- k.addrs.Size() 205 } 206 // log.Trace(fmt.Sprintf("%x registered %v peers, %v known, total: %v", k.BaseAddr()[:4], size, known, k.addrs.Size())) 207 208 k.sendNeighbourhoodDepthChange() 209 return nil 210 } 211 212 // SuggestPeer returns a known peer for the lowest proximity bin for the 213 // lowest bincount below depth 214 // naturally if there is an empty row it returns a peer for that 215 func (k *Kademlia) SuggestPeer() (a OverlayAddr, o int, want bool) { 216 k.lock.Lock() 217 defer k.lock.Unlock() 218 minsize := k.MinBinSize 219 depth := k.neighbourhoodDepth() 220 // if there is a callable neighbour within the current proxBin, connect 221 // this makes sure nearest neighbour set is fully connected 222 var ppo int 223 k.addrs.EachNeighbour(k.base, pof, func(val pot.Val, po int) bool { 224 if po < depth { 225 return false 226 } 227 a = k.callable(val) 228 ppo = po 229 return a == nil 230 }) 231 if a != nil { 232 log.Trace(fmt.Sprintf("%08x candidate nearest neighbour found: %v (%v)", k.BaseAddr()[:4], a, ppo)) 233 return a, 0, false 234 } 235 // log.Trace(fmt.Sprintf("%08x no candidate nearest neighbours to connect to (Depth: %v, minProxSize: %v) %#v", k.BaseAddr()[:4], depth, k.MinProxBinSize, a)) 236 237 var bpo []int 238 prev := -1 239 k.conns.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool { 240 prev++ 241 for ; prev < po; prev++ { 242 bpo = append(bpo, prev) 243 minsize = 0 244 } 245 if size < minsize { 246 bpo = append(bpo, po) 247 minsize = size 248 } 249 return size > 0 && po < depth 250 }) 251 // all buckets are full, ie., minsize == k.MinBinSize 252 if len(bpo) == 0 { 253 // log.Debug(fmt.Sprintf("%08x: all bins saturated", k.BaseAddr()[:4])) 254 return nil, 0, false 255 } 256 // as long as we got candidate peers to connect to 257 // dont ask for new peers (want = false) 258 // try to select a candidate peer 259 // find the first callable peer 260 nxt := bpo[0] 261 k.addrs.EachBin(k.base, pof, nxt, func(po, _ int, f func(func(pot.Val, int) bool) bool) bool { 262 // for each bin (up until depth) we find callable candidate peers 263 if po >= depth { 264 return false 265 } 266 return f(func(val pot.Val, _ int) bool { 267 a = k.callable(val) 268 return a == nil 269 }) 270 }) 271 // found a candidate 272 if a != nil { 273 return a, 0, false 274 } 275 // no candidate peer found, request for the short bin 276 var changed bool 277 if uint8(nxt) < k.depth { 278 k.depth = uint8(nxt) 279 changed = true 280 } 281 return a, nxt, changed 282 } 283 284 // On inserts the peer as a kademlia peer into the live peers 285 func (k *Kademlia) On(p OverlayConn) (uint8, bool) { 286 k.lock.Lock() 287 defer k.lock.Unlock() 288 e := newEntry(p) 289 var ins bool 290 k.conns, _, _, _ = pot.Swap(k.conns, p, pof, func(v pot.Val) pot.Val { 291 // if not found live 292 if v == nil { 293 ins = true 294 // insert new online peer into conns 295 return e 296 } 297 // found among live peers, do nothing 298 return v 299 }) 300 if ins { 301 // insert new online peer into addrs 302 k.addrs, _, _, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val { 303 return e 304 }) 305 // send new address count value only if the peer is inserted 306 if k.addrCountC != nil { 307 k.addrCountC <- k.addrs.Size() 308 } 309 } 310 log.Trace(k.string()) 311 // calculate if depth of saturation changed 312 depth := uint8(k.saturation(k.MinBinSize)) 313 var changed bool 314 if depth != k.depth { 315 changed = true 316 k.depth = depth 317 } 318 k.sendNeighbourhoodDepthChange() 319 return k.depth, changed 320 } 321 322 // NeighbourhoodDepthC returns the channel that sends a new kademlia 323 // neighbourhood depth on each change. 324 // Not receiving from the returned channel will block On function 325 // when the neighbourhood depth is changed. 326 func (k *Kademlia) NeighbourhoodDepthC() <-chan int { 327 if k.nDepthC == nil { 328 k.nDepthC = make(chan int) 329 } 330 return k.nDepthC 331 } 332 333 // sendNeighbourhoodDepthChange sends new neighbourhood depth to k.nDepth channel 334 // if it is initialized. 335 func (k *Kademlia) sendNeighbourhoodDepthChange() { 336 // nDepthC is initialized when NeighbourhoodDepthC is called and returned by it. 337 // It provides signaling of neighbourhood depth change. 338 // This part of the code is sending new neighbourhood depth to nDepthC if that condition is met. 339 if k.nDepthC != nil { 340 nDepth := k.neighbourhoodDepth() 341 if nDepth != k.nDepth { 342 k.nDepth = nDepth 343 k.nDepthC <- nDepth 344 } 345 } 346 } 347 348 // AddrCountC returns the channel that sends a new 349 // address count value on each change. 350 // Not receiving from the returned channel will block Register function 351 // when address count value changes. 352 func (k *Kademlia) AddrCountC() <-chan int { 353 if k.addrCountC == nil { 354 k.addrCountC = make(chan int) 355 } 356 return k.addrCountC 357 } 358 359 // Off removes a peer from among live peers 360 func (k *Kademlia) Off(p OverlayConn) { 361 k.lock.Lock() 362 defer k.lock.Unlock() 363 var del bool 364 k.addrs, _, _, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val { 365 // v cannot be nil, must check otherwise we overwrite entry 366 if v == nil { 367 panic(fmt.Sprintf("connected peer not found %v", p)) 368 } 369 del = true 370 return newEntry(p.Off()) 371 }) 372 373 if del { 374 k.conns, _, _, _ = pot.Swap(k.conns, p, pof, func(_ pot.Val) pot.Val { 375 // v cannot be nil, but no need to check 376 return nil 377 }) 378 // send new address count value only if the peer is deleted 379 if k.addrCountC != nil { 380 k.addrCountC <- k.addrs.Size() 381 } 382 k.sendNeighbourhoodDepthChange() 383 } 384 } 385 386 func (k *Kademlia) EachBin(base []byte, pof pot.Pof, o int, eachBinFunc func(conn OverlayConn, po int) bool) { 387 k.lock.RLock() 388 defer k.lock.RUnlock() 389 390 var startPo int 391 var endPo int 392 kadDepth := k.neighbourhoodDepth() 393 394 k.conns.EachBin(base, pof, o, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool { 395 if startPo > 0 && endPo != k.MaxProxDisplay { 396 startPo = endPo + 1 397 } 398 if po < kadDepth { 399 endPo = po 400 } else { 401 endPo = k.MaxProxDisplay 402 } 403 404 for bin := startPo; bin <= endPo; bin++ { 405 f(func(val pot.Val, _ int) bool { 406 return eachBinFunc(val.(*entry).conn(), bin) 407 }) 408 } 409 return true 410 }) 411 } 412 413 // EachConn is an iterator with args (base, po, f) applies f to each live peer 414 // that has proximity order po or less as measured from the base 415 // if base is nil, kademlia base address is used 416 func (k *Kademlia) EachConn(base []byte, o int, f func(OverlayConn, int, bool) bool) { 417 k.lock.RLock() 418 defer k.lock.RUnlock() 419 k.eachConn(base, o, f) 420 } 421 422 func (k *Kademlia) eachConn(base []byte, o int, f func(OverlayConn, int, bool) bool) { 423 if len(base) == 0 { 424 base = k.base 425 } 426 depth := k.neighbourhoodDepth() 427 k.conns.EachNeighbour(base, pof, func(val pot.Val, po int) bool { 428 if po > o { 429 return true 430 } 431 return f(val.(*entry).conn(), po, po >= depth) 432 }) 433 } 434 435 // EachAddr called with (base, po, f) is an iterator applying f to each known peer 436 // that has proximity order po or less as measured from the base 437 // if base is nil, kademlia base address is used 438 func (k *Kademlia) EachAddr(base []byte, o int, f func(OverlayAddr, int, bool) bool) { 439 k.lock.RLock() 440 defer k.lock.RUnlock() 441 k.eachAddr(base, o, f) 442 } 443 444 func (k *Kademlia) eachAddr(base []byte, o int, f func(OverlayAddr, int, bool) bool) { 445 if len(base) == 0 { 446 base = k.base 447 } 448 depth := k.neighbourhoodDepth() 449 k.addrs.EachNeighbour(base, pof, func(val pot.Val, po int) bool { 450 if po > o { 451 return true 452 } 453 return f(val.(*entry).addr(), po, po >= depth) 454 }) 455 } 456 457 // neighbourhoodDepth returns the proximity order that defines the distance of 458 // the nearest neighbour set with cardinality >= MinProxBinSize 459 // if there is altogather less than MinProxBinSize peers it returns 0 460 // caller must hold the lock 461 func (k *Kademlia) neighbourhoodDepth() (depth int) { 462 if k.conns.Size() < k.MinProxBinSize { 463 return 0 464 } 465 var size int 466 f := func(v pot.Val, i int) bool { 467 size++ 468 depth = i 469 return size < k.MinProxBinSize 470 } 471 k.conns.EachNeighbour(k.base, pof, f) 472 return depth 473 } 474 475 // callable when called with val, 476 func (k *Kademlia) callable(val pot.Val) OverlayAddr { 477 e := val.(*entry) 478 // not callable if peer is live or exceeded maxRetries 479 if e.conn() != nil || e.retries > k.MaxRetries { 480 return nil 481 } 482 // calculate the allowed number of retries based on time lapsed since last seen 483 timeAgo := int64(time.Since(e.seenAt)) 484 div := int64(k.RetryExponent) 485 div += (150000 - rand.Int63n(300000)) * div / 1000000 486 var retries int 487 for delta := timeAgo; delta > k.RetryInterval; delta /= div { 488 retries++ 489 } 490 // this is never called concurrently, so safe to increment 491 // peer can be retried again 492 if retries < e.retries { 493 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)) 494 return nil 495 } 496 // function to sanction or prevent suggesting a peer 497 if k.Reachable != nil && !k.Reachable(e.addr()) { 498 log.Trace(fmt.Sprintf("%08x: peer %v is temporarily not callable", k.BaseAddr()[:4], e)) 499 return nil 500 } 501 e.retries++ 502 log.Trace(fmt.Sprintf("%08x: peer %v is callable", k.BaseAddr()[:4], e)) 503 504 return e.addr() 505 } 506 507 // BaseAddr return the kademlia base address 508 func (k *Kademlia) BaseAddr() []byte { 509 return k.base 510 } 511 512 // String returns kademlia table + kaddb table displayed with ascii 513 func (k *Kademlia) String() string { 514 k.lock.RLock() 515 defer k.lock.RUnlock() 516 return k.string() 517 } 518 519 // String returns kademlia table + kaddb table displayed with ascii 520 func (k *Kademlia) string() string { 521 wsrow := " " 522 var rows []string 523 524 rows = append(rows, "=========================================================================") 525 rows = append(rows, fmt.Sprintf("%v KΛÐΞMLIΛ hive: queen's address: %x", time.Now().UTC().Format(time.UnixDate), k.BaseAddr()[:3])) 526 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)) 527 528 liverows := make([]string, k.MaxProxDisplay) 529 peersrows := make([]string, k.MaxProxDisplay) 530 531 depth := k.neighbourhoodDepth() 532 rest := k.conns.Size() 533 k.conns.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool { 534 var rowlen int 535 if po >= k.MaxProxDisplay { 536 po = k.MaxProxDisplay - 1 537 } 538 row := []string{fmt.Sprintf("%2d", size)} 539 rest -= size 540 f(func(val pot.Val, vpo int) bool { 541 e := val.(*entry) 542 row = append(row, fmt.Sprintf("%x", e.Address()[:2])) 543 rowlen++ 544 return rowlen < 4 545 }) 546 r := strings.Join(row, " ") 547 r = r + wsrow 548 liverows[po] = r[:31] 549 return true 550 }) 551 552 k.addrs.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool { 553 var rowlen int 554 if po >= k.MaxProxDisplay { 555 po = k.MaxProxDisplay - 1 556 } 557 if size < 0 { 558 panic("wtf") 559 } 560 row := []string{fmt.Sprintf("%2d", size)} 561 // we are displaying live peers too 562 f(func(val pot.Val, vpo int) bool { 563 e := val.(*entry) 564 row = append(row, Label(e)) 565 rowlen++ 566 return rowlen < 4 567 }) 568 peersrows[po] = strings.Join(row, " ") 569 return true 570 }) 571 572 for i := 0; i < k.MaxProxDisplay; i++ { 573 if i == depth { 574 rows = append(rows, fmt.Sprintf("============ DEPTH: %d ==========================================", i)) 575 } 576 left := liverows[i] 577 right := peersrows[i] 578 if len(left) == 0 { 579 left = " 0 " 580 } 581 if len(right) == 0 { 582 right = " 0" 583 } 584 rows = append(rows, fmt.Sprintf("%03d %v | %v", i, left, right)) 585 } 586 rows = append(rows, "=========================================================================") 587 return "\n" + strings.Join(rows, "\n") 588 } 589 590 // PeerPot keeps info about expected nearest neighbours and empty bins 591 // used for testing only 592 type PeerPot struct { 593 NNSet [][]byte 594 EmptyBins []int 595 } 596 597 // NewPeerPotMap creates a map of pot record of OverlayAddr with keys 598 // as hexadecimal representations of the address. 599 func NewPeerPotMap(kadMinProxSize int, addrs [][]byte) map[string]*PeerPot { 600 // create a table of all nodes for health check 601 np := pot.NewPot(nil, 0) 602 for _, addr := range addrs { 603 np, _, _ = pot.Add(np, addr, pof) 604 } 605 ppmap := make(map[string]*PeerPot) 606 607 for i, a := range addrs { 608 pl := 256 609 prev := 256 610 var emptyBins []int 611 var nns [][]byte 612 np.EachNeighbour(addrs[i], pof, func(val pot.Val, po int) bool { 613 a := val.([]byte) 614 if po == 256 { 615 return true 616 } 617 if pl == 256 || pl == po { 618 nns = append(nns, a) 619 } 620 if pl == 256 && len(nns) >= kadMinProxSize { 621 pl = po 622 prev = po 623 } 624 if prev < pl { 625 for j := prev; j > po; j-- { 626 emptyBins = append(emptyBins, j) 627 } 628 } 629 prev = po - 1 630 return true 631 }) 632 for j := prev; j >= 0; j-- { 633 emptyBins = append(emptyBins, j) 634 } 635 log.Trace(fmt.Sprintf("%x NNS: %s", addrs[i][:4], LogAddrs(nns))) 636 ppmap[common.Bytes2Hex(a)] = &PeerPot{nns, emptyBins} 637 } 638 return ppmap 639 } 640 641 // saturation returns the lowest proximity order that the bin for that order 642 // has less than n peers 643 func (k *Kademlia) saturation(n int) int { 644 prev := -1 645 k.addrs.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool { 646 prev++ 647 return prev == po && size >= n 648 }) 649 depth := k.neighbourhoodDepth() 650 if depth < prev { 651 return depth 652 } 653 return prev 654 } 655 656 // full returns true if all required bins have connected peers. 657 // It is used in Healthy function. 658 func (k *Kademlia) full(emptyBins []int) (full bool) { 659 prev := 0 660 e := len(emptyBins) 661 ok := true 662 depth := k.neighbourhoodDepth() 663 k.conns.EachBin(k.base, pof, 0, func(po, _ int, _ func(func(val pot.Val, i int) bool) bool) bool { 664 if prev == depth+1 { 665 return true 666 } 667 for i := prev; i < po; i++ { 668 e-- 669 if e < 0 { 670 ok = false 671 return false 672 } 673 if emptyBins[e] != i { 674 log.Trace(fmt.Sprintf("%08x po: %d, i: %d, e: %d, emptybins: %v", k.BaseAddr()[:4], po, i, e, logEmptyBins(emptyBins))) 675 if emptyBins[e] < i { 676 panic("incorrect peerpot") 677 } 678 ok = false 679 return false 680 } 681 } 682 prev = po + 1 683 return true 684 }) 685 if !ok { 686 return false 687 } 688 return e == 0 689 } 690 691 func (k *Kademlia) knowNearestNeighbours(peers [][]byte) bool { 692 pm := make(map[string]bool) 693 694 k.eachAddr(nil, 255, func(p OverlayAddr, po int, nn bool) bool { 695 if !nn { 696 return false 697 } 698 pk := fmt.Sprintf("%x", p.Address()) 699 pm[pk] = true 700 return true 701 }) 702 for _, p := range peers { 703 pk := fmt.Sprintf("%x", p) 704 if !pm[pk] { 705 log.Trace(fmt.Sprintf("%08x: known nearest neighbour %s not found", k.BaseAddr()[:4], pk[:8])) 706 return false 707 } 708 } 709 return true 710 } 711 712 func (k *Kademlia) gotNearestNeighbours(peers [][]byte) (got bool, n int, missing [][]byte) { 713 pm := make(map[string]bool) 714 715 k.eachConn(nil, 255, func(p OverlayConn, po int, nn bool) bool { 716 if !nn { 717 return false 718 } 719 pk := fmt.Sprintf("%x", p.Address()) 720 pm[pk] = true 721 return true 722 }) 723 var gots int 724 var culprits [][]byte 725 for _, p := range peers { 726 pk := fmt.Sprintf("%x", p) 727 if pm[pk] { 728 gots++ 729 } else { 730 log.Trace(fmt.Sprintf("%08x: ExpNN: %s not found", k.BaseAddr()[:4], pk[:8])) 731 culprits = append(culprits, p) 732 } 733 } 734 return gots == len(peers), gots, culprits 735 } 736 737 // Health state of the Kademlia 738 type Health struct { 739 KnowNN bool // whather node knows all its nearest neighbours 740 GotNN bool // whather node is connected to all its nearest neighbours 741 CountNN int // amount of nearest neighbors connected to 742 CulpritsNN [][]byte // which known NNs are missing 743 Full bool // whather node has a peer in each kademlia bin (where there is such a peer) 744 Hive string 745 } 746 747 // Healthy reports the health state of the kademlia connectivity 748 // returns a Health struct 749 func (k *Kademlia) Healthy(pp *PeerPot) *Health { 750 k.lock.RLock() 751 defer k.lock.RUnlock() 752 gotnn, countnn, culpritsnn := k.gotNearestNeighbours(pp.NNSet) 753 knownn := k.knowNearestNeighbours(pp.NNSet) 754 full := k.full(pp.EmptyBins) 755 log.Trace(fmt.Sprintf("%08x: healthy: knowNNs: %v, gotNNs: %v, full: %v\n", k.BaseAddr()[:4], knownn, gotnn, full)) 756 return &Health{knownn, gotnn, countnn, culpritsnn, full, k.string()} 757 } 758 759 func logEmptyBins(ebs []int) string { 760 var ebss []string 761 for _, eb := range ebs { 762 ebss = append(ebss, fmt.Sprintf("%d", eb)) 763 } 764 return strings.Join(ebss, ", ") 765 }