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