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