func (r *PEXReactor) RequestAddrs(p Peer) {
	r.Logger.Debug("Request addrs", "from", p)
	id := string(p.ID())
	if r.requestsSent.Has(id) {
		return
	}
	r.requestsSent.Set(id, struct{}{})
	p.Send(PexChannel, cdc.MustMarshalBinaryBare(&pexRequestMessage{}))
}
RequestAddrs asks peer for more addresses if we do not already
have a request out for this peer.
package pex
import (
	"fmt"
	"reflect"
	"sort"
	"sync"
	"time"
	amino "github.com/tendermint/go-amino"
	cmn "github.com/tendermint/tendermint/libs/common"
	"github.com/tendermint/tendermint/p2p"
	"github.com/tendermint/tendermint/p2p/conn"
)
type Peer = p2p.Peer
const (
	PexChannel = byte(0x00)
	maxAddressSize = 256
	maxMsgSize = maxAddressSize * maxGetSelection
	defaultEnsurePeersPeriod   = 30 * time.Second
	defaultMinNumOutboundPeers = p2p.DefaultMinNumOutboundPeers
	defaultSeedDisconnectWaitPeriod = 3 * time.Hour
	defaultCrawlPeerInterval = 2 * time.Minute  
	defaultCrawlPeersPeriod = 30 * time.Second  
	maxAttemptsToDial = 16  
	biasToSelectNewPeers = 30  
)
type PEXReactor struct {
	p2p.BaseReactor
	book              AddrBook
	config            *PEXReactorConfig
	ensurePeersPeriod time.Duration  
	requestsSent         *cmn.CMap  
	lastReceivedRequests *cmn.CMap  
	attemptsToDial sync.Map  
}
func (r *PEXReactor) minReceiveRequestInterval() time.Duration {
	return r.ensurePeersPeriod / 3
}
type PEXReactorConfig struct {
	SeedMode bool
	Seeds []string
}
type _attemptsToDial struct {
	number     int
	lastDialed time.Time
}
func NewPEXReactor(b AddrBook, config *PEXReactorConfig) *PEXReactor {
	r := &PEXReactor{
		book:                 b,
		config:               config,
		ensurePeersPeriod:    defaultEnsurePeersPeriod,
		requestsSent:         cmn.NewCMap(),
		lastReceivedRequests: cmn.NewCMap(),
	}
	r.BaseReactor = *p2p.NewBaseReactor("PEXReactor", r)
	return r
}
func (r *PEXReactor) OnStart() error {
	if err := r.BaseReactor.OnStart(); err != nil {
		return err
	}
	err := r.book.Start()
	if err != nil && err != cmn.ErrAlreadyStarted {
		return err
	}
	if err := r.checkSeeds(); err != nil {
		return err
	}
	if r.config.SeedMode {
		go r.crawlPeersRoutine()
	} else {
		go r.ensurePeersRoutine()
	}
	return nil
}
func (r *PEXReactor) OnStop() {
	r.BaseReactor.OnStop()
	r.book.Stop()
}
func (r *PEXReactor) GetChannels() []*conn.ChannelDescriptor {
	return []*conn.ChannelDescriptor{
		{
			ID:                PexChannel,
			Priority:          1,
			SendQueueCapacity: 10,
		},
	}
}
func (r *PEXReactor) AddPeer(p Peer) {
	if p.IsOutbound() {
		if r.book.NeedMoreAddrs() {
			r.RequestAddrs(p)
		}
	} else {
		addr := p.NodeInfo().NetAddress()
		src := addr
		err := r.book.AddAddress(addr, src)
		r.logErrAddrBook(err)
	}
}
func (r *PEXReactor) logErrAddrBook(err error) {
	if err != nil {
		switch err.(type) {
		case ErrAddrBookNilAddr:
			r.Logger.Error("Failed to add new address", "err", err)
		default:
			r.Logger.Debug("Failed to add new address", "err", err)
		}
	}
}
func (r *PEXReactor) RemovePeer(p Peer, reason interface{}) {
	id := string(p.ID())
	r.requestsSent.Delete(id)
	r.lastReceivedRequests.Delete(id)
}
func (r *PEXReactor) Receive(chID byte, src Peer, msgBytes []byte) {
	msg, err := decodeMsg(msgBytes)
	if err != nil {
		r.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
		r.Switch.StopPeerForError(src, err)
		return
	}
	r.Logger.Debug("Received message", "src", src, "chId", chID, "msg", msg)
	switch msg := msg.(type) {
	case *pexRequestMessage:
		if err := r.receiveRequest(src); err != nil {
			r.Switch.StopPeerForError(src, err)
			return
		}
		if r.config.SeedMode {
			r.SendAddrs(src, r.book.GetSelectionWithBias(biasToSelectNewPeers))
			r.Switch.StopPeerGracefully(src)
		} else {
			r.SendAddrs(src, r.book.GetSelection())
		}
	case *pexAddrsMessage:
		if err := r.ReceiveAddrs(msg.Addrs, src); err != nil {
			r.Switch.StopPeerForError(src, err)
			return
		}
	default:
		r.Logger.Error(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg)))
	}
}
func (r *PEXReactor) receiveRequest(src Peer) error {
	id := string(src.ID())
	v := r.lastReceivedRequests.Get(id)
	if v == nil {
		lastReceived := time.Time{}
		r.lastReceivedRequests.Set(id, lastReceived)
		return nil
	}
	lastReceived := v.(time.Time)
	if lastReceived.Equal(time.Time{}) {
		lastReceived = time.Now()
		r.lastReceivedRequests.Set(id, lastReceived)
		return nil
	}
	now := time.Now()
	minInterval := r.minReceiveRequestInterval()
	if now.Sub(lastReceived) < minInterval {
		return fmt.Errorf("Peer (%v) sent next PEX request too soon. lastReceived: %v, now: %v, minInterval: %v. Disconnecting",
			src.ID(),
			lastReceived,
			now,
			minInterval,
		)
	}
	r.lastReceivedRequests.Set(id, now)
	return nil
}