github.com/number571/tendermint@v0.34.11-gost/internal/p2p/pex/pex_reactor.go (about)

     1  package pex
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net"
     7  	"sync"
     8  	"time"
     9  
    10  	"github.com/gogo/protobuf/proto"
    11  
    12  	"github.com/number571/tendermint/internal/p2p"
    13  	"github.com/number571/tendermint/internal/p2p/conn"
    14  	"github.com/number571/tendermint/libs/cmap"
    15  	tmmath "github.com/number571/tendermint/libs/math"
    16  	tmrand "github.com/number571/tendermint/libs/rand"
    17  	"github.com/number571/tendermint/libs/service"
    18  	tmp2p "github.com/number571/tendermint/proto/tendermint/p2p"
    19  	"github.com/number571/tendermint/types"
    20  )
    21  
    22  type Peer = p2p.Peer
    23  
    24  const (
    25  	// PexChannel is a channel for PEX messages
    26  	PexChannel = byte(0x00)
    27  
    28  	// over-estimate of max NetAddress size
    29  	// hexID (40) + IP (16) + Port (2) + Name (100) ...
    30  	// NOTE: dont use massive DNS name ..
    31  	maxAddressSize = 256
    32  
    33  	// NOTE: amplificaiton factor!
    34  	// small request results in up to maxMsgSize response
    35  	maxMsgSize = maxAddressSize * maxGetSelection
    36  
    37  	// ensure we have enough peers
    38  	defaultEnsurePeersPeriod = 30 * time.Second
    39  
    40  	// Seed/Crawler constants
    41  
    42  	// minTimeBetweenCrawls is a minimum time between attempts to crawl a peer.
    43  	minTimeBetweenCrawls = 2 * time.Minute
    44  
    45  	// check some peers every this
    46  	crawlPeerPeriod = 30 * time.Second
    47  
    48  	maxAttemptsToDial = 16 // ~ 35h in total (last attempt - 18h)
    49  
    50  	// if node connects to seed, it does not have any trusted peers.
    51  	// Especially in the beginning, node should have more trusted peers than
    52  	// untrusted.
    53  	biasToSelectNewPeers = 30 // 70 to select good peers
    54  
    55  	// if a peer is marked bad, it will be banned for at least this time period
    56  	defaultBanTime = 24 * time.Hour
    57  )
    58  
    59  type errMaxAttemptsToDial struct {
    60  }
    61  
    62  func (e errMaxAttemptsToDial) Error() string {
    63  	return fmt.Sprintf("reached max attempts %d to dial", maxAttemptsToDial)
    64  }
    65  
    66  type errTooEarlyToDial struct {
    67  	backoffDuration time.Duration
    68  	lastDialed      time.Time
    69  }
    70  
    71  func (e errTooEarlyToDial) Error() string {
    72  	return fmt.Sprintf(
    73  		"too early to dial (backoff duration: %d, last dialed: %v, time since: %v)",
    74  		e.backoffDuration, e.lastDialed, time.Since(e.lastDialed))
    75  }
    76  
    77  // Reactor handles PEX (peer exchange) and ensures that an
    78  // adequate number of peers are connected to the switch.
    79  //
    80  // It uses `AddrBook` (address book) to store `NetAddress`es of the peers.
    81  //
    82  // ## Preventing abuse
    83  //
    84  // Only accept pexAddrsMsg from peers we sent a corresponding pexRequestMsg too.
    85  // Only accept one pexRequestMsg every ~defaultEnsurePeersPeriod.
    86  type Reactor struct {
    87  	p2p.BaseReactor
    88  
    89  	book              AddrBook
    90  	config            *ReactorConfig
    91  	ensurePeersPeriod time.Duration // TODO: should go in the config
    92  
    93  	// maps to prevent abuse
    94  	requestsSent         *cmap.CMap // ID->struct{}: unanswered send requests
    95  	lastReceivedRequests *cmap.CMap // ID->time.Time: last time peer requested from us
    96  
    97  	seedAddrs []*p2p.NetAddress
    98  
    99  	attemptsToDial sync.Map // address (string) -> {number of attempts (int), last time dialed (time.Time)}
   100  
   101  	// seed/crawled mode fields
   102  	crawlPeerInfos map[types.NodeID]crawlPeerInfo
   103  }
   104  
   105  func (r *Reactor) minReceiveRequestInterval() time.Duration {
   106  	// NOTE: must be less than ensurePeersPeriod, otherwise we'll request
   107  	// peers too quickly from others and they'll think we're bad!
   108  	return r.ensurePeersPeriod / 3
   109  }
   110  
   111  // ReactorConfig holds reactor specific configuration data.
   112  type ReactorConfig struct {
   113  	// Seed/Crawler mode
   114  	SeedMode bool
   115  
   116  	// We want seeds to only advertise good peers. Therefore they should wait at
   117  	// least as long as we expect it to take for a peer to become good before
   118  	// disconnecting.
   119  	SeedDisconnectWaitPeriod time.Duration
   120  
   121  	// Maximum pause when redialing a persistent peer (if zero, exponential backoff is used)
   122  	PersistentPeersMaxDialPeriod time.Duration
   123  
   124  	// Seeds is a list of addresses reactor may use
   125  	// if it can't connect to peers in the addrbook.
   126  	Seeds []string
   127  }
   128  
   129  type _attemptsToDial struct {
   130  	number     int
   131  	lastDialed time.Time
   132  }
   133  
   134  // NewReactor creates new PEX reactor.
   135  func NewReactor(b AddrBook, config *ReactorConfig) *Reactor {
   136  	r := &Reactor{
   137  		book:                 b,
   138  		config:               config,
   139  		ensurePeersPeriod:    defaultEnsurePeersPeriod,
   140  		requestsSent:         cmap.NewCMap(),
   141  		lastReceivedRequests: cmap.NewCMap(),
   142  		crawlPeerInfos:       make(map[types.NodeID]crawlPeerInfo),
   143  	}
   144  	r.BaseReactor = *p2p.NewBaseReactor("PEX", r)
   145  	return r
   146  }
   147  
   148  // OnStart implements BaseService
   149  func (r *Reactor) OnStart() error {
   150  	err := r.book.Start()
   151  	if err != nil && err != service.ErrAlreadyStarted {
   152  		return err
   153  	}
   154  
   155  	numOnline, seedAddrs, err := r.checkSeeds()
   156  	if err != nil {
   157  		return err
   158  	} else if numOnline == 0 && r.book.Empty() {
   159  		return errors.New("address book is empty and couldn't resolve any seed nodes")
   160  	}
   161  
   162  	r.seedAddrs = seedAddrs
   163  
   164  	// Check if this node should run
   165  	// in seed/crawler mode
   166  	if r.config.SeedMode {
   167  		go r.crawlPeersRoutine()
   168  	} else {
   169  		go r.ensurePeersRoutine()
   170  	}
   171  	return nil
   172  }
   173  
   174  // OnStop implements BaseService
   175  func (r *Reactor) OnStop() {
   176  	if err := r.book.Stop(); err != nil {
   177  		r.Logger.Error("Error stopping address book", "err", err)
   178  	}
   179  }
   180  
   181  // GetChannels implements Reactor
   182  func (r *Reactor) GetChannels() []*conn.ChannelDescriptor {
   183  	return []*conn.ChannelDescriptor{
   184  		{
   185  			ID:                  PexChannel,
   186  			Priority:            1,
   187  			SendQueueCapacity:   10,
   188  			RecvMessageCapacity: maxMsgSize,
   189  
   190  			MaxSendBytes: 200,
   191  		},
   192  	}
   193  }
   194  
   195  // AddPeer implements Reactor by adding peer to the address book (if inbound)
   196  // or by requesting more addresses (if outbound).
   197  func (r *Reactor) AddPeer(p Peer) {
   198  	if p.IsOutbound() {
   199  		// For outbound peers, the address is already in the books -
   200  		// either via DialPeersAsync or r.Receive.
   201  		// Ask it for more peers if we need.
   202  		if r.book.NeedMoreAddrs() {
   203  			r.RequestAddrs(p)
   204  		}
   205  	} else {
   206  		// inbound peer is its own source
   207  		addr, err := p.NodeInfo().NetAddress()
   208  		if err != nil {
   209  			r.Logger.Error("Failed to get peer NetAddress", "err", err, "peer", p)
   210  			return
   211  		}
   212  
   213  		// Make it explicit that addr and src are the same for an inbound peer.
   214  		src := addr
   215  
   216  		// add to book. dont RequestAddrs right away because
   217  		// we don't trust inbound as much - let ensurePeersRoutine handle it.
   218  		err = r.book.AddAddress(addr, src)
   219  		r.logErrAddrBook(err)
   220  	}
   221  }
   222  
   223  // RemovePeer implements Reactor by resetting peer's requests info.
   224  func (r *Reactor) RemovePeer(p Peer, reason interface{}) {
   225  	id := string(p.ID())
   226  	r.requestsSent.Delete(id)
   227  	r.lastReceivedRequests.Delete(id)
   228  }
   229  
   230  func (r *Reactor) logErrAddrBook(err error) {
   231  	if err != nil {
   232  		switch err.(type) {
   233  		case ErrAddrBookNilAddr:
   234  			r.Logger.Error("Failed to add new address", "err", err)
   235  		default:
   236  			// non-routable, self, full book, private, etc.
   237  			r.Logger.Debug("Failed to add new address", "err", err)
   238  		}
   239  	}
   240  }
   241  
   242  // Receive implements Reactor by handling incoming PEX messages.
   243  // XXX: do not call any methods that can block or incur heavy processing.
   244  // https://github.com/number571/tendermint/issues/2888
   245  func (r *Reactor) Receive(chID byte, src Peer, msgBytes []byte) {
   246  	msg, err := decodeMsg(msgBytes)
   247  	if err != nil {
   248  		r.Logger.Error("Error decoding message", "src", src, "chId", chID, "err", err)
   249  		r.Switch.StopPeerForError(src, err)
   250  		return
   251  	}
   252  	r.Logger.Debug("Received message", "src", src, "chId", chID, "msg", msg)
   253  
   254  	switch msg := msg.(type) {
   255  	case *tmp2p.PexRequest:
   256  
   257  		// NOTE: this is a prime candidate for amplification attacks,
   258  		// so it's important we
   259  		// 1) restrict how frequently peers can request
   260  		// 2) limit the output size
   261  
   262  		// If we're a seed and this is an inbound peer,
   263  		// respond once and disconnect.
   264  		if r.config.SeedMode && !src.IsOutbound() {
   265  			id := string(src.ID())
   266  			v := r.lastReceivedRequests.Get(id)
   267  			if v != nil {
   268  				// FlushStop/StopPeer are already
   269  				// running in a go-routine.
   270  				return
   271  			}
   272  			r.lastReceivedRequests.Set(id, time.Now())
   273  
   274  			// Send addrs and disconnect
   275  			r.SendAddrs(src, r.book.GetSelectionWithBias(biasToSelectNewPeers))
   276  			go func() {
   277  				// In a go-routine so it doesn't block .Receive.
   278  				src.FlushStop()
   279  				r.Switch.StopPeerGracefully(src)
   280  			}()
   281  
   282  		} else {
   283  			// Check we're not receiving requests too frequently.
   284  			if err := r.receiveRequest(src); err != nil {
   285  				r.Switch.StopPeerForError(src, err)
   286  				r.book.MarkBad(src.SocketAddr(), defaultBanTime)
   287  				return
   288  			}
   289  			r.SendAddrs(src, r.book.GetSelection())
   290  		}
   291  
   292  	case *tmp2p.PexResponse:
   293  		// If we asked for addresses, add them to the book
   294  		addrs, err := NetAddressesFromProto(msg.Addresses)
   295  		if err != nil {
   296  			r.Switch.StopPeerForError(src, err)
   297  			r.book.MarkBad(src.SocketAddr(), defaultBanTime)
   298  			return
   299  		}
   300  		err = r.ReceiveAddrs(addrs, src)
   301  		if err != nil {
   302  			r.Switch.StopPeerForError(src, err)
   303  			if err == ErrUnsolicitedList {
   304  				r.book.MarkBad(src.SocketAddr(), defaultBanTime)
   305  			}
   306  			return
   307  		}
   308  
   309  	default:
   310  		r.Logger.Error(fmt.Sprintf("Unknown message type %T", msg))
   311  	}
   312  }
   313  
   314  // enforces a minimum amount of time between requests
   315  func (r *Reactor) receiveRequest(src Peer) error {
   316  	id := string(src.ID())
   317  	v := r.lastReceivedRequests.Get(id)
   318  	if v == nil {
   319  		// initialize with empty time
   320  		lastReceived := time.Time{}
   321  		r.lastReceivedRequests.Set(id, lastReceived)
   322  		return nil
   323  	}
   324  
   325  	lastReceived := v.(time.Time)
   326  	if lastReceived.Equal(time.Time{}) {
   327  		// first time gets a free pass. then we start tracking the time
   328  		lastReceived = time.Now()
   329  		r.lastReceivedRequests.Set(id, lastReceived)
   330  		return nil
   331  	}
   332  
   333  	now := time.Now()
   334  	minInterval := r.minReceiveRequestInterval()
   335  	if now.Sub(lastReceived) < minInterval {
   336  		return fmt.Errorf(
   337  			"peer (%v) sent next PEX request too soon. lastReceived: %v, now: %v, minInterval: %v. Disconnecting",
   338  			src.ID(),
   339  			lastReceived,
   340  			now,
   341  			minInterval,
   342  		)
   343  	}
   344  	r.lastReceivedRequests.Set(id, now)
   345  	return nil
   346  }
   347  
   348  // RequestAddrs asks peer for more addresses if we do not already have a
   349  // request out for this peer.
   350  func (r *Reactor) RequestAddrs(p Peer) {
   351  	id := string(p.ID())
   352  	if r.requestsSent.Has(id) {
   353  		return
   354  	}
   355  	r.Logger.Debug("Request addrs", "from", p)
   356  	r.requestsSent.Set(id, struct{}{})
   357  	p.Send(PexChannel, mustEncode(&tmp2p.PexRequest{}))
   358  }
   359  
   360  // ReceiveAddrs adds the given addrs to the addrbook if theres an open
   361  // request for this peer and deletes the open request.
   362  // If there's no open request for the src peer, it returns an error.
   363  func (r *Reactor) ReceiveAddrs(addrs []*p2p.NetAddress, src Peer) error {
   364  	id := string(src.ID())
   365  	if !r.requestsSent.Has(id) {
   366  		return ErrUnsolicitedList
   367  	}
   368  	r.requestsSent.Delete(id)
   369  
   370  	srcAddr, err := src.NodeInfo().NetAddress()
   371  	if err != nil {
   372  		return err
   373  	}
   374  
   375  	srcIsSeed := false
   376  	for _, seedAddr := range r.seedAddrs {
   377  		if seedAddr.Equals(srcAddr) {
   378  			srcIsSeed = true
   379  			break
   380  		}
   381  	}
   382  
   383  	for _, netAddr := range addrs {
   384  		// NOTE: we check netAddr validity and routability in book#AddAddress.
   385  		err = r.book.AddAddress(netAddr, srcAddr)
   386  		if err != nil {
   387  			r.logErrAddrBook(err)
   388  			// XXX: should we be strict about incoming data and disconnect from a
   389  			// peer here too?
   390  			continue
   391  		}
   392  
   393  		// If this address came from a seed node, try to connect to it without
   394  		// waiting (#2093)
   395  		if srcIsSeed {
   396  			r.Logger.Info("Will dial address, which came from seed", "addr", netAddr, "seed", srcAddr)
   397  			go func(addr *p2p.NetAddress) {
   398  				err := r.dialPeer(addr)
   399  				if err != nil {
   400  					switch err.(type) {
   401  					case errMaxAttemptsToDial, errTooEarlyToDial, p2p.ErrCurrentlyDialingOrExistingAddress:
   402  						r.Logger.Debug(err.Error(), "addr", addr)
   403  					default:
   404  						r.Logger.Error(err.Error(), "addr", addr)
   405  					}
   406  				}
   407  			}(netAddr)
   408  		}
   409  	}
   410  
   411  	return nil
   412  }
   413  
   414  // SendAddrs sends addrs to the peer.
   415  func (r *Reactor) SendAddrs(p Peer, netAddrs []*p2p.NetAddress) {
   416  	p.Send(PexChannel, mustEncode(&tmp2p.PexResponse{Addresses: NetAddressesToProto(netAddrs)}))
   417  }
   418  
   419  // SetEnsurePeersPeriod sets period to ensure peers connected.
   420  func (r *Reactor) SetEnsurePeersPeriod(d time.Duration) {
   421  	r.ensurePeersPeriod = d
   422  }
   423  
   424  // Ensures that sufficient peers are connected. (continuous)
   425  func (r *Reactor) ensurePeersRoutine() {
   426  	var (
   427  		seed   = tmrand.NewRand()
   428  		jitter = seed.Int63n(r.ensurePeersPeriod.Nanoseconds())
   429  	)
   430  
   431  	// Randomize first round of communication to avoid thundering herd.
   432  	// If no peers are present directly start connecting so we guarantee swift
   433  	// setup with the help of configured seeds.
   434  	if r.nodeHasSomePeersOrDialingAny() {
   435  		time.Sleep(time.Duration(jitter))
   436  	}
   437  
   438  	// fire once immediately.
   439  	// ensures we dial the seeds right away if the book is empty
   440  	r.ensurePeers()
   441  
   442  	// fire periodically
   443  	ticker := time.NewTicker(r.ensurePeersPeriod)
   444  	for {
   445  		select {
   446  		case <-ticker.C:
   447  			r.ensurePeers()
   448  		case <-r.Quit():
   449  			ticker.Stop()
   450  			return
   451  		}
   452  	}
   453  }
   454  
   455  // ensurePeers ensures that sufficient peers are connected. (once)
   456  //
   457  // heuristic that we haven't perfected yet, or, perhaps is manually edited by
   458  // the node operator. It should not be used to compute what addresses are
   459  // already connected or not.
   460  func (r *Reactor) ensurePeers() {
   461  	var (
   462  		out, in, dial = r.Switch.NumPeers()
   463  		numToDial     = r.Switch.MaxNumOutboundPeers() - (out + dial)
   464  	)
   465  	r.Logger.Info(
   466  		"Ensure peers",
   467  		"numOutPeers", out,
   468  		"numInPeers", in,
   469  		"numDialing", dial,
   470  		"numToDial", numToDial,
   471  	)
   472  
   473  	if numToDial <= 0 {
   474  		return
   475  	}
   476  
   477  	// bias to prefer more vetted peers when we have fewer connections.
   478  	// not perfect, but somewhate ensures that we prioritize connecting to more-vetted
   479  	// NOTE: range here is [10, 90]. Too high ?
   480  	newBias := tmmath.MinInt(out, 8)*10 + 10
   481  
   482  	toDial := make(map[types.NodeID]*p2p.NetAddress)
   483  	// Try maxAttempts times to pick numToDial addresses to dial
   484  	maxAttempts := numToDial * 3
   485  
   486  	for i := 0; i < maxAttempts && len(toDial) < numToDial; i++ {
   487  		try := r.book.PickAddress(newBias)
   488  		if try == nil {
   489  			continue
   490  		}
   491  		if _, selected := toDial[try.ID]; selected {
   492  			continue
   493  		}
   494  		if r.Switch.IsDialingOrExistingAddress(try) {
   495  			continue
   496  		}
   497  		// TODO: consider moving some checks from toDial into here
   498  		// so we don't even consider dialing peers that we want to wait
   499  		// before dialing again, or have dialed too many times already
   500  		r.Logger.Info("Will dial address", "addr", try)
   501  		toDial[try.ID] = try
   502  	}
   503  
   504  	// Dial picked addresses
   505  	for _, addr := range toDial {
   506  		go func(addr *p2p.NetAddress) {
   507  			err := r.dialPeer(addr)
   508  			if err != nil {
   509  				switch err.(type) {
   510  				case errMaxAttemptsToDial, errTooEarlyToDial:
   511  					r.Logger.Debug(err.Error(), "addr", addr)
   512  				default:
   513  					r.Logger.Error(err.Error(), "addr", addr)
   514  				}
   515  			}
   516  		}(addr)
   517  	}
   518  
   519  	if r.book.NeedMoreAddrs() {
   520  		// Check if banned nodes can be reinstated
   521  		r.book.ReinstateBadPeers()
   522  	}
   523  
   524  	if r.book.NeedMoreAddrs() {
   525  
   526  		// 1) Pick a random peer and ask for more.
   527  		peers := r.Switch.Peers().List()
   528  		peersCount := len(peers)
   529  		if peersCount > 0 {
   530  			rand := tmrand.NewRand()
   531  			peer := peers[rand.Int()%peersCount]
   532  			r.Logger.Info("We need more addresses. Sending pexRequest to random peer", "peer", peer)
   533  			r.RequestAddrs(peer)
   534  		}
   535  
   536  		// 2) Dial seeds if we are not dialing anyone.
   537  		// This is done in addition to asking a peer for addresses to work-around
   538  		// peers not participating in PEX.
   539  		if len(toDial) == 0 {
   540  			r.Logger.Info("No addresses to dial. Falling back to seeds")
   541  			r.dialSeeds()
   542  		}
   543  	}
   544  }
   545  
   546  func (r *Reactor) dialAttemptsInfo(addr *p2p.NetAddress) (attempts int, lastDialed time.Time) {
   547  	_attempts, ok := r.attemptsToDial.Load(addr.DialString())
   548  	if !ok {
   549  		return
   550  	}
   551  	atd := _attempts.(_attemptsToDial)
   552  	return atd.number, atd.lastDialed
   553  }
   554  
   555  func (r *Reactor) dialPeer(addr *p2p.NetAddress) error {
   556  	attempts, lastDialed := r.dialAttemptsInfo(addr)
   557  	if !r.Switch.IsPeerPersistent(addr) && attempts > maxAttemptsToDial {
   558  		r.book.MarkBad(addr, defaultBanTime)
   559  		return errMaxAttemptsToDial{}
   560  	}
   561  
   562  	// exponential backoff if it's not our first attempt to dial given address
   563  	if attempts > 0 {
   564  		rand := tmrand.NewRand()
   565  		jitter := time.Duration(rand.Float64() * float64(time.Second)) // 1s == (1e9 ns)
   566  		backoffDuration := jitter + ((1 << uint(attempts)) * time.Second)
   567  		backoffDuration = r.maxBackoffDurationForPeer(addr, backoffDuration)
   568  		sinceLastDialed := time.Since(lastDialed)
   569  		if sinceLastDialed < backoffDuration {
   570  			return errTooEarlyToDial{backoffDuration, lastDialed}
   571  		}
   572  	}
   573  
   574  	err := r.Switch.DialPeerWithAddress(addr)
   575  	if err != nil {
   576  		if _, ok := err.(p2p.ErrCurrentlyDialingOrExistingAddress); ok {
   577  			return err
   578  		}
   579  
   580  		markAddrInBookBasedOnErr(addr, r.book, err)
   581  		switch err.(type) {
   582  		case p2p.ErrSwitchAuthenticationFailure:
   583  			// NOTE: addr is removed from addrbook in markAddrInBookBasedOnErr
   584  			r.attemptsToDial.Delete(addr.DialString())
   585  		default:
   586  			r.attemptsToDial.Store(addr.DialString(), _attemptsToDial{attempts + 1, time.Now()})
   587  		}
   588  		return fmt.Errorf("dialing failed (attempts: %d): %w", attempts+1, err)
   589  	}
   590  
   591  	// cleanup any history
   592  	r.attemptsToDial.Delete(addr.DialString())
   593  	return nil
   594  }
   595  
   596  // maxBackoffDurationForPeer caps the backoff duration for persistent peers.
   597  func (r *Reactor) maxBackoffDurationForPeer(addr *p2p.NetAddress, planned time.Duration) time.Duration {
   598  	if r.config.PersistentPeersMaxDialPeriod > 0 &&
   599  		planned > r.config.PersistentPeersMaxDialPeriod &&
   600  		r.Switch.IsPeerPersistent(addr) {
   601  		return r.config.PersistentPeersMaxDialPeriod
   602  	}
   603  	return planned
   604  }
   605  
   606  // checkSeeds checks that addresses are well formed.
   607  // Returns number of seeds we can connect to, along with all seeds addrs.
   608  // return err if user provided any badly formatted seed addresses.
   609  // Doesn't error if the seed node can't be reached.
   610  // numOnline returns -1 if no seed nodes were in the initial configuration.
   611  func (r *Reactor) checkSeeds() (numOnline int, netAddrs []*p2p.NetAddress, err error) {
   612  	lSeeds := len(r.config.Seeds)
   613  	if lSeeds == 0 {
   614  		return -1, nil, nil
   615  	}
   616  	netAddrs, errs := p2p.NewNetAddressStrings(r.config.Seeds)
   617  	numOnline = lSeeds - len(errs)
   618  	for _, err := range errs {
   619  		switch e := err.(type) {
   620  		case types.ErrNetAddressLookup:
   621  			r.Logger.Error("Connecting to seed failed", "err", e)
   622  		default:
   623  			return 0, nil, fmt.Errorf("seed node configuration has error: %w", e)
   624  		}
   625  	}
   626  	return numOnline, netAddrs, nil
   627  }
   628  
   629  // randomly dial seeds until we connect to one or exhaust them
   630  func (r *Reactor) dialSeeds() {
   631  	rand := tmrand.NewRand()
   632  	perm := rand.Perm(len(r.seedAddrs))
   633  	// perm := r.Switch.rng.Perm(lSeeds)
   634  	for _, i := range perm {
   635  		// dial a random seed
   636  		seedAddr := r.seedAddrs[i]
   637  		err := r.Switch.DialPeerWithAddress(seedAddr)
   638  
   639  		switch err.(type) {
   640  		case nil, p2p.ErrCurrentlyDialingOrExistingAddress:
   641  			return
   642  		}
   643  		r.Switch.Logger.Error("Error dialing seed", "err", err, "seed", seedAddr)
   644  	}
   645  	// do not write error message if there were no seeds specified in config
   646  	if len(r.seedAddrs) > 0 {
   647  		r.Switch.Logger.Error("Couldn't connect to any seeds")
   648  	}
   649  }
   650  
   651  // AttemptsToDial returns the number of attempts to dial specific address. It
   652  // returns 0 if never attempted or successfully connected.
   653  func (r *Reactor) AttemptsToDial(addr *p2p.NetAddress) int {
   654  	lAttempts, attempted := r.attemptsToDial.Load(addr.DialString())
   655  	if attempted {
   656  		return lAttempts.(_attemptsToDial).number
   657  	}
   658  	return 0
   659  }
   660  
   661  //----------------------------------------------------------
   662  
   663  // Explores the network searching for more peers. (continuous)
   664  // Seed/Crawler Mode causes this node to quickly disconnect
   665  // from peers, except other seed nodes.
   666  func (r *Reactor) crawlPeersRoutine() {
   667  	// If we have any seed nodes, consult them first
   668  	if len(r.seedAddrs) > 0 {
   669  		r.dialSeeds()
   670  	} else {
   671  		// Do an initial crawl
   672  		r.crawlPeers(r.book.GetSelection())
   673  	}
   674  
   675  	// Fire periodically
   676  	ticker := time.NewTicker(crawlPeerPeriod)
   677  
   678  	for {
   679  		select {
   680  		case <-ticker.C:
   681  			r.attemptDisconnects()
   682  			r.crawlPeers(r.book.GetSelection())
   683  			r.cleanupCrawlPeerInfos()
   684  		case <-r.Quit():
   685  			return
   686  		}
   687  	}
   688  }
   689  
   690  // nodeHasSomePeersOrDialingAny returns true if the node is connected to some
   691  // peers or dialing them currently.
   692  func (r *Reactor) nodeHasSomePeersOrDialingAny() bool {
   693  	out, in, dial := r.Switch.NumPeers()
   694  	return out+in+dial > 0
   695  }
   696  
   697  // crawlPeerInfo handles temporary data needed for the network crawling
   698  // performed during seed/crawler mode.
   699  type crawlPeerInfo struct {
   700  	Addr *p2p.NetAddress `json:"addr"`
   701  	// The last time we crawled the peer or attempted to do so.
   702  	LastCrawled time.Time `json:"last_crawled"`
   703  }
   704  
   705  // crawlPeers will crawl the network looking for new peer addresses.
   706  func (r *Reactor) crawlPeers(addrs []*p2p.NetAddress) {
   707  	now := time.Now()
   708  
   709  	for _, addr := range addrs {
   710  		peerInfo, ok := r.crawlPeerInfos[addr.ID]
   711  
   712  		// Do not attempt to connect with peers we recently crawled.
   713  		if ok && now.Sub(peerInfo.LastCrawled) < minTimeBetweenCrawls {
   714  			continue
   715  		}
   716  
   717  		// Record crawling attempt.
   718  		r.crawlPeerInfos[addr.ID] = crawlPeerInfo{
   719  			Addr:        addr,
   720  			LastCrawled: now,
   721  		}
   722  
   723  		err := r.dialPeer(addr)
   724  		if err != nil {
   725  			switch err.(type) {
   726  			case errMaxAttemptsToDial, errTooEarlyToDial, p2p.ErrCurrentlyDialingOrExistingAddress:
   727  				r.Logger.Debug(err.Error(), "addr", addr)
   728  			default:
   729  				r.Logger.Error(err.Error(), "addr", addr)
   730  			}
   731  			continue
   732  		}
   733  
   734  		peer := r.Switch.Peers().Get(addr.ID)
   735  		if peer != nil {
   736  			r.RequestAddrs(peer)
   737  		}
   738  	}
   739  }
   740  
   741  func (r *Reactor) cleanupCrawlPeerInfos() {
   742  	for id, info := range r.crawlPeerInfos {
   743  		// If we did not crawl a peer for 24 hours, it means the peer was removed
   744  		// from the addrbook => remove
   745  		//
   746  		// 10000 addresses / maxGetSelection = 40 cycles to get all addresses in
   747  		// the ideal case,
   748  		// 40 * crawlPeerPeriod ~ 20 minutes
   749  		if time.Since(info.LastCrawled) > 24*time.Hour {
   750  			delete(r.crawlPeerInfos, id)
   751  		}
   752  	}
   753  }
   754  
   755  // attemptDisconnects checks if we've been with each peer long enough to disconnect
   756  func (r *Reactor) attemptDisconnects() {
   757  	for _, peer := range r.Switch.Peers().List() {
   758  		if peer.Status().Duration < r.config.SeedDisconnectWaitPeriod {
   759  			continue
   760  		}
   761  		if peer.IsPersistent() {
   762  			continue
   763  		}
   764  		r.Switch.StopPeerGracefully(peer)
   765  	}
   766  }
   767  
   768  func markAddrInBookBasedOnErr(addr *p2p.NetAddress, book AddrBook, err error) {
   769  	// TODO: detect more "bad peer" scenarios
   770  	switch err.(type) {
   771  	case p2p.ErrSwitchAuthenticationFailure:
   772  		book.MarkBad(addr, defaultBanTime)
   773  	default:
   774  		book.MarkAttempt(addr)
   775  	}
   776  }
   777  
   778  //-----------------------------------------------------------------------------
   779  // Messages
   780  
   781  // mustEncode proto encodes a tmp2p.Message
   782  func mustEncode(pb proto.Message) []byte {
   783  	msg := tmp2p.PexMessage{}
   784  	switch pb := pb.(type) {
   785  	case *tmp2p.PexRequest:
   786  		msg.Sum = &tmp2p.PexMessage_PexRequest{PexRequest: pb}
   787  	case *tmp2p.PexResponse:
   788  		msg.Sum = &tmp2p.PexMessage_PexResponse{PexResponse: pb}
   789  	default:
   790  		panic(fmt.Sprintf("Unknown message type %T", pb))
   791  	}
   792  
   793  	bz, err := msg.Marshal()
   794  	if err != nil {
   795  		panic(fmt.Errorf("unable to marshal %T: %w", pb, err))
   796  	}
   797  	return bz
   798  }
   799  
   800  func decodeMsg(bz []byte) (proto.Message, error) {
   801  	pb := &tmp2p.PexMessage{}
   802  
   803  	err := pb.Unmarshal(bz)
   804  	if err != nil {
   805  		return nil, err
   806  	}
   807  
   808  	switch msg := pb.Sum.(type) {
   809  	case *tmp2p.PexMessage_PexRequest:
   810  		return msg.PexRequest, nil
   811  	case *tmp2p.PexMessage_PexResponse:
   812  		return msg.PexResponse, nil
   813  	default:
   814  		return nil, fmt.Errorf("unknown message: %T", msg)
   815  	}
   816  }
   817  
   818  //-----------------------------------------------------------------------------
   819  // address converters
   820  
   821  // NetAddressFromProto converts a Protobuf PexAddress into a native struct.
   822  func NetAddressFromProto(pb tmp2p.PexAddress) (*types.NetAddress, error) {
   823  	ip := net.ParseIP(pb.IP)
   824  	if ip == nil {
   825  		return nil, fmt.Errorf("invalid IP address %v", pb.IP)
   826  	}
   827  	if pb.Port >= 1<<16 {
   828  		return nil, fmt.Errorf("invalid port number %v", pb.Port)
   829  	}
   830  	return &types.NetAddress{
   831  		ID:   types.NodeID(pb.ID),
   832  		IP:   ip,
   833  		Port: uint16(pb.Port),
   834  	}, nil
   835  }
   836  
   837  // NetAddressesFromProto converts a slice of Protobuf PexAddresses into a native slice.
   838  func NetAddressesFromProto(pbs []tmp2p.PexAddress) ([]*types.NetAddress, error) {
   839  	nas := make([]*types.NetAddress, 0, len(pbs))
   840  	for _, pb := range pbs {
   841  		na, err := NetAddressFromProto(pb)
   842  		if err != nil {
   843  			return nil, err
   844  		}
   845  		nas = append(nas, na)
   846  	}
   847  	return nas, nil
   848  }
   849  
   850  // NetAddressesToProto converts a slice of NetAddresses into a Protobuf PexAddress slice.
   851  func NetAddressesToProto(nas []*types.NetAddress) []tmp2p.PexAddress {
   852  	pbs := make([]tmp2p.PexAddress, 0, len(nas))
   853  	for _, na := range nas {
   854  		if na != nil {
   855  			pbs = append(pbs, tmp2p.PexAddress{
   856  				ID:   string(na.ID),
   857  				IP:   na.IP.String(),
   858  				Port: uint32(na.Port),
   859  			})
   860  		}
   861  	}
   862  	return pbs
   863  }