github.com/evdatsion/aphelion-dpos-bft@v0.32.1/p2p/pex/pex_reactor_test.go (about)

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