github.com/pure-x-eth/consensus_tm@v0.0.0-20230502163723-e3c2ff987250/p2p/pex/pex_reactor_test.go (about)

     1  package pex
     2  
     3  import (
     4  	"encoding/hex"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/gogo/protobuf/proto"
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  
    15  	"github.com/pure-x-eth/consensus_tm/config"
    16  	"github.com/pure-x-eth/consensus_tm/libs/log"
    17  	"github.com/pure-x-eth/consensus_tm/p2p"
    18  	"github.com/pure-x-eth/consensus_tm/p2p/mock"
    19  	tmp2p "github.com/pure-x-eth/consensus_tm/proto/tendermint/p2p"
    20  )
    21  
    22  var cfg *config.P2PConfig
    23  
    24  func init() {
    25  	cfg = config.DefaultP2PConfig()
    26  	cfg.PexReactor = true
    27  	cfg.AllowDuplicateIP = true
    28  }
    29  
    30  func TestPEXReactorBasic(t *testing.T) {
    31  	r, book := createReactor(&ReactorConfig{})
    32  	defer teardownReactor(book)
    33  
    34  	assert.NotNil(t, r)
    35  	assert.NotEmpty(t, r.GetChannels())
    36  }
    37  
    38  func TestPEXReactorAddRemovePeer(t *testing.T) {
    39  	r, book := createReactor(&ReactorConfig{})
    40  	defer teardownReactor(book)
    41  
    42  	size := book.Size()
    43  	peer := p2p.CreateRandomPeer(false)
    44  
    45  	r.AddPeer(peer)
    46  	assert.Equal(t, size+1, book.Size())
    47  
    48  	r.RemovePeer(peer, "peer not available")
    49  
    50  	outboundPeer := p2p.CreateRandomPeer(true)
    51  
    52  	r.AddPeer(outboundPeer)
    53  	assert.Equal(t, size+1, book.Size(), "outbound peers should not be added to the address book")
    54  
    55  	r.RemovePeer(outboundPeer, "peer not available")
    56  }
    57  
    58  // --- FAIL: TestPEXReactorRunning (11.10s)
    59  //
    60  //	pex_reactor_test.go:411: expected all switches to be connected to at
    61  //	least one peer (switches: 0 => {outbound: 1, inbound: 0}, 1 =>
    62  //	{outbound: 0, inbound: 1}, 2 => {outbound: 0, inbound: 0}, )
    63  //
    64  // EXPLANATION: peers are getting rejected because in switch#addPeer we check
    65  // if any peer (who we already connected to) has the same IP. Even though local
    66  // peers have different IP addresses, they all have the same underlying remote
    67  // IP: 127.0.0.1.
    68  func TestPEXReactorRunning(t *testing.T) {
    69  	N := 3
    70  	switches := make([]*p2p.Switch, N)
    71  
    72  	// directory to store address books
    73  	dir, err := os.MkdirTemp("", "pex_reactor")
    74  	require.Nil(t, err)
    75  	defer os.RemoveAll(dir)
    76  
    77  	books := make([]AddrBook, N)
    78  	logger := log.TestingLogger()
    79  
    80  	// create switches
    81  	for i := 0; i < N; i++ {
    82  		switches[i] = p2p.MakeSwitch(cfg, i, "testing", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch {
    83  			books[i] = NewAddrBook(filepath.Join(dir, fmt.Sprintf("addrbook%d.json", i)), false)
    84  			books[i].SetLogger(logger.With("pex", i))
    85  			sw.SetAddrBook(books[i])
    86  
    87  			sw.SetLogger(logger.With("pex", i))
    88  
    89  			r := NewReactor(books[i], &ReactorConfig{})
    90  			r.SetLogger(logger.With("pex", i))
    91  			r.SetEnsurePeersPeriod(250 * time.Millisecond)
    92  			sw.AddReactor("pex", r)
    93  
    94  			return sw
    95  		})
    96  	}
    97  
    98  	addOtherNodeAddrToAddrBook := func(switchIndex, otherSwitchIndex int) {
    99  		addr := switches[otherSwitchIndex].NetAddress()
   100  		err := books[switchIndex].AddAddress(addr, addr)
   101  		require.NoError(t, err)
   102  	}
   103  
   104  	addOtherNodeAddrToAddrBook(0, 1)
   105  	addOtherNodeAddrToAddrBook(1, 0)
   106  	addOtherNodeAddrToAddrBook(2, 1)
   107  
   108  	for _, sw := range switches {
   109  		err := sw.Start() // start switch and reactors
   110  		require.Nil(t, err)
   111  	}
   112  
   113  	assertPeersWithTimeout(t, switches, 10*time.Millisecond, 10*time.Second, N-1)
   114  
   115  	// stop them
   116  	for _, s := range switches {
   117  		err := s.Stop()
   118  		require.NoError(t, err)
   119  	}
   120  }
   121  
   122  func TestPEXReactorReceive(t *testing.T) {
   123  	r, book := createReactor(&ReactorConfig{})
   124  	defer teardownReactor(book)
   125  
   126  	peer := p2p.CreateRandomPeer(false)
   127  
   128  	// we have to send a request to receive responses
   129  	r.RequestAddrs(peer)
   130  
   131  	size := book.Size()
   132  	msg := &tmp2p.PexAddrs{Addrs: []tmp2p.NetAddress{peer.SocketAddr().ToProto()}}
   133  	r.ReceiveEnvelope(p2p.Envelope{ChannelID: PexChannel, Src: peer, Message: msg})
   134  	assert.Equal(t, size+1, book.Size())
   135  
   136  	r.ReceiveEnvelope(p2p.Envelope{ChannelID: PexChannel, Src: peer, Message: &tmp2p.PexRequest{}})
   137  }
   138  
   139  func TestPEXReactorRequestMessageAbuse(t *testing.T) {
   140  	r, book := createReactor(&ReactorConfig{})
   141  	defer teardownReactor(book)
   142  
   143  	sw := createSwitchAndAddReactors(r)
   144  	sw.SetAddrBook(book)
   145  
   146  	peer := mock.NewPeer(nil)
   147  	peerAddr := peer.SocketAddr()
   148  	p2p.AddPeerToSwitchPeerSet(sw, peer)
   149  	assert.True(t, sw.Peers().Has(peer.ID()))
   150  	err := book.AddAddress(peerAddr, peerAddr)
   151  	require.NoError(t, err)
   152  	require.True(t, book.HasAddress(peerAddr))
   153  
   154  	id := string(peer.ID())
   155  
   156  	// first time creates the entry
   157  	r.ReceiveEnvelope(p2p.Envelope{ChannelID: PexChannel, Src: peer, Message: &tmp2p.PexRequest{}})
   158  	assert.True(t, r.lastReceivedRequests.Has(id))
   159  	assert.True(t, sw.Peers().Has(peer.ID()))
   160  
   161  	// next time sets the last time value
   162  	r.ReceiveEnvelope(p2p.Envelope{ChannelID: PexChannel, Src: peer, Message: &tmp2p.PexRequest{}})
   163  	assert.True(t, r.lastReceivedRequests.Has(id))
   164  	assert.True(t, sw.Peers().Has(peer.ID()))
   165  
   166  	// third time is too many too soon - peer is removed
   167  	r.ReceiveEnvelope(p2p.Envelope{ChannelID: PexChannel, Src: peer, Message: &tmp2p.PexRequest{}})
   168  	assert.False(t, r.lastReceivedRequests.Has(id))
   169  	assert.False(t, sw.Peers().Has(peer.ID()))
   170  	assert.True(t, book.IsBanned(peerAddr))
   171  }
   172  
   173  func TestPEXReactorAddrsMessageAbuse(t *testing.T) {
   174  	r, book := createReactor(&ReactorConfig{})
   175  	defer teardownReactor(book)
   176  
   177  	sw := createSwitchAndAddReactors(r)
   178  	sw.SetAddrBook(book)
   179  
   180  	peer := mock.NewPeer(nil)
   181  	p2p.AddPeerToSwitchPeerSet(sw, peer)
   182  	assert.True(t, sw.Peers().Has(peer.ID()))
   183  
   184  	id := string(peer.ID())
   185  
   186  	// request addrs from the peer
   187  	r.RequestAddrs(peer)
   188  	assert.True(t, r.requestsSent.Has(id))
   189  	assert.True(t, sw.Peers().Has(peer.ID()))
   190  
   191  	msg := &tmp2p.PexAddrs{Addrs: []tmp2p.NetAddress{peer.SocketAddr().ToProto()}}
   192  
   193  	// receive some addrs. should clear the request
   194  	r.ReceiveEnvelope(p2p.Envelope{ChannelID: PexChannel, Src: peer, Message: msg})
   195  	assert.False(t, r.requestsSent.Has(id))
   196  	assert.True(t, sw.Peers().Has(peer.ID()))
   197  
   198  	// receiving more unsolicited addrs causes a disconnect and ban
   199  	r.ReceiveEnvelope(p2p.Envelope{ChannelID: PexChannel, Src: peer, Message: msg})
   200  	assert.False(t, sw.Peers().Has(peer.ID()))
   201  	assert.True(t, book.IsBanned(peer.SocketAddr()))
   202  }
   203  
   204  func TestCheckSeeds(t *testing.T) {
   205  	// directory to store address books
   206  	dir, err := os.MkdirTemp("", "pex_reactor")
   207  	require.Nil(t, err)
   208  	defer os.RemoveAll(dir)
   209  
   210  	// 1. test creating peer with no seeds works
   211  	peerSwitch := testCreateDefaultPeer(dir, 0)
   212  	require.Nil(t, peerSwitch.Start())
   213  	peerSwitch.Stop() //nolint:errcheck // ignore for tests
   214  
   215  	// 2. create seed
   216  	seed := testCreateSeed(dir, 1, []*p2p.NetAddress{}, []*p2p.NetAddress{})
   217  
   218  	// 3. test create peer with online seed works
   219  	peerSwitch = testCreatePeerWithSeed(dir, 2, seed)
   220  	require.Nil(t, peerSwitch.Start())
   221  	peerSwitch.Stop() //nolint:errcheck // ignore for tests
   222  
   223  	// 4. test create peer with all seeds having unresolvable DNS fails
   224  	badPeerConfig := &ReactorConfig{
   225  		Seeds: []string{
   226  			"ed3dfd27bfc4af18f67a49862f04cc100696e84d@bad.network.addr:26657",
   227  			"d824b13cb5d40fa1d8a614e089357c7eff31b670@anotherbad.network.addr:26657",
   228  		},
   229  	}
   230  	peerSwitch = testCreatePeerWithConfig(dir, 2, badPeerConfig)
   231  	require.Error(t, peerSwitch.Start())
   232  	peerSwitch.Stop() //nolint:errcheck // ignore for tests
   233  
   234  	// 5. test create peer with one good seed address succeeds
   235  	badPeerConfig = &ReactorConfig{
   236  		Seeds: []string{
   237  			"ed3dfd27bfc4af18f67a49862f04cc100696e84d@bad.network.addr:26657",
   238  			"d824b13cb5d40fa1d8a614e089357c7eff31b670@anotherbad.network.addr:26657",
   239  			seed.NetAddress().String(),
   240  		},
   241  	}
   242  	peerSwitch = testCreatePeerWithConfig(dir, 2, badPeerConfig)
   243  	require.Nil(t, peerSwitch.Start())
   244  	peerSwitch.Stop() //nolint:errcheck // ignore for tests
   245  }
   246  
   247  func TestPEXReactorUsesSeedsIfNeeded(t *testing.T) {
   248  	// directory to store address books
   249  	dir, err := os.MkdirTemp("", "pex_reactor")
   250  	require.Nil(t, err)
   251  	defer os.RemoveAll(dir)
   252  
   253  	// 1. create seed
   254  	seed := testCreateSeed(dir, 0, []*p2p.NetAddress{}, []*p2p.NetAddress{})
   255  	require.Nil(t, seed.Start())
   256  	defer seed.Stop() //nolint:errcheck // ignore for tests
   257  
   258  	// 2. create usual peer with only seed configured.
   259  	peer := testCreatePeerWithSeed(dir, 1, seed)
   260  	require.Nil(t, peer.Start())
   261  	defer peer.Stop() //nolint:errcheck // ignore for tests
   262  
   263  	// 3. check that the peer connects to seed immediately
   264  	assertPeersWithTimeout(t, []*p2p.Switch{peer}, 10*time.Millisecond, 3*time.Second, 1)
   265  }
   266  
   267  func TestConnectionSpeedForPeerReceivedFromSeed(t *testing.T) {
   268  	// directory to store address books
   269  	dir, err := os.MkdirTemp("", "pex_reactor")
   270  	require.Nil(t, err)
   271  	defer os.RemoveAll(dir)
   272  
   273  	// 1. create peer
   274  	peerSwitch := testCreateDefaultPeer(dir, 1)
   275  	require.Nil(t, peerSwitch.Start())
   276  	defer peerSwitch.Stop() //nolint:errcheck // ignore for tests
   277  
   278  	// 2. Create seed which knows about the peer
   279  	peerAddr := peerSwitch.NetAddress()
   280  	seed := testCreateSeed(dir, 2, []*p2p.NetAddress{peerAddr}, []*p2p.NetAddress{peerAddr})
   281  	require.Nil(t, seed.Start())
   282  	defer seed.Stop() //nolint:errcheck // ignore for tests
   283  
   284  	// 3. create another peer with only seed configured.
   285  	secondPeer := testCreatePeerWithSeed(dir, 3, seed)
   286  	require.Nil(t, secondPeer.Start())
   287  	defer secondPeer.Stop() //nolint:errcheck // ignore for tests
   288  
   289  	// 4. check that the second peer connects to seed immediately
   290  	assertPeersWithTimeout(t, []*p2p.Switch{secondPeer}, 10*time.Millisecond, 3*time.Second, 1)
   291  
   292  	// 5. check that the second peer connects to the first peer immediately
   293  	assertPeersWithTimeout(t, []*p2p.Switch{secondPeer}, 10*time.Millisecond, 1*time.Second, 2)
   294  }
   295  
   296  func TestPEXReactorSeedMode(t *testing.T) {
   297  	// directory to store address books
   298  	dir, err := os.MkdirTemp("", "pex_reactor")
   299  	require.Nil(t, err)
   300  	defer os.RemoveAll(dir)
   301  
   302  	pexRConfig := &ReactorConfig{SeedMode: true, SeedDisconnectWaitPeriod: 10 * time.Millisecond}
   303  	pexR, book := createReactor(pexRConfig)
   304  	defer teardownReactor(book)
   305  
   306  	sw := createSwitchAndAddReactors(pexR)
   307  	sw.SetAddrBook(book)
   308  	err = sw.Start()
   309  	require.NoError(t, err)
   310  	defer sw.Stop() //nolint:errcheck // ignore for tests
   311  
   312  	assert.Zero(t, sw.Peers().Size())
   313  
   314  	peerSwitch := testCreateDefaultPeer(dir, 1)
   315  	require.NoError(t, peerSwitch.Start())
   316  	defer peerSwitch.Stop() //nolint:errcheck // ignore for tests
   317  
   318  	// 1. Test crawlPeers dials the peer
   319  	pexR.crawlPeers([]*p2p.NetAddress{peerSwitch.NetAddress()})
   320  	assert.Equal(t, 1, sw.Peers().Size())
   321  	assert.True(t, sw.Peers().Has(peerSwitch.NodeInfo().ID()))
   322  
   323  	// 2. attemptDisconnects should not disconnect because of wait period
   324  	pexR.attemptDisconnects()
   325  	assert.Equal(t, 1, sw.Peers().Size())
   326  
   327  	// sleep for SeedDisconnectWaitPeriod
   328  	time.Sleep(pexRConfig.SeedDisconnectWaitPeriod + 1*time.Millisecond)
   329  
   330  	// 3. attemptDisconnects should disconnect after wait period
   331  	pexR.attemptDisconnects()
   332  	assert.Equal(t, 0, sw.Peers().Size())
   333  }
   334  
   335  func TestPEXReactorDoesNotDisconnectFromPersistentPeerInSeedMode(t *testing.T) {
   336  	// directory to store address books
   337  	dir, err := os.MkdirTemp("", "pex_reactor")
   338  	require.Nil(t, err)
   339  	defer os.RemoveAll(dir)
   340  
   341  	pexRConfig := &ReactorConfig{SeedMode: true, SeedDisconnectWaitPeriod: 1 * time.Millisecond}
   342  	pexR, book := createReactor(pexRConfig)
   343  	defer teardownReactor(book)
   344  
   345  	sw := createSwitchAndAddReactors(pexR)
   346  	sw.SetAddrBook(book)
   347  	err = sw.Start()
   348  	require.NoError(t, err)
   349  	defer sw.Stop() //nolint:errcheck // ignore for tests
   350  
   351  	assert.Zero(t, sw.Peers().Size())
   352  
   353  	peerSwitch := testCreateDefaultPeer(dir, 1)
   354  	require.NoError(t, peerSwitch.Start())
   355  	defer peerSwitch.Stop() //nolint:errcheck // ignore for tests
   356  
   357  	err = sw.AddPersistentPeers([]string{peerSwitch.NetAddress().String()})
   358  	require.NoError(t, err)
   359  
   360  	// 1. Test crawlPeers dials the peer
   361  	pexR.crawlPeers([]*p2p.NetAddress{peerSwitch.NetAddress()})
   362  	assert.Equal(t, 1, sw.Peers().Size())
   363  	assert.True(t, sw.Peers().Has(peerSwitch.NodeInfo().ID()))
   364  
   365  	// sleep for SeedDisconnectWaitPeriod
   366  	time.Sleep(pexRConfig.SeedDisconnectWaitPeriod + 1*time.Millisecond)
   367  
   368  	// 2. attemptDisconnects should not disconnect because the peer is persistent
   369  	pexR.attemptDisconnects()
   370  	assert.Equal(t, 1, sw.Peers().Size())
   371  }
   372  
   373  func TestPEXReactorDialsPeerUpToMaxAttemptsInSeedMode(t *testing.T) {
   374  	// directory to store address books
   375  	dir, err := os.MkdirTemp("", "pex_reactor")
   376  	require.Nil(t, err)
   377  	defer os.RemoveAll(dir)
   378  
   379  	pexR, book := createReactor(&ReactorConfig{SeedMode: true})
   380  	defer teardownReactor(book)
   381  
   382  	sw := createSwitchAndAddReactors(pexR)
   383  	sw.SetAddrBook(book)
   384  	// No need to start sw since crawlPeers is called manually here.
   385  
   386  	peer := mock.NewPeer(nil)
   387  	addr := peer.SocketAddr()
   388  
   389  	err = book.AddAddress(addr, addr)
   390  	require.NoError(t, err)
   391  
   392  	assert.True(t, book.HasAddress(addr))
   393  
   394  	// imitate maxAttemptsToDial reached
   395  	pexR.attemptsToDial.Store(addr.DialString(), _attemptsToDial{maxAttemptsToDial + 1, time.Now()})
   396  	pexR.crawlPeers([]*p2p.NetAddress{addr})
   397  
   398  	assert.False(t, book.HasAddress(addr))
   399  }
   400  
   401  // connect a peer to a seed, wait a bit, then stop it.
   402  // this should give it time to request addrs and for the seed
   403  // to call FlushStop, and allows us to test calling Stop concurrently
   404  // with FlushStop. Before a fix, this non-deterministically reproduced
   405  // https://github.com/pure-x-eth/consensus_tm/issues/3231.
   406  func TestPEXReactorSeedModeFlushStop(t *testing.T) {
   407  	N := 2
   408  	switches := make([]*p2p.Switch, N)
   409  
   410  	// directory to store address books
   411  	dir, err := os.MkdirTemp("", "pex_reactor")
   412  	require.Nil(t, err)
   413  	defer os.RemoveAll(dir)
   414  
   415  	books := make([]AddrBook, N)
   416  	logger := log.TestingLogger()
   417  
   418  	// create switches
   419  	for i := 0; i < N; i++ {
   420  		switches[i] = p2p.MakeSwitch(cfg, i, "testing", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch {
   421  			books[i] = NewAddrBook(filepath.Join(dir, fmt.Sprintf("addrbook%d.json", i)), false)
   422  			books[i].SetLogger(logger.With("pex", i))
   423  			sw.SetAddrBook(books[i])
   424  
   425  			sw.SetLogger(logger.With("pex", i))
   426  
   427  			config := &ReactorConfig{}
   428  			if i == 0 {
   429  				// first one is a seed node
   430  				config = &ReactorConfig{SeedMode: true}
   431  			}
   432  			r := NewReactor(books[i], config)
   433  			r.SetLogger(logger.With("pex", i))
   434  			r.SetEnsurePeersPeriod(250 * time.Millisecond)
   435  			sw.AddReactor("pex", r)
   436  
   437  			return sw
   438  		})
   439  	}
   440  
   441  	for _, sw := range switches {
   442  		err := sw.Start() // start switch and reactors
   443  		require.Nil(t, err)
   444  	}
   445  
   446  	reactor := switches[0].Reactors()["pex"].(*Reactor)
   447  	peerID := switches[1].NodeInfo().ID()
   448  
   449  	err = switches[1].DialPeerWithAddress(switches[0].NetAddress())
   450  	assert.NoError(t, err)
   451  
   452  	// sleep up to a second while waiting for the peer to send us a message.
   453  	// this isn't perfect since it's possible the peer sends us a msg and we FlushStop
   454  	// before this loop catches it. but non-deterministically it works pretty well.
   455  	for i := 0; i < 1000; i++ {
   456  		v := reactor.lastReceivedRequests.Get(string(peerID))
   457  		if v != nil {
   458  			break
   459  		}
   460  		time.Sleep(time.Millisecond)
   461  	}
   462  
   463  	// by now the FlushStop should have happened. Try stopping the peer.
   464  	// it should be safe to do this.
   465  	peers := switches[0].Peers().List()
   466  	for _, peer := range peers {
   467  		err := peer.Stop()
   468  		require.NoError(t, err)
   469  	}
   470  
   471  	// stop the switches
   472  	for _, s := range switches {
   473  		err := s.Stop()
   474  		require.NoError(t, err)
   475  	}
   476  }
   477  
   478  func TestPEXReactorDoesNotAddPrivatePeersToAddrBook(t *testing.T) {
   479  	peer := p2p.CreateRandomPeer(false)
   480  
   481  	pexR, book := createReactor(&ReactorConfig{})
   482  	book.AddPrivateIDs([]string{string(peer.NodeInfo().ID())})
   483  	defer teardownReactor(book)
   484  
   485  	// we have to send a request to receive responses
   486  	pexR.RequestAddrs(peer)
   487  
   488  	size := book.Size()
   489  	msg := &tmp2p.PexAddrs{Addrs: []tmp2p.NetAddress{peer.SocketAddr().ToProto()}}
   490  	pexR.ReceiveEnvelope(p2p.Envelope{
   491  		ChannelID: PexChannel,
   492  		Src:       peer,
   493  		Message:   msg,
   494  	})
   495  	assert.Equal(t, size, book.Size())
   496  
   497  	pexR.AddPeer(peer)
   498  	assert.Equal(t, size, book.Size())
   499  }
   500  
   501  func TestLegacyReactorReceiveBasic(t *testing.T) {
   502  	pexR, _ := createReactor(&ReactorConfig{})
   503  	peer := p2p.CreateRandomPeer(false)
   504  
   505  	pexR.InitPeer(peer)
   506  	pexR.AddPeer(peer)
   507  	m := &tmp2p.PexAddrs{}
   508  	wm := m.Wrap()
   509  	msg, err := proto.Marshal(wm)
   510  	assert.NoError(t, err)
   511  
   512  	assert.NotPanics(t, func() {
   513  		pexR.Receive(PexChannel, peer, msg)
   514  	})
   515  }
   516  
   517  func TestPEXReactorDialPeer(t *testing.T) {
   518  	pexR, book := createReactor(&ReactorConfig{})
   519  	defer teardownReactor(book)
   520  
   521  	sw := createSwitchAndAddReactors(pexR)
   522  	sw.SetAddrBook(book)
   523  
   524  	peer := mock.NewPeer(nil)
   525  	addr := peer.SocketAddr()
   526  
   527  	assert.Equal(t, 0, pexR.AttemptsToDial(addr))
   528  
   529  	// 1st unsuccessful attempt
   530  	err := pexR.dialPeer(addr)
   531  	require.Error(t, err)
   532  
   533  	assert.Equal(t, 1, pexR.AttemptsToDial(addr))
   534  
   535  	// 2nd unsuccessful attempt
   536  	err = pexR.dialPeer(addr)
   537  	require.Error(t, err)
   538  
   539  	// must be skipped because it is too early
   540  	assert.Equal(t, 1, pexR.AttemptsToDial(addr))
   541  
   542  	if !testing.Short() {
   543  		time.Sleep(3 * time.Second)
   544  
   545  		// 3rd attempt
   546  		err = pexR.dialPeer(addr)
   547  		require.Error(t, err)
   548  
   549  		assert.Equal(t, 2, pexR.AttemptsToDial(addr))
   550  	}
   551  }
   552  
   553  func assertPeersWithTimeout(
   554  	t *testing.T,
   555  	switches []*p2p.Switch,
   556  	checkPeriod, timeout time.Duration,
   557  	nPeers int,
   558  ) {
   559  	var (
   560  		ticker    = time.NewTicker(checkPeriod)
   561  		remaining = timeout
   562  	)
   563  
   564  	for {
   565  		select {
   566  		case <-ticker.C:
   567  			// check peers are connected
   568  			allGood := true
   569  			for _, s := range switches {
   570  				outbound, inbound, _ := s.NumPeers()
   571  				if outbound+inbound < nPeers {
   572  					allGood = false
   573  					break
   574  				}
   575  			}
   576  			remaining -= checkPeriod
   577  			if remaining < 0 {
   578  				remaining = 0
   579  			}
   580  			if allGood {
   581  				return
   582  			}
   583  		case <-time.After(remaining):
   584  			numPeersStr := ""
   585  			for i, s := range switches {
   586  				outbound, inbound, _ := s.NumPeers()
   587  				numPeersStr += fmt.Sprintf("%d => {outbound: %d, inbound: %d}, ", i, outbound, inbound)
   588  			}
   589  			t.Errorf(
   590  				"expected all switches to be connected to at least %d peer(s) (switches: %s)",
   591  				nPeers, numPeersStr,
   592  			)
   593  			return
   594  		}
   595  	}
   596  }
   597  
   598  // Creates a peer with the provided config
   599  func testCreatePeerWithConfig(dir string, id int, config *ReactorConfig) *p2p.Switch {
   600  	peer := p2p.MakeSwitch(
   601  		cfg,
   602  		id,
   603  		"127.0.0.1",
   604  		"123.123.123",
   605  		func(i int, sw *p2p.Switch) *p2p.Switch {
   606  			book := NewAddrBook(filepath.Join(dir, fmt.Sprintf("addrbook%d.json", id)), false)
   607  			book.SetLogger(log.TestingLogger())
   608  			sw.SetAddrBook(book)
   609  
   610  			sw.SetLogger(log.TestingLogger())
   611  
   612  			r := NewReactor(
   613  				book,
   614  				config,
   615  			)
   616  			r.SetLogger(log.TestingLogger())
   617  			sw.AddReactor("pex", r)
   618  			return sw
   619  		},
   620  	)
   621  	return peer
   622  }
   623  
   624  // Creates a peer with the default config
   625  func testCreateDefaultPeer(dir string, id int) *p2p.Switch {
   626  	return testCreatePeerWithConfig(dir, id, &ReactorConfig{})
   627  }
   628  
   629  // Creates a seed which knows about the provided addresses / source address pairs.
   630  // Starting and stopping the seed is left to the caller
   631  func testCreateSeed(dir string, id int, knownAddrs, srcAddrs []*p2p.NetAddress) *p2p.Switch {
   632  	seed := p2p.MakeSwitch(
   633  		cfg,
   634  		id,
   635  		"127.0.0.1",
   636  		"123.123.123",
   637  		func(i int, sw *p2p.Switch) *p2p.Switch {
   638  			book := NewAddrBook(filepath.Join(dir, "addrbookSeed.json"), false)
   639  			book.SetLogger(log.TestingLogger())
   640  			for j := 0; j < len(knownAddrs); j++ {
   641  				book.AddAddress(knownAddrs[j], srcAddrs[j]) //nolint:errcheck // ignore for tests
   642  				book.MarkGood(knownAddrs[j].ID)
   643  			}
   644  			sw.SetAddrBook(book)
   645  
   646  			sw.SetLogger(log.TestingLogger())
   647  
   648  			r := NewReactor(book, &ReactorConfig{})
   649  			r.SetLogger(log.TestingLogger())
   650  			sw.AddReactor("pex", r)
   651  			return sw
   652  		},
   653  	)
   654  	return seed
   655  }
   656  
   657  // Creates a peer which knows about the provided seed.
   658  // Starting and stopping the peer is left to the caller
   659  func testCreatePeerWithSeed(dir string, id int, seed *p2p.Switch) *p2p.Switch {
   660  	conf := &ReactorConfig{
   661  		Seeds: []string{seed.NetAddress().String()},
   662  	}
   663  	return testCreatePeerWithConfig(dir, id, conf)
   664  }
   665  
   666  func createReactor(conf *ReactorConfig) (r *Reactor, book AddrBook) {
   667  	// directory to store address book
   668  	dir, err := os.MkdirTemp("", "pex_reactor")
   669  	if err != nil {
   670  		panic(err)
   671  	}
   672  	book = NewAddrBook(filepath.Join(dir, "addrbook.json"), true)
   673  	book.SetLogger(log.TestingLogger())
   674  
   675  	r = NewReactor(book, conf)
   676  	r.SetLogger(log.TestingLogger())
   677  	return
   678  }
   679  
   680  func teardownReactor(book AddrBook) {
   681  	// FIXME Shouldn't rely on .(*addrBook) assertion
   682  	err := os.RemoveAll(filepath.Dir(book.(*addrBook).FilePath()))
   683  	if err != nil {
   684  		panic(err)
   685  	}
   686  }
   687  
   688  func createSwitchAndAddReactors(reactors ...p2p.Reactor) *p2p.Switch {
   689  	sw := p2p.MakeSwitch(cfg, 0, "127.0.0.1", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch { return sw })
   690  	sw.SetLogger(log.TestingLogger())
   691  	for _, r := range reactors {
   692  		sw.AddReactor(r.String(), r)
   693  		r.SetSwitch(sw)
   694  	}
   695  	return sw
   696  }
   697  
   698  func TestPexVectors(t *testing.T) {
   699  	addr := tmp2p.NetAddress{
   700  		ID:   "1",
   701  		IP:   "127.0.0.1",
   702  		Port: 9090,
   703  	}
   704  
   705  	testCases := []struct {
   706  		testName string
   707  		msg      proto.Message
   708  		expBytes string
   709  	}{
   710  		{"PexRequest", &tmp2p.PexRequest{}, "0a00"},
   711  		{"PexAddrs", &tmp2p.PexAddrs{Addrs: []tmp2p.NetAddress{addr}}, "12130a110a013112093132372e302e302e31188247"},
   712  	}
   713  
   714  	for _, tc := range testCases {
   715  		tc := tc
   716  
   717  		w := tc.msg.(p2p.Wrapper).Wrap()
   718  		bz, err := proto.Marshal(w)
   719  		require.NoError(t, err)
   720  
   721  		require.Equal(t, tc.expBytes, hex.EncodeToString(bz), tc.testName)
   722  	}
   723  }