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