github.com/ethersphere/bee/v2@v2.2.0/pkg/topology/kademlia/kademlia.go (about)

     1  // Copyright 2020 The Swarm Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package kademlia
     6  
     7  import (
     8  	"context"
     9  	random "crypto/rand"
    10  	"encoding/json"
    11  	"errors"
    12  	"fmt"
    13  	"math/big"
    14  	"math/rand"
    15  	"path/filepath"
    16  	"sync"
    17  	"time"
    18  
    19  	"github.com/ethersphere/bee/v2/pkg/addressbook"
    20  	"github.com/ethersphere/bee/v2/pkg/discovery"
    21  	"github.com/ethersphere/bee/v2/pkg/log"
    22  	"github.com/ethersphere/bee/v2/pkg/p2p"
    23  	"github.com/ethersphere/bee/v2/pkg/shed"
    24  	"github.com/ethersphere/bee/v2/pkg/swarm"
    25  	"github.com/ethersphere/bee/v2/pkg/topology"
    26  	im "github.com/ethersphere/bee/v2/pkg/topology/kademlia/internal/metrics"
    27  	"github.com/ethersphere/bee/v2/pkg/topology/kademlia/internal/waitnext"
    28  	"github.com/ethersphere/bee/v2/pkg/topology/pslice"
    29  	"github.com/ethersphere/bee/v2/pkg/util/ioutil"
    30  	ma "github.com/multiformats/go-multiaddr"
    31  	"golang.org/x/sync/errgroup"
    32  )
    33  
    34  // loggerName is the tree path name of the logger for this package.
    35  const loggerName = "kademlia"
    36  
    37  const (
    38  	maxConnAttempts     = 1 // when there is maxConnAttempts failed connect calls for a given peer it is considered non-connectable
    39  	maxBootNodeAttempts = 3 // how many attempts to dial to boot-nodes before giving up
    40  	maxNeighborAttempts = 3 // how many attempts to dial to boot-nodes before giving up
    41  
    42  	addPeerBatchSize = 500
    43  
    44  	// To avoid context.Timeout errors during network failure, the value of
    45  	// the peerConnectionAttemptTimeout constant must be equal to or greater
    46  	// than 5 seconds (empirically verified).
    47  	peerConnectionAttemptTimeout = 15 * time.Second // timeout for establishing a new connection with peer.
    48  )
    49  
    50  // Default option values
    51  const (
    52  	defaultBitSuffixLength             = 4 // the number of bits used to create pseudo addresses for balancing, 2^4, 16 addresses
    53  	defaultLowWaterMark                = 3 // the number of peers in consecutive deepest bins that constitute as nearest neighbours
    54  	defaultSaturationPeers             = 8
    55  	defaultOverSaturationPeers         = 18
    56  	defaultBootNodeOverSaturationPeers = 20
    57  	defaultShortRetry                  = 30 * time.Second
    58  	defaultTimeToRetry                 = 2 * defaultShortRetry
    59  	defaultPruneWakeup                 = 5 * time.Minute
    60  	defaultBroadcastBinSize            = 2
    61  )
    62  
    63  var (
    64  	errOverlayMismatch   = errors.New("overlay mismatch")
    65  	errPruneEntry        = errors.New("prune entry")
    66  	errEmptyBin          = errors.New("empty bin")
    67  	errAnnounceLightNode = errors.New("announcing light node")
    68  )
    69  
    70  type (
    71  	binSaturationFunc  func(bin uint8, connected *pslice.PSlice, exclude peerExcludeFunc) bool
    72  	sanctionedPeerFunc func(peer swarm.Address) bool
    73  	pruneFunc          func(depth uint8)
    74  	pruneCountFunc     func(bin uint8, connected *pslice.PSlice, exclude peerExcludeFunc) (int, int)
    75  	staticPeerFunc     func(peer swarm.Address) bool
    76  	peerExcludeFunc    func(peer swarm.Address) bool
    77  	excludeFunc        func(...im.ExcludeOp) peerExcludeFunc
    78  )
    79  
    80  var noopSanctionedPeerFn = func(_ swarm.Address) bool { return false }
    81  
    82  // Options for injecting services to Kademlia.
    83  type Options struct {
    84  	SaturationFunc binSaturationFunc
    85  	PruneCountFunc pruneCountFunc
    86  	Bootnodes      []ma.Multiaddr
    87  	BootnodeMode   bool
    88  	PruneFunc      pruneFunc
    89  	StaticNodes    []swarm.Address
    90  	ExcludeFunc    excludeFunc
    91  	DataDir        string
    92  
    93  	BitSuffixLength             *int
    94  	TimeToRetry                 *time.Duration
    95  	ShortRetry                  *time.Duration
    96  	PruneWakeup                 *time.Duration
    97  	SaturationPeers             *int
    98  	OverSaturationPeers         *int
    99  	BootnodeOverSaturationPeers *int
   100  	BroadcastBinSize            *int
   101  	LowWaterMark                *int
   102  }
   103  
   104  // kadOptions are made from Options with default values set
   105  type kadOptions struct {
   106  	SaturationFunc binSaturationFunc
   107  	Bootnodes      []ma.Multiaddr
   108  	BootnodeMode   bool
   109  	PruneCountFunc pruneCountFunc
   110  	PruneFunc      pruneFunc
   111  	StaticNodes    []swarm.Address
   112  	ExcludeFunc    excludeFunc
   113  
   114  	TimeToRetry                 time.Duration
   115  	ShortRetry                  time.Duration
   116  	PruneWakeup                 time.Duration
   117  	BitSuffixLength             int // additional depth of common prefix for bin
   118  	SaturationPeers             int
   119  	OverSaturationPeers         int
   120  	BootnodeOverSaturationPeers int
   121  	BroadcastBinSize            int
   122  	LowWaterMark                int
   123  }
   124  
   125  func newKadOptions(o Options) kadOptions {
   126  	ko := kadOptions{
   127  		// copy values
   128  		SaturationFunc: o.SaturationFunc,
   129  		Bootnodes:      o.Bootnodes,
   130  		BootnodeMode:   o.BootnodeMode,
   131  		PruneFunc:      o.PruneFunc,
   132  		StaticNodes:    o.StaticNodes,
   133  		ExcludeFunc:    o.ExcludeFunc,
   134  		// copy or use default
   135  		TimeToRetry:                 defaultValDuration(o.TimeToRetry, defaultTimeToRetry),
   136  		ShortRetry:                  defaultValDuration(o.ShortRetry, defaultShortRetry),
   137  		PruneWakeup:                 defaultValDuration(o.PruneWakeup, defaultPruneWakeup),
   138  		BitSuffixLength:             defaultValInt(o.BitSuffixLength, defaultBitSuffixLength),
   139  		SaturationPeers:             defaultValInt(o.SaturationPeers, defaultSaturationPeers),
   140  		OverSaturationPeers:         defaultValInt(o.OverSaturationPeers, defaultOverSaturationPeers),
   141  		BootnodeOverSaturationPeers: defaultValInt(o.BootnodeOverSaturationPeers, defaultBootNodeOverSaturationPeers),
   142  		BroadcastBinSize:            defaultValInt(o.BroadcastBinSize, defaultBroadcastBinSize),
   143  		LowWaterMark:                defaultValInt(o.LowWaterMark, defaultLowWaterMark),
   144  	}
   145  
   146  	if ko.SaturationFunc == nil {
   147  		ko.SaturationFunc = makeSaturationFunc(ko)
   148  	}
   149  
   150  	return ko
   151  }
   152  
   153  func defaultValInt(v *int, d int) int {
   154  	if v == nil {
   155  		return d
   156  	}
   157  	return *v
   158  }
   159  
   160  func defaultValDuration(v *time.Duration, d time.Duration) time.Duration {
   161  	if v == nil {
   162  		return d
   163  	}
   164  	return *v
   165  }
   166  
   167  func makeSaturationFunc(o kadOptions) binSaturationFunc {
   168  	os := o.OverSaturationPeers
   169  	if o.BootnodeMode {
   170  		os = o.BootnodeOverSaturationPeers
   171  	}
   172  	return binSaturated(os, isStaticPeer(o.StaticNodes))
   173  }
   174  
   175  // Kad is the Swarm forwarding kademlia implementation.
   176  type Kad struct {
   177  	opt               kadOptions
   178  	base              swarm.Address         // this node's overlay address
   179  	discovery         discovery.Driver      // the discovery driver
   180  	addressBook       addressbook.Interface // address book to get underlays
   181  	p2p               p2p.Service           // p2p service to connect to nodes with
   182  	commonBinPrefixes [][]swarm.Address     // list of address prefixes for each bin
   183  	connectedPeers    *pslice.PSlice        // a slice of peers sorted and indexed by po, indexes kept in `bins`
   184  	knownPeers        *pslice.PSlice        // both are po aware slice of addresses
   185  	depth             uint8                 // current neighborhood depth
   186  	storageRadius     uint8                 // storage area of responsibility
   187  	depthMu           sync.RWMutex          // protect depth changes
   188  	manageC           chan struct{}         // trigger the manage forever loop to connect to new peers
   189  	peerSig           []chan struct{}
   190  	peerSigMtx        sync.Mutex
   191  	logger            log.Logger // logger
   192  	bootnode          bool       // indicates whether the node is working in bootnode mode
   193  	collector         *im.Collector
   194  	quit              chan struct{} // quit channel
   195  	halt              chan struct{} // halt channel
   196  	done              chan struct{} // signal that `manage` has quit
   197  	wg                sync.WaitGroup
   198  	waitNext          *waitnext.WaitNext
   199  	metrics           metrics
   200  	staticPeer        staticPeerFunc
   201  	bgBroadcastCtx    context.Context
   202  	bgBroadcastCancel context.CancelFunc
   203  	reachability      p2p.ReachabilityStatus
   204  }
   205  
   206  // New returns a new Kademlia.
   207  func New(
   208  	base swarm.Address,
   209  	addressbook addressbook.Interface,
   210  	discovery discovery.Driver,
   211  	p2pSvc p2p.Service,
   212  	logger log.Logger,
   213  	o Options,
   214  ) (*Kad, error) {
   215  	var k *Kad
   216  
   217  	if o.DataDir == "" {
   218  		logger.Warning("using in-mem store for kademlia metrics, no state will be persisted")
   219  	} else {
   220  		o.DataDir = filepath.Join(o.DataDir, ioutil.DataPathKademlia)
   221  	}
   222  	sdb, err := shed.NewDB(o.DataDir, nil)
   223  	if err != nil {
   224  		return nil, fmt.Errorf("unable to create metrics storage: %w", err)
   225  	}
   226  	imc, err := im.NewCollector(sdb)
   227  	if err != nil {
   228  		return nil, fmt.Errorf("unable to create metrics collector: %w", err)
   229  	}
   230  
   231  	opt := newKadOptions(o)
   232  
   233  	k = &Kad{
   234  		opt:               opt,
   235  		base:              base,
   236  		discovery:         discovery,
   237  		addressBook:       addressbook,
   238  		p2p:               p2pSvc,
   239  		commonBinPrefixes: make([][]swarm.Address, int(swarm.MaxBins)),
   240  		connectedPeers:    pslice.New(int(swarm.MaxBins), base),
   241  		knownPeers:        pslice.New(int(swarm.MaxBins), base),
   242  		manageC:           make(chan struct{}, 1),
   243  		waitNext:          waitnext.New(),
   244  		logger:            logger.WithName(loggerName).Register(),
   245  		bootnode:          opt.BootnodeMode,
   246  		collector:         imc,
   247  		quit:              make(chan struct{}),
   248  		halt:              make(chan struct{}),
   249  		done:              make(chan struct{}),
   250  		metrics:           newMetrics(),
   251  		staticPeer:        isStaticPeer(opt.StaticNodes),
   252  		storageRadius:     swarm.MaxPO,
   253  	}
   254  
   255  	if k.opt.PruneFunc == nil {
   256  		k.opt.PruneFunc = k.pruneOversaturatedBins
   257  	}
   258  
   259  	os := k.opt.OverSaturationPeers
   260  	if k.opt.BootnodeMode {
   261  		os = k.opt.BootnodeOverSaturationPeers
   262  	}
   263  	k.opt.PruneCountFunc = binPruneCount(os, isStaticPeer(k.opt.StaticNodes))
   264  
   265  	if k.opt.ExcludeFunc == nil {
   266  		k.opt.ExcludeFunc = func(f ...im.ExcludeOp) peerExcludeFunc {
   267  			return func(peer swarm.Address) bool {
   268  				return k.collector.Exclude(peer, f...)
   269  			}
   270  		}
   271  	}
   272  
   273  	if k.opt.BitSuffixLength > 0 {
   274  		k.commonBinPrefixes = generateCommonBinPrefixes(k.base, k.opt.BitSuffixLength)
   275  	}
   276  
   277  	k.bgBroadcastCtx, k.bgBroadcastCancel = context.WithCancel(context.Background())
   278  
   279  	k.metrics.ReachabilityStatus.WithLabelValues(p2p.ReachabilityStatusUnknown.String()).Set(0)
   280  	return k, nil
   281  }
   282  
   283  type peerConnInfo struct {
   284  	po   uint8
   285  	addr swarm.Address
   286  }
   287  
   288  // connectBalanced attempts to connect to the balanced peers first.
   289  func (k *Kad) connectBalanced(wg *sync.WaitGroup, peerConnChan chan<- *peerConnInfo) {
   290  	skipPeers := func(peer swarm.Address) bool {
   291  		if k.waitNext.Waiting(peer) {
   292  			k.metrics.TotalBeforeExpireWaits.Inc()
   293  			return true
   294  		}
   295  		return false
   296  	}
   297  
   298  	depth := k.neighborhoodDepth()
   299  
   300  	for i := range k.commonBinPrefixes {
   301  
   302  		binPeersLength := k.knownPeers.BinSize(uint8(i))
   303  
   304  		// balancer should skip on bins where neighborhood connector would connect to peers anyway
   305  		// and there are not enough peers in known addresses to properly balance the bin
   306  		if i >= int(depth) && binPeersLength < len(k.commonBinPrefixes[i]) {
   307  			continue
   308  		}
   309  
   310  		binPeers := k.knownPeers.BinPeers(uint8(i))
   311  		binConnectedPeers := k.connectedPeers.BinPeers(uint8(i))
   312  
   313  		for j := range k.commonBinPrefixes[i] {
   314  			pseudoAddr := k.commonBinPrefixes[i][j]
   315  
   316  			// Connect to closest known peer which we haven't tried connecting to recently.
   317  
   318  			_, exists := nClosePeerInSlice(binConnectedPeers, pseudoAddr, noopSanctionedPeerFn, uint8(i+k.opt.BitSuffixLength+1))
   319  			if exists {
   320  				continue
   321  			}
   322  
   323  			closestKnownPeer, exists := nClosePeerInSlice(binPeers, pseudoAddr, skipPeers, uint8(i+k.opt.BitSuffixLength+1))
   324  			if !exists {
   325  				continue
   326  			}
   327  
   328  			if k.connectedPeers.Exists(closestKnownPeer) {
   329  				continue
   330  			}
   331  
   332  			blocklisted, err := k.p2p.Blocklisted(closestKnownPeer)
   333  			if err != nil {
   334  				k.logger.Warning("peer blocklist check failed", "error", err)
   335  			}
   336  			if blocklisted {
   337  				continue
   338  			}
   339  
   340  			wg.Add(1)
   341  			select {
   342  			case peerConnChan <- &peerConnInfo{
   343  				po:   swarm.Proximity(k.base.Bytes(), closestKnownPeer.Bytes()),
   344  				addr: closestKnownPeer,
   345  			}:
   346  			case <-k.quit:
   347  				wg.Done()
   348  				return
   349  			}
   350  		}
   351  	}
   352  }
   353  
   354  // connectNeighbours attempts to connect to the neighbours
   355  // which were not considered by the connectBalanced method.
   356  func (k *Kad) connectNeighbours(wg *sync.WaitGroup, peerConnChan chan<- *peerConnInfo) {
   357  
   358  	sent := 0
   359  	var currentPo uint8 = 0
   360  
   361  	_ = k.knownPeers.EachBinRev(func(addr swarm.Address, po uint8) (bool, bool, error) {
   362  
   363  		// out of depth, skip bin
   364  		if po < k.neighborhoodDepth() {
   365  			return false, true, nil
   366  		}
   367  
   368  		if po != currentPo {
   369  			currentPo = po
   370  			sent = 0
   371  		}
   372  
   373  		if k.connectedPeers.Exists(addr) {
   374  			return false, false, nil
   375  		}
   376  
   377  		blocklisted, err := k.p2p.Blocklisted(addr)
   378  		if err != nil {
   379  			k.logger.Warning("peer blocklist check failed", "error", err)
   380  		}
   381  		if blocklisted {
   382  			return false, false, nil
   383  		}
   384  
   385  		if k.waitNext.Waiting(addr) {
   386  			k.metrics.TotalBeforeExpireWaits.Inc()
   387  			return false, false, nil
   388  		}
   389  
   390  		wg.Add(1)
   391  		select {
   392  		case peerConnChan <- &peerConnInfo{po: po, addr: addr}:
   393  		case <-k.quit:
   394  			wg.Done()
   395  			return true, false, nil
   396  		}
   397  
   398  		sent++
   399  
   400  		// We want 'sent' equal to 'saturationPeers'
   401  		// in order to skip to the next bin and speed up the topology build.
   402  		return false, sent == k.opt.SaturationPeers, nil
   403  	})
   404  }
   405  
   406  // connectionAttemptsHandler handles the connection attempts
   407  // to peers sent by the producers to the peerConnChan.
   408  func (k *Kad) connectionAttemptsHandler(ctx context.Context, wg *sync.WaitGroup, neighbourhoodChan, balanceChan <-chan *peerConnInfo) {
   409  	connect := func(peer *peerConnInfo) {
   410  		bzzAddr, err := k.addressBook.Get(peer.addr)
   411  		switch {
   412  		case errors.Is(err, addressbook.ErrNotFound):
   413  			k.logger.Debug("empty address book entry for peer", "peer_address", peer.addr)
   414  			k.knownPeers.Remove(peer.addr)
   415  			return
   416  		case err != nil:
   417  			k.logger.Debug("failed to get address book entry for peer", "peer_address", peer.addr, "error", err)
   418  			return
   419  		}
   420  
   421  		remove := func(peer *peerConnInfo) {
   422  			k.waitNext.Remove(peer.addr)
   423  			k.knownPeers.Remove(peer.addr)
   424  			if err := k.addressBook.Remove(peer.addr); err != nil {
   425  				k.logger.Debug("could not remove peer from addressbook", "peer_address", peer.addr)
   426  			}
   427  		}
   428  
   429  		switch err = k.connect(ctx, peer.addr, bzzAddr.Underlay); {
   430  		case errors.Is(err, p2p.ErrNetworkUnavailable):
   431  			k.logger.Debug("network unavailable when reaching peer", "peer_overlay_address", peer.addr, "peer_underlay_address", bzzAddr.Underlay)
   432  			return
   433  		case errors.Is(err, errPruneEntry):
   434  			k.logger.Debug("dial to light node", "peer_overlay_address", peer.addr, "peer_underlay_address", bzzAddr.Underlay)
   435  			remove(peer)
   436  			return
   437  		case errors.Is(err, errOverlayMismatch):
   438  			k.logger.Debug("overlay mismatch has occurred", "peer_overlay_address", peer.addr, "peer_underlay_address", bzzAddr.Underlay)
   439  			remove(peer)
   440  			return
   441  		case errors.Is(err, p2p.ErrPeerBlocklisted):
   442  			k.logger.Debug("peer still in blocklist", "peer_address", bzzAddr)
   443  			k.logger.Warning("peer still in blocklist")
   444  			return
   445  		case err != nil:
   446  			k.logger.Debug("peer not reachable from kademlia", "peer_address", bzzAddr, "error", err)
   447  			k.logger.Warning("peer not reachable when attempting to connect")
   448  			return
   449  		}
   450  
   451  		k.waitNext.Set(peer.addr, time.Now().Add(k.opt.ShortRetry), 0)
   452  
   453  		k.connectedPeers.Add(peer.addr)
   454  
   455  		k.metrics.TotalOutboundConnections.Inc()
   456  		k.collector.Record(peer.addr, im.PeerLogIn(time.Now(), im.PeerConnectionDirectionOutbound))
   457  
   458  		k.recalcDepth()
   459  
   460  		k.logger.Info("connected to peer", "peer_address", peer.addr, "proximity_order", peer.po)
   461  		k.notifyManageLoop()
   462  		k.notifyPeerSig()
   463  	}
   464  
   465  	var (
   466  		// The inProgress helps to avoid making a connection
   467  		// to a peer who has the connection already in progress.
   468  		inProgress   = make(map[string]bool)
   469  		inProgressMu sync.Mutex
   470  	)
   471  	connAttempt := func(peerConnChan <-chan *peerConnInfo) {
   472  		for {
   473  			select {
   474  			case <-k.quit:
   475  				return
   476  			case peer := <-peerConnChan:
   477  				addr := peer.addr.String()
   478  
   479  				if k.waitNext.Waiting(peer.addr) {
   480  					k.metrics.TotalBeforeExpireWaits.Inc()
   481  					wg.Done()
   482  					continue
   483  				}
   484  
   485  				inProgressMu.Lock()
   486  				if !inProgress[addr] {
   487  					inProgress[addr] = true
   488  					inProgressMu.Unlock()
   489  					connect(peer)
   490  					inProgressMu.Lock()
   491  					delete(inProgress, addr)
   492  				}
   493  				inProgressMu.Unlock()
   494  				wg.Done()
   495  			}
   496  		}
   497  	}
   498  	for i := 0; i < 32; i++ {
   499  		go connAttempt(balanceChan)
   500  	}
   501  	for i := 0; i < 32; i++ {
   502  		go connAttempt(neighbourhoodChan)
   503  	}
   504  }
   505  
   506  // notifyManageLoop notifies kademlia manage loop.
   507  func (k *Kad) notifyManageLoop() {
   508  	select {
   509  	case k.manageC <- struct{}{}:
   510  	default:
   511  	}
   512  }
   513  
   514  // manage is a forever loop that manages the connection to new peers
   515  // once they get added or once others leave.
   516  func (k *Kad) manage() {
   517  	loggerV1 := k.logger.V(1).Register()
   518  
   519  	defer k.wg.Done()
   520  	defer close(k.done)
   521  	defer k.logger.Debug("kademlia manage loop exited")
   522  
   523  	ctx, cancel := context.WithCancel(context.Background())
   524  	go func() {
   525  		<-k.quit
   526  		cancel()
   527  	}()
   528  
   529  	// The wg makes sure that we wait for all the connection attempts,
   530  	// spun up by goroutines, to finish before we try the boot-nodes.
   531  	var wg sync.WaitGroup
   532  	neighbourhoodChan := make(chan *peerConnInfo)
   533  	balanceChan := make(chan *peerConnInfo)
   534  	go k.connectionAttemptsHandler(ctx, &wg, neighbourhoodChan, balanceChan)
   535  
   536  	k.wg.Add(1)
   537  	go func() {
   538  		defer k.wg.Done()
   539  		for {
   540  			select {
   541  			case <-k.halt:
   542  				return
   543  			case <-k.quit:
   544  				return
   545  			case <-time.After(k.opt.PruneWakeup):
   546  				k.opt.PruneFunc(k.neighborhoodDepth())
   547  			}
   548  		}
   549  	}()
   550  
   551  	k.wg.Add(1)
   552  	go func() {
   553  		defer k.wg.Done()
   554  		for {
   555  			select {
   556  			case <-k.halt:
   557  				return
   558  			case <-k.quit:
   559  				return
   560  			case <-time.After(5 * time.Minute):
   561  				start := time.Now()
   562  				loggerV1.Debug("starting to flush metrics", "start_time", start)
   563  				if err := k.collector.Flush(); err != nil {
   564  					k.metrics.InternalMetricsFlushTotalErrors.Inc()
   565  					k.logger.Debug("unable to flush metrics counters to the persistent store", "error", err)
   566  				} else {
   567  					k.metrics.InternalMetricsFlushTime.Observe(time.Since(start).Seconds())
   568  					loggerV1.Debug("flush metrics done", "elapsed", time.Since(start))
   569  				}
   570  			}
   571  		}
   572  	}()
   573  
   574  	// tell each neighbor about other neighbors periodically
   575  	k.wg.Add(1)
   576  	go func() {
   577  		defer k.wg.Done()
   578  		for {
   579  			select {
   580  			case <-k.halt:
   581  				return
   582  			case <-k.quit:
   583  				return
   584  			case <-time.After(15 * time.Minute):
   585  				var neighbors []swarm.Address
   586  				_ = k.connectedPeers.EachBin(func(addr swarm.Address, bin uint8) (stop bool, jumpToNext bool, err error) {
   587  					if bin < k.neighborhoodDepth() {
   588  						return true, false, nil
   589  					}
   590  					neighbors = append(neighbors, addr)
   591  					return false, false, nil
   592  				})
   593  				for i, peer := range neighbors {
   594  					if err := k.discovery.BroadcastPeers(ctx, peer, append(neighbors[:i], neighbors[i+1:]...)...); err != nil {
   595  						k.logger.Debug("broadcast neighborhood failure", "peer_address", peer, "error", err)
   596  					}
   597  				}
   598  			}
   599  		}
   600  	}()
   601  
   602  	for {
   603  		select {
   604  		case <-k.quit:
   605  			return
   606  		case <-time.After(15 * time.Second):
   607  			k.notifyManageLoop()
   608  		case <-k.manageC:
   609  			start := time.Now()
   610  
   611  			select {
   612  			case <-k.halt:
   613  				// halt stops dial-outs while shutting down
   614  				return
   615  			case <-k.quit:
   616  				return
   617  			default:
   618  			}
   619  
   620  			if k.bootnode {
   621  				depth := k.neighborhoodDepth()
   622  
   623  				k.metrics.CurrentDepth.Set(float64(depth))
   624  				k.metrics.CurrentlyKnownPeers.Set(float64(k.knownPeers.Length()))
   625  				k.metrics.CurrentlyConnectedPeers.Set(float64(k.connectedPeers.Length()))
   626  
   627  				continue
   628  			}
   629  
   630  			oldDepth := k.neighborhoodDepth()
   631  			k.connectBalanced(&wg, balanceChan)
   632  			k.connectNeighbours(&wg, neighbourhoodChan)
   633  			wg.Wait()
   634  
   635  			depth := k.neighborhoodDepth()
   636  
   637  			loggerV1.Debug("connector finished", "elapsed", time.Since(start), "old_depth", oldDepth, "new_depth", depth)
   638  
   639  			k.metrics.CurrentDepth.Set(float64(depth))
   640  			k.metrics.CurrentlyKnownPeers.Set(float64(k.knownPeers.Length()))
   641  			k.metrics.CurrentlyConnectedPeers.Set(float64(k.connectedPeers.Length()))
   642  
   643  			if k.connectedPeers.Length() == 0 {
   644  				select {
   645  				case <-k.halt:
   646  					continue
   647  				default:
   648  				}
   649  				k.logger.Debug("kademlia: no connected peers, trying bootnodes")
   650  				k.connectBootNodes(ctx)
   651  			} else {
   652  				rs := make(map[string]float64)
   653  				ss := k.collector.Snapshot(time.Now())
   654  
   655  				if err := k.connectedPeers.EachBin(func(addr swarm.Address, _ uint8) (bool, bool, error) {
   656  					if ss, ok := ss[addr.ByteString()]; ok {
   657  						rs[ss.Reachability.String()]++
   658  					}
   659  					return false, false, nil
   660  				}); err != nil {
   661  					k.logger.Error(err, "unable to set peers reachability status")
   662  				}
   663  
   664  				for status, count := range rs {
   665  					k.metrics.PeersReachabilityStatus.WithLabelValues(status).Set(count)
   666  				}
   667  			}
   668  		}
   669  	}
   670  }
   671  
   672  // pruneOversaturatedBins disconnects out of depth peers from oversaturated bins
   673  // while maintaining the balance of the bin and favoring healthy and reachable peers.
   674  func (k *Kad) pruneOversaturatedBins(depth uint8) {
   675  
   676  	for i := range k.commonBinPrefixes {
   677  
   678  		if i >= int(depth) {
   679  			return
   680  		}
   681  
   682  		// skip to next bin if prune count is zero or fewer
   683  		oldCount, pruneCount := k.opt.PruneCountFunc(uint8(i), k.connectedPeers, k.opt.ExcludeFunc(im.Reachability(false)))
   684  		if pruneCount <= 0 {
   685  			continue
   686  		}
   687  
   688  		for j := 0; j < len(k.commonBinPrefixes[i]); j++ {
   689  
   690  			// skip to next bin if prune count is zero or fewer
   691  			_, pruneCount := k.opt.PruneCountFunc(uint8(i), k.connectedPeers, k.opt.ExcludeFunc(im.Reachability(false)))
   692  			if pruneCount <= 0 {
   693  				break
   694  			}
   695  
   696  			binPeers := k.connectedPeers.BinPeers(uint8(i))
   697  			peers := k.balancedSlotPeers(k.commonBinPrefixes[i][j], binPeers, i)
   698  			if len(peers) <= 1 {
   699  				continue
   700  			}
   701  
   702  			var disconnectPeer = swarm.ZeroAddress
   703  			var unreachablePeer = swarm.ZeroAddress
   704  			for _, peer := range peers {
   705  				if ss := k.collector.Inspect(peer); ss != nil {
   706  					if !ss.Healthy {
   707  						disconnectPeer = peer
   708  						break
   709  					}
   710  					if ss.Reachability != p2p.ReachabilityStatusPublic {
   711  						unreachablePeer = peer
   712  					}
   713  				}
   714  			}
   715  
   716  			if disconnectPeer.IsZero() {
   717  				if unreachablePeer.IsZero() {
   718  					disconnectPeer = peers[rand.Intn(len(peers))]
   719  				} else {
   720  					disconnectPeer = unreachablePeer // pick unreachable peer
   721  				}
   722  			}
   723  
   724  			err := k.p2p.Disconnect(disconnectPeer, "pruned from oversaturated bin")
   725  			if err != nil {
   726  				k.logger.Debug("prune disconnect failed", "error", err)
   727  			}
   728  		}
   729  
   730  		newCount, _ := k.opt.PruneCountFunc(uint8(i), k.connectedPeers, k.opt.ExcludeFunc(im.Reachability(false)))
   731  
   732  		k.logger.Debug("pruning", "bin", i, "oldBinSize", oldCount, "newBinSize", newCount)
   733  	}
   734  }
   735  
   736  func (k *Kad) balancedSlotPeers(pseudoAddr swarm.Address, peers []swarm.Address, po int) []swarm.Address {
   737  
   738  	var ret []swarm.Address
   739  
   740  	for _, peer := range peers {
   741  		if int(swarm.ExtendedProximity(peer.Bytes(), pseudoAddr.Bytes())) >= po+k.opt.BitSuffixLength+1 {
   742  			ret = append(ret, peer)
   743  		}
   744  	}
   745  
   746  	return ret
   747  }
   748  
   749  func (k *Kad) Start(_ context.Context) error {
   750  	k.wg.Add(1)
   751  	go k.manage()
   752  
   753  	k.AddPeers(k.previouslyConnected()...)
   754  
   755  	go func() {
   756  		select {
   757  		case <-k.halt:
   758  			return
   759  		case <-k.quit:
   760  			return
   761  		default:
   762  		}
   763  		var (
   764  			start     = time.Now()
   765  			addresses []swarm.Address
   766  		)
   767  
   768  		err := k.addressBook.IterateOverlays(func(addr swarm.Address) (stop bool, err error) {
   769  			addresses = append(addresses, addr)
   770  			if len(addresses) == addPeerBatchSize {
   771  				k.AddPeers(addresses...)
   772  				addresses = nil
   773  			}
   774  			return false, nil
   775  		})
   776  		if err != nil {
   777  			k.logger.Error(err, "addressbook iterate overlays failed")
   778  			return
   779  		}
   780  		k.AddPeers(addresses...)
   781  		k.metrics.StartAddAddressBookOverlaysTime.Observe(time.Since(start).Seconds())
   782  	}()
   783  
   784  	// trigger the first manage loop immediately so that
   785  	// we can start connecting to the bootnode quickly
   786  	k.notifyManageLoop()
   787  
   788  	return nil
   789  }
   790  
   791  func (k *Kad) previouslyConnected() []swarm.Address {
   792  	loggerV1 := k.logger.V(1).Register()
   793  
   794  	now := time.Now()
   795  	ss := k.collector.Snapshot(now)
   796  	loggerV1.Debug("metrics snapshot taken", "elapsed", time.Since(now))
   797  
   798  	var peers []swarm.Address
   799  
   800  	for addr, p := range ss {
   801  		if p.ConnectionTotalDuration > 0 {
   802  			peers = append(peers, swarm.NewAddress([]byte(addr)))
   803  		}
   804  	}
   805  
   806  	return peers
   807  }
   808  
   809  func (k *Kad) connectBootNodes(ctx context.Context) {
   810  	loggerV1 := k.logger.V(1).Register()
   811  
   812  	var attempts, connected int
   813  	totalAttempts := maxBootNodeAttempts * len(k.opt.Bootnodes)
   814  
   815  	ctx, cancel := context.WithTimeout(ctx, 15*time.Second)
   816  	defer cancel()
   817  
   818  	for _, addr := range k.opt.Bootnodes {
   819  		if attempts >= totalAttempts || connected >= 3 {
   820  			return
   821  		}
   822  
   823  		if _, err := p2p.Discover(ctx, addr, func(addr ma.Multiaddr) (stop bool, err error) {
   824  			loggerV1.Debug("connecting to bootnode", "bootnode_address", addr)
   825  			if attempts >= maxBootNodeAttempts {
   826  				return true, nil
   827  			}
   828  			bzzAddress, err := k.p2p.Connect(ctx, addr)
   829  
   830  			attempts++
   831  			k.metrics.TotalBootNodesConnectionAttempts.Inc()
   832  
   833  			if err != nil {
   834  				if !errors.Is(err, p2p.ErrAlreadyConnected) {
   835  					k.logger.Debug("connect to bootnode failed", "bootnode_address", addr, "error", err)
   836  					k.logger.Warning("connect to bootnode failed", "bootnode_address", addr)
   837  					return false, err
   838  				}
   839  				k.logger.Debug("connect to bootnode failed", "bootnode_address", addr, "error", err)
   840  				return false, nil
   841  			}
   842  
   843  			if err := k.onConnected(ctx, bzzAddress.Overlay); err != nil {
   844  				return false, err
   845  			}
   846  
   847  			k.metrics.TotalOutboundConnections.Inc()
   848  			k.collector.Record(bzzAddress.Overlay, im.PeerLogIn(time.Now(), im.PeerConnectionDirectionOutbound))
   849  			loggerV1.Debug("connected to bootnode", "bootnode_address", addr)
   850  			connected++
   851  
   852  			// connect to max 3 bootnodes
   853  			return connected >= 3, nil
   854  		}); err != nil && !errors.Is(err, context.Canceled) {
   855  			k.logger.Debug("discover to bootnode failed", "bootnode_address", addr, "error", err)
   856  			k.logger.Warning("discover to bootnode failed", "bootnode_address", addr)
   857  			return
   858  		}
   859  	}
   860  }
   861  
   862  // binSaturated indicates whether a certain bin is saturated or not.
   863  // when a bin is not saturated it means we would like to proactively
   864  // initiate connections to other peers in the bin.
   865  func binSaturated(oversaturationAmount int, staticNode staticPeerFunc) binSaturationFunc {
   866  	return func(bin uint8, connected *pslice.PSlice, exclude peerExcludeFunc) bool {
   867  		size := 0
   868  		_ = connected.EachBin(func(addr swarm.Address, po uint8) (bool, bool, error) {
   869  			if po == bin && !exclude(addr) && !staticNode(addr) {
   870  				size++
   871  			}
   872  			return false, false, nil
   873  		})
   874  
   875  		return size >= oversaturationAmount
   876  	}
   877  }
   878  
   879  // binPruneCount counts how many peers should be pruned from a bin.
   880  func binPruneCount(oversaturationAmount int, staticNode staticPeerFunc) pruneCountFunc {
   881  	return func(bin uint8, connected *pslice.PSlice, exclude peerExcludeFunc) (int, int) {
   882  		size := 0
   883  		_ = connected.EachBin(func(addr swarm.Address, po uint8) (bool, bool, error) {
   884  			if po == bin && !exclude(addr) && !staticNode(addr) {
   885  				size++
   886  			}
   887  			return false, false, nil
   888  		})
   889  
   890  		return size, size - oversaturationAmount
   891  	}
   892  }
   893  
   894  // recalcDepth calculates, assigns the new depth, and returns if depth has changed
   895  func (k *Kad) recalcDepth() {
   896  
   897  	k.depthMu.Lock()
   898  	defer k.depthMu.Unlock()
   899  
   900  	var (
   901  		peers                 = k.connectedPeers
   902  		exclude               = k.opt.ExcludeFunc(im.Reachability(false))
   903  		binCount              = 0
   904  		shallowestUnsaturated = uint8(0)
   905  		depth                 uint8
   906  	)
   907  
   908  	// handle edge case separately
   909  	if peers.Length() <= k.opt.LowWaterMark {
   910  		k.depth = 0
   911  		return
   912  	}
   913  
   914  	_ = peers.EachBinRev(func(addr swarm.Address, bin uint8) (bool, bool, error) {
   915  		if exclude(addr) {
   916  			return false, false, nil
   917  		}
   918  		if bin == shallowestUnsaturated {
   919  			binCount++
   920  			return false, false, nil
   921  		}
   922  		if bin > shallowestUnsaturated && binCount < k.opt.SaturationPeers {
   923  			// this means we have less than quickSaturationPeers in the previous bin
   924  			// therefore we can return assuming that bin is the unsaturated one.
   925  			return true, false, nil
   926  		}
   927  		shallowestUnsaturated = bin
   928  		binCount = 1
   929  
   930  		return false, false, nil
   931  	})
   932  	depth = shallowestUnsaturated
   933  
   934  	shallowestEmpty, noEmptyBins := peers.ShallowestEmpty()
   935  	// if there are some empty bins and the shallowestEmpty is
   936  	// smaller than the shallowestUnsaturated then set shallowest
   937  	// unsaturated to the empty bin.
   938  	if !noEmptyBins && shallowestEmpty < depth {
   939  		depth = shallowestEmpty
   940  	}
   941  
   942  	var (
   943  		peersCtr  = uint(0)
   944  		candidate = uint8(0)
   945  	)
   946  	_ = peers.EachBin(func(addr swarm.Address, po uint8) (bool, bool, error) {
   947  		if exclude(addr) {
   948  			return false, false, nil
   949  		}
   950  		peersCtr++
   951  		if peersCtr >= uint(k.opt.LowWaterMark) {
   952  			candidate = po
   953  			return true, false, nil
   954  		}
   955  		return false, false, nil
   956  	})
   957  
   958  	if depth > candidate {
   959  		depth = candidate
   960  	}
   961  
   962  	k.depth = depth
   963  }
   964  
   965  // connect connects to a peer and gossips its address to our connected peers,
   966  // as well as sends the peers we are connected to the newly connected peer
   967  func (k *Kad) connect(ctx context.Context, peer swarm.Address, ma ma.Multiaddr) error {
   968  	k.logger.Debug("attempting connect to peer", "peer_address", peer)
   969  
   970  	ctx, cancel := context.WithTimeout(ctx, peerConnectionAttemptTimeout)
   971  	defer cancel()
   972  
   973  	k.metrics.TotalOutboundConnectionAttempts.Inc()
   974  
   975  	switch i, err := k.p2p.Connect(ctx, ma); {
   976  	case errors.Is(err, p2p.ErrNetworkUnavailable):
   977  		return err
   978  	case k.p2p.NetworkStatus() == p2p.NetworkStatusUnavailable:
   979  		return p2p.ErrNetworkUnavailable
   980  	case errors.Is(err, p2p.ErrDialLightNode):
   981  		return errPruneEntry
   982  	case errors.Is(err, p2p.ErrAlreadyConnected):
   983  		if !i.Overlay.Equal(peer) {
   984  			return errOverlayMismatch
   985  		}
   986  		return nil
   987  	case errors.Is(err, context.Canceled):
   988  		return err
   989  	case errors.Is(err, p2p.ErrPeerBlocklisted):
   990  		return err
   991  	case err != nil:
   992  		k.logger.Debug("could not connect to peer", "peer_address", peer, "error", err)
   993  
   994  		retryTime := time.Now().Add(k.opt.TimeToRetry)
   995  		var e *p2p.ConnectionBackoffError
   996  		failedAttempts := 0
   997  		if errors.As(err, &e) {
   998  			retryTime = e.TryAfter()
   999  		} else {
  1000  			failedAttempts = k.waitNext.Attempts(peer)
  1001  			failedAttempts++
  1002  		}
  1003  
  1004  		k.metrics.TotalOutboundConnectionFailedAttempts.Inc()
  1005  		k.collector.Record(peer, im.IncSessionConnectionRetry())
  1006  
  1007  		maxAttempts := maxConnAttempts
  1008  		if swarm.Proximity(k.base.Bytes(), peer.Bytes()) >= k.neighborhoodDepth() {
  1009  			maxAttempts = maxNeighborAttempts
  1010  		}
  1011  
  1012  		if failedAttempts >= maxAttempts {
  1013  			k.waitNext.Remove(peer)
  1014  			k.knownPeers.Remove(peer)
  1015  			if err := k.addressBook.Remove(peer); err != nil {
  1016  				k.logger.Debug("could not remove peer from addressbook", "peer_address", peer)
  1017  			}
  1018  			k.logger.Debug("peer pruned from address book", "peer_address", peer)
  1019  		} else {
  1020  			k.waitNext.Set(peer, retryTime, failedAttempts)
  1021  		}
  1022  
  1023  		return err
  1024  	case !i.Overlay.Equal(peer):
  1025  		_ = k.p2p.Disconnect(peer, errOverlayMismatch.Error())
  1026  		_ = k.p2p.Disconnect(i.Overlay, errOverlayMismatch.Error())
  1027  		return errOverlayMismatch
  1028  	}
  1029  
  1030  	return k.Announce(ctx, peer, true)
  1031  }
  1032  
  1033  // Announce a newly connected peer to our connected peers, but also
  1034  // notify the peer about our already connected peers
  1035  func (k *Kad) Announce(ctx context.Context, peer swarm.Address, fullnode bool) error {
  1036  	var addrs []swarm.Address
  1037  
  1038  	depth := k.neighborhoodDepth()
  1039  	isNeighbor := swarm.Proximity(peer.Bytes(), k.base.Bytes()) >= depth
  1040  
  1041  outer:
  1042  	for bin := uint8(0); bin < swarm.MaxBins; bin++ {
  1043  
  1044  		var (
  1045  			connectedPeers []swarm.Address
  1046  			err            error
  1047  		)
  1048  
  1049  		if bin >= depth && isNeighbor {
  1050  			connectedPeers = k.binPeers(bin, false) // broadcast all neighborhood peers
  1051  		} else {
  1052  			connectedPeers, err = randomSubset(k.binPeers(bin, true), k.opt.BroadcastBinSize)
  1053  			if err != nil {
  1054  				return err
  1055  			}
  1056  		}
  1057  
  1058  		for _, connectedPeer := range connectedPeers {
  1059  			if connectedPeer.Equal(peer) {
  1060  				continue
  1061  			}
  1062  
  1063  			addrs = append(addrs, connectedPeer)
  1064  
  1065  			if !fullnode {
  1066  				// we continue here so we dont gossip
  1067  				// about lightnodes to others.
  1068  				continue
  1069  			}
  1070  			// if kademlia is closing, dont enqueue anymore broadcast requests
  1071  			select {
  1072  			case <-k.bgBroadcastCtx.Done():
  1073  				// we will not interfere with the announce operation by returning here
  1074  				continue
  1075  			case <-k.halt:
  1076  				break outer
  1077  			default:
  1078  			}
  1079  			go func(connectedPeer swarm.Address) {
  1080  
  1081  				// Create a new deadline ctx to prevent goroutine pile up
  1082  				cCtx, cCancel := context.WithTimeout(k.bgBroadcastCtx, time.Minute)
  1083  				defer cCancel()
  1084  
  1085  				if err := k.discovery.BroadcastPeers(cCtx, connectedPeer, peer); err != nil {
  1086  					k.logger.Debug("peer gossip failed", "new_peer_address", peer, "connected_peer_address", connectedPeer, "error", err)
  1087  				}
  1088  			}(connectedPeer)
  1089  		}
  1090  	}
  1091  
  1092  	if len(addrs) == 0 {
  1093  		return nil
  1094  	}
  1095  
  1096  	select {
  1097  	case <-k.halt:
  1098  		return nil
  1099  	default:
  1100  	}
  1101  
  1102  	err := k.discovery.BroadcastPeers(ctx, peer, addrs...)
  1103  	if err != nil {
  1104  		k.logger.Error(err, "could not broadcast to peer", "peer_address", peer)
  1105  		_ = k.p2p.Disconnect(peer, "failed broadcasting to peer")
  1106  	}
  1107  
  1108  	return err
  1109  }
  1110  
  1111  // AnnounceTo announces a selected peer to another.
  1112  func (k *Kad) AnnounceTo(ctx context.Context, addressee, peer swarm.Address, fullnode bool) error {
  1113  	if !fullnode {
  1114  		return errAnnounceLightNode
  1115  	}
  1116  
  1117  	return k.discovery.BroadcastPeers(ctx, addressee, peer)
  1118  }
  1119  
  1120  // AddPeers adds peers to the knownPeers list.
  1121  // This does not guarantee that a connection will immediately
  1122  // be made to the peer.
  1123  func (k *Kad) AddPeers(addrs ...swarm.Address) {
  1124  	k.knownPeers.Add(addrs...)
  1125  	k.notifyManageLoop()
  1126  }
  1127  
  1128  func (k *Kad) Pick(peer p2p.Peer) bool {
  1129  	k.metrics.PickCalls.Inc()
  1130  	if k.bootnode || !peer.FullNode {
  1131  		// shortcircuit for bootnode mode AND light node peers - always accept connections,
  1132  		// at least until we find a better solution.
  1133  		return true
  1134  	}
  1135  	po := swarm.Proximity(k.base.Bytes(), peer.Address.Bytes())
  1136  	oversaturated := k.opt.SaturationFunc(po, k.connectedPeers, k.opt.ExcludeFunc(im.Reachability(false)))
  1137  	// pick the peer if we are not oversaturated
  1138  	if !oversaturated {
  1139  		return true
  1140  	}
  1141  	k.metrics.PickCallsFalse.Inc()
  1142  	return false
  1143  }
  1144  
  1145  func (k *Kad) binPeers(bin uint8, reachable bool) (peers []swarm.Address) {
  1146  
  1147  	_ = k.EachConnectedPeerRev(func(p swarm.Address, po uint8) (bool, bool, error) {
  1148  
  1149  		if po == bin {
  1150  			peers = append(peers, p)
  1151  			return false, false, nil
  1152  		}
  1153  
  1154  		if po > bin {
  1155  			return true, false, nil
  1156  		}
  1157  
  1158  		return false, true, nil
  1159  
  1160  	}, topology.Select{Reachable: reachable})
  1161  
  1162  	return
  1163  }
  1164  
  1165  func isStaticPeer(staticNodes []swarm.Address) func(overlay swarm.Address) bool {
  1166  	return func(overlay swarm.Address) bool {
  1167  		return swarm.ContainsAddress(staticNodes, overlay)
  1168  	}
  1169  }
  1170  
  1171  // Connected is called when a peer has dialed in.
  1172  // If forceConnection is true `overSaturated` is ignored for non-bootnodes.
  1173  func (k *Kad) Connected(ctx context.Context, peer p2p.Peer, forceConnection bool) (err error) {
  1174  	defer func() {
  1175  		if err == nil {
  1176  			k.metrics.TotalInboundConnections.Inc()
  1177  			k.collector.Record(peer.Address, im.PeerLogIn(time.Now(), im.PeerConnectionDirectionInbound))
  1178  		}
  1179  	}()
  1180  
  1181  	address := peer.Address
  1182  	po := swarm.Proximity(k.base.Bytes(), address.Bytes())
  1183  
  1184  	if overSaturated := k.opt.SaturationFunc(po, k.connectedPeers, k.opt.ExcludeFunc(im.Reachability(false))); overSaturated {
  1185  		if k.bootnode {
  1186  			randPeer, err := k.randomPeer(po)
  1187  			if err != nil {
  1188  				return fmt.Errorf("failed to get random peer to kick-out: %w", err)
  1189  			}
  1190  			_ = k.p2p.Disconnect(randPeer, "kicking out random peer to accommodate node")
  1191  			return k.onConnected(ctx, address)
  1192  		}
  1193  		if !forceConnection {
  1194  			return topology.ErrOversaturated
  1195  		}
  1196  	}
  1197  
  1198  	return k.onConnected(ctx, address)
  1199  }
  1200  
  1201  func (k *Kad) onConnected(ctx context.Context, addr swarm.Address) error {
  1202  	if err := k.Announce(ctx, addr, true); err != nil {
  1203  		return err
  1204  	}
  1205  
  1206  	k.knownPeers.Add(addr)
  1207  	k.connectedPeers.Add(addr)
  1208  
  1209  	k.waitNext.Remove(addr)
  1210  
  1211  	k.recalcDepth()
  1212  
  1213  	k.notifyManageLoop()
  1214  	k.notifyPeerSig()
  1215  
  1216  	return nil
  1217  }
  1218  
  1219  // Disconnected is called when peer disconnects.
  1220  func (k *Kad) Disconnected(peer p2p.Peer) {
  1221  	k.logger.Info("disconnected peer", "peer_address", peer.Address)
  1222  
  1223  	k.connectedPeers.Remove(peer.Address)
  1224  
  1225  	k.waitNext.SetTryAfter(peer.Address, time.Now().Add(k.opt.TimeToRetry))
  1226  
  1227  	k.metrics.TotalInboundDisconnections.Inc()
  1228  	k.collector.Record(peer.Address, im.PeerLogOut(time.Now()))
  1229  
  1230  	k.recalcDepth()
  1231  
  1232  	k.notifyManageLoop()
  1233  	k.notifyPeerSig()
  1234  }
  1235  
  1236  func (k *Kad) notifyPeerSig() {
  1237  	k.peerSigMtx.Lock()
  1238  	defer k.peerSigMtx.Unlock()
  1239  
  1240  	for _, c := range k.peerSig {
  1241  		// Every peerSig channel has a buffer capacity of 1,
  1242  		// so every receiver will get the signal even if the
  1243  		// select statement has the default case to avoid blocking.
  1244  		select {
  1245  		case c <- struct{}{}:
  1246  		default:
  1247  		}
  1248  	}
  1249  }
  1250  
  1251  func nClosePeerInSlice(peers []swarm.Address, addr swarm.Address, spf sanctionedPeerFunc, minPO uint8) (swarm.Address, bool) {
  1252  	for _, peer := range peers {
  1253  		if spf(peer) {
  1254  			continue
  1255  		}
  1256  
  1257  		if swarm.ExtendedProximity(peer.Bytes(), addr.Bytes()) >= minPO {
  1258  			return peer, true
  1259  		}
  1260  	}
  1261  
  1262  	return swarm.ZeroAddress, false
  1263  }
  1264  
  1265  func (k *Kad) IsReachable() bool {
  1266  	return k.reachability == p2p.ReachabilityStatusPublic
  1267  }
  1268  
  1269  // ClosestPeer returns the closest peer to a given address.
  1270  func (k *Kad) ClosestPeer(addr swarm.Address, includeSelf bool, filter topology.Select, skipPeers ...swarm.Address) (swarm.Address, error) {
  1271  	if k.connectedPeers.Length() == 0 {
  1272  		return swarm.Address{}, topology.ErrNotFound
  1273  	}
  1274  
  1275  	closest := swarm.ZeroAddress
  1276  
  1277  	if includeSelf && k.reachability == p2p.ReachabilityStatusPublic {
  1278  		closest = k.base
  1279  	}
  1280  
  1281  	err := k.EachConnectedPeerRev(func(peer swarm.Address, po uint8) (bool, bool, error) {
  1282  		if swarm.ContainsAddress(skipPeers, peer) {
  1283  			return false, false, nil
  1284  		}
  1285  
  1286  		if closest.IsZero() {
  1287  			closest = peer
  1288  			return false, false, nil
  1289  		}
  1290  
  1291  		closer, err := peer.Closer(addr, closest)
  1292  		if closer {
  1293  			closest = peer
  1294  		}
  1295  		if err != nil {
  1296  			k.logger.Debug("closest peer", "peer", peer, "addr", addr, "error", err)
  1297  		}
  1298  		return false, false, nil
  1299  	}, filter)
  1300  
  1301  	if err != nil {
  1302  		return swarm.Address{}, err
  1303  	}
  1304  
  1305  	if closest.IsZero() { // no peers
  1306  		return swarm.Address{}, topology.ErrNotFound // only for light nodes
  1307  	}
  1308  
  1309  	// check if self
  1310  	if closest.Equal(k.base) {
  1311  		return swarm.Address{}, topology.ErrWantSelf
  1312  	}
  1313  
  1314  	return closest, nil
  1315  }
  1316  
  1317  // EachConnectedPeer implements topology.PeerIterator interface.
  1318  func (k *Kad) EachConnectedPeer(f topology.EachPeerFunc, filter topology.Select) error {
  1319  	filters := excludeOps(filter)
  1320  	return k.connectedPeers.EachBin(func(addr swarm.Address, po uint8) (bool, bool, error) {
  1321  		if len(filters) > 0 && k.opt.ExcludeFunc(filters...)(addr) {
  1322  			return false, false, nil
  1323  		}
  1324  		return f(addr, po)
  1325  	})
  1326  }
  1327  
  1328  // EachConnectedPeerRev implements topology.PeerIterator interface.
  1329  func (k *Kad) EachConnectedPeerRev(f topology.EachPeerFunc, filter topology.Select) error {
  1330  	filters := excludeOps(filter)
  1331  	return k.connectedPeers.EachBinRev(func(addr swarm.Address, po uint8) (bool, bool, error) {
  1332  		if len(filters) > 0 && k.opt.ExcludeFunc(filters...)(addr) {
  1333  			return false, false, nil
  1334  		}
  1335  		return f(addr, po)
  1336  	})
  1337  }
  1338  
  1339  // Reachable sets the peer reachability status.
  1340  func (k *Kad) Reachable(addr swarm.Address, status p2p.ReachabilityStatus) {
  1341  	k.collector.Record(addr, im.PeerReachability(status))
  1342  	k.logger.Debug("reachability of peer updated", "peer_address", addr, "reachability", status)
  1343  	if status == p2p.ReachabilityStatusPublic {
  1344  		k.recalcDepth()
  1345  		k.notifyManageLoop()
  1346  	}
  1347  }
  1348  
  1349  // UpdateReachability updates node reachability status.
  1350  // The status will be updated only once. Updates to status
  1351  // p2p.ReachabilityStatusUnknown are ignored.
  1352  func (k *Kad) UpdateReachability(status p2p.ReachabilityStatus) {
  1353  	if status == p2p.ReachabilityStatusUnknown {
  1354  		return
  1355  	}
  1356  	k.logger.Debug("reachability updated", "reachability", status)
  1357  	k.reachability = status
  1358  	k.metrics.ReachabilityStatus.WithLabelValues(status.String()).Set(0)
  1359  }
  1360  
  1361  // UpdateReachability updates node reachability status.
  1362  // The status will be updated only once. Updates to status
  1363  // p2p.ReachabilityStatusUnknown are ignored.
  1364  func (k *Kad) UpdatePeerHealth(peer swarm.Address, health bool, dur time.Duration) {
  1365  	k.collector.Record(peer, im.PeerHealth(health), im.PeerLatency(dur))
  1366  }
  1367  
  1368  // SubscribeTopologyChange returns the channel that signals when the connected peers
  1369  // set and depth changes. Returned function is safe to be called multiple times.
  1370  func (k *Kad) SubscribeTopologyChange() (c <-chan struct{}, unsubscribe func()) {
  1371  	channel := make(chan struct{}, 1)
  1372  	var closeOnce sync.Once
  1373  
  1374  	k.peerSigMtx.Lock()
  1375  	defer k.peerSigMtx.Unlock()
  1376  
  1377  	k.peerSig = append(k.peerSig, channel)
  1378  
  1379  	unsubscribe = func() {
  1380  		k.peerSigMtx.Lock()
  1381  		defer k.peerSigMtx.Unlock()
  1382  
  1383  		for i, c := range k.peerSig {
  1384  			if c == channel {
  1385  				k.peerSig = append(k.peerSig[:i], k.peerSig[i+1:]...)
  1386  				break
  1387  			}
  1388  		}
  1389  
  1390  		closeOnce.Do(func() { close(channel) })
  1391  	}
  1392  
  1393  	return channel, unsubscribe
  1394  }
  1395  
  1396  func excludeOps(filter topology.Select) []im.ExcludeOp {
  1397  
  1398  	ops := make([]im.ExcludeOp, 0, 2)
  1399  
  1400  	if filter.Reachable {
  1401  		ops = append(ops, im.Reachability(false))
  1402  	}
  1403  	if filter.Healthy {
  1404  		ops = append(ops, im.Health(false))
  1405  	}
  1406  
  1407  	return ops
  1408  }
  1409  
  1410  // NeighborhoodDepth returns the current Kademlia depth.
  1411  func (k *Kad) neighborhoodDepth() uint8 {
  1412  	k.depthMu.RLock()
  1413  	defer k.depthMu.RUnlock()
  1414  
  1415  	return k.storageRadius
  1416  }
  1417  
  1418  func (k *Kad) SetStorageRadius(d uint8) {
  1419  
  1420  	k.depthMu.Lock()
  1421  	defer k.depthMu.Unlock()
  1422  
  1423  	if k.storageRadius == d {
  1424  		return
  1425  	}
  1426  
  1427  	k.storageRadius = d
  1428  	k.metrics.CurrentStorageDepth.Set(float64(k.storageRadius))
  1429  	k.logger.Debug("kademlia set storage radius", "radius", k.storageRadius)
  1430  
  1431  	k.notifyManageLoop()
  1432  	k.notifyPeerSig()
  1433  }
  1434  
  1435  func (k *Kad) Snapshot() *topology.KadParams {
  1436  	var infos []topology.BinInfo
  1437  	for i := int(swarm.MaxPO); i >= 0; i-- {
  1438  		infos = append(infos, topology.BinInfo{})
  1439  	}
  1440  
  1441  	ss := k.collector.Snapshot(time.Now())
  1442  
  1443  	_ = k.connectedPeers.EachBin(func(addr swarm.Address, po uint8) (bool, bool, error) {
  1444  		infos[po].BinConnected++
  1445  		infos[po].ConnectedPeers = append(
  1446  			infos[po].ConnectedPeers,
  1447  			&topology.PeerInfo{
  1448  				Address: addr,
  1449  				Metrics: createMetricsSnapshotView(ss[addr.ByteString()]),
  1450  			},
  1451  		)
  1452  		return false, false, nil
  1453  	})
  1454  
  1455  	// output (k.knownPeers ¬ k.connectedPeers) here to not repeat the peers we already have in the connected peers list
  1456  	_ = k.knownPeers.EachBin(func(addr swarm.Address, po uint8) (bool, bool, error) {
  1457  		infos[po].BinPopulation++
  1458  
  1459  		for _, v := range infos[po].ConnectedPeers {
  1460  			// peer already connected, don't show in the known peers list
  1461  			if v.Address.Equal(addr) {
  1462  				return false, false, nil
  1463  			}
  1464  		}
  1465  
  1466  		infos[po].DisconnectedPeers = append(
  1467  			infos[po].DisconnectedPeers,
  1468  			&topology.PeerInfo{
  1469  				Address: addr,
  1470  				Metrics: createMetricsSnapshotView(ss[addr.ByteString()]),
  1471  			},
  1472  		)
  1473  		return false, false, nil
  1474  	})
  1475  
  1476  	return &topology.KadParams{
  1477  		Base:                k.base.String(),
  1478  		Population:          k.knownPeers.Length(),
  1479  		Connected:           k.connectedPeers.Length(),
  1480  		Timestamp:           time.Now(),
  1481  		NNLowWatermark:      k.opt.LowWaterMark,
  1482  		Depth:               k.neighborhoodDepth(),
  1483  		Reachability:        k.reachability.String(),
  1484  		NetworkAvailability: k.p2p.NetworkStatus().String(),
  1485  		Bins: topology.KadBins{
  1486  			Bin0:  infos[0],
  1487  			Bin1:  infos[1],
  1488  			Bin2:  infos[2],
  1489  			Bin3:  infos[3],
  1490  			Bin4:  infos[4],
  1491  			Bin5:  infos[5],
  1492  			Bin6:  infos[6],
  1493  			Bin7:  infos[7],
  1494  			Bin8:  infos[8],
  1495  			Bin9:  infos[9],
  1496  			Bin10: infos[10],
  1497  			Bin11: infos[11],
  1498  			Bin12: infos[12],
  1499  			Bin13: infos[13],
  1500  			Bin14: infos[14],
  1501  			Bin15: infos[15],
  1502  			Bin16: infos[16],
  1503  			Bin17: infos[17],
  1504  			Bin18: infos[18],
  1505  			Bin19: infos[19],
  1506  			Bin20: infos[20],
  1507  			Bin21: infos[21],
  1508  			Bin22: infos[22],
  1509  			Bin23: infos[23],
  1510  			Bin24: infos[24],
  1511  			Bin25: infos[25],
  1512  			Bin26: infos[26],
  1513  			Bin27: infos[27],
  1514  			Bin28: infos[28],
  1515  			Bin29: infos[29],
  1516  			Bin30: infos[30],
  1517  			Bin31: infos[31],
  1518  		},
  1519  	}
  1520  }
  1521  
  1522  // String returns a string represenstation of Kademlia.
  1523  func (k *Kad) String() string {
  1524  	j := k.Snapshot()
  1525  	b, err := json.MarshalIndent(j, "", "  ")
  1526  	if err != nil {
  1527  		k.logger.Error(err, "could not marshal kademlia into json")
  1528  		return ""
  1529  	}
  1530  	return string(b)
  1531  }
  1532  
  1533  // Halt stops outgoing connections from happening.
  1534  // This is needed while we shut down, so that further topology
  1535  // changes do not happen while we shut down.
  1536  func (k *Kad) Halt() {
  1537  	close(k.halt)
  1538  }
  1539  
  1540  // Close shuts down kademlia.
  1541  func (k *Kad) Close() error {
  1542  	k.logger.Info("kademlia shutting down")
  1543  	close(k.quit)
  1544  	cc := make(chan struct{})
  1545  
  1546  	k.bgBroadcastCancel()
  1547  
  1548  	go func() {
  1549  		k.wg.Wait()
  1550  		close(cc)
  1551  	}()
  1552  
  1553  	eg := errgroup.Group{}
  1554  
  1555  	errTimeout := errors.New("timeout")
  1556  
  1557  	eg.Go(func() error {
  1558  		select {
  1559  		case <-cc:
  1560  		case <-time.After(peerConnectionAttemptTimeout):
  1561  			return fmt.Errorf("kademlia shutting down with running goroutines: %w", errTimeout)
  1562  		}
  1563  		return nil
  1564  	})
  1565  
  1566  	eg.Go(func() error {
  1567  		select {
  1568  		case <-k.done:
  1569  		case <-time.After(time.Second * 5):
  1570  			return fmt.Errorf("kademlia manage loop did not shut down properly: %w", errTimeout)
  1571  		}
  1572  		return nil
  1573  	})
  1574  
  1575  	err := eg.Wait()
  1576  
  1577  	k.logger.Info("kademlia persisting peer metrics")
  1578  	start := time.Now()
  1579  	if err := k.collector.Finalize(start, false); err != nil {
  1580  		k.logger.Debug("unable to finalize open sessions", "error", err)
  1581  	}
  1582  	k.logger.Debug("metrics collector finalized", "elapsed", time.Since(start))
  1583  
  1584  	return err
  1585  }
  1586  
  1587  func randomSubset(addrs []swarm.Address, count int) ([]swarm.Address, error) {
  1588  	if count >= len(addrs) {
  1589  		return addrs, nil
  1590  	}
  1591  
  1592  	for i := 0; i < len(addrs); i++ {
  1593  		b, err := random.Int(random.Reader, big.NewInt(int64(len(addrs))))
  1594  		if err != nil {
  1595  			return nil, err
  1596  		}
  1597  		j := int(b.Int64())
  1598  		addrs[i], addrs[j] = addrs[j], addrs[i]
  1599  	}
  1600  
  1601  	return addrs[:count], nil
  1602  }
  1603  
  1604  func (k *Kad) randomPeer(bin uint8) (swarm.Address, error) {
  1605  	peers := k.connectedPeers.BinPeers(bin)
  1606  
  1607  	for idx := 0; idx < len(peers); {
  1608  		// do not consider protected peers
  1609  		if k.staticPeer(peers[idx]) {
  1610  			peers = append(peers[:idx], peers[idx+1:]...)
  1611  			continue
  1612  		}
  1613  		idx++
  1614  	}
  1615  
  1616  	if len(peers) == 0 {
  1617  		return swarm.ZeroAddress, errEmptyBin
  1618  	}
  1619  
  1620  	rndIndx, err := random.Int(random.Reader, big.NewInt(int64(len(peers))))
  1621  	if err != nil {
  1622  		return swarm.ZeroAddress, err
  1623  	}
  1624  
  1625  	return peers[rndIndx.Int64()], nil
  1626  }
  1627  
  1628  // createMetricsSnapshotView creates new topology.MetricSnapshotView from the
  1629  // given metrics.Snapshot and rounds all the timestamps and durations to its
  1630  // nearest second, except for the peer latency, which is given in milliseconds.
  1631  func createMetricsSnapshotView(ss *im.Snapshot) *topology.MetricSnapshotView {
  1632  	if ss == nil {
  1633  		return nil
  1634  	}
  1635  	return &topology.MetricSnapshotView{
  1636  		LastSeenTimestamp:          time.Unix(0, ss.LastSeenTimestamp).Unix(),
  1637  		SessionConnectionRetry:     ss.SessionConnectionRetry,
  1638  		ConnectionTotalDuration:    ss.ConnectionTotalDuration.Truncate(time.Second).Seconds(),
  1639  		SessionConnectionDuration:  ss.SessionConnectionDuration.Truncate(time.Second).Seconds(),
  1640  		SessionConnectionDirection: string(ss.SessionConnectionDirection),
  1641  		LatencyEWMA:                ss.LatencyEWMA.Milliseconds(),
  1642  		Reachability:               ss.Reachability.String(),
  1643  		Healthy:                    ss.Healthy,
  1644  	}
  1645  }