github.com/jincm/wesharechain@v0.0.0-20210122032815-1537409ce26a/chain/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 log.Trace("kademlia trying to register", "addr", p) 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 log.Trace("registering new peer", "addr", p) 154 // insert new offline peer into conns 155 return newEntry(p) 156 } 157 158 e := v.(*entry) 159 160 // if underlay address is different, still add 161 if !bytes.Equal(e.BzzAddr.UAddr, p.UAddr) { 162 log.Trace("underlay addr is different, so add again", "new", p, "old", e.BzzAddr) 163 // insert new offline peer into conns 164 return newEntry(p) 165 } 166 167 log.Trace("found among known peers, underlay addr is same, do nothing", "new", p, "old", e.BzzAddr) 168 169 return v 170 }) 171 if found { 172 known++ 173 } 174 size++ 175 } 176 // send new address count value only if there are new addresses 177 if k.addrCountC != nil && size-known > 0 { 178 k.addrCountC <- k.addrs.Size() 179 } 180 181 k.sendNeighbourhoodDepthChange() 182 return nil 183 } 184 185 // SuggestPeer returns an unconnected peer address as a peer suggestion for connection 186 func (k *Kademlia) SuggestPeer() (suggestedPeer *BzzAddr, saturationDepth int, changed bool) { 187 k.lock.Lock() 188 defer k.lock.Unlock() 189 radius := neighbourhoodRadiusForPot(k.conns, k.NeighbourhoodSize, k.base) 190 // collect undersaturated bins in ascending order of number of connected peers 191 // and from shallow to deep (ascending order of PO) 192 // insert them in a map of bin arrays, keyed with the number of connected peers 193 saturation := make(map[int][]int) 194 var lastPO int // the last non-empty PO bin in the iteration 195 saturationDepth = -1 // the deepest PO such that all shallower bins have >= k.MinBinSize peers 196 var pastDepth bool // whether po of iteration >= depth 197 k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { 198 // process skipped empty bins 199 for ; lastPO < po; lastPO++ { 200 // find the lowest unsaturated bin 201 if saturationDepth == -1 { 202 saturationDepth = lastPO 203 } 204 // if there is an empty bin, depth is surely passed 205 pastDepth = true 206 saturation[0] = append(saturation[0], lastPO) 207 } 208 lastPO = po + 1 209 // past radius, depth is surely passed 210 if po >= radius { 211 pastDepth = true 212 } 213 // beyond depth the bin is treated as unsaturated even if size >= k.MinBinSize 214 // in order to achieve full connectivity to all neighbours 215 if pastDepth && size >= k.MinBinSize { 216 size = k.MinBinSize - 1 217 } 218 // process non-empty unsaturated bins 219 if size < k.MinBinSize { 220 // find the lowest unsaturated bin 221 if saturationDepth == -1 { 222 saturationDepth = po 223 } 224 saturation[size] = append(saturation[size], po) 225 } 226 return true 227 }) 228 // to trigger peer requests for peers closer than closest connection, include 229 // all bins from nearest connection upto nearest address as unsaturated 230 var nearestAddrAt int 231 k.addrs.EachNeighbour(k.base, Pof, func(_ pot.Val, po int) bool { 232 nearestAddrAt = po 233 return false 234 }) 235 // including bins as size 0 has the effect that requesting connection 236 // is prioritised over non-empty shallower bins 237 for ; lastPO <= nearestAddrAt; lastPO++ { 238 saturation[0] = append(saturation[0], lastPO) 239 } 240 // all PO bins are saturated, ie., minsize >= k.MinBinSize, no peer suggested 241 if len(saturation) == 0 { 242 return nil, 0, false 243 } 244 // find the first callable peer in the address book 245 // starting from the bins with smallest size proceeding from shallow to deep 246 // for each bin (up until neighbourhood radius) we find callable candidate peers 247 for size := 0; size < k.MinBinSize && suggestedPeer == nil; size++ { 248 bins, ok := saturation[size] 249 if !ok { 250 // no bin with this size 251 continue 252 } 253 cur := 0 254 curPO := bins[0] 255 k.addrs.EachBin(k.base, Pof, curPO, func(po, _ int, f func(func(pot.Val) bool) bool) bool { 256 curPO = bins[cur] 257 // find the next bin that has size size 258 if curPO == po { 259 cur++ 260 } else { 261 // skip bins that have no addresses 262 for ; cur < len(bins) && curPO < po; cur++ { 263 curPO = bins[cur] 264 } 265 if po < curPO { 266 cur-- 267 return true 268 } 269 // stop if there are no addresses 270 if curPO < po { 271 return false 272 } 273 } 274 // curPO found 275 // find a callable peer out of the addresses in the unsaturated bin 276 // stop if found 277 f(func(val pot.Val) bool { 278 e := val.(*entry) 279 if k.callable(e) { 280 suggestedPeer = e.BzzAddr 281 return false 282 } 283 return true 284 }) 285 return cur < len(bins) && suggestedPeer == nil 286 }) 287 } 288 289 if uint8(saturationDepth) < k.depth { 290 k.depth = uint8(saturationDepth) 291 return suggestedPeer, saturationDepth, true 292 } 293 return suggestedPeer, 0, false 294 } 295 296 // On inserts the peer as a kademlia peer into the live peers 297 func (k *Kademlia) On(p *Peer) (uint8, bool) { 298 k.lock.Lock() 299 defer k.lock.Unlock() 300 var ins bool 301 k.conns, _, _, _ = pot.Swap(k.conns, p, Pof, func(v pot.Val) pot.Val { 302 // if not found live 303 if v == nil { 304 ins = true 305 // insert new online peer into conns 306 return p 307 } 308 // found among live peers, do nothing 309 return v 310 }) 311 if ins && !p.BzzPeer.LightNode { 312 a := newEntry(p.BzzAddr) 313 a.conn = p 314 // insert new online peer into addrs 315 k.addrs, _, _, _ = pot.Swap(k.addrs, p, Pof, func(v pot.Val) pot.Val { 316 return a 317 }) 318 // send new address count value only if the peer is inserted 319 if k.addrCountC != nil { 320 k.addrCountC <- k.addrs.Size() 321 } 322 } 323 log.Trace(k.string()) 324 // calculate if depth of saturation changed 325 depth := uint8(k.saturation()) 326 var changed bool 327 if depth != k.depth { 328 changed = true 329 k.depth = depth 330 } 331 k.sendNeighbourhoodDepthChange() 332 return k.depth, changed 333 } 334 335 // NeighbourhoodDepthC returns the channel that sends a new kademlia 336 // neighbourhood depth on each change. 337 // Not receiving from the returned channel will block On function 338 // when the neighbourhood depth is changed. 339 // TODO: Why is this exported, and if it should be; why can't we have more subscribers than one? 340 func (k *Kademlia) NeighbourhoodDepthC() <-chan int { 341 k.lock.Lock() 342 defer k.lock.Unlock() 343 if k.nDepthC == nil { 344 k.nDepthC = make(chan int) 345 } 346 return k.nDepthC 347 } 348 349 // CloseNeighbourhoodDepthC closes the channel returned by 350 // NeighbourhoodDepthC and stops sending neighbourhood change. 351 func (k *Kademlia) CloseNeighbourhoodDepthC() { 352 k.lock.Lock() 353 defer k.lock.Unlock() 354 355 if k.nDepthC != nil { 356 close(k.nDepthC) 357 k.nDepthC = nil 358 } 359 } 360 361 // sendNeighbourhoodDepthChange sends new neighbourhood depth to k.nDepth channel 362 // if it is initialized. 363 func (k *Kademlia) sendNeighbourhoodDepthChange() { 364 // nDepthC is initialized when NeighbourhoodDepthC is called and returned by it. 365 // It provides signaling of neighbourhood depth change. 366 // This part of the code is sending new neighbourhood depth to nDepthC if that condition is met. 367 if k.nDepthC != nil { 368 nDepth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) 369 if nDepth != k.nDepth { 370 k.nDepth = nDepth 371 k.nDepthC <- nDepth 372 } 373 } 374 } 375 376 // AddrCountC returns the channel that sends a new 377 // address count value on each change. 378 // Not receiving from the returned channel will block Register function 379 // when address count value changes. 380 func (k *Kademlia) AddrCountC() <-chan int { 381 k.lock.Lock() 382 defer k.lock.Unlock() 383 384 if k.addrCountC == nil { 385 k.addrCountC = make(chan int) 386 } 387 return k.addrCountC 388 } 389 390 // CloseAddrCountC closes the channel returned by 391 // AddrCountC and stops sending address count change. 392 func (k *Kademlia) CloseAddrCountC() { 393 k.lock.Lock() 394 defer k.lock.Unlock() 395 396 if k.addrCountC != nil { 397 close(k.addrCountC) 398 k.addrCountC = nil 399 } 400 } 401 402 // Off removes a peer from among live peers 403 func (k *Kademlia) Off(p *Peer) { 404 k.lock.Lock() 405 defer k.lock.Unlock() 406 var del bool 407 if !p.BzzPeer.LightNode { 408 k.addrs, _, _, _ = pot.Swap(k.addrs, p, Pof, func(v pot.Val) pot.Val { 409 // v cannot be nil, must check otherwise we overwrite entry 410 if v == nil { 411 panic(fmt.Sprintf("connected peer not found %v", p)) 412 } 413 del = true 414 return newEntry(p.BzzAddr) 415 }) 416 } else { 417 del = true 418 } 419 420 if del { 421 k.conns, _, _, _ = pot.Swap(k.conns, p, Pof, func(_ pot.Val) pot.Val { 422 // v cannot be nil, but no need to check 423 return nil 424 }) 425 // send new address count value only if the peer is deleted 426 if k.addrCountC != nil { 427 k.addrCountC <- k.addrs.Size() 428 } 429 k.sendNeighbourhoodDepthChange() 430 } 431 } 432 433 func (k *Kademlia) ListKnown() []*BzzAddr { 434 res := []*BzzAddr{} 435 436 k.addrs.Each(func(val pot.Val) bool { 437 e := val.(*entry) 438 res = append(res, e.BzzAddr) 439 return true 440 }) 441 442 return res 443 } 444 445 // EachConn is an iterator with args (base, po, f) applies f to each live peer 446 // that has proximity order po or less as measured from the base 447 // if base is nil, kademlia base address is used 448 func (k *Kademlia) EachConn(base []byte, o int, f func(*Peer, int) bool) { 449 k.lock.RLock() 450 defer k.lock.RUnlock() 451 k.eachConn(base, o, f) 452 } 453 454 func (k *Kademlia) eachConn(base []byte, o int, f func(*Peer, int) bool) { 455 if len(base) == 0 { 456 base = k.base 457 } 458 k.conns.EachNeighbour(base, Pof, func(val pot.Val, po int) bool { 459 if po > o { 460 return true 461 } 462 return f(val.(*Peer), po) 463 }) 464 } 465 466 // EachAddr called with (base, po, f) is an iterator applying f to each known peer 467 // that has proximity order o or less as measured from the base 468 // if base is nil, kademlia base address is used 469 func (k *Kademlia) EachAddr(base []byte, o int, f func(*BzzAddr, int) bool) { 470 k.lock.RLock() 471 defer k.lock.RUnlock() 472 k.eachAddr(base, o, f) 473 } 474 475 func (k *Kademlia) eachAddr(base []byte, o int, f func(*BzzAddr, int) bool) { 476 if len(base) == 0 { 477 base = k.base 478 } 479 k.addrs.EachNeighbour(base, Pof, func(val pot.Val, po int) bool { 480 if po > o { 481 return true 482 } 483 return f(val.(*entry).BzzAddr, po) 484 }) 485 } 486 487 // NeighbourhoodDepth returns the depth for the pot, see depthForPot 488 func (k *Kademlia) NeighbourhoodDepth() (depth int) { 489 k.lock.RLock() 490 defer k.lock.RUnlock() 491 return depthForPot(k.conns, k.NeighbourhoodSize, k.base) 492 } 493 494 // neighbourhoodRadiusForPot returns the neighbourhood radius of the kademlia 495 // neighbourhood radius encloses the nearest neighbour set with size >= neighbourhoodSize 496 // i.e., neighbourhood radius is the deepest PO such that all bins not shallower altogether 497 // contain at least neighbourhoodSize connected peers 498 // if there is altogether less than neighbourhoodSize peers connected, it returns 0 499 // caller must hold the lock 500 func neighbourhoodRadiusForPot(p *pot.Pot, neighbourhoodSize int, pivotAddr []byte) (depth int) { 501 if p.Size() <= neighbourhoodSize { 502 return 0 503 } 504 // total number of peers in iteration 505 var size int 506 f := func(v pot.Val, i int) bool { 507 // po == 256 means that addr is the pivot address(self) 508 if i == 256 { 509 return true 510 } 511 size++ 512 513 // this means we have all nn-peers. 514 // depth is by default set to the bin of the farthest nn-peer 515 if size == neighbourhoodSize { 516 depth = i 517 return false 518 } 519 520 return true 521 } 522 p.EachNeighbour(pivotAddr, Pof, f) 523 return depth 524 } 525 526 // depthForPot returns the depth for the pot 527 // depth is the radius of the minimal extension of nearest neighbourhood that 528 // includes all empty PO bins. I.e., depth is the deepest PO such that 529 // - it is not deeper than neighbourhood radius 530 // - all bins shallower than depth are not empty 531 // caller must hold the lock 532 func depthForPot(p *pot.Pot, neighbourhoodSize int, pivotAddr []byte) (depth int) { 533 if p.Size() <= neighbourhoodSize { 534 return 0 535 } 536 // determining the depth is a two-step process 537 // first we find the proximity bin of the shallowest of the neighbourhoodSize peers 538 // the numeric value of depth cannot be higher than this 539 maxDepth := neighbourhoodRadiusForPot(p, neighbourhoodSize, pivotAddr) 540 541 // the second step is to test for empty bins in order from shallowest to deepest 542 // if an empty bin is found, this will be the actual depth 543 // we stop iterating if we hit the maxDepth determined in the first step 544 p.EachBin(pivotAddr, Pof, 0, func(po int, _ int, f func(func(pot.Val) bool) bool) bool { 545 if po == depth { 546 if maxDepth == depth { 547 return false 548 } 549 depth++ 550 return true 551 } 552 return false 553 }) 554 555 return depth 556 } 557 558 // callable decides if an address entry represents a callable peer 559 func (k *Kademlia) callable(e *entry) bool { 560 // not callable if peer is live or exceeded maxRetries 561 if e.conn != nil || e.retries > k.MaxRetries { 562 return false 563 } 564 // calculate the allowed number of retries based on time lapsed since last seen 565 timeAgo := int64(time.Since(e.seenAt)) 566 div := int64(k.RetryExponent) 567 div += (150000 - rand.Int63n(300000)) * div / 1000000 568 var retries int 569 for delta := timeAgo; delta > k.RetryInterval; delta /= div { 570 retries++ 571 } 572 // this is never called concurrently, so safe to increment 573 // peer can be retried again 574 if retries < e.retries { 575 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)) 576 return false 577 } 578 // function to sanction or prevent suggesting a peer 579 if k.Reachable != nil && !k.Reachable(e.BzzAddr) { 580 log.Trace(fmt.Sprintf("%08x: peer %v is temporarily not callable", k.BaseAddr()[:4], e)) 581 return false 582 } 583 e.retries++ 584 log.Trace(fmt.Sprintf("%08x: peer %v is callable", k.BaseAddr()[:4], e)) 585 586 return true 587 } 588 589 // BaseAddr return the kademlia base address 590 func (k *Kademlia) BaseAddr() []byte { 591 return k.base 592 } 593 594 // String returns kademlia table + kaddb table displayed with ascii 595 func (k *Kademlia) String() string { 596 k.lock.RLock() 597 defer k.lock.RUnlock() 598 return k.string() 599 } 600 601 // string returns kademlia table + kaddb table displayed with ascii 602 // caller must hold the lock 603 func (k *Kademlia) string() string { 604 wsrow := " " 605 var rows []string 606 607 rows = append(rows, "=========================================================================") 608 if len(sv.GitCommit) > 0 { 609 rows = append(rows, fmt.Sprintf("commit hash: %s", sv.GitCommit)) 610 } 611 rows = append(rows, fmt.Sprintf("%v KΛÐΞMLIΛ hive: queen's address: %x", time.Now().UTC().Format(time.UnixDate), k.BaseAddr()[:3])) 612 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)) 613 614 liverows := make([]string, k.MaxProxDisplay) 615 peersrows := make([]string, k.MaxProxDisplay) 616 617 depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) 618 rest := k.conns.Size() 619 k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { 620 var rowlen int 621 if po >= k.MaxProxDisplay { 622 po = k.MaxProxDisplay - 1 623 } 624 row := []string{fmt.Sprintf("%2d", size)} 625 rest -= size 626 f(func(val pot.Val) bool { 627 e := val.(*Peer) 628 row = append(row, fmt.Sprintf("%x", e.Address()[:2])) 629 rowlen++ 630 return rowlen < 4 631 }) 632 r := strings.Join(row, " ") 633 r = r + wsrow 634 liverows[po] = r[:31] 635 return true 636 }) 637 638 k.addrs.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { 639 var rowlen int 640 if po >= k.MaxProxDisplay { 641 po = k.MaxProxDisplay - 1 642 } 643 if size < 0 { 644 panic("wtf") 645 } 646 row := []string{fmt.Sprintf("%2d", size)} 647 // we are displaying live peers too 648 f(func(val pot.Val) bool { 649 e := val.(*entry) 650 row = append(row, Label(e)) 651 rowlen++ 652 return rowlen < 4 653 }) 654 peersrows[po] = strings.Join(row, " ") 655 return true 656 }) 657 658 for i := 0; i < k.MaxProxDisplay; i++ { 659 if i == depth { 660 rows = append(rows, fmt.Sprintf("============ DEPTH: %d ==========================================", i)) 661 } 662 left := liverows[i] 663 right := peersrows[i] 664 if len(left) == 0 { 665 left = " 0 " 666 } 667 if len(right) == 0 { 668 right = " 0" 669 } 670 rows = append(rows, fmt.Sprintf("%03d %v | %v", i, left, right)) 671 } 672 rows = append(rows, "=========================================================================") 673 return "\n" + strings.Join(rows, "\n") 674 } 675 676 // PeerPot keeps info about expected nearest neighbours 677 // used for testing only 678 // TODO move to separate testing tools file 679 type PeerPot struct { 680 NNSet [][]byte 681 PeersPerBin []int 682 } 683 684 // NewPeerPotMap creates a map of pot record of *BzzAddr with keys 685 // as hexadecimal representations of the address. 686 // the NeighbourhoodSize of the passed kademlia is used 687 // used for testing only 688 // TODO move to separate testing tools file 689 func NewPeerPotMap(neighbourhoodSize int, addrs [][]byte) map[string]*PeerPot { 690 691 // create a table of all nodes for health check 692 np := pot.NewPot(nil, 0) 693 for _, addr := range addrs { 694 np, _, _ = pot.Add(np, addr, Pof) 695 } 696 ppmap := make(map[string]*PeerPot) 697 698 // generate an allknowing source of truth for connections 699 // for every kademlia passed 700 for i, a := range addrs { 701 702 // actual kademlia depth 703 depth := depthForPot(np, neighbourhoodSize, a) 704 705 // all nn-peers 706 var nns [][]byte 707 peersPerBin := make([]int, depth) 708 709 // iterate through the neighbours, going from the deepest to the shallowest 710 np.EachNeighbour(a, Pof, func(val pot.Val, po int) bool { 711 addr := val.([]byte) 712 // po == 256 means that addr is the pivot address(self) 713 // we do not include self in the map 714 if po == 256 { 715 return true 716 } 717 // append any neighbors found 718 // a neighbor is any peer in or deeper than the depth 719 if po >= depth { 720 nns = append(nns, addr) 721 } else { 722 // for peers < depth, we just count the number in each bin 723 // the bin is the index of the slice 724 peersPerBin[po]++ 725 } 726 return true 727 }) 728 729 log.Trace(fmt.Sprintf("%x PeerPotMap NNS: %s, peersPerBin", addrs[i][:4], LogAddrs(nns))) 730 ppmap[common.Bytes2Hex(a)] = &PeerPot{ 731 NNSet: nns, 732 PeersPerBin: peersPerBin, 733 } 734 } 735 return ppmap 736 } 737 738 // saturation returns the smallest po value in which the node has less than MinBinSize peers 739 // if the iterator reaches neighbourhood radius, then the last bin + 1 is returned 740 func (k *Kademlia) saturation() int { 741 prev := -1 742 radius := neighbourhoodRadiusForPot(k.conns, k.NeighbourhoodSize, k.base) 743 k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { 744 prev++ 745 if po >= radius { 746 return false 747 } 748 return prev == po && size >= k.MinBinSize 749 }) 750 if prev < 0 { 751 return 0 752 } 753 return prev 754 } 755 756 // isSaturated returns true if the kademlia is considered saturated, or false if not. 757 // It checks this by checking an array of ints called unsaturatedBins; each item in that array corresponds 758 // to the bin which is unsaturated (number of connections < k.MinBinSize). 759 // The bin is considered unsaturated only if there are actual peers in that PeerPot's bin (peersPerBin) 760 // (if there is no peer for a given bin, then no connection could ever be established; 761 // in a God's view this is relevant as no more peers will ever appear on that bin) 762 func (k *Kademlia) isSaturated(peersPerBin []int, depth int) bool { 763 // depth could be calculated from k but as this is called from `GetHealthInfo()`, 764 // the depth has already been calculated so we can require it as a parameter 765 766 // early check for depth 767 if depth != len(peersPerBin) { 768 return false 769 } 770 unsaturatedBins := make([]int, 0) 771 k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { 772 773 if po >= depth { 774 return false 775 } 776 log.Trace("peers per bin", "peersPerBin[po]", peersPerBin[po], "po", po) 777 // if there are actually peers in the PeerPot who can fulfill k.MinBinSize 778 if size < k.MinBinSize && size < peersPerBin[po] { 779 log.Trace("connections for po", "po", po, "size", size) 780 unsaturatedBins = append(unsaturatedBins, po) 781 } 782 return true 783 }) 784 785 log.Trace("list of unsaturated bins", "unsaturatedBins", unsaturatedBins) 786 return len(unsaturatedBins) == 0 787 } 788 789 // knowNeighbours tests if all neighbours in the peerpot 790 // are found among the peers known to the kademlia 791 // It is used in Healthy function for testing only 792 // TODO move to separate testing tools file 793 func (k *Kademlia) knowNeighbours(addrs [][]byte) (got bool, n int, missing [][]byte) { 794 pm := make(map[string]bool) 795 depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) 796 // create a map with all peers at depth and deeper known in the kademlia 797 k.eachAddr(nil, 255, func(p *BzzAddr, po int) bool { 798 // in order deepest to shallowest compared to the kademlia base address 799 // all bins (except self) are included (0 <= bin <= 255) 800 if po < depth { 801 return false 802 } 803 pk := common.Bytes2Hex(p.Address()) 804 pm[pk] = true 805 return true 806 }) 807 808 // iterate through nearest neighbors in the peerpot map 809 // if we can't find the neighbor in the map we created above 810 // then we don't know all our neighbors 811 // (which sadly is all too common in modern society) 812 var gots int 813 var culprits [][]byte 814 for _, p := range addrs { 815 pk := common.Bytes2Hex(p) 816 if pm[pk] { 817 gots++ 818 } else { 819 log.Trace(fmt.Sprintf("%08x: known nearest neighbour %s not found", k.base, pk)) 820 culprits = append(culprits, p) 821 } 822 } 823 return gots == len(addrs), gots, culprits 824 } 825 826 // connectedNeighbours tests if all neighbours in the peerpot 827 // are currently connected in the kademlia 828 // It is used in Healthy function for testing only 829 func (k *Kademlia) connectedNeighbours(peers [][]byte) (got bool, n int, missing [][]byte) { 830 pm := make(map[string]bool) 831 832 // create a map with all peers at depth and deeper that are connected in the kademlia 833 // in order deepest to shallowest compared to the kademlia base address 834 // all bins (except self) are included (0 <= bin <= 255) 835 depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) 836 k.eachConn(nil, 255, func(p *Peer, po int) bool { 837 if po < depth { 838 return false 839 } 840 pk := common.Bytes2Hex(p.Address()) 841 pm[pk] = true 842 return true 843 }) 844 845 // iterate through nearest neighbors in the peerpot map 846 // if we can't find the neighbor in the map we created above 847 // then we don't know all our neighbors 848 var gots int 849 var culprits [][]byte 850 for _, p := range peers { 851 pk := common.Bytes2Hex(p) 852 if pm[pk] { 853 gots++ 854 } else { 855 log.Trace(fmt.Sprintf("%08x: ExpNN: %s not found", k.base, pk)) 856 culprits = append(culprits, p) 857 } 858 } 859 return gots == len(peers), gots, culprits 860 } 861 862 // Health state of the Kademlia 863 // used for testing only 864 type Health struct { 865 KnowNN bool // whether node knows all its neighbours 866 CountKnowNN int // amount of neighbors known 867 MissingKnowNN [][]byte // which neighbours we should have known but we don't 868 ConnectNN bool // whether node is connected to all its neighbours 869 CountConnectNN int // amount of neighbours connected to 870 MissingConnectNN [][]byte // which neighbours we should have been connected to but we're not 871 // Saturated: if in all bins < depth number of connections >= MinBinsize or, 872 // if number of connections < MinBinSize, to the number of available peers in that bin 873 Saturated bool 874 Hive string 875 } 876 877 // GetHealthInfo reports the health state of the kademlia connectivity 878 // 879 // The PeerPot argument provides an all-knowing view of the network 880 // The resulting Health object is a result of comparisons between 881 // what is the actual composition of the kademlia in question (the receiver), and 882 // what SHOULD it have been when we take all we know about the network into consideration. 883 // 884 // used for testing only 885 func (k *Kademlia) GetHealthInfo(pp *PeerPot) *Health { 886 k.lock.RLock() 887 defer k.lock.RUnlock() 888 if len(pp.NNSet) < k.NeighbourhoodSize { 889 log.Warn("peerpot NNSet < NeighbourhoodSize") 890 } 891 gotnn, countgotnn, culpritsgotnn := k.connectedNeighbours(pp.NNSet) 892 knownn, countknownn, culpritsknownn := k.knowNeighbours(pp.NNSet) 893 depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) 894 895 // check saturation 896 saturated := k.isSaturated(pp.PeersPerBin, depth) 897 898 log.Trace(fmt.Sprintf("%08x: healthy: knowNNs: %v, gotNNs: %v, saturated: %v\n", k.base, knownn, gotnn, saturated)) 899 return &Health{ 900 KnowNN: knownn, 901 CountKnowNN: countknownn, 902 MissingKnowNN: culpritsknownn, 903 ConnectNN: gotnn, 904 CountConnectNN: countgotnn, 905 MissingConnectNN: culpritsgotnn, 906 Saturated: saturated, 907 Hive: k.string(), 908 } 909 } 910 911 // Healthy return the strict interpretation of `Healthy` given a `Health` struct 912 // definition of strict health: all conditions must be true: 913 // - we at least know one peer 914 // - we know all neighbors 915 // - we are connected to all known neighbors 916 // - it is saturated 917 func (h *Health) Healthy() bool { 918 return h.KnowNN && h.ConnectNN && h.CountKnowNN > 0 && h.Saturated 919 }