github.com/etsc3259/etsc@v0.0.0-20190109113336-a9c2c10f9c95/swarm/network/kademlia.go (about)

     1  // Copyright 2017 The go-etsc Authors
     2  // This file is part of the go-etsc library.
     3  //
     4  // The go-etsc 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-etsc 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-etsc 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/ETSC3259/etsc/common"
    28  	"github.com/ETSC3259/etsc/swarm/log"
    29  	"github.com/ETSC3259/etsc/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 && !p.BzzPeer.LightNode {
   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  	if !p.BzzPeer.LightNode {
   333  		k.addrs, _, _, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val {
   334  			// v cannot be nil, must check otherwise we overwrite entry
   335  			if v == nil {
   336  				panic(fmt.Sprintf("connected peer not found %v", p))
   337  			}
   338  			del = true
   339  			return newEntry(p.BzzAddr)
   340  		})
   341  	} else {
   342  		del = true
   343  	}
   344  
   345  	if del {
   346  		k.conns, _, _, _ = pot.Swap(k.conns, p, pof, func(_ pot.Val) pot.Val {
   347  			// v cannot be nil, but no need to check
   348  			return nil
   349  		})
   350  		// send new address count value only if the peer is deleted
   351  		if k.addrCountC != nil {
   352  			k.addrCountC <- k.addrs.Size()
   353  		}
   354  		k.sendNeighbourhoodDepthChange()
   355  	}
   356  }
   357  
   358  func (k *Kademlia) EachBin(base []byte, pof pot.Pof, o int, eachBinFunc func(conn *Peer, po int) bool) {
   359  	k.lock.RLock()
   360  	defer k.lock.RUnlock()
   361  
   362  	var startPo int
   363  	var endPo int
   364  	kadDepth := k.neighbourhoodDepth()
   365  
   366  	k.conns.EachBin(base, pof, o, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
   367  		if startPo > 0 && endPo != k.MaxProxDisplay {
   368  			startPo = endPo + 1
   369  		}
   370  		if po < kadDepth {
   371  			endPo = po
   372  		} else {
   373  			endPo = k.MaxProxDisplay
   374  		}
   375  
   376  		for bin := startPo; bin <= endPo; bin++ {
   377  			f(func(val pot.Val, _ int) bool {
   378  				return eachBinFunc(val.(*Peer), bin)
   379  			})
   380  		}
   381  		return true
   382  	})
   383  }
   384  
   385  // EachConn is an iterator with args (base, po, f) applies f to each live peer
   386  // that has proximity order po or less as measured from the base
   387  // if base is nil, kademlia base address is used
   388  func (k *Kademlia) EachConn(base []byte, o int, f func(*Peer, int, bool) bool) {
   389  	k.lock.RLock()
   390  	defer k.lock.RUnlock()
   391  	k.eachConn(base, o, f)
   392  }
   393  
   394  func (k *Kademlia) eachConn(base []byte, o int, f func(*Peer, int, bool) bool) {
   395  	if len(base) == 0 {
   396  		base = k.base
   397  	}
   398  	depth := k.neighbourhoodDepth()
   399  	k.conns.EachNeighbour(base, pof, func(val pot.Val, po int) bool {
   400  		if po > o {
   401  			return true
   402  		}
   403  		return f(val.(*Peer), po, po >= depth)
   404  	})
   405  }
   406  
   407  // EachAddr called with (base, po, f) is an iterator applying f to each known peer
   408  // that has proximity order po or less as measured from the base
   409  // if base is nil, kademlia base address is used
   410  func (k *Kademlia) EachAddr(base []byte, o int, f func(*BzzAddr, int, bool) bool) {
   411  	k.lock.RLock()
   412  	defer k.lock.RUnlock()
   413  	k.eachAddr(base, o, f)
   414  }
   415  
   416  func (k *Kademlia) eachAddr(base []byte, o int, f func(*BzzAddr, int, bool) bool) {
   417  	if len(base) == 0 {
   418  		base = k.base
   419  	}
   420  	depth := k.neighbourhoodDepth()
   421  	k.addrs.EachNeighbour(base, pof, func(val pot.Val, po int) bool {
   422  		if po > o {
   423  			return true
   424  		}
   425  		return f(val.(*entry).BzzAddr, po, po >= depth)
   426  	})
   427  }
   428  
   429  // neighbourhoodDepth returns the proximity order that defines the distance of
   430  // the nearest neighbour set with cardinality >= MinProxBinSize
   431  // if there is altogether less than MinProxBinSize peers it returns 0
   432  // caller must hold the lock
   433  func (k *Kademlia) neighbourhoodDepth() (depth int) {
   434  	if k.conns.Size() < k.MinProxBinSize {
   435  		return 0
   436  	}
   437  	var size int
   438  	f := func(v pot.Val, i int) bool {
   439  		size++
   440  		depth = i
   441  		return size < k.MinProxBinSize
   442  	}
   443  	k.conns.EachNeighbour(k.base, pof, f)
   444  	return depth
   445  }
   446  
   447  // callable decides if an address entry represents a callable peer
   448  func (k *Kademlia) callable(e *entry) bool {
   449  	// not callable if peer is live or exceeded maxRetries
   450  	if e.conn != nil || e.retries > k.MaxRetries {
   451  		return false
   452  	}
   453  	// calculate the allowed number of retries based on time lapsed since last seen
   454  	timeAgo := int64(time.Since(e.seenAt))
   455  	div := int64(k.RetryExponent)
   456  	div += (150000 - rand.Int63n(300000)) * div / 1000000
   457  	var retries int
   458  	for delta := timeAgo; delta > k.RetryInterval; delta /= div {
   459  		retries++
   460  	}
   461  	// this is never called concurrently, so safe to increment
   462  	// peer can be retried again
   463  	if retries < e.retries {
   464  		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))
   465  		return false
   466  	}
   467  	// function to sanction or prevent suggesting a peer
   468  	if k.Reachable != nil && !k.Reachable(e.BzzAddr) {
   469  		log.Trace(fmt.Sprintf("%08x: peer %v is temporarily not callable", k.BaseAddr()[:4], e))
   470  		return false
   471  	}
   472  	e.retries++
   473  	log.Trace(fmt.Sprintf("%08x: peer %v is callable", k.BaseAddr()[:4], e))
   474  
   475  	return true
   476  }
   477  
   478  // BaseAddr return the kademlia base address
   479  func (k *Kademlia) BaseAddr() []byte {
   480  	return k.base
   481  }
   482  
   483  // String returns kademlia table + kaddb table displayed with ascii
   484  func (k *Kademlia) String() string {
   485  	k.lock.RLock()
   486  	defer k.lock.RUnlock()
   487  	return k.string()
   488  }
   489  
   490  // string returns kademlia table + kaddb table displayed with ascii
   491  // caller must hold the lock
   492  func (k *Kademlia) string() string {
   493  	wsrow := "                          "
   494  	var rows []string
   495  
   496  	rows = append(rows, "=========================================================================")
   497  	rows = append(rows, fmt.Sprintf("%v KΛÐΞMLIΛ hive: queen's address: %x", time.Now().UTC().Format(time.UnixDate), k.BaseAddr()[:3]))
   498  	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))
   499  
   500  	liverows := make([]string, k.MaxProxDisplay)
   501  	peersrows := make([]string, k.MaxProxDisplay)
   502  
   503  	depth := k.neighbourhoodDepth()
   504  	rest := k.conns.Size()
   505  	k.conns.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
   506  		var rowlen int
   507  		if po >= k.MaxProxDisplay {
   508  			po = k.MaxProxDisplay - 1
   509  		}
   510  		row := []string{fmt.Sprintf("%2d", size)}
   511  		rest -= size
   512  		f(func(val pot.Val, vpo int) bool {
   513  			e := val.(*Peer)
   514  			row = append(row, fmt.Sprintf("%x", e.Address()[:2]))
   515  			rowlen++
   516  			return rowlen < 4
   517  		})
   518  		r := strings.Join(row, " ")
   519  		r = r + wsrow
   520  		liverows[po] = r[:31]
   521  		return true
   522  	})
   523  
   524  	k.addrs.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
   525  		var rowlen int
   526  		if po >= k.MaxProxDisplay {
   527  			po = k.MaxProxDisplay - 1
   528  		}
   529  		if size < 0 {
   530  			panic("wtf")
   531  		}
   532  		row := []string{fmt.Sprintf("%2d", size)}
   533  		// we are displaying live peers too
   534  		f(func(val pot.Val, vpo int) bool {
   535  			e := val.(*entry)
   536  			row = append(row, Label(e))
   537  			rowlen++
   538  			return rowlen < 4
   539  		})
   540  		peersrows[po] = strings.Join(row, " ")
   541  		return true
   542  	})
   543  
   544  	for i := 0; i < k.MaxProxDisplay; i++ {
   545  		if i == depth {
   546  			rows = append(rows, fmt.Sprintf("============ DEPTH: %d ==========================================", i))
   547  		}
   548  		left := liverows[i]
   549  		right := peersrows[i]
   550  		if len(left) == 0 {
   551  			left = " 0                             "
   552  		}
   553  		if len(right) == 0 {
   554  			right = " 0"
   555  		}
   556  		rows = append(rows, fmt.Sprintf("%03d %v | %v", i, left, right))
   557  	}
   558  	rows = append(rows, "=========================================================================")
   559  	return "\n" + strings.Join(rows, "\n")
   560  }
   561  
   562  // PeerPot keeps info about expected nearest neighbours and empty bins
   563  // used for testing only
   564  type PeerPot struct {
   565  	NNSet     [][]byte
   566  	EmptyBins []int
   567  }
   568  
   569  // NewPeerPotMap creates a map of pot record of *BzzAddr with keys
   570  // as hexadecimal representations of the address.
   571  // used for testing only
   572  func NewPeerPotMap(kadMinProxSize int, addrs [][]byte) map[string]*PeerPot {
   573  	// create a table of all nodes for health check
   574  	np := pot.NewPot(nil, 0)
   575  	for _, addr := range addrs {
   576  		np, _, _ = pot.Add(np, addr, pof)
   577  	}
   578  	ppmap := make(map[string]*PeerPot)
   579  
   580  	for i, a := range addrs {
   581  		pl := 256
   582  		prev := 256
   583  		var emptyBins []int
   584  		var nns [][]byte
   585  		np.EachNeighbour(addrs[i], pof, func(val pot.Val, po int) bool {
   586  			a := val.([]byte)
   587  			if po == 256 {
   588  				return true
   589  			}
   590  			if pl == 256 || pl == po {
   591  				nns = append(nns, a)
   592  			}
   593  			if pl == 256 && len(nns) >= kadMinProxSize {
   594  				pl = po
   595  				prev = po
   596  			}
   597  			if prev < pl {
   598  				for j := prev; j > po; j-- {
   599  					emptyBins = append(emptyBins, j)
   600  				}
   601  			}
   602  			prev = po - 1
   603  			return true
   604  		})
   605  		for j := prev; j >= 0; j-- {
   606  			emptyBins = append(emptyBins, j)
   607  		}
   608  		log.Trace(fmt.Sprintf("%x NNS: %s", addrs[i][:4], LogAddrs(nns)))
   609  		ppmap[common.Bytes2Hex(a)] = &PeerPot{nns, emptyBins}
   610  	}
   611  	return ppmap
   612  }
   613  
   614  // saturation returns the lowest proximity order that the bin for that order
   615  // has less than n peers
   616  // It is used in Healthy function for testing only
   617  func (k *Kademlia) saturation(n int) int {
   618  	prev := -1
   619  	k.addrs.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
   620  		prev++
   621  		return prev == po && size >= n
   622  	})
   623  	depth := k.neighbourhoodDepth()
   624  	if depth < prev {
   625  		return depth
   626  	}
   627  	return prev
   628  }
   629  
   630  // full returns true if all required bins have connected peers.
   631  // It is used in Healthy function for testing only
   632  func (k *Kademlia) full(emptyBins []int) (full bool) {
   633  	prev := 0
   634  	e := len(emptyBins)
   635  	ok := true
   636  	depth := k.neighbourhoodDepth()
   637  	k.conns.EachBin(k.base, pof, 0, func(po, _ int, _ func(func(val pot.Val, i int) bool) bool) bool {
   638  		if prev == depth+1 {
   639  			return true
   640  		}
   641  		for i := prev; i < po; i++ {
   642  			e--
   643  			if e < 0 {
   644  				ok = false
   645  				return false
   646  			}
   647  			if emptyBins[e] != i {
   648  				log.Trace(fmt.Sprintf("%08x po: %d, i: %d, e: %d, emptybins: %v", k.BaseAddr()[:4], po, i, e, logEmptyBins(emptyBins)))
   649  				if emptyBins[e] < i {
   650  					panic("incorrect peerpot")
   651  				}
   652  				ok = false
   653  				return false
   654  			}
   655  		}
   656  		prev = po + 1
   657  		return true
   658  	})
   659  	if !ok {
   660  		return false
   661  	}
   662  	return e == 0
   663  }
   664  
   665  // knowNearestNeighbours tests if all known nearest neighbours given as arguments
   666  // are found in the addressbook
   667  // It is used in Healthy function for testing only
   668  func (k *Kademlia) knowNearestNeighbours(peers [][]byte) bool {
   669  	pm := make(map[string]bool)
   670  
   671  	k.eachAddr(nil, 255, func(p *BzzAddr, po int, nn bool) bool {
   672  		if !nn {
   673  			return false
   674  		}
   675  		pk := fmt.Sprintf("%x", p.Address())
   676  		pm[pk] = true
   677  		return true
   678  	})
   679  	for _, p := range peers {
   680  		pk := fmt.Sprintf("%x", p)
   681  		if !pm[pk] {
   682  			log.Trace(fmt.Sprintf("%08x: known nearest neighbour %s not found", k.BaseAddr()[:4], pk[:8]))
   683  			return false
   684  		}
   685  	}
   686  	return true
   687  }
   688  
   689  // gotNearestNeighbours tests if all known nearest neighbours given as arguments
   690  // are connected peers
   691  // It is used in Healthy function for testing only
   692  func (k *Kademlia) gotNearestNeighbours(peers [][]byte) (got bool, n int, missing [][]byte) {
   693  	pm := make(map[string]bool)
   694  
   695  	k.eachConn(nil, 255, func(p *Peer, po int, nn bool) bool {
   696  		if !nn {
   697  			return false
   698  		}
   699  		pk := fmt.Sprintf("%x", p.Address())
   700  		pm[pk] = true
   701  		return true
   702  	})
   703  	var gots int
   704  	var culprits [][]byte
   705  	for _, p := range peers {
   706  		pk := fmt.Sprintf("%x", p)
   707  		if pm[pk] {
   708  			gots++
   709  		} else {
   710  			log.Trace(fmt.Sprintf("%08x: ExpNN: %s not found", k.BaseAddr()[:4], pk[:8]))
   711  			culprits = append(culprits, p)
   712  		}
   713  	}
   714  	return gots == len(peers), gots, culprits
   715  }
   716  
   717  // Health state of the Kademlia
   718  // used for testing only
   719  type Health struct {
   720  	KnowNN     bool     // whether node knows all its nearest neighbours
   721  	GotNN      bool     // whether node is connected to all its nearest neighbours
   722  	CountNN    int      // amount of nearest neighbors connected to
   723  	CulpritsNN [][]byte // which known NNs are missing
   724  	Full       bool     // whether node has a peer in each kademlia bin (where there is such a peer)
   725  	Hive       string
   726  }
   727  
   728  // Healthy reports the health state of the kademlia connectivity
   729  // returns a Health struct
   730  // used for testing only
   731  func (k *Kademlia) Healthy(pp *PeerPot) *Health {
   732  	k.lock.RLock()
   733  	defer k.lock.RUnlock()
   734  	gotnn, countnn, culpritsnn := k.gotNearestNeighbours(pp.NNSet)
   735  	knownn := k.knowNearestNeighbours(pp.NNSet)
   736  	full := k.full(pp.EmptyBins)
   737  	log.Trace(fmt.Sprintf("%08x: healthy: knowNNs: %v, gotNNs: %v, full: %v\n", k.BaseAddr()[:4], knownn, gotnn, full))
   738  	return &Health{knownn, gotnn, countnn, culpritsnn, full, k.string()}
   739  }
   740  
   741  func logEmptyBins(ebs []int) string {
   742  	var ebss []string
   743  	for _, eb := range ebs {
   744  		ebss = append(ebss, fmt.Sprintf("%d", eb))
   745  	}
   746  	return strings.Join(ebss, ", ")
   747  }