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  }