gitlab.com/gpdionisio/tendermint@v0.34.19-dev2/p2p/pex/pex_reactor_test.go (about)

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