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