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  }