github.com/rayrapetyan/go-ethereum@v1.8.21/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  	NeighbourhoodSize 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 `json:"-"`
    66  }
    67  
    68  // NewKadParams returns a params struct with default values
    69  func NewKadParams() *KadParams {
    70  	return &KadParams{
    71  		MaxProxDisplay:    16,
    72  		NeighbourhoodSize: 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 := depthForPot(k.conns, k.NeighbourhoodSize, k.base)
   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) 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) 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) 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())
   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  // TODO: Why is this exported, and if it should be; why can't we have more subscribers than one?
   293  func (k *Kademlia) NeighbourhoodDepthC() <-chan int {
   294  	k.lock.Lock()
   295  	defer k.lock.Unlock()
   296  	if k.nDepthC == nil {
   297  		k.nDepthC = make(chan int)
   298  	}
   299  	return k.nDepthC
   300  }
   301  
   302  // sendNeighbourhoodDepthChange sends new neighbourhood depth to k.nDepth channel
   303  // if it is initialized.
   304  func (k *Kademlia) sendNeighbourhoodDepthChange() {
   305  	// nDepthC is initialized when NeighbourhoodDepthC is called and returned by it.
   306  	// It provides signaling of neighbourhood depth change.
   307  	// This part of the code is sending new neighbourhood depth to nDepthC if that condition is met.
   308  	if k.nDepthC != nil {
   309  		nDepth := depthForPot(k.conns, k.NeighbourhoodSize, k.base)
   310  		if nDepth != k.nDepth {
   311  			k.nDepth = nDepth
   312  			k.nDepthC <- nDepth
   313  		}
   314  	}
   315  }
   316  
   317  // AddrCountC returns the channel that sends a new
   318  // address count value on each change.
   319  // Not receiving from the returned channel will block Register function
   320  // when address count value changes.
   321  func (k *Kademlia) AddrCountC() <-chan int {
   322  	if k.addrCountC == nil {
   323  		k.addrCountC = make(chan int)
   324  	}
   325  	return k.addrCountC
   326  }
   327  
   328  // Off removes a peer from among live peers
   329  func (k *Kademlia) Off(p *Peer) {
   330  	k.lock.Lock()
   331  	defer k.lock.Unlock()
   332  	var del bool
   333  	if !p.BzzPeer.LightNode {
   334  		k.addrs, _, _, _ = pot.Swap(k.addrs, p, Pof, func(v pot.Val) pot.Val {
   335  			// v cannot be nil, must check otherwise we overwrite entry
   336  			if v == nil {
   337  				panic(fmt.Sprintf("connected peer not found %v", p))
   338  			}
   339  			del = true
   340  			return newEntry(p.BzzAddr)
   341  		})
   342  	} else {
   343  		del = true
   344  	}
   345  
   346  	if del {
   347  		k.conns, _, _, _ = pot.Swap(k.conns, p, Pof, func(_ pot.Val) pot.Val {
   348  			// v cannot be nil, but no need to check
   349  			return nil
   350  		})
   351  		// send new address count value only if the peer is deleted
   352  		if k.addrCountC != nil {
   353  			k.addrCountC <- k.addrs.Size()
   354  		}
   355  		k.sendNeighbourhoodDepthChange()
   356  	}
   357  }
   358  
   359  // EachConn is an iterator with args (base, po, f) applies f to each live peer
   360  // that has proximity order po or less as measured from the base
   361  // if base is nil, kademlia base address is used
   362  func (k *Kademlia) EachConn(base []byte, o int, f func(*Peer, int) bool) {
   363  	k.lock.RLock()
   364  	defer k.lock.RUnlock()
   365  	k.eachConn(base, o, f)
   366  }
   367  
   368  func (k *Kademlia) eachConn(base []byte, o int, f func(*Peer, int) bool) {
   369  	if len(base) == 0 {
   370  		base = k.base
   371  	}
   372  	k.conns.EachNeighbour(base, Pof, func(val pot.Val, po int) bool {
   373  		if po > o {
   374  			return true
   375  		}
   376  		return f(val.(*Peer), po)
   377  	})
   378  }
   379  
   380  // EachAddr called with (base, po, f) is an iterator applying f to each known peer
   381  // that has proximity order o or less as measured from the base
   382  // if base is nil, kademlia base address is used
   383  func (k *Kademlia) EachAddr(base []byte, o int, f func(*BzzAddr, int) bool) {
   384  	k.lock.RLock()
   385  	defer k.lock.RUnlock()
   386  	k.eachAddr(base, o, f)
   387  }
   388  
   389  func (k *Kademlia) eachAddr(base []byte, o int, f func(*BzzAddr, int) bool) {
   390  	if len(base) == 0 {
   391  		base = k.base
   392  	}
   393  	k.addrs.EachNeighbour(base, Pof, func(val pot.Val, po int) bool {
   394  		if po > o {
   395  			return true
   396  		}
   397  		return f(val.(*entry).BzzAddr, po)
   398  	})
   399  }
   400  
   401  func (k *Kademlia) NeighbourhoodDepth() (depth int) {
   402  	k.lock.RLock()
   403  	defer k.lock.RUnlock()
   404  	return depthForPot(k.conns, k.NeighbourhoodSize, k.base)
   405  }
   406  
   407  // depthForPot returns the proximity order that defines the distance of
   408  // the nearest neighbour set with cardinality >= NeighbourhoodSize
   409  // if there is altogether less than NeighbourhoodSize peers it returns 0
   410  // caller must hold the lock
   411  func depthForPot(p *pot.Pot, neighbourhoodSize int, pivotAddr []byte) (depth int) {
   412  	if p.Size() <= neighbourhoodSize {
   413  		return 0
   414  	}
   415  
   416  	// total number of peers in iteration
   417  	var size int
   418  
   419  	// determining the depth is a two-step process
   420  	// first we find the proximity bin of the shallowest of the NeighbourhoodSize peers
   421  	// the numeric value of depth cannot be higher than this
   422  	var maxDepth int
   423  
   424  	f := func(v pot.Val, i int) bool {
   425  		// po == 256 means that addr is the pivot address(self)
   426  		if i == 256 {
   427  			return true
   428  		}
   429  		size++
   430  
   431  		// this means we have all nn-peers.
   432  		// depth is by default set to the bin of the farthest nn-peer
   433  		if size == neighbourhoodSize {
   434  			maxDepth = i
   435  			return false
   436  		}
   437  
   438  		return true
   439  	}
   440  	p.EachNeighbour(pivotAddr, Pof, f)
   441  
   442  	// the second step is to test for empty bins in order from shallowest to deepest
   443  	// if an empty bin is found, this will be the actual depth
   444  	// we stop iterating if we hit the maxDepth determined in the first step
   445  	p.EachBin(pivotAddr, Pof, 0, func(po int, _ int, f func(func(pot.Val) bool) bool) bool {
   446  		if po == depth {
   447  			if maxDepth == depth {
   448  				return false
   449  			}
   450  			depth++
   451  			return true
   452  		}
   453  		return false
   454  	})
   455  
   456  	return depth
   457  }
   458  
   459  // callable decides if an address entry represents a callable peer
   460  func (k *Kademlia) callable(e *entry) bool {
   461  	// not callable if peer is live or exceeded maxRetries
   462  	if e.conn != nil || e.retries > k.MaxRetries {
   463  		return false
   464  	}
   465  	// calculate the allowed number of retries based on time lapsed since last seen
   466  	timeAgo := int64(time.Since(e.seenAt))
   467  	div := int64(k.RetryExponent)
   468  	div += (150000 - rand.Int63n(300000)) * div / 1000000
   469  	var retries int
   470  	for delta := timeAgo; delta > k.RetryInterval; delta /= div {
   471  		retries++
   472  	}
   473  	// this is never called concurrently, so safe to increment
   474  	// peer can be retried again
   475  	if retries < e.retries {
   476  		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))
   477  		return false
   478  	}
   479  	// function to sanction or prevent suggesting a peer
   480  	if k.Reachable != nil && !k.Reachable(e.BzzAddr) {
   481  		log.Trace(fmt.Sprintf("%08x: peer %v is temporarily not callable", k.BaseAddr()[:4], e))
   482  		return false
   483  	}
   484  	e.retries++
   485  	log.Trace(fmt.Sprintf("%08x: peer %v is callable", k.BaseAddr()[:4], e))
   486  
   487  	return true
   488  }
   489  
   490  // BaseAddr return the kademlia base address
   491  func (k *Kademlia) BaseAddr() []byte {
   492  	return k.base
   493  }
   494  
   495  // String returns kademlia table + kaddb table displayed with ascii
   496  func (k *Kademlia) String() string {
   497  	k.lock.RLock()
   498  	defer k.lock.RUnlock()
   499  	return k.string()
   500  }
   501  
   502  // string returns kademlia table + kaddb table displayed with ascii
   503  // caller must hold the lock
   504  func (k *Kademlia) string() string {
   505  	wsrow := "                          "
   506  	var rows []string
   507  
   508  	rows = append(rows, "=========================================================================")
   509  	rows = append(rows, fmt.Sprintf("%v KΛÐΞMLIΛ hive: queen's address: %x", time.Now().UTC().Format(time.UnixDate), k.BaseAddr()[:3]))
   510  	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))
   511  
   512  	liverows := make([]string, k.MaxProxDisplay)
   513  	peersrows := make([]string, k.MaxProxDisplay)
   514  
   515  	depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base)
   516  	rest := k.conns.Size()
   517  	k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool {
   518  		var rowlen int
   519  		if po >= k.MaxProxDisplay {
   520  			po = k.MaxProxDisplay - 1
   521  		}
   522  		row := []string{fmt.Sprintf("%2d", size)}
   523  		rest -= size
   524  		f(func(val pot.Val) bool {
   525  			e := val.(*Peer)
   526  			row = append(row, fmt.Sprintf("%x", e.Address()[:2]))
   527  			rowlen++
   528  			return rowlen < 4
   529  		})
   530  		r := strings.Join(row, " ")
   531  		r = r + wsrow
   532  		liverows[po] = r[:31]
   533  		return true
   534  	})
   535  
   536  	k.addrs.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool {
   537  		var rowlen int
   538  		if po >= k.MaxProxDisplay {
   539  			po = k.MaxProxDisplay - 1
   540  		}
   541  		if size < 0 {
   542  			panic("wtf")
   543  		}
   544  		row := []string{fmt.Sprintf("%2d", size)}
   545  		// we are displaying live peers too
   546  		f(func(val pot.Val) bool {
   547  			e := val.(*entry)
   548  			row = append(row, Label(e))
   549  			rowlen++
   550  			return rowlen < 4
   551  		})
   552  		peersrows[po] = strings.Join(row, " ")
   553  		return true
   554  	})
   555  
   556  	for i := 0; i < k.MaxProxDisplay; i++ {
   557  		if i == depth {
   558  			rows = append(rows, fmt.Sprintf("============ DEPTH: %d ==========================================", i))
   559  		}
   560  		left := liverows[i]
   561  		right := peersrows[i]
   562  		if len(left) == 0 {
   563  			left = " 0                             "
   564  		}
   565  		if len(right) == 0 {
   566  			right = " 0"
   567  		}
   568  		rows = append(rows, fmt.Sprintf("%03d %v | %v", i, left, right))
   569  	}
   570  	rows = append(rows, "=========================================================================")
   571  	return "\n" + strings.Join(rows, "\n")
   572  }
   573  
   574  // PeerPot keeps info about expected nearest neighbours
   575  // used for testing only
   576  // TODO move to separate testing tools file
   577  type PeerPot struct {
   578  	NNSet [][]byte
   579  }
   580  
   581  // NewPeerPotMap creates a map of pot record of *BzzAddr with keys
   582  // as hexadecimal representations of the address.
   583  // the NeighbourhoodSize of the passed kademlia is used
   584  // used for testing only
   585  // TODO move to separate testing tools file
   586  func NewPeerPotMap(neighbourhoodSize int, addrs [][]byte) map[string]*PeerPot {
   587  
   588  	// create a table of all nodes for health check
   589  	np := pot.NewPot(nil, 0)
   590  	for _, addr := range addrs {
   591  		np, _, _ = pot.Add(np, addr, Pof)
   592  	}
   593  	ppmap := make(map[string]*PeerPot)
   594  
   595  	// generate an allknowing source of truth for connections
   596  	// for every kademlia passed
   597  	for i, a := range addrs {
   598  
   599  		// actual kademlia depth
   600  		depth := depthForPot(np, neighbourhoodSize, a)
   601  
   602  		// all nn-peers
   603  		var nns [][]byte
   604  
   605  		// iterate through the neighbours, going from the deepest to the shallowest
   606  		np.EachNeighbour(a, Pof, func(val pot.Val, po int) bool {
   607  			addr := val.([]byte)
   608  			// po == 256 means that addr is the pivot address(self)
   609  			// we do not include self in the map
   610  			if po == 256 {
   611  				return true
   612  			}
   613  			// append any neighbors found
   614  			// a neighbor is any peer in or deeper than the depth
   615  			if po >= depth {
   616  				nns = append(nns, addr)
   617  				return true
   618  			}
   619  			return false
   620  		})
   621  
   622  		log.Trace(fmt.Sprintf("%x PeerPotMap NNS: %s", addrs[i][:4], LogAddrs(nns)))
   623  		ppmap[common.Bytes2Hex(a)] = &PeerPot{
   624  			NNSet: nns,
   625  		}
   626  	}
   627  	return ppmap
   628  }
   629  
   630  // saturation iterates through all peers and
   631  // returns the smallest po value in which the node has less than n peers
   632  // if the iterator reaches depth, then value for depth is returned
   633  // TODO move to separate testing tools file
   634  // TODO this function will stop at the first bin with less than MinBinSize peers, even if there are empty bins between that bin and the depth. This may not be correct behavior
   635  func (k *Kademlia) saturation() int {
   636  	prev := -1
   637  	k.addrs.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool {
   638  		prev++
   639  		return prev == po && size >= k.MinBinSize
   640  	})
   641  	// TODO evaluate whether this check cannot just as well be done within the eachbin
   642  	depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base)
   643  	if depth < prev {
   644  		return depth
   645  	}
   646  	return prev
   647  }
   648  
   649  // knowNeighbours tests if all neighbours in the peerpot
   650  // are found among the peers known to the kademlia
   651  // It is used in Healthy function for testing only
   652  // TODO move to separate testing tools file
   653  func (k *Kademlia) knowNeighbours(addrs [][]byte) (got bool, n int, missing [][]byte) {
   654  	pm := make(map[string]bool)
   655  	depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base)
   656  	// create a map with all peers at depth and deeper known in the kademlia
   657  	k.eachAddr(nil, 255, func(p *BzzAddr, po int) bool {
   658  		// in order deepest to shallowest compared to the kademlia base address
   659  		// all bins (except self) are included (0 <= bin <= 255)
   660  		if po < depth {
   661  			return false
   662  		}
   663  		pk := common.Bytes2Hex(p.Address())
   664  		pm[pk] = true
   665  		return true
   666  	})
   667  
   668  	// iterate through nearest neighbors in the peerpot map
   669  	// if we can't find the neighbor in the map we created above
   670  	// then we don't know all our neighbors
   671  	// (which sadly is all too common in modern society)
   672  	var gots int
   673  	var culprits [][]byte
   674  	for _, p := range addrs {
   675  		pk := common.Bytes2Hex(p)
   676  		if pm[pk] {
   677  			gots++
   678  		} else {
   679  			log.Trace(fmt.Sprintf("%08x: known nearest neighbour %s not found", k.base, pk))
   680  			culprits = append(culprits, p)
   681  		}
   682  	}
   683  	return gots == len(addrs), gots, culprits
   684  }
   685  
   686  // connectedNeighbours tests if all neighbours in the peerpot
   687  // are currently connected in the kademlia
   688  // It is used in Healthy function for testing only
   689  func (k *Kademlia) connectedNeighbours(peers [][]byte) (got bool, n int, missing [][]byte) {
   690  	pm := make(map[string]bool)
   691  
   692  	// create a map with all peers at depth and deeper that are connected in the kademlia
   693  	// in order deepest to shallowest compared to the kademlia base address
   694  	// all bins (except self) are included (0 <= bin <= 255)
   695  	depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base)
   696  	k.eachConn(nil, 255, func(p *Peer, po int) bool {
   697  		if po < depth {
   698  			return false
   699  		}
   700  		pk := common.Bytes2Hex(p.Address())
   701  		pm[pk] = true
   702  		return true
   703  	})
   704  
   705  	// iterate through nearest neighbors in the peerpot map
   706  	// if we can't find the neighbor in the map we created above
   707  	// then we don't know all our neighbors
   708  	var gots int
   709  	var culprits [][]byte
   710  	for _, p := range peers {
   711  		pk := common.Bytes2Hex(p)
   712  		if pm[pk] {
   713  			gots++
   714  		} else {
   715  			log.Trace(fmt.Sprintf("%08x: ExpNN: %s not found", k.base, pk))
   716  			culprits = append(culprits, p)
   717  		}
   718  	}
   719  	return gots == len(peers), gots, culprits
   720  }
   721  
   722  // Health state of the Kademlia
   723  // used for testing only
   724  type Health struct {
   725  	KnowNN           bool     // whether node knows all its neighbours
   726  	CountKnowNN      int      // amount of neighbors known
   727  	MissingKnowNN    [][]byte // which neighbours we should have known but we don't
   728  	ConnectNN        bool     // whether node is connected to all its neighbours
   729  	CountConnectNN   int      // amount of neighbours connected to
   730  	MissingConnectNN [][]byte // which neighbours we should have been connected to but we're not
   731  	Saturated        bool     // whether we are connected to all the peers we would have liked to
   732  	Hive             string
   733  }
   734  
   735  // Healthy reports the health state of the kademlia connectivity
   736  //
   737  // The PeerPot argument provides an all-knowing view of the network
   738  // The resulting Health object is a result of comparisons between
   739  // what is the actual composition of the kademlia in question (the receiver), and
   740  // what SHOULD it have been when we take all we know about the network into consideration.
   741  //
   742  // used for testing only
   743  func (k *Kademlia) Healthy(pp *PeerPot) *Health {
   744  	k.lock.RLock()
   745  	defer k.lock.RUnlock()
   746  	gotnn, countgotnn, culpritsgotnn := k.connectedNeighbours(pp.NNSet)
   747  	knownn, countknownn, culpritsknownn := k.knowNeighbours(pp.NNSet)
   748  	depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base)
   749  	saturated := k.saturation() < depth
   750  	log.Trace(fmt.Sprintf("%08x: healthy: knowNNs: %v, gotNNs: %v, saturated: %v\n", k.base, knownn, gotnn, saturated))
   751  	return &Health{
   752  		KnowNN:           knownn,
   753  		CountKnowNN:      countknownn,
   754  		MissingKnowNN:    culpritsknownn,
   755  		ConnectNN:        gotnn,
   756  		CountConnectNN:   countgotnn,
   757  		MissingConnectNN: culpritsgotnn,
   758  		Saturated:        saturated,
   759  		Hive:             k.string(),
   760  	}
   761  }