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