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