github.com/letterj/go-ethereum@v1.8.22-0.20190204142846-520024dfd689/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 sv "github.com/ethereum/go-ethereum/swarm/version" 31 ) 32 33 /* 34 35 Taking the proximity order relative to a fix point x classifies the points in 36 the space (n byte long byte sequences) into bins. Items in each are at 37 most half as distant from x as items in the previous bin. Given a sample of 38 uniformly distributed items (a hash function over arbitrary sequence) the 39 proximity scale maps onto series of subsets with cardinalities on a negative 40 exponential scale. 41 42 It also has the property that any two item belonging to the same bin are at 43 most half as distant from each other as they are from x. 44 45 If we think of random sample of items in the bins as connections in a network of 46 interconnected nodes then relative proximity can serve as the basis for local 47 decisions for graph traversal where the task is to find a route between two 48 points. Since in every hop, the finite distance halves, there is 49 a guaranteed constant maximum limit on the number of hops needed to reach one 50 node from the other. 51 */ 52 53 var Pof = pot.DefaultPof(256) 54 55 // KadParams holds the config params for Kademlia 56 type KadParams struct { 57 // adjustable parameters 58 MaxProxDisplay int // number of rows the table shows 59 NeighbourhoodSize int // nearest neighbour core minimum cardinality 60 MinBinSize int // minimum number of peers in a row 61 MaxBinSize int // maximum number of peers in a row before pruning 62 RetryInterval int64 // initial interval before a peer is first redialed 63 RetryExponent int // exponent to multiply retry intervals with 64 MaxRetries int // maximum number of redial attempts 65 // function to sanction or prevent suggesting a peer 66 Reachable func(*BzzAddr) bool `json:"-"` 67 } 68 69 // NewKadParams returns a params struct with default values 70 func NewKadParams() *KadParams { 71 return &KadParams{ 72 MaxProxDisplay: 16, 73 NeighbourhoodSize: 2, 74 MinBinSize: 2, 75 MaxBinSize: 4, 76 RetryInterval: 4200000000, // 4.2 sec 77 MaxRetries: 42, 78 RetryExponent: 2, 79 } 80 } 81 82 // Kademlia is a table of live peers and a db of known peers (node records) 83 type Kademlia struct { 84 lock sync.RWMutex 85 *KadParams // Kademlia configuration parameters 86 base []byte // immutable baseaddress of the table 87 addrs *pot.Pot // pots container for known peer addresses 88 conns *pot.Pot // pots container for live peer connections 89 depth uint8 // stores the last current depth of saturation 90 nDepth int // stores the last neighbourhood depth 91 nDepthC chan int // returned by DepthC function to signal neighbourhood depth change 92 addrCountC chan int // returned by AddrCountC function to signal peer count change 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 } 108 } 109 110 // entry represents a Kademlia table entry (an extension of BzzAddr) 111 type entry struct { 112 *BzzAddr 113 conn *Peer 114 seenAt time.Time 115 retries int 116 } 117 118 // newEntry creates a kademlia peer from a *Peer 119 func newEntry(p *BzzAddr) *entry { 120 return &entry{ 121 BzzAddr: p, 122 seenAt: time.Now(), 123 } 124 } 125 126 // Label is a short tag for the entry for debug 127 func Label(e *entry) string { 128 return fmt.Sprintf("%s (%d)", e.Hex()[:4], e.retries) 129 } 130 131 // Hex is the hexadecimal serialisation of the entry address 132 func (e *entry) Hex() string { 133 return fmt.Sprintf("%x", e.Address()) 134 } 135 136 // Register enters each address as kademlia peer record into the 137 // database of known peer addresses 138 func (k *Kademlia) Register(peers ...*BzzAddr) error { 139 k.lock.Lock() 140 defer k.lock.Unlock() 141 var known, size int 142 for _, p := range peers { 143 // error if self received, peer should know better 144 // and should be punished for this 145 if bytes.Equal(p.Address(), k.base) { 146 return fmt.Errorf("add peers: %x is self", k.base) 147 } 148 var found bool 149 k.addrs, _, found, _ = pot.Swap(k.addrs, p, Pof, func(v pot.Val) pot.Val { 150 // if not found 151 if v == nil { 152 // insert new offline peer into conns 153 return newEntry(p) 154 } 155 // found among known peers, do nothing 156 return v 157 }) 158 if found { 159 known++ 160 } 161 size++ 162 } 163 // send new address count value only if there are new addresses 164 if k.addrCountC != nil && size-known > 0 { 165 k.addrCountC <- k.addrs.Size() 166 } 167 168 k.sendNeighbourhoodDepthChange() 169 return nil 170 } 171 172 // SuggestPeer returns an unconnected peer address as a peer suggestion for connection 173 func (k *Kademlia) SuggestPeer() (suggestedPeer *BzzAddr, saturationDepth int, changed bool) { 174 k.lock.Lock() 175 defer k.lock.Unlock() 176 radius := neighbourhoodRadiusForPot(k.conns, k.NeighbourhoodSize, k.base) 177 // collect undersaturated bins in ascending order of number of connected peers 178 // and from shallow to deep (ascending order of PO) 179 // insert them in a map of bin arrays, keyed with the number of connected peers 180 saturation := make(map[int][]int) 181 var lastPO int // the last non-empty PO bin in the iteration 182 saturationDepth = -1 // the deepest PO such that all shallower bins have >= k.MinBinSize peers 183 var pastDepth bool // whether po of iteration >= depth 184 k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { 185 // process skipped empty bins 186 for ; lastPO < po; lastPO++ { 187 // find the lowest unsaturated bin 188 if saturationDepth == -1 { 189 saturationDepth = lastPO 190 } 191 // if there is an empty bin, depth is surely passed 192 pastDepth = true 193 saturation[0] = append(saturation[0], lastPO) 194 } 195 lastPO = po + 1 196 // past radius, depth is surely passed 197 if po >= radius { 198 pastDepth = true 199 } 200 // beyond depth the bin is treated as unsaturated even if size >= k.MinBinSize 201 // in order to achieve full connectivity to all neighbours 202 if pastDepth && size >= k.MinBinSize { 203 size = k.MinBinSize - 1 204 } 205 // process non-empty unsaturated bins 206 if size < k.MinBinSize { 207 // find the lowest unsaturated bin 208 if saturationDepth == -1 { 209 saturationDepth = po 210 } 211 saturation[size] = append(saturation[size], po) 212 } 213 return true 214 }) 215 // to trigger peer requests for peers closer than closest connection, include 216 // all bins from nearest connection upto nearest address as unsaturated 217 var nearestAddrAt int 218 k.addrs.EachNeighbour(k.base, Pof, func(_ pot.Val, po int) bool { 219 nearestAddrAt = po 220 return false 221 }) 222 // including bins as size 0 has the effect that requesting connection 223 // is prioritised over non-empty shallower bins 224 for ; lastPO <= nearestAddrAt; lastPO++ { 225 saturation[0] = append(saturation[0], lastPO) 226 } 227 // all PO bins are saturated, ie., minsize >= k.MinBinSize, no peer suggested 228 if len(saturation) == 0 { 229 return nil, 0, false 230 } 231 // find the first callable peer in the address book 232 // starting from the bins with smallest size proceeding from shallow to deep 233 // for each bin (up until neighbourhood radius) we find callable candidate peers 234 for size := 0; size < k.MinBinSize && suggestedPeer == nil; size++ { 235 bins, ok := saturation[size] 236 if !ok { 237 // no bin with this size 238 continue 239 } 240 cur := 0 241 curPO := bins[0] 242 k.addrs.EachBin(k.base, Pof, curPO, func(po, _ int, f func(func(pot.Val) bool) bool) bool { 243 curPO = bins[cur] 244 // find the next bin that has size size 245 if curPO == po { 246 cur++ 247 } else { 248 // skip bins that have no addresses 249 for ; cur < len(bins) && curPO < po; cur++ { 250 curPO = bins[cur] 251 } 252 if po < curPO { 253 cur-- 254 return true 255 } 256 // stop if there are no addresses 257 if curPO < po { 258 return false 259 } 260 } 261 // curPO found 262 // find a callable peer out of the addresses in the unsaturated bin 263 // stop if found 264 f(func(val pot.Val) bool { 265 e := val.(*entry) 266 if k.callable(e) { 267 suggestedPeer = e.BzzAddr 268 return false 269 } 270 return true 271 }) 272 return cur < len(bins) && suggestedPeer == nil 273 }) 274 } 275 276 if uint8(saturationDepth) < k.depth { 277 k.depth = uint8(saturationDepth) 278 return suggestedPeer, saturationDepth, true 279 } 280 return suggestedPeer, 0, false 281 } 282 283 // On inserts the peer as a kademlia peer into the live peers 284 func (k *Kademlia) On(p *Peer) (uint8, bool) { 285 k.lock.Lock() 286 defer k.lock.Unlock() 287 var ins bool 288 k.conns, _, _, _ = pot.Swap(k.conns, p, Pof, func(v pot.Val) pot.Val { 289 // if not found live 290 if v == nil { 291 ins = true 292 // insert new online peer into conns 293 return p 294 } 295 // found among live peers, do nothing 296 return v 297 }) 298 if ins && !p.BzzPeer.LightNode { 299 a := newEntry(p.BzzAddr) 300 a.conn = p 301 // insert new online peer into addrs 302 k.addrs, _, _, _ = pot.Swap(k.addrs, p, Pof, func(v pot.Val) pot.Val { 303 return a 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()) 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 // TODO: Why is this exported, and if it should be; why can't we have more subscribers than one? 327 func (k *Kademlia) NeighbourhoodDepthC() <-chan int { 328 k.lock.Lock() 329 defer k.lock.Unlock() 330 if k.nDepthC == nil { 331 k.nDepthC = make(chan int) 332 } 333 return k.nDepthC 334 } 335 336 // sendNeighbourhoodDepthChange sends new neighbourhood depth to k.nDepth channel 337 // if it is initialized. 338 func (k *Kademlia) sendNeighbourhoodDepthChange() { 339 // nDepthC is initialized when NeighbourhoodDepthC is called and returned by it. 340 // It provides signaling of neighbourhood depth change. 341 // This part of the code is sending new neighbourhood depth to nDepthC if that condition is met. 342 if k.nDepthC != nil { 343 nDepth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) 344 if nDepth != k.nDepth { 345 k.nDepth = nDepth 346 k.nDepthC <- nDepth 347 } 348 } 349 } 350 351 // AddrCountC returns the channel that sends a new 352 // address count value on each change. 353 // Not receiving from the returned channel will block Register function 354 // when address count value changes. 355 func (k *Kademlia) AddrCountC() <-chan int { 356 if k.addrCountC == nil { 357 k.addrCountC = make(chan int) 358 } 359 return k.addrCountC 360 } 361 362 // Off removes a peer from among live peers 363 func (k *Kademlia) Off(p *Peer) { 364 k.lock.Lock() 365 defer k.lock.Unlock() 366 var del bool 367 if !p.BzzPeer.LightNode { 368 k.addrs, _, _, _ = pot.Swap(k.addrs, p, Pof, func(v pot.Val) pot.Val { 369 // v cannot be nil, must check otherwise we overwrite entry 370 if v == nil { 371 panic(fmt.Sprintf("connected peer not found %v", p)) 372 } 373 del = true 374 return newEntry(p.BzzAddr) 375 }) 376 } else { 377 del = true 378 } 379 380 if del { 381 k.conns, _, _, _ = pot.Swap(k.conns, p, Pof, func(_ pot.Val) pot.Val { 382 // v cannot be nil, but no need to check 383 return nil 384 }) 385 // send new address count value only if the peer is deleted 386 if k.addrCountC != nil { 387 k.addrCountC <- k.addrs.Size() 388 } 389 k.sendNeighbourhoodDepthChange() 390 } 391 } 392 393 // EachConn is an iterator with args (base, po, f) applies f to each live peer 394 // that has proximity order po or less as measured from the base 395 // if base is nil, kademlia base address is used 396 func (k *Kademlia) EachConn(base []byte, o int, f func(*Peer, int) bool) { 397 k.lock.RLock() 398 defer k.lock.RUnlock() 399 k.eachConn(base, o, f) 400 } 401 402 func (k *Kademlia) eachConn(base []byte, o int, f func(*Peer, int) bool) { 403 if len(base) == 0 { 404 base = k.base 405 } 406 k.conns.EachNeighbour(base, Pof, func(val pot.Val, po int) bool { 407 if po > o { 408 return true 409 } 410 return f(val.(*Peer), po) 411 }) 412 } 413 414 // EachAddr called with (base, po, f) is an iterator applying f to each known peer 415 // that has proximity order o or less as measured from the base 416 // if base is nil, kademlia base address is used 417 func (k *Kademlia) EachAddr(base []byte, o int, f func(*BzzAddr, int) bool) { 418 k.lock.RLock() 419 defer k.lock.RUnlock() 420 k.eachAddr(base, o, f) 421 } 422 423 func (k *Kademlia) eachAddr(base []byte, o int, f func(*BzzAddr, int) bool) { 424 if len(base) == 0 { 425 base = k.base 426 } 427 k.addrs.EachNeighbour(base, Pof, func(val pot.Val, po int) bool { 428 if po > o { 429 return true 430 } 431 return f(val.(*entry).BzzAddr, po) 432 }) 433 } 434 435 // NeighbourhoodDepth returns the depth for the pot, see depthForPot 436 func (k *Kademlia) NeighbourhoodDepth() (depth int) { 437 k.lock.RLock() 438 defer k.lock.RUnlock() 439 return depthForPot(k.conns, k.NeighbourhoodSize, k.base) 440 } 441 442 // neighbourhoodRadiusForPot returns the neighbourhood radius of the kademlia 443 // neighbourhood radius encloses the nearest neighbour set with size >= neighbourhoodSize 444 // i.e., neighbourhood radius is the deepest PO such that all bins not shallower altogether 445 // contain at least neighbourhoodSize connected peers 446 // if there is altogether less than neighbourhoodSize peers connected, it returns 0 447 // caller must hold the lock 448 func neighbourhoodRadiusForPot(p *pot.Pot, neighbourhoodSize int, pivotAddr []byte) (depth int) { 449 if p.Size() <= neighbourhoodSize { 450 return 0 451 } 452 // total number of peers in iteration 453 var size int 454 f := func(v pot.Val, i int) bool { 455 // po == 256 means that addr is the pivot address(self) 456 if i == 256 { 457 return true 458 } 459 size++ 460 461 // this means we have all nn-peers. 462 // depth is by default set to the bin of the farthest nn-peer 463 if size == neighbourhoodSize { 464 depth = i 465 return false 466 } 467 468 return true 469 } 470 p.EachNeighbour(pivotAddr, Pof, f) 471 return depth 472 } 473 474 // depthForPot returns the depth for the pot 475 // depth is the radius of the minimal extension of nearest neighbourhood that 476 // includes all empty PO bins. I.e., depth is the deepest PO such that 477 // - it is not deeper than neighbourhood radius 478 // - all bins shallower than depth are not empty 479 // caller must hold the lock 480 func depthForPot(p *pot.Pot, neighbourhoodSize int, pivotAddr []byte) (depth int) { 481 if p.Size() <= neighbourhoodSize { 482 return 0 483 } 484 // determining the depth is a two-step process 485 // first we find the proximity bin of the shallowest of the neighbourhoodSize peers 486 // the numeric value of depth cannot be higher than this 487 maxDepth := neighbourhoodRadiusForPot(p, neighbourhoodSize, pivotAddr) 488 489 // the second step is to test for empty bins in order from shallowest to deepest 490 // if an empty bin is found, this will be the actual depth 491 // we stop iterating if we hit the maxDepth determined in the first step 492 p.EachBin(pivotAddr, Pof, 0, func(po int, _ int, f func(func(pot.Val) bool) bool) bool { 493 if po == depth { 494 if maxDepth == depth { 495 return false 496 } 497 depth++ 498 return true 499 } 500 return false 501 }) 502 503 return depth 504 } 505 506 // callable decides if an address entry represents a callable peer 507 func (k *Kademlia) callable(e *entry) bool { 508 // not callable if peer is live or exceeded maxRetries 509 if e.conn != nil || e.retries > k.MaxRetries { 510 return false 511 } 512 // calculate the allowed number of retries based on time lapsed since last seen 513 timeAgo := int64(time.Since(e.seenAt)) 514 div := int64(k.RetryExponent) 515 div += (150000 - rand.Int63n(300000)) * div / 1000000 516 var retries int 517 for delta := timeAgo; delta > k.RetryInterval; delta /= div { 518 retries++ 519 } 520 // this is never called concurrently, so safe to increment 521 // peer can be retried again 522 if retries < e.retries { 523 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)) 524 return false 525 } 526 // function to sanction or prevent suggesting a peer 527 if k.Reachable != nil && !k.Reachable(e.BzzAddr) { 528 log.Trace(fmt.Sprintf("%08x: peer %v is temporarily not callable", k.BaseAddr()[:4], e)) 529 return false 530 } 531 e.retries++ 532 log.Trace(fmt.Sprintf("%08x: peer %v is callable", k.BaseAddr()[:4], e)) 533 534 return true 535 } 536 537 // BaseAddr return the kademlia base address 538 func (k *Kademlia) BaseAddr() []byte { 539 return k.base 540 } 541 542 // String returns kademlia table + kaddb table displayed with ascii 543 func (k *Kademlia) String() string { 544 k.lock.RLock() 545 defer k.lock.RUnlock() 546 return k.string() 547 } 548 549 // string returns kademlia table + kaddb table displayed with ascii 550 // caller must hold the lock 551 func (k *Kademlia) string() string { 552 wsrow := " " 553 var rows []string 554 555 rows = append(rows, "=========================================================================") 556 if len(sv.GitCommit) > 0 { 557 rows = append(rows, fmt.Sprintf("commit hash: %s", sv.GitCommit)) 558 } 559 rows = append(rows, fmt.Sprintf("%v KΛÐΞMLIΛ hive: queen's address: %x", time.Now().UTC().Format(time.UnixDate), k.BaseAddr()[:3])) 560 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)) 561 562 liverows := make([]string, k.MaxProxDisplay) 563 peersrows := make([]string, k.MaxProxDisplay) 564 565 depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) 566 rest := k.conns.Size() 567 k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { 568 var rowlen int 569 if po >= k.MaxProxDisplay { 570 po = k.MaxProxDisplay - 1 571 } 572 row := []string{fmt.Sprintf("%2d", size)} 573 rest -= size 574 f(func(val pot.Val) bool { 575 e := val.(*Peer) 576 row = append(row, fmt.Sprintf("%x", e.Address()[:2])) 577 rowlen++ 578 return rowlen < 4 579 }) 580 r := strings.Join(row, " ") 581 r = r + wsrow 582 liverows[po] = r[:31] 583 return true 584 }) 585 586 k.addrs.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { 587 var rowlen int 588 if po >= k.MaxProxDisplay { 589 po = k.MaxProxDisplay - 1 590 } 591 if size < 0 { 592 panic("wtf") 593 } 594 row := []string{fmt.Sprintf("%2d", size)} 595 // we are displaying live peers too 596 f(func(val pot.Val) bool { 597 e := val.(*entry) 598 row = append(row, Label(e)) 599 rowlen++ 600 return rowlen < 4 601 }) 602 peersrows[po] = strings.Join(row, " ") 603 return true 604 }) 605 606 for i := 0; i < k.MaxProxDisplay; i++ { 607 if i == depth { 608 rows = append(rows, fmt.Sprintf("============ DEPTH: %d ==========================================", i)) 609 } 610 left := liverows[i] 611 right := peersrows[i] 612 if len(left) == 0 { 613 left = " 0 " 614 } 615 if len(right) == 0 { 616 right = " 0" 617 } 618 rows = append(rows, fmt.Sprintf("%03d %v | %v", i, left, right)) 619 } 620 rows = append(rows, "=========================================================================") 621 return "\n" + strings.Join(rows, "\n") 622 } 623 624 // PeerPot keeps info about expected nearest neighbours 625 // used for testing only 626 // TODO move to separate testing tools file 627 type PeerPot struct { 628 NNSet [][]byte 629 } 630 631 // NewPeerPotMap creates a map of pot record of *BzzAddr with keys 632 // as hexadecimal representations of the address. 633 // the NeighbourhoodSize of the passed kademlia is used 634 // used for testing only 635 // TODO move to separate testing tools file 636 func NewPeerPotMap(neighbourhoodSize int, addrs [][]byte) map[string]*PeerPot { 637 638 // create a table of all nodes for health check 639 np := pot.NewPot(nil, 0) 640 for _, addr := range addrs { 641 np, _, _ = pot.Add(np, addr, Pof) 642 } 643 ppmap := make(map[string]*PeerPot) 644 645 // generate an allknowing source of truth for connections 646 // for every kademlia passed 647 for i, a := range addrs { 648 649 // actual kademlia depth 650 depth := depthForPot(np, neighbourhoodSize, a) 651 652 // all nn-peers 653 var nns [][]byte 654 655 // iterate through the neighbours, going from the deepest to the shallowest 656 np.EachNeighbour(a, Pof, func(val pot.Val, po int) bool { 657 addr := val.([]byte) 658 // po == 256 means that addr is the pivot address(self) 659 // we do not include self in the map 660 if po == 256 { 661 return true 662 } 663 // append any neighbors found 664 // a neighbor is any peer in or deeper than the depth 665 if po >= depth { 666 nns = append(nns, addr) 667 return true 668 } 669 return false 670 }) 671 672 log.Trace(fmt.Sprintf("%x PeerPotMap NNS: %s", addrs[i][:4], LogAddrs(nns))) 673 ppmap[common.Bytes2Hex(a)] = &PeerPot{ 674 NNSet: nns, 675 } 676 } 677 return ppmap 678 } 679 680 // saturation returns the smallest po value in which the node has less than MinBinSize peers 681 // if the iterator reaches neighbourhood radius, then the last bin + 1 is returned 682 func (k *Kademlia) saturation() int { 683 prev := -1 684 radius := neighbourhoodRadiusForPot(k.conns, k.NeighbourhoodSize, k.base) 685 k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { 686 prev++ 687 if po >= radius { 688 return false 689 } 690 return prev == po && size >= k.MinBinSize 691 }) 692 if prev < 0 { 693 return 0 694 } 695 return prev 696 } 697 698 // knowNeighbours tests if all neighbours in the peerpot 699 // are found among the peers known to the kademlia 700 // It is used in Healthy function for testing only 701 // TODO move to separate testing tools file 702 func (k *Kademlia) knowNeighbours(addrs [][]byte) (got bool, n int, missing [][]byte) { 703 pm := make(map[string]bool) 704 depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) 705 // create a map with all peers at depth and deeper known in the kademlia 706 k.eachAddr(nil, 255, func(p *BzzAddr, po int) bool { 707 // in order deepest to shallowest compared to the kademlia base address 708 // all bins (except self) are included (0 <= bin <= 255) 709 if po < depth { 710 return false 711 } 712 pk := common.Bytes2Hex(p.Address()) 713 pm[pk] = true 714 return true 715 }) 716 717 // iterate through nearest neighbors in the peerpot map 718 // if we can't find the neighbor in the map we created above 719 // then we don't know all our neighbors 720 // (which sadly is all too common in modern society) 721 var gots int 722 var culprits [][]byte 723 for _, p := range addrs { 724 pk := common.Bytes2Hex(p) 725 if pm[pk] { 726 gots++ 727 } else { 728 log.Trace(fmt.Sprintf("%08x: known nearest neighbour %s not found", k.base, pk)) 729 culprits = append(culprits, p) 730 } 731 } 732 return gots == len(addrs), gots, culprits 733 } 734 735 // connectedNeighbours tests if all neighbours in the peerpot 736 // are currently connected in the kademlia 737 // It is used in Healthy function for testing only 738 func (k *Kademlia) connectedNeighbours(peers [][]byte) (got bool, n int, missing [][]byte) { 739 pm := make(map[string]bool) 740 741 // create a map with all peers at depth and deeper that are connected in the kademlia 742 // in order deepest to shallowest compared to the kademlia base address 743 // all bins (except self) are included (0 <= bin <= 255) 744 depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) 745 k.eachConn(nil, 255, func(p *Peer, po int) bool { 746 if po < depth { 747 return false 748 } 749 pk := common.Bytes2Hex(p.Address()) 750 pm[pk] = true 751 return true 752 }) 753 754 // iterate through nearest neighbors in the peerpot map 755 // if we can't find the neighbor in the map we created above 756 // then we don't know all our neighbors 757 var gots int 758 var culprits [][]byte 759 for _, p := range peers { 760 pk := common.Bytes2Hex(p) 761 if pm[pk] { 762 gots++ 763 } else { 764 log.Trace(fmt.Sprintf("%08x: ExpNN: %s not found", k.base, pk)) 765 culprits = append(culprits, p) 766 } 767 } 768 return gots == len(peers), gots, culprits 769 } 770 771 // Health state of the Kademlia 772 // used for testing only 773 type Health struct { 774 KnowNN bool // whether node knows all its neighbours 775 CountKnowNN int // amount of neighbors known 776 MissingKnowNN [][]byte // which neighbours we should have known but we don't 777 ConnectNN bool // whether node is connected to all its neighbours 778 CountConnectNN int // amount of neighbours connected to 779 MissingConnectNN [][]byte // which neighbours we should have been connected to but we're not 780 Saturated bool // whether we are connected to all the peers we would have liked to 781 Hive string 782 } 783 784 // Healthy reports the health state of the kademlia connectivity 785 // 786 // The PeerPot argument provides an all-knowing view of the network 787 // The resulting Health object is a result of comparisons between 788 // what is the actual composition of the kademlia in question (the receiver), and 789 // what SHOULD it have been when we take all we know about the network into consideration. 790 // 791 // used for testing only 792 func (k *Kademlia) Healthy(pp *PeerPot) *Health { 793 k.lock.RLock() 794 defer k.lock.RUnlock() 795 if len(pp.NNSet) < k.NeighbourhoodSize { 796 log.Warn("peerpot NNSet < NeighbourhoodSize") 797 } 798 gotnn, countgotnn, culpritsgotnn := k.connectedNeighbours(pp.NNSet) 799 knownn, countknownn, culpritsknownn := k.knowNeighbours(pp.NNSet) 800 depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) 801 saturated := k.saturation() < depth 802 log.Trace(fmt.Sprintf("%08x: healthy: knowNNs: %v, gotNNs: %v, saturated: %v\n", k.base, knownn, gotnn, saturated)) 803 return &Health{ 804 KnowNN: knownn, 805 CountKnowNN: countknownn, 806 MissingKnowNN: culpritsknownn, 807 ConnectNN: gotnn, 808 CountConnectNN: countgotnn, 809 MissingConnectNN: culpritsgotnn, 810 Saturated: saturated, 811 Hive: k.string(), 812 } 813 }