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  }