github.com/okex/exchain@v1.8.0/libs/tendermint/p2p/pex/pex_reactor.go (about)

     1  package pex
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"sync"
     7  	"time"
     8  
     9  	"github.com/pkg/errors"
    10  
    11  	"github.com/tendermint/go-amino"
    12  
    13  	"github.com/okex/exchain/libs/tendermint/libs/cmap"
    14  	tmmath "github.com/okex/exchain/libs/tendermint/libs/math"
    15  	"github.com/okex/exchain/libs/tendermint/libs/rand"
    16  	tmrand "github.com/okex/exchain/libs/tendermint/libs/rand"
    17  	"github.com/okex/exchain/libs/tendermint/libs/service"
    18  	"github.com/okex/exchain/libs/tendermint/p2p"
    19  	"github.com/okex/exchain/libs/tendermint/p2p/conn"
    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[p2p.ID]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[p2p.ID]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  	r.book.Stop()
   177  }
   178  
   179  // GetChannels implements Reactor
   180  func (r *Reactor) GetChannels() []*conn.ChannelDescriptor {
   181  	return []*conn.ChannelDescriptor{
   182  		{
   183  			ID:                PexChannel,
   184  			Priority:          1,
   185  			SendQueueCapacity: 10,
   186  		},
   187  	}
   188  }
   189  
   190  // AddPeer implements Reactor by adding peer to the address book (if inbound)
   191  // or by requesting more addresses (if outbound).
   192  func (r *Reactor) AddPeer(p Peer) {
   193  	if p.IsOutbound() {
   194  		// For outbound peers, the address is already in the books -
   195  		// either via DialPeersAsync or r.Receive.
   196  		// Ask it for more peers if we need.
   197  		if r.book.NeedMoreAddrs() {
   198  			r.RequestAddrs(p)
   199  		}
   200  	} else {
   201  		// inbound peer is its own source
   202  		addr, err := p.NodeInfo().NetAddress()
   203  		if err != nil {
   204  			r.Logger.Error("Failed to get peer NetAddress", "err", err, "peer", p)
   205  			return
   206  		}
   207  
   208  		// Make it explicit that addr and src are the same for an inbound peer.
   209  		src := addr
   210  
   211  		// add to book. dont RequestAddrs right away because
   212  		// we don't trust inbound as much - let ensurePeersRoutine handle it.
   213  		err = r.book.AddAddress(addr, src)
   214  		r.logErrAddrBook(err)
   215  	}
   216  }
   217  
   218  // RemovePeer implements Reactor by resetting peer's requests info.
   219  func (r *Reactor) RemovePeer(p Peer, reason interface{}) {
   220  	id := string(p.ID())
   221  	r.requestsSent.Delete(id)
   222  	r.lastReceivedRequests.Delete(id)
   223  }
   224  
   225  func (r *Reactor) logErrAddrBook(err error) {
   226  	if err != nil {
   227  		switch err.(type) {
   228  		case ErrAddrBookNilAddr:
   229  			r.Logger.Error("Failed to add new address", "err", err)
   230  		default:
   231  			// non-routable, self, full book, private, etc.
   232  			r.Logger.Debug("Failed to add new address", "err", err)
   233  		}
   234  	}
   235  }
   236  
   237  // Receive implements Reactor by handling incoming PEX messages.
   238  func (r *Reactor) Receive(chID byte, src Peer, msgBytes []byte) {
   239  	msg, err := decodeMsg(msgBytes)
   240  	if err != nil {
   241  		r.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
   242  		r.Switch.StopPeerForError(src, err)
   243  		return
   244  	}
   245  	r.Logger.Debug("Received message", "src", src, "chId", chID, "msg", msg)
   246  
   247  	switch msg := msg.(type) {
   248  	case *pexRequestMessage:
   249  
   250  		// NOTE: this is a prime candidate for amplification attacks,
   251  		// so it's important we
   252  		// 1) restrict how frequently peers can request
   253  		// 2) limit the output size
   254  
   255  		// If we're a seed and this is an inbound peer,
   256  		// respond once and disconnect.
   257  		if r.config.SeedMode && !src.IsOutbound() {
   258  			id := string(src.ID())
   259  			v := r.lastReceivedRequests.Get(id)
   260  			if v != nil {
   261  				// FlushStop/StopPeer are already
   262  				// running in a go-routine.
   263  				return
   264  			}
   265  			r.lastReceivedRequests.Set(id, time.Now())
   266  
   267  			// Send addrs and disconnect
   268  			r.SendAddrs(src, r.book.GetSelectionWithBias(biasToSelectNewPeers))
   269  			go func() {
   270  				// In a go-routine so it doesn't block .Receive.
   271  				src.FlushStop()
   272  				r.Switch.StopPeerGracefully(src)
   273  			}()
   274  
   275  		} else {
   276  			// Check we're not receiving requests too frequently.
   277  			if err := r.receiveRequest(src); err != nil {
   278  				r.Switch.StopPeerForError(src, err)
   279  				r.book.MarkBad(src.SocketAddr(), defaultBanTime)
   280  				return
   281  			}
   282  			r.SendAddrs(src, r.book.GetSelection())
   283  		}
   284  
   285  	case *pexAddrsMessage:
   286  		// If we asked for addresses, add them to the book
   287  		if err := r.ReceiveAddrs(msg.Addrs, src); err != nil {
   288  			r.Switch.StopPeerForError(src, err)
   289  			if err == ErrUnsolicitedList {
   290  				r.book.MarkBad(src.SocketAddr(), defaultBanTime)
   291  			}
   292  			return
   293  		}
   294  	default:
   295  		r.Logger.Error(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg)))
   296  	}
   297  }
   298  
   299  // enforces a minimum amount of time between requests
   300  func (r *Reactor) receiveRequest(src Peer) error {
   301  	id := string(src.ID())
   302  	v := r.lastReceivedRequests.Get(id)
   303  	if v == nil {
   304  		// initialize with empty time
   305  		lastReceived := time.Time{}
   306  		r.lastReceivedRequests.Set(id, lastReceived)
   307  		return nil
   308  	}
   309  
   310  	lastReceived := v.(time.Time)
   311  	if lastReceived.Equal(time.Time{}) {
   312  		// first time gets a free pass. then we start tracking the time
   313  		lastReceived = time.Now()
   314  		r.lastReceivedRequests.Set(id, lastReceived)
   315  		return nil
   316  	}
   317  
   318  	now := time.Now()
   319  	minInterval := r.minReceiveRequestInterval()
   320  	if now.Sub(lastReceived) < minInterval {
   321  		return fmt.Errorf(
   322  			"peer (%v) sent next PEX request too soon. lastReceived: %v, now: %v, minInterval: %v. Disconnecting",
   323  			src.ID(),
   324  			lastReceived,
   325  			now,
   326  			minInterval,
   327  		)
   328  	}
   329  	r.lastReceivedRequests.Set(id, now)
   330  	return nil
   331  }
   332  
   333  // RequestAddrs asks peer for more addresses if we do not already have a
   334  // request out for this peer.
   335  func (r *Reactor) RequestAddrs(p Peer) {
   336  	id := string(p.ID())
   337  	if r.requestsSent.Has(id) {
   338  		return
   339  	}
   340  	r.Logger.Debug("Request addrs", "from", p)
   341  	r.requestsSent.Set(id, struct{}{})
   342  	p.Send(PexChannel, cdc.MustMarshalBinaryBare(&pexRequestMessage{}))
   343  }
   344  
   345  // ReceiveAddrs adds the given addrs to the addrbook if theres an open
   346  // request for this peer and deletes the open request.
   347  // If there's no open request for the src peer, it returns an error.
   348  func (r *Reactor) ReceiveAddrs(addrs []*p2p.NetAddress, src Peer) error {
   349  	id := string(src.ID())
   350  	if !r.requestsSent.Has(id) {
   351  		return ErrUnsolicitedList
   352  	}
   353  	r.requestsSent.Delete(id)
   354  
   355  	srcAddr, err := src.NodeInfo().NetAddress()
   356  	if err != nil {
   357  		return err
   358  	}
   359  
   360  	srcIsSeed := false
   361  	for _, seedAddr := range r.seedAddrs {
   362  		if seedAddr.Equals(srcAddr) {
   363  			srcIsSeed = true
   364  			break
   365  		}
   366  	}
   367  
   368  	for _, netAddr := range addrs {
   369  		// NOTE: we check netAddr validity and routability in book#AddAddress.
   370  		err = r.book.AddAddress(netAddr, srcAddr)
   371  		if err != nil {
   372  			r.logErrAddrBook(err)
   373  			// XXX: should we be strict about incoming data and disconnect from a
   374  			// peer here too?
   375  			continue
   376  		}
   377  
   378  		// If this address came from a seed node, try to connect to it without
   379  		// waiting (#2093)
   380  		if srcIsSeed {
   381  			r.Logger.Info("Will dial address, which came from seed", "addr", netAddr, "seed", srcAddr)
   382  			go func(addr *p2p.NetAddress) {
   383  				err := r.dialPeer(addr)
   384  				if err != nil {
   385  					switch err.(type) {
   386  					case errMaxAttemptsToDial, errTooEarlyToDial, p2p.ErrCurrentlyDialingOrExistingAddress:
   387  						r.Logger.Debug(err.Error(), "addr", addr)
   388  					default:
   389  						r.Logger.Error(err.Error(), "addr", addr)
   390  					}
   391  				}
   392  			}(netAddr)
   393  		}
   394  	}
   395  
   396  	return nil
   397  }
   398  
   399  // SendAddrs sends addrs to the peer.
   400  func (r *Reactor) SendAddrs(p Peer, netAddrs []*p2p.NetAddress) {
   401  	p.Send(PexChannel, cdc.MustMarshalBinaryBare(&pexAddrsMessage{Addrs: netAddrs}))
   402  }
   403  
   404  // SetEnsurePeersPeriod sets period to ensure peers connected.
   405  func (r *Reactor) SetEnsurePeersPeriod(d time.Duration) {
   406  	r.ensurePeersPeriod = d
   407  }
   408  
   409  // Ensures that sufficient peers are connected. (continuous)
   410  func (r *Reactor) ensurePeersRoutine() {
   411  	var (
   412  		seed   = rand.NewRand()
   413  		jitter = seed.Int63n(r.ensurePeersPeriod.Nanoseconds())
   414  	)
   415  
   416  	// Randomize first round of communication to avoid thundering herd.
   417  	// If no peers are present directly start connecting so we guarantee swift
   418  	// setup with the help of configured seeds.
   419  	if r.nodeHasSomePeersOrDialingAny() {
   420  		time.Sleep(time.Duration(jitter))
   421  	}
   422  
   423  	// fire once immediately.
   424  	// ensures we dial the seeds right away if the book is empty
   425  	r.ensurePeers()
   426  
   427  	// fire periodically
   428  	ticker := time.NewTicker(r.ensurePeersPeriod)
   429  	for {
   430  		select {
   431  		case <-ticker.C:
   432  			r.ensurePeers()
   433  		case <-r.Quit():
   434  			ticker.Stop()
   435  			return
   436  		}
   437  	}
   438  }
   439  
   440  // ensurePeers ensures that sufficient peers are connected. (once)
   441  //
   442  // heuristic that we haven't perfected yet, or, perhaps is manually edited by
   443  // the node operator. It should not be used to compute what addresses are
   444  // already connected or not.
   445  func (r *Reactor) ensurePeers() {
   446  	var (
   447  		out, in, dial = r.Switch.NumPeers()
   448  		numToDial     = r.Switch.MaxNumOutboundPeers() - (out + dial)
   449  	)
   450  	r.Logger.Info(
   451  		"Ensure peers",
   452  		"numOutPeers", out,
   453  		"numInPeers", in,
   454  		"numDialing", dial,
   455  		"numToDial", numToDial,
   456  	)
   457  
   458  	if numToDial <= 0 {
   459  		return
   460  	}
   461  
   462  	// bias to prefer more vetted peers when we have fewer connections.
   463  	// not perfect, but somewhate ensures that we prioritize connecting to more-vetted
   464  	// NOTE: range here is [10, 90]. Too high ?
   465  	newBias := tmmath.MinInt(out, 8)*10 + 10
   466  
   467  	toDial := make(map[p2p.ID]*p2p.NetAddress)
   468  	// Try maxAttempts times to pick numToDial addresses to dial
   469  	maxAttempts := numToDial * 3
   470  
   471  	for i := 0; i < maxAttempts && len(toDial) < numToDial; i++ {
   472  		try := r.book.PickAddress(newBias)
   473  		if try == nil {
   474  			continue
   475  		}
   476  		if _, selected := toDial[try.ID]; selected {
   477  			continue
   478  		}
   479  		if r.Switch.IsDialingOrExistingAddress(try) {
   480  			continue
   481  		}
   482  		// TODO: consider moving some checks from toDial into here
   483  		// so we don't even consider dialing peers that we want to wait
   484  		// before dialling again, or have dialed too many times already
   485  		r.Logger.Info("Will dial address", "addr", try)
   486  		toDial[try.ID] = try
   487  	}
   488  
   489  	// Dial picked addresses
   490  	for _, addr := range toDial {
   491  		go func(addr *p2p.NetAddress) {
   492  			err := r.dialPeer(addr)
   493  			if err != nil {
   494  				switch err.(type) {
   495  				case errMaxAttemptsToDial, errTooEarlyToDial:
   496  					r.Logger.Debug(err.Error(), "addr", addr)
   497  				default:
   498  					r.Logger.Error(err.Error(), "addr", addr)
   499  				}
   500  			}
   501  		}(addr)
   502  	}
   503  
   504  	if r.book.NeedMoreAddrs() {
   505  		// Check if banned nodes can be reinstated
   506  		r.book.ReinstateBadPeers()
   507  	}
   508  
   509  	if r.book.NeedMoreAddrs() {
   510  
   511  		// 1) Pick a random peer and ask for more.
   512  		peers := r.Switch.Peers().List()
   513  		peersCount := len(peers)
   514  		if peersCount > 0 {
   515  			peer := peers[tmrand.Int()%peersCount]
   516  			r.Logger.Info("We need more addresses. Sending pexRequest to random peer", "peer", peer)
   517  			r.RequestAddrs(peer)
   518  		}
   519  
   520  		// 2) Dial seeds if we are not dialing anyone.
   521  		// This is done in addition to asking a peer for addresses to work-around
   522  		// peers not participating in PEX.
   523  		if len(toDial) == 0 {
   524  			r.Logger.Info("No addresses to dial. Falling back to seeds")
   525  			r.dialSeeds()
   526  		}
   527  	}
   528  }
   529  
   530  func (r *Reactor) dialAttemptsInfo(addr *p2p.NetAddress) (attempts int, lastDialed time.Time) {
   531  	_attempts, ok := r.attemptsToDial.Load(addr.DialString())
   532  	if !ok {
   533  		return
   534  	}
   535  	atd := _attempts.(_attemptsToDial)
   536  	return atd.number, atd.lastDialed
   537  }
   538  
   539  func (r *Reactor) dialPeer(addr *p2p.NetAddress) error {
   540  	attempts, lastDialed := r.dialAttemptsInfo(addr)
   541  	if !r.Switch.IsPeerPersistent(addr) && attempts > maxAttemptsToDial {
   542  		r.book.MarkBad(addr, defaultBanTime)
   543  		return errMaxAttemptsToDial{}
   544  	}
   545  
   546  	// exponential backoff if it's not our first attempt to dial given address
   547  	if attempts > 0 {
   548  		jitterSeconds := time.Duration(tmrand.Float64() * float64(time.Second)) // 1s == (1e9 ns)
   549  		backoffDuration := jitterSeconds + ((1 << uint(attempts)) * time.Second)
   550  		backoffDuration = r.maxBackoffDurationForPeer(addr, backoffDuration)
   551  		sinceLastDialed := time.Since(lastDialed)
   552  		if sinceLastDialed < backoffDuration {
   553  			return errTooEarlyToDial{backoffDuration, lastDialed}
   554  		}
   555  	}
   556  
   557  	err := r.Switch.DialPeerWithAddress(addr)
   558  	if err != nil {
   559  		if _, ok := err.(p2p.ErrCurrentlyDialingOrExistingAddress); ok {
   560  			return err
   561  		}
   562  
   563  		markAddrInBookBasedOnErr(addr, r.book, err)
   564  		switch err.(type) {
   565  		case p2p.ErrSwitchAuthenticationFailure:
   566  			// NOTE: addr is removed from addrbook in markAddrInBookBasedOnErr
   567  			r.attemptsToDial.Delete(addr.DialString())
   568  		default:
   569  			r.attemptsToDial.Store(addr.DialString(), _attemptsToDial{attempts + 1, time.Now()})
   570  		}
   571  		return errors.Wrapf(err, "dialing failed (attempts: %d)", attempts+1)
   572  	}
   573  
   574  	// cleanup any history
   575  	r.attemptsToDial.Delete(addr.DialString())
   576  	return nil
   577  }
   578  
   579  // maxBackoffDurationForPeer caps the backoff duration for persistent peers.
   580  func (r *Reactor) maxBackoffDurationForPeer(addr *p2p.NetAddress, planned time.Duration) time.Duration {
   581  	if r.config.PersistentPeersMaxDialPeriod > 0 &&
   582  		planned > r.config.PersistentPeersMaxDialPeriod &&
   583  		r.Switch.IsPeerPersistent(addr) {
   584  		return r.config.PersistentPeersMaxDialPeriod
   585  	}
   586  	return planned
   587  }
   588  
   589  // checkSeeds checks that addresses are well formed.
   590  // Returns number of seeds we can connect to, along with all seeds addrs.
   591  // return err if user provided any badly formatted seed addresses.
   592  // Doesn't error if the seed node can't be reached.
   593  // numOnline returns -1 if no seed nodes were in the initial configuration.
   594  func (r *Reactor) checkSeeds() (numOnline int, netAddrs []*p2p.NetAddress, err error) {
   595  	lSeeds := len(r.config.Seeds)
   596  	if lSeeds == 0 {
   597  		return -1, nil, nil
   598  	}
   599  	netAddrs, errs := p2p.NewNetAddressStrings(r.config.Seeds)
   600  	numOnline = lSeeds - len(errs)
   601  	for _, err := range errs {
   602  		switch e := err.(type) {
   603  		case p2p.ErrNetAddressLookup:
   604  			r.Logger.Error("Connecting to seed failed", "err", e)
   605  		default:
   606  			return 0, nil, errors.Wrap(e, "seed node configuration has error")
   607  		}
   608  	}
   609  	return numOnline, netAddrs, nil
   610  }
   611  
   612  // randomly dial seeds until we connect to one or exhaust them
   613  func (r *Reactor) dialSeeds() {
   614  	perm := tmrand.Perm(len(r.seedAddrs))
   615  	// perm := r.Switch.rng.Perm(lSeeds)
   616  	for _, i := range perm {
   617  		// dial a random seed
   618  		seedAddr := r.seedAddrs[i]
   619  		err := r.Switch.DialPeerWithAddress(seedAddr)
   620  
   621  		switch err.(type) {
   622  		case nil, p2p.ErrCurrentlyDialingOrExistingAddress:
   623  			return
   624  		}
   625  		r.Switch.Logger.Error("Error dialing seed", "err", err, "seed", seedAddr)
   626  	}
   627  	// do not write error message if there were no seeds specified in config
   628  	if len(r.seedAddrs) > 0 {
   629  		r.Switch.Logger.Error("Couldn't connect to any seeds")
   630  	}
   631  }
   632  
   633  // AttemptsToDial returns the number of attempts to dial specific address. It
   634  // returns 0 if never attempted or successfully connected.
   635  func (r *Reactor) AttemptsToDial(addr *p2p.NetAddress) int {
   636  	lAttempts, attempted := r.attemptsToDial.Load(addr.DialString())
   637  	if attempted {
   638  		return lAttempts.(_attemptsToDial).number
   639  	}
   640  	return 0
   641  }
   642  
   643  //----------------------------------------------------------
   644  
   645  // Explores the network searching for more peers. (continuous)
   646  // Seed/Crawler Mode causes this node to quickly disconnect
   647  // from peers, except other seed nodes.
   648  func (r *Reactor) crawlPeersRoutine() {
   649  	// If we have any seed nodes, consult them first
   650  	if len(r.seedAddrs) > 0 {
   651  		r.dialSeeds()
   652  	} else {
   653  		// Do an initial crawl
   654  		r.crawlPeers(r.book.GetSelection())
   655  	}
   656  
   657  	// Fire periodically
   658  	ticker := time.NewTicker(crawlPeerPeriod)
   659  
   660  	for {
   661  		select {
   662  		case <-ticker.C:
   663  			r.attemptDisconnects()
   664  			r.crawlPeers(r.book.GetSelection())
   665  			r.cleanupCrawlPeerInfos()
   666  		case <-r.Quit():
   667  			return
   668  		}
   669  	}
   670  }
   671  
   672  // nodeHasSomePeersOrDialingAny returns true if the node is connected to some
   673  // peers or dialing them currently.
   674  func (r *Reactor) nodeHasSomePeersOrDialingAny() bool {
   675  	out, in, dial := r.Switch.NumPeers()
   676  	return out+in+dial > 0
   677  }
   678  
   679  // crawlPeerInfo handles temporary data needed for the network crawling
   680  // performed during seed/crawler mode.
   681  type crawlPeerInfo struct {
   682  	Addr *p2p.NetAddress `json:"addr"`
   683  	// The last time we crawled the peer or attempted to do so.
   684  	LastCrawled time.Time `json:"last_crawled"`
   685  }
   686  
   687  // crawlPeers will crawl the network looking for new peer addresses.
   688  func (r *Reactor) crawlPeers(addrs []*p2p.NetAddress) {
   689  	now := time.Now()
   690  
   691  	for _, addr := range addrs {
   692  		peerInfo, ok := r.crawlPeerInfos[addr.ID]
   693  
   694  		// Do not attempt to connect with peers we recently crawled.
   695  		if ok && now.Sub(peerInfo.LastCrawled) < minTimeBetweenCrawls {
   696  			continue
   697  		}
   698  
   699  		// Record crawling attempt.
   700  		r.crawlPeerInfos[addr.ID] = crawlPeerInfo{
   701  			Addr:        addr,
   702  			LastCrawled: now,
   703  		}
   704  
   705  		err := r.dialPeer(addr)
   706  		if err != nil {
   707  			switch err.(type) {
   708  			case errMaxAttemptsToDial, errTooEarlyToDial, p2p.ErrCurrentlyDialingOrExistingAddress:
   709  				r.Logger.Debug(err.Error(), "addr", addr)
   710  			default:
   711  				r.Logger.Error(err.Error(), "addr", addr)
   712  			}
   713  			continue
   714  		}
   715  
   716  		peer := r.Switch.Peers().Get(addr.ID)
   717  		if peer != nil {
   718  			r.RequestAddrs(peer)
   719  		}
   720  	}
   721  }
   722  
   723  func (r *Reactor) cleanupCrawlPeerInfos() {
   724  	for id, info := range r.crawlPeerInfos {
   725  		// If we did not crawl a peer for 24 hours, it means the peer was removed
   726  		// from the addrbook => remove
   727  		//
   728  		// 10000 addresses / maxGetSelection = 40 cycles to get all addresses in
   729  		// the ideal case,
   730  		// 40 * crawlPeerPeriod ~ 20 minutes
   731  		if time.Since(info.LastCrawled) > 24*time.Hour {
   732  			delete(r.crawlPeerInfos, id)
   733  		}
   734  	}
   735  }
   736  
   737  // attemptDisconnects checks if we've been with each peer long enough to disconnect
   738  func (r *Reactor) attemptDisconnects() {
   739  	for _, peer := range r.Switch.Peers().List() {
   740  		if peer.Status().Duration < r.config.SeedDisconnectWaitPeriod {
   741  			continue
   742  		}
   743  		if peer.IsPersistent() {
   744  			continue
   745  		}
   746  		r.Switch.StopPeerGracefully(peer)
   747  	}
   748  }
   749  
   750  func markAddrInBookBasedOnErr(addr *p2p.NetAddress, book AddrBook, err error) {
   751  	// TODO: detect more "bad peer" scenarios
   752  	switch err.(type) {
   753  	case p2p.ErrSwitchAuthenticationFailure:
   754  		book.MarkBad(addr, defaultBanTime)
   755  	default:
   756  		book.MarkAttempt(addr)
   757  	}
   758  }
   759  
   760  //-----------------------------------------------------------------------------
   761  // Messages
   762  
   763  // Message is a primary type for PEX messages. Underneath, it could contain
   764  // either pexRequestMessage, or pexAddrsMessage messages.
   765  type Message interface{}
   766  
   767  func RegisterMessages(cdc *amino.Codec) {
   768  	cdc.RegisterInterface((*Message)(nil), nil)
   769  	cdc.RegisterConcrete(&pexRequestMessage{}, "tendermint/p2p/PexRequestMessage", nil)
   770  	cdc.RegisterConcrete(&pexAddrsMessage{}, "tendermint/p2p/PexAddrsMessage", nil)
   771  }
   772  
   773  func decodeMsg(bz []byte) (msg Message, err error) {
   774  	if len(bz) > maxMsgSize {
   775  		return msg, fmt.Errorf("msg exceeds max size (%d > %d)", len(bz), maxMsgSize)
   776  	}
   777  	err = cdc.UnmarshalBinaryBare(bz, &msg)
   778  	return
   779  }
   780  
   781  /*
   782  A pexRequestMessage requests additional peer addresses.
   783  */
   784  type pexRequestMessage struct {
   785  }
   786  
   787  func (m *pexRequestMessage) String() string {
   788  	return "[pexRequest]"
   789  }
   790  
   791  /*
   792  A message with announced peer addresses.
   793  */
   794  type pexAddrsMessage struct {
   795  	Addrs []*p2p.NetAddress
   796  }
   797  
   798  func (m *pexAddrsMessage) String() string {
   799  	return fmt.Sprintf("[pexAddrs %v]", m.Addrs)
   800  }