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