github.com/oskarth/go-ethereum@v1.6.8-0.20191013093314-dac24a9d3494/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  )
    31  
    32  /*
    33  
    34  Taking the proximity order relative to a fix point x classifies the points in
    35  the space (n byte long byte sequences) into bins. Items in each are at
    36  most half as distant from x as items in the previous bin. Given a sample of
    37  uniformly distributed items (a hash function over arbitrary sequence) the
    38  proximity scale maps onto series of subsets with cardinalities on a negative
    39  exponential scale.
    40  
    41  It also has the property that any two item belonging to the same bin are at
    42  most half as distant from each other as they are from x.
    43  
    44  If we think of random sample of items in the bins as connections in a network of
    45  interconnected nodes then relative proximity can serve as the basis for local
    46  decisions for graph traversal where the task is to find a route between two
    47  points. Since in every hop, the finite distance halves, there is
    48  a guaranteed constant maximum limit on the number of hops needed to reach one
    49  node from the other.
    50  */
    51  
    52  var pof = pot.DefaultPof(256)
    53  
    54  // KadParams holds the config params for Kademlia
    55  type KadParams struct {
    56  	// adjustable parameters
    57  	MaxProxDisplay int   // number of rows the table shows
    58  	MinProxBinSize int   // nearest neighbour core minimum cardinality
    59  	MinBinSize     int   // minimum number of peers in a row
    60  	MaxBinSize     int   // maximum number of peers in a row before pruning
    61  	RetryInterval  int64 // initial interval before a peer is first redialed
    62  	RetryExponent  int   // exponent to multiply retry intervals with
    63  	MaxRetries     int   // maximum number of redial attempts
    64  	// function to sanction or prevent suggesting a peer
    65  	Reachable func(*BzzAddr) bool
    66  }
    67  
    68  // NewKadParams returns a params struct with default values
    69  func NewKadParams() *KadParams {
    70  	return &KadParams{
    71  		MaxProxDisplay: 16,
    72  		MinProxBinSize: 2,
    73  		MinBinSize:     2,
    74  		MaxBinSize:     4,
    75  		RetryInterval:  4200000000, // 4.2 sec
    76  		MaxRetries:     42,
    77  		RetryExponent:  2,
    78  	}
    79  }
    80  
    81  // Kademlia is a table of live peers and a db of known peers (node records)
    82  type Kademlia struct {
    83  	lock       sync.RWMutex
    84  	*KadParams          // Kademlia configuration parameters
    85  	base       []byte   // immutable baseaddress of the table
    86  	addrs      *pot.Pot // pots container for known peer addresses
    87  	conns      *pot.Pot // pots container for live peer connections
    88  	depth      uint8    // stores the last current depth of saturation
    89  	nDepth     int      // stores the last neighbourhood depth
    90  	nDepthC    chan int // returned by DepthC function to signal neighbourhood depth change
    91  	addrCountC chan int // returned by AddrCountC function to signal peer count change
    92  }
    93  
    94  // NewKademlia creates a Kademlia table for base address addr
    95  // with parameters as in params
    96  // if params is nil, it uses default values
    97  func NewKademlia(addr []byte, params *KadParams) *Kademlia {
    98  	if params == nil {
    99  		params = NewKadParams()
   100  	}
   101  	return &Kademlia{
   102  		base:      addr,
   103  		KadParams: params,
   104  		addrs:     pot.NewPot(nil, 0),
   105  		conns:     pot.NewPot(nil, 0),
   106  	}
   107  }
   108  
   109  // entry represents a Kademlia table entry (an extension of BzzAddr)
   110  type entry struct {
   111  	*BzzAddr
   112  	conn    *Peer
   113  	seenAt  time.Time
   114  	retries int
   115  }
   116  
   117  // newEntry creates a kademlia peer from a *Peer
   118  func newEntry(p *BzzAddr) *entry {
   119  	return &entry{
   120  		BzzAddr: p,
   121  		seenAt:  time.Now(),
   122  	}
   123  }
   124  
   125  // Label is a short tag for the entry for debug
   126  func Label(e *entry) string {
   127  	return fmt.Sprintf("%s (%d)", e.Hex()[:4], e.retries)
   128  }
   129  
   130  // Hex is the hexadecimal serialisation of the entry address
   131  func (e *entry) Hex() string {
   132  	return fmt.Sprintf("%x", e.Address())
   133  }
   134  
   135  // Register enters each address as kademlia peer record into the
   136  // database of known peer addresses
   137  func (k *Kademlia) Register(peers ...*BzzAddr) error {
   138  	k.lock.Lock()
   139  	defer k.lock.Unlock()
   140  	var known, size int
   141  	for _, p := range peers {
   142  		// error if self received, peer should know better
   143  		// and should be punished for this
   144  		if bytes.Equal(p.Address(), k.base) {
   145  			return fmt.Errorf("add peers: %x is self", k.base)
   146  		}
   147  		var found bool
   148  		k.addrs, _, found, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val {
   149  			// if not found
   150  			if v == nil {
   151  				// insert new offline peer into conns
   152  				return newEntry(p)
   153  			}
   154  			// found among known peers, do nothing
   155  			return v
   156  		})
   157  		if found {
   158  			known++
   159  		}
   160  		size++
   161  	}
   162  	// send new address count value only if there are new addresses
   163  	if k.addrCountC != nil && size-known > 0 {
   164  		k.addrCountC <- k.addrs.Size()
   165  	}
   166  
   167  	k.sendNeighbourhoodDepthChange()
   168  	return nil
   169  }
   170  
   171  // SuggestPeer returns a known peer for the lowest proximity bin for the
   172  // lowest bincount below depth
   173  // naturally if there is an empty row it returns a peer for that
   174  func (k *Kademlia) SuggestPeer() (a *BzzAddr, o int, want bool) {
   175  	k.lock.Lock()
   176  	defer k.lock.Unlock()
   177  	minsize := k.MinBinSize
   178  	depth := k.neighbourhoodDepth()
   179  	// if there is a callable neighbour within the current proxBin, connect
   180  	// this makes sure nearest neighbour set is fully connected
   181  	var ppo int
   182  	k.addrs.EachNeighbour(k.base, pof, func(val pot.Val, po int) bool {
   183  		if po < depth {
   184  			return false
   185  		}
   186  		e := val.(*entry)
   187  		c := k.callable(e)
   188  		if c {
   189  			a = e.BzzAddr
   190  		}
   191  		ppo = po
   192  		return !c
   193  	})
   194  	if a != nil {
   195  		log.Trace(fmt.Sprintf("%08x candidate nearest neighbour found: %v (%v)", k.BaseAddr()[:4], a, ppo))
   196  		return a, 0, false
   197  	}
   198  
   199  	var bpo []int
   200  	prev := -1
   201  	k.conns.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
   202  		prev++
   203  		for ; prev < po; prev++ {
   204  			bpo = append(bpo, prev)
   205  			minsize = 0
   206  		}
   207  		if size < minsize {
   208  			bpo = append(bpo, po)
   209  			minsize = size
   210  		}
   211  		return size > 0 && po < depth
   212  	})
   213  	// all buckets are full, ie., minsize == k.MinBinSize
   214  	if len(bpo) == 0 {
   215  		return nil, 0, false
   216  	}
   217  	// as long as we got candidate peers to connect to
   218  	// dont ask for new peers (want = false)
   219  	// try to select a candidate peer
   220  	// find the first callable peer
   221  	nxt := bpo[0]
   222  	k.addrs.EachBin(k.base, pof, nxt, func(po, _ int, f func(func(pot.Val, int) bool) bool) bool {
   223  		// for each bin (up until depth) we find callable candidate peers
   224  		if po >= depth {
   225  			return false
   226  		}
   227  		return f(func(val pot.Val, _ int) bool {
   228  			e := val.(*entry)
   229  			c := k.callable(e)
   230  			if c {
   231  				a = e.BzzAddr
   232  			}
   233  			return !c
   234  		})
   235  	})
   236  	// found a candidate
   237  	if a != nil {
   238  		return a, 0, false
   239  	}
   240  	// no candidate peer found, request for the short bin
   241  	var changed bool
   242  	if uint8(nxt) < k.depth {
   243  		k.depth = uint8(nxt)
   244  		changed = true
   245  	}
   246  	return a, nxt, changed
   247  }
   248  
   249  // On inserts the peer as a kademlia peer into the live peers
   250  func (k *Kademlia) On(p *Peer) (uint8, bool) {
   251  	k.lock.Lock()
   252  	defer k.lock.Unlock()
   253  	var ins bool
   254  	k.conns, _, _, _ = pot.Swap(k.conns, p, pof, func(v pot.Val) pot.Val {
   255  		// if not found live
   256  		if v == nil {
   257  			ins = true
   258  			// insert new online peer into conns
   259  			return p
   260  		}
   261  		// found among live peers, do nothing
   262  		return v
   263  	})
   264  	if ins {
   265  		a := newEntry(p.BzzAddr)
   266  		a.conn = p
   267  		// insert new online peer into addrs
   268  		k.addrs, _, _, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val {
   269  			return a
   270  		})
   271  		// send new address count value only if the peer is inserted
   272  		if k.addrCountC != nil {
   273  			k.addrCountC <- k.addrs.Size()
   274  		}
   275  	}
   276  	log.Trace(k.string())
   277  	// calculate if depth of saturation changed
   278  	depth := uint8(k.saturation(k.MinBinSize))
   279  	var changed bool
   280  	if depth != k.depth {
   281  		changed = true
   282  		k.depth = depth
   283  	}
   284  	k.sendNeighbourhoodDepthChange()
   285  	return k.depth, changed
   286  }
   287  
   288  // NeighbourhoodDepthC returns the channel that sends a new kademlia
   289  // neighbourhood depth on each change.
   290  // Not receiving from the returned channel will block On function
   291  // when the neighbourhood depth is changed.
   292  func (k *Kademlia) NeighbourhoodDepthC() <-chan int {
   293  	k.lock.Lock()
   294  	defer k.lock.Unlock()
   295  	if k.nDepthC == nil {
   296  		k.nDepthC = make(chan int)
   297  	}
   298  	return k.nDepthC
   299  }
   300  
   301  // sendNeighbourhoodDepthChange sends new neighbourhood depth to k.nDepth channel
   302  // if it is initialized.
   303  func (k *Kademlia) sendNeighbourhoodDepthChange() {
   304  	// nDepthC is initialized when NeighbourhoodDepthC is called and returned by it.
   305  	// It provides signaling of neighbourhood depth change.
   306  	// This part of the code is sending new neighbourhood depth to nDepthC if that condition is met.
   307  	if k.nDepthC != nil {
   308  		nDepth := k.neighbourhoodDepth()
   309  		if nDepth != k.nDepth {
   310  			k.nDepth = nDepth
   311  			k.nDepthC <- nDepth
   312  		}
   313  	}
   314  }
   315  
   316  // AddrCountC returns the channel that sends a new
   317  // address count value on each change.
   318  // Not receiving from the returned channel will block Register function
   319  // when address count value changes.
   320  func (k *Kademlia) AddrCountC() <-chan int {
   321  	if k.addrCountC == nil {
   322  		k.addrCountC = make(chan int)
   323  	}
   324  	return k.addrCountC
   325  }
   326  
   327  // Off removes a peer from among live peers
   328  func (k *Kademlia) Off(p *Peer) {
   329  	k.lock.Lock()
   330  	defer k.lock.Unlock()
   331  	var del bool
   332  	k.addrs, _, _, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val {
   333  		// v cannot be nil, must check otherwise we overwrite entry
   334  		if v == nil {
   335  			panic(fmt.Sprintf("connected peer not found %v", p))
   336  		}
   337  		del = true
   338  		return newEntry(p.BzzAddr)
   339  	})
   340  
   341  	if del {
   342  		k.conns, _, _, _ = pot.Swap(k.conns, p, pof, func(_ pot.Val) pot.Val {
   343  			// v cannot be nil, but no need to check
   344  			return nil
   345  		})
   346  		// send new address count value only if the peer is deleted
   347  		if k.addrCountC != nil {
   348  			k.addrCountC <- k.addrs.Size()
   349  		}
   350  		k.sendNeighbourhoodDepthChange()
   351  	}
   352  }
   353  
   354  func (k *Kademlia) EachBin(base []byte, pof pot.Pof, o int, eachBinFunc func(conn *Peer, po int) bool) {
   355  	k.lock.RLock()
   356  	defer k.lock.RUnlock()
   357  
   358  	var startPo int
   359  	var endPo int
   360  	kadDepth := k.neighbourhoodDepth()
   361  
   362  	k.conns.EachBin(base, pof, o, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
   363  		if startPo > 0 && endPo != k.MaxProxDisplay {
   364  			startPo = endPo + 1
   365  		}
   366  		if po < kadDepth {
   367  			endPo = po
   368  		} else {
   369  			endPo = k.MaxProxDisplay
   370  		}
   371  
   372  		for bin := startPo; bin <= endPo; bin++ {
   373  			f(func(val pot.Val, _ int) bool {
   374  				return eachBinFunc(val.(*Peer), bin)
   375  			})
   376  		}
   377  		return true
   378  	})
   379  }
   380  
   381  // EachConn is an iterator with args (base, po, f) applies f to each live peer
   382  // that has proximity order po or less as measured from the base
   383  // if base is nil, kademlia base address is used
   384  func (k *Kademlia) EachConn(base []byte, o int, f func(*Peer, int, bool) bool) {
   385  	k.lock.RLock()
   386  	defer k.lock.RUnlock()
   387  	k.eachConn(base, o, f)
   388  }
   389  
   390  func (k *Kademlia) eachConn(base []byte, o int, f func(*Peer, int, bool) bool) {
   391  	if len(base) == 0 {
   392  		base = k.base
   393  	}
   394  	depth := k.neighbourhoodDepth()
   395  	k.conns.EachNeighbour(base, pof, func(val pot.Val, po int) bool {
   396  		if po > o {
   397  			return true
   398  		}
   399  		return f(val.(*Peer), po, po >= depth)
   400  	})
   401  }
   402  
   403  // EachAddr called with (base, po, f) is an iterator applying f to each known peer
   404  // that has proximity order po or less as measured from the base
   405  // if base is nil, kademlia base address is used
   406  func (k *Kademlia) EachAddr(base []byte, o int, f func(*BzzAddr, int, bool) bool) {
   407  	k.lock.RLock()
   408  	defer k.lock.RUnlock()
   409  	k.eachAddr(base, o, f)
   410  }
   411  
   412  func (k *Kademlia) eachAddr(base []byte, o int, f func(*BzzAddr, int, bool) bool) {
   413  	if len(base) == 0 {
   414  		base = k.base
   415  	}
   416  	depth := k.neighbourhoodDepth()
   417  	k.addrs.EachNeighbour(base, pof, func(val pot.Val, po int) bool {
   418  		if po > o {
   419  			return true
   420  		}
   421  		return f(val.(*entry).BzzAddr, po, po >= depth)
   422  	})
   423  }
   424  
   425  // neighbourhoodDepth returns the proximity order that defines the distance of
   426  // the nearest neighbour set with cardinality >= MinProxBinSize
   427  // if there is altogether less than MinProxBinSize peers it returns 0
   428  // caller must hold the lock
   429  func (k *Kademlia) neighbourhoodDepth() (depth int) {
   430  	if k.conns.Size() < k.MinProxBinSize {
   431  		return 0
   432  	}
   433  	var size int
   434  	f := func(v pot.Val, i int) bool {
   435  		size++
   436  		depth = i
   437  		return size < k.MinProxBinSize
   438  	}
   439  	k.conns.EachNeighbour(k.base, pof, f)
   440  	return depth
   441  }
   442  
   443  // callable decides if an address entry represents a callable peer
   444  func (k *Kademlia) callable(e *entry) bool {
   445  	// not callable if peer is live or exceeded maxRetries
   446  	if e.conn != nil || e.retries > k.MaxRetries {
   447  		return false
   448  	}
   449  	// calculate the allowed number of retries based on time lapsed since last seen
   450  	timeAgo := int64(time.Since(e.seenAt))
   451  	div := int64(k.RetryExponent)
   452  	div += (150000 - rand.Int63n(300000)) * div / 1000000
   453  	var retries int
   454  	for delta := timeAgo; delta > k.RetryInterval; delta /= div {
   455  		retries++
   456  	}
   457  	// this is never called concurrently, so safe to increment
   458  	// peer can be retried again
   459  	if retries < e.retries {
   460  		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))
   461  		return false
   462  	}
   463  	// function to sanction or prevent suggesting a peer
   464  	if k.Reachable != nil && !k.Reachable(e.BzzAddr) {
   465  		log.Trace(fmt.Sprintf("%08x: peer %v is temporarily not callable", k.BaseAddr()[:4], e))
   466  		return false
   467  	}
   468  	e.retries++
   469  	log.Trace(fmt.Sprintf("%08x: peer %v is callable", k.BaseAddr()[:4], e))
   470  
   471  	return true
   472  }
   473  
   474  // BaseAddr return the kademlia base address
   475  func (k *Kademlia) BaseAddr() []byte {
   476  	return k.base
   477  }
   478  
   479  // String returns kademlia table + kaddb table displayed with ascii
   480  func (k *Kademlia) String() string {
   481  	k.lock.RLock()
   482  	defer k.lock.RUnlock()
   483  	return k.string()
   484  }
   485  
   486  // string returns kademlia table + kaddb table displayed with ascii
   487  // caller must hold the lock
   488  func (k *Kademlia) string() string {
   489  	wsrow := "                          "
   490  	var rows []string
   491  
   492  	rows = append(rows, "=========================================================================")
   493  	rows = append(rows, fmt.Sprintf("%v KΛÐΞMLIΛ hive: queen's address: %x", time.Now().UTC().Format(time.UnixDate), k.BaseAddr()[:3]))
   494  	rows = append(rows, fmt.Sprintf("population: %d (%d), MinProxBinSize: %d, MinBinSize: %d, MaxBinSize: %d", k.conns.Size(), k.addrs.Size(), k.MinProxBinSize, k.MinBinSize, k.MaxBinSize))
   495  
   496  	liverows := make([]string, k.MaxProxDisplay)
   497  	peersrows := make([]string, k.MaxProxDisplay)
   498  
   499  	depth := k.neighbourhoodDepth()
   500  	rest := k.conns.Size()
   501  	k.conns.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
   502  		var rowlen int
   503  		if po >= k.MaxProxDisplay {
   504  			po = k.MaxProxDisplay - 1
   505  		}
   506  		row := []string{fmt.Sprintf("%2d", size)}
   507  		rest -= size
   508  		f(func(val pot.Val, vpo int) bool {
   509  			e := val.(*Peer)
   510  			row = append(row, fmt.Sprintf("%x", e.Address()[:2]))
   511  			rowlen++
   512  			return rowlen < 4
   513  		})
   514  		r := strings.Join(row, " ")
   515  		r = r + wsrow
   516  		liverows[po] = r[:31]
   517  		return true
   518  	})
   519  
   520  	k.addrs.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
   521  		var rowlen int
   522  		if po >= k.MaxProxDisplay {
   523  			po = k.MaxProxDisplay - 1
   524  		}
   525  		if size < 0 {
   526  			panic("wtf")
   527  		}
   528  		row := []string{fmt.Sprintf("%2d", size)}
   529  		// we are displaying live peers too
   530  		f(func(val pot.Val, vpo int) bool {
   531  			e := val.(*entry)
   532  			row = append(row, Label(e))
   533  			rowlen++
   534  			return rowlen < 4
   535  		})
   536  		peersrows[po] = strings.Join(row, " ")
   537  		return true
   538  	})
   539  
   540  	for i := 0; i < k.MaxProxDisplay; i++ {
   541  		if i == depth {
   542  			rows = append(rows, fmt.Sprintf("============ DEPTH: %d ==========================================", i))
   543  		}
   544  		left := liverows[i]
   545  		right := peersrows[i]
   546  		if len(left) == 0 {
   547  			left = " 0                             "
   548  		}
   549  		if len(right) == 0 {
   550  			right = " 0"
   551  		}
   552  		rows = append(rows, fmt.Sprintf("%03d %v | %v", i, left, right))
   553  	}
   554  	rows = append(rows, "=========================================================================")
   555  	return "\n" + strings.Join(rows, "\n")
   556  }
   557  
   558  // PeerPot keeps info about expected nearest neighbours and empty bins
   559  // used for testing only
   560  type PeerPot struct {
   561  	NNSet     [][]byte
   562  	EmptyBins []int
   563  }
   564  
   565  // NewPeerPotMap creates a map of pot record of *BzzAddr with keys
   566  // as hexadecimal representations of the address.
   567  // used for testing only
   568  func NewPeerPotMap(kadMinProxSize int, addrs [][]byte) map[string]*PeerPot {
   569  	// create a table of all nodes for health check
   570  	np := pot.NewPot(nil, 0)
   571  	for _, addr := range addrs {
   572  		np, _, _ = pot.Add(np, addr, pof)
   573  	}
   574  	ppmap := make(map[string]*PeerPot)
   575  
   576  	for i, a := range addrs {
   577  		pl := 256
   578  		prev := 256
   579  		var emptyBins []int
   580  		var nns [][]byte
   581  		np.EachNeighbour(addrs[i], pof, func(val pot.Val, po int) bool {
   582  			a := val.([]byte)
   583  			if po == 256 {
   584  				return true
   585  			}
   586  			if pl == 256 || pl == po {
   587  				nns = append(nns, a)
   588  			}
   589  			if pl == 256 && len(nns) >= kadMinProxSize {
   590  				pl = po
   591  				prev = po
   592  			}
   593  			if prev < pl {
   594  				for j := prev; j > po; j-- {
   595  					emptyBins = append(emptyBins, j)
   596  				}
   597  			}
   598  			prev = po - 1
   599  			return true
   600  		})
   601  		for j := prev; j >= 0; j-- {
   602  			emptyBins = append(emptyBins, j)
   603  		}
   604  		log.Trace(fmt.Sprintf("%x NNS: %s", addrs[i][:4], LogAddrs(nns)))
   605  		ppmap[common.Bytes2Hex(a)] = &PeerPot{nns, emptyBins}
   606  	}
   607  	return ppmap
   608  }
   609  
   610  // saturation returns the lowest proximity order that the bin for that order
   611  // has less than n peers
   612  // It is used in Healthy function for testing only
   613  func (k *Kademlia) saturation(n int) int {
   614  	prev := -1
   615  	k.addrs.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
   616  		prev++
   617  		return prev == po && size >= n
   618  	})
   619  	depth := k.neighbourhoodDepth()
   620  	if depth < prev {
   621  		return depth
   622  	}
   623  	return prev
   624  }
   625  
   626  // full returns true if all required bins have connected peers.
   627  // It is used in Healthy function for testing only
   628  func (k *Kademlia) full(emptyBins []int) (full bool) {
   629  	prev := 0
   630  	e := len(emptyBins)
   631  	ok := true
   632  	depth := k.neighbourhoodDepth()
   633  	k.conns.EachBin(k.base, pof, 0, func(po, _ int, _ func(func(val pot.Val, i int) bool) bool) bool {
   634  		if prev == depth+1 {
   635  			return true
   636  		}
   637  		for i := prev; i < po; i++ {
   638  			e--
   639  			if e < 0 {
   640  				ok = false
   641  				return false
   642  			}
   643  			if emptyBins[e] != i {
   644  				log.Trace(fmt.Sprintf("%08x po: %d, i: %d, e: %d, emptybins: %v", k.BaseAddr()[:4], po, i, e, logEmptyBins(emptyBins)))
   645  				if emptyBins[e] < i {
   646  					panic("incorrect peerpot")
   647  				}
   648  				ok = false
   649  				return false
   650  			}
   651  		}
   652  		prev = po + 1
   653  		return true
   654  	})
   655  	if !ok {
   656  		return false
   657  	}
   658  	return e == 0
   659  }
   660  
   661  // knowNearestNeighbours tests if all known nearest neighbours given as arguments
   662  // are found in the addressbook
   663  // It is used in Healthy function for testing only
   664  func (k *Kademlia) knowNearestNeighbours(peers [][]byte) bool {
   665  	pm := make(map[string]bool)
   666  
   667  	k.eachAddr(nil, 255, func(p *BzzAddr, po int, nn bool) bool {
   668  		if !nn {
   669  			return false
   670  		}
   671  		pk := fmt.Sprintf("%x", p.Address())
   672  		pm[pk] = true
   673  		return true
   674  	})
   675  	for _, p := range peers {
   676  		pk := fmt.Sprintf("%x", p)
   677  		if !pm[pk] {
   678  			log.Trace(fmt.Sprintf("%08x: known nearest neighbour %s not found", k.BaseAddr()[:4], pk[:8]))
   679  			return false
   680  		}
   681  	}
   682  	return true
   683  }
   684  
   685  // gotNearestNeighbours tests if all known nearest neighbours given as arguments
   686  // are connected peers
   687  // It is used in Healthy function for testing only
   688  func (k *Kademlia) gotNearestNeighbours(peers [][]byte) (got bool, n int, missing [][]byte) {
   689  	pm := make(map[string]bool)
   690  
   691  	k.eachConn(nil, 255, func(p *Peer, po int, nn bool) bool {
   692  		if !nn {
   693  			return false
   694  		}
   695  		pk := fmt.Sprintf("%x", p.Address())
   696  		pm[pk] = true
   697  		return true
   698  	})
   699  	var gots int
   700  	var culprits [][]byte
   701  	for _, p := range peers {
   702  		pk := fmt.Sprintf("%x", p)
   703  		if pm[pk] {
   704  			gots++
   705  		} else {
   706  			log.Trace(fmt.Sprintf("%08x: ExpNN: %s not found", k.BaseAddr()[:4], pk[:8]))
   707  			culprits = append(culprits, p)
   708  		}
   709  	}
   710  	return gots == len(peers), gots, culprits
   711  }
   712  
   713  // Health state of the Kademlia
   714  // used for testing only
   715  type Health struct {
   716  	KnowNN     bool     // whether node knows all its nearest neighbours
   717  	GotNN      bool     // whether node is connected to all its nearest neighbours
   718  	CountNN    int      // amount of nearest neighbors connected to
   719  	CulpritsNN [][]byte // which known NNs are missing
   720  	Full       bool     // whether node has a peer in each kademlia bin (where there is such a peer)
   721  	Hive       string
   722  }
   723  
   724  // Healthy reports the health state of the kademlia connectivity
   725  // returns a Health struct
   726  // used for testing only
   727  func (k *Kademlia) Healthy(pp *PeerPot) *Health {
   728  	k.lock.RLock()
   729  	defer k.lock.RUnlock()
   730  	gotnn, countnn, culpritsnn := k.gotNearestNeighbours(pp.NNSet)
   731  	knownn := k.knowNearestNeighbours(pp.NNSet)
   732  	full := k.full(pp.EmptyBins)
   733  	log.Trace(fmt.Sprintf("%08x: healthy: knowNNs: %v, gotNNs: %v, full: %v\n", k.BaseAddr()[:4], knownn, gotnn, full))
   734  	return &Health{knownn, gotnn, countnn, culpritsnn, full, k.string()}
   735  }
   736  
   737  func logEmptyBins(ebs []int) string {
   738  	var ebss []string
   739  	for _, eb := range ebs {
   740  		ebss = append(ebss, fmt.Sprintf("%d", eb))
   741  	}
   742  	return strings.Join(ebss, ", ")
   743  }