mirror of
https://github.com/tendermint/tendermint.git
synced 2026-08-20 14:16:22 +00:00
This test occasionally fails because the peer is already stopped. It is unclear to me exactly what this test is supposed to do, since calling `FlushStop()` will stop the peer, but the test asserts that the peer shouldn't have been stopped by `FlushStop()` since calling `Stop()` afterwards will error in that case. The current PEX reactor will be removed in the new P2P stack anyway.
678 lines
19 KiB
Go
678 lines
19 KiB
Go
package pex
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gogo/protobuf/proto"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/tendermint/tendermint/config"
|
|
"github.com/tendermint/tendermint/libs/log"
|
|
"github.com/tendermint/tendermint/p2p"
|
|
"github.com/tendermint/tendermint/p2p/mock"
|
|
tmp2p "github.com/tendermint/tendermint/proto/tendermint/p2p"
|
|
)
|
|
|
|
var (
|
|
cfg *config.P2PConfig
|
|
)
|
|
|
|
func init() {
|
|
cfg = config.DefaultP2PConfig()
|
|
cfg.PexReactor = true
|
|
cfg.AllowDuplicateIP = true
|
|
}
|
|
|
|
func TestPEXReactorBasic(t *testing.T) {
|
|
r, _ := createReactor(t, &ReactorConfig{})
|
|
|
|
assert.NotNil(t, r)
|
|
assert.NotEmpty(t, r.GetChannels())
|
|
}
|
|
|
|
func TestPEXReactorAddRemovePeer(t *testing.T) {
|
|
r, book := createReactor(t, &ReactorConfig{})
|
|
|
|
size := book.Size()
|
|
peer := p2p.CreateRandomPeer(false)
|
|
|
|
r.AddPeer(peer)
|
|
assert.Equal(t, size+1, book.Size())
|
|
|
|
r.RemovePeer(peer, "peer not available")
|
|
|
|
outboundPeer := p2p.CreateRandomPeer(true)
|
|
|
|
r.AddPeer(outboundPeer)
|
|
assert.Equal(t, size+1, book.Size(), "outbound peers should not be added to the address book")
|
|
|
|
r.RemovePeer(outboundPeer, "peer not available")
|
|
}
|
|
|
|
// --- FAIL: TestPEXReactorRunning (11.10s)
|
|
// pex_reactor_test.go:411: expected all switches to be connected to at
|
|
// least one peer (switches: 0 => {outbound: 1, inbound: 0}, 1 =>
|
|
// {outbound: 0, inbound: 1}, 2 => {outbound: 0, inbound: 0}, )
|
|
//
|
|
// EXPLANATION: peers are getting rejected because in switch#addPeer we check
|
|
// if any peer (who we already connected to) has the same IP. Even though local
|
|
// peers have different IP addresses, they all have the same underlying remote
|
|
// IP: 127.0.0.1.
|
|
//
|
|
func TestPEXReactorRunning(t *testing.T) {
|
|
N := 3
|
|
switches := make([]*p2p.Switch, N)
|
|
|
|
// directory to store address books
|
|
dir := tempDir(t)
|
|
|
|
books := make([]AddrBook, N)
|
|
logger := log.TestingLogger()
|
|
|
|
// create switches
|
|
for i := 0; i < N; i++ {
|
|
switches[i] = p2p.MakeSwitch(cfg, i, "testing", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch {
|
|
books[i] = NewAddrBook(filepath.Join(dir, fmt.Sprintf("addrbook%d.json", i)), false)
|
|
books[i].SetLogger(logger.With("pex", i))
|
|
sw.SetAddrBook(books[i])
|
|
|
|
sw.SetLogger(logger.With("pex", i))
|
|
|
|
r := NewReactor(books[i], &ReactorConfig{})
|
|
r.SetLogger(logger.With("pex", i))
|
|
r.SetEnsurePeersPeriod(250 * time.Millisecond)
|
|
sw.AddReactor("pex", r)
|
|
|
|
return sw
|
|
})
|
|
}
|
|
|
|
for _, sw := range switches {
|
|
err := sw.Start() // start switch and reactors
|
|
require.Nil(t, err)
|
|
}
|
|
|
|
addOtherNodeAddrToAddrBook := func(switchIndex, otherSwitchIndex int) {
|
|
addr := switches[otherSwitchIndex].NetAddress()
|
|
err := books[switchIndex].AddAddress(addr, addr)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
addOtherNodeAddrToAddrBook(0, 1)
|
|
addOtherNodeAddrToAddrBook(1, 0)
|
|
addOtherNodeAddrToAddrBook(2, 1)
|
|
|
|
assertPeersWithTimeout(t, switches, 10*time.Millisecond, 10*time.Second, N-1)
|
|
|
|
// stop them
|
|
for _, s := range switches {
|
|
err := s.Stop()
|
|
require.NoError(t, err)
|
|
}
|
|
}
|
|
|
|
func TestPEXReactorReceive(t *testing.T) {
|
|
r, book := createReactor(t, &ReactorConfig{})
|
|
peer := p2p.CreateRandomPeer(false)
|
|
|
|
// we have to send a request to receive responses
|
|
r.RequestAddrs(peer)
|
|
|
|
size := book.Size()
|
|
na, err := peer.NodeInfo().NetAddress()
|
|
require.NoError(t, err)
|
|
msg := mustEncode(&tmp2p.PexResponse{Addresses: []tmp2p.PexAddress{na.ToProto()}})
|
|
r.Receive(PexChannel, peer, msg)
|
|
assert.Equal(t, size+1, book.Size())
|
|
|
|
msg = mustEncode(&tmp2p.PexRequest{})
|
|
r.Receive(PexChannel, peer, msg) // should not panic.
|
|
}
|
|
|
|
func TestPEXReactorRequestMessageAbuse(t *testing.T) {
|
|
r, book := createReactor(t, &ReactorConfig{})
|
|
sw := createSwitchAndAddReactors(r)
|
|
sw.SetAddrBook(book)
|
|
|
|
peer := mock.NewPeer(nil)
|
|
peerAddr := peer.SocketAddr()
|
|
p2p.AddPeerToSwitchPeerSet(sw, peer)
|
|
assert.True(t, sw.Peers().Has(peer.ID()))
|
|
err := book.AddAddress(peerAddr, peerAddr)
|
|
require.NoError(t, err)
|
|
require.True(t, book.HasAddress(peerAddr))
|
|
|
|
id := string(peer.ID())
|
|
msg := mustEncode(&tmp2p.PexRequest{})
|
|
|
|
// first time creates the entry
|
|
r.Receive(PexChannel, peer, msg)
|
|
assert.True(t, r.lastReceivedRequests.Has(id))
|
|
assert.True(t, sw.Peers().Has(peer.ID()))
|
|
|
|
// next time sets the last time value
|
|
r.Receive(PexChannel, peer, msg)
|
|
assert.True(t, r.lastReceivedRequests.Has(id))
|
|
assert.True(t, sw.Peers().Has(peer.ID()))
|
|
|
|
// third time is too many too soon - peer is removed
|
|
r.Receive(PexChannel, peer, msg)
|
|
assert.False(t, r.lastReceivedRequests.Has(id))
|
|
assert.False(t, sw.Peers().Has(peer.ID()))
|
|
assert.True(t, book.IsBanned(peerAddr))
|
|
}
|
|
|
|
func TestPEXReactorAddrsMessageAbuse(t *testing.T) {
|
|
r, book := createReactor(t, &ReactorConfig{})
|
|
sw := createSwitchAndAddReactors(r)
|
|
sw.SetAddrBook(book)
|
|
|
|
peer := mock.NewPeer(nil)
|
|
p2p.AddPeerToSwitchPeerSet(sw, peer)
|
|
assert.True(t, sw.Peers().Has(peer.ID()))
|
|
|
|
id := string(peer.ID())
|
|
|
|
// request addrs from the peer
|
|
r.RequestAddrs(peer)
|
|
assert.True(t, r.requestsSent.Has(id))
|
|
assert.True(t, sw.Peers().Has(peer.ID()))
|
|
|
|
msg := mustEncode(&tmp2p.PexResponse{Addresses: []tmp2p.PexAddress{peer.SocketAddr().ToProto()}})
|
|
|
|
// receive some addrs. should clear the request
|
|
r.Receive(PexChannel, peer, msg)
|
|
assert.False(t, r.requestsSent.Has(id))
|
|
assert.True(t, sw.Peers().Has(peer.ID()))
|
|
|
|
// receiving more unsolicited addrs causes a disconnect and ban
|
|
r.Receive(PexChannel, peer, msg)
|
|
assert.False(t, sw.Peers().Has(peer.ID()))
|
|
assert.True(t, book.IsBanned(peer.SocketAddr()))
|
|
}
|
|
|
|
func TestCheckSeeds(t *testing.T) {
|
|
// directory to store address books
|
|
dir := tempDir(t)
|
|
|
|
// 1. test creating peer with no seeds works
|
|
peerSwitch := testCreateDefaultPeer(dir, 0)
|
|
require.Nil(t, peerSwitch.Start())
|
|
peerSwitch.Stop() // nolint:errcheck // ignore for tests
|
|
|
|
// 2. create seed
|
|
seed := testCreateSeed(dir, 1, []*p2p.NetAddress{}, []*p2p.NetAddress{})
|
|
|
|
// 3. test create peer with online seed works
|
|
peerSwitch = testCreatePeerWithSeed(dir, 2, seed)
|
|
require.Nil(t, peerSwitch.Start())
|
|
peerSwitch.Stop() // nolint:errcheck // ignore for tests
|
|
|
|
// 4. test create peer with all seeds having unresolvable DNS fails
|
|
badPeerConfig := &ReactorConfig{
|
|
Seeds: []string{"ed3dfd27bfc4af18f67a49862f04cc100696e84d@bad.network.addr:26657",
|
|
"d824b13cb5d40fa1d8a614e089357c7eff31b670@anotherbad.network.addr:26657"},
|
|
}
|
|
peerSwitch = testCreatePeerWithConfig(dir, 2, badPeerConfig)
|
|
require.Error(t, peerSwitch.Start())
|
|
peerSwitch.Stop() // nolint:errcheck // ignore for tests
|
|
|
|
// 5. test create peer with one good seed address succeeds
|
|
badPeerConfig = &ReactorConfig{
|
|
Seeds: []string{"ed3dfd27bfc4af18f67a49862f04cc100696e84d@bad.network.addr:26657",
|
|
"d824b13cb5d40fa1d8a614e089357c7eff31b670@anotherbad.network.addr:26657",
|
|
seed.NetAddress().String()},
|
|
}
|
|
peerSwitch = testCreatePeerWithConfig(dir, 2, badPeerConfig)
|
|
require.Nil(t, peerSwitch.Start())
|
|
peerSwitch.Stop() // nolint:errcheck // ignore for tests
|
|
}
|
|
|
|
func TestPEXReactorUsesSeedsIfNeeded(t *testing.T) {
|
|
// directory to store address books
|
|
dir := tempDir(t)
|
|
|
|
// 1. create seed
|
|
seed := testCreateSeed(dir, 0, []*p2p.NetAddress{}, []*p2p.NetAddress{})
|
|
require.Nil(t, seed.Start())
|
|
t.Cleanup(func() { _ = seed.Stop() })
|
|
|
|
// 2. create usual peer with only seed configured.
|
|
peer := testCreatePeerWithSeed(dir, 1, seed)
|
|
require.Nil(t, peer.Start())
|
|
t.Cleanup(func() { _ = peer.Stop() })
|
|
|
|
// 3. check that the peer connects to seed immediately
|
|
assertPeersWithTimeout(t, []*p2p.Switch{peer}, 10*time.Millisecond, 3*time.Second, 1)
|
|
}
|
|
|
|
func TestConnectionSpeedForPeerReceivedFromSeed(t *testing.T) {
|
|
// directory to store address books
|
|
dir := tempDir(t)
|
|
|
|
// 1. create peer
|
|
peerSwitch := testCreateDefaultPeer(dir, 1)
|
|
require.Nil(t, peerSwitch.Start())
|
|
t.Cleanup(func() { _ = peerSwitch.Stop() })
|
|
|
|
// 2. Create seed which knows about the peer
|
|
peerAddr := peerSwitch.NetAddress()
|
|
seed := testCreateSeed(dir, 2, []*p2p.NetAddress{peerAddr}, []*p2p.NetAddress{peerAddr})
|
|
require.Nil(t, seed.Start())
|
|
t.Cleanup(func() { _ = seed.Stop() })
|
|
|
|
// 3. create another peer with only seed configured.
|
|
secondPeer := testCreatePeerWithSeed(dir, 3, seed)
|
|
require.Nil(t, secondPeer.Start())
|
|
t.Cleanup(func() { _ = secondPeer.Stop() })
|
|
|
|
// 4. check that the second peer connects to seed immediately
|
|
assertPeersWithTimeout(t, []*p2p.Switch{secondPeer}, 10*time.Millisecond, 3*time.Second, 1)
|
|
|
|
// 5. check that the second peer connects to the first peer immediately
|
|
assertPeersWithTimeout(t, []*p2p.Switch{secondPeer}, 10*time.Millisecond, 1*time.Second, 2)
|
|
}
|
|
|
|
func TestPEXReactorSeedMode(t *testing.T) {
|
|
// directory to store address books
|
|
dir := tempDir(t)
|
|
|
|
pexRConfig := &ReactorConfig{SeedMode: true, SeedDisconnectWaitPeriod: 10 * time.Millisecond}
|
|
pexR, book := createReactor(t, pexRConfig)
|
|
sw := createSwitchAndAddReactors(pexR)
|
|
|
|
sw.SetAddrBook(book)
|
|
require.NoError(t, sw.Start())
|
|
t.Cleanup(func() { _ = sw.Stop() })
|
|
|
|
assert.Zero(t, sw.Peers().Size())
|
|
|
|
peerSwitch := testCreateDefaultPeer(dir, 1)
|
|
require.NoError(t, peerSwitch.Start())
|
|
t.Cleanup(func() { _ = peerSwitch.Stop() })
|
|
|
|
// 1. Test crawlPeers dials the peer
|
|
pexR.crawlPeers([]*p2p.NetAddress{peerSwitch.NetAddress()})
|
|
assert.Equal(t, 1, sw.Peers().Size())
|
|
assert.True(t, sw.Peers().Has(peerSwitch.NodeInfo().ID()))
|
|
|
|
// 2. attemptDisconnects should not disconnect because of wait period
|
|
pexR.attemptDisconnects()
|
|
assert.Equal(t, 1, sw.Peers().Size())
|
|
|
|
// sleep for SeedDisconnectWaitPeriod
|
|
time.Sleep(pexRConfig.SeedDisconnectWaitPeriod + 1*time.Millisecond)
|
|
|
|
// 3. attemptDisconnects should disconnect after wait period
|
|
pexR.attemptDisconnects()
|
|
assert.Equal(t, 0, sw.Peers().Size())
|
|
}
|
|
|
|
func TestPEXReactorDoesNotDisconnectFromPersistentPeerInSeedMode(t *testing.T) {
|
|
// directory to store address books
|
|
dir := tempDir(t)
|
|
|
|
pexRConfig := &ReactorConfig{SeedMode: true, SeedDisconnectWaitPeriod: 1 * time.Millisecond}
|
|
pexR, book := createReactor(t, pexRConfig)
|
|
sw := createSwitchAndAddReactors(pexR)
|
|
|
|
sw.SetAddrBook(book)
|
|
require.NoError(t, sw.Start())
|
|
t.Cleanup(func() { _ = sw.Stop() })
|
|
|
|
assert.Zero(t, sw.Peers().Size())
|
|
|
|
peerSwitch := testCreatePeerWithConfig(dir, 1, pexRConfig)
|
|
require.NoError(t, peerSwitch.Start())
|
|
t.Cleanup(func() { _ = peerSwitch.Stop() })
|
|
|
|
require.NoError(t, sw.AddPersistentPeers([]string{peerSwitch.NetAddress().String()}))
|
|
|
|
// 1. Test crawlPeers dials the peer
|
|
pexR.crawlPeers([]*p2p.NetAddress{peerSwitch.NetAddress()})
|
|
assert.Equal(t, 1, sw.Peers().Size())
|
|
assert.True(t, sw.Peers().Has(peerSwitch.NodeInfo().ID()))
|
|
|
|
// sleep for SeedDisconnectWaitPeriod
|
|
time.Sleep(pexRConfig.SeedDisconnectWaitPeriod + 1*time.Millisecond)
|
|
|
|
// 2. attemptDisconnects should not disconnect because the peer is persistent
|
|
pexR.attemptDisconnects()
|
|
assert.Equal(t, 1, sw.Peers().Size())
|
|
}
|
|
|
|
func TestPEXReactorDialsPeerUpToMaxAttemptsInSeedMode(t *testing.T) {
|
|
// directory to store address books
|
|
pexR, book := createReactor(t, &ReactorConfig{SeedMode: true})
|
|
sw := createSwitchAndAddReactors(pexR)
|
|
|
|
sw.SetAddrBook(book)
|
|
// No need to start sw since crawlPeers is called manually here.
|
|
|
|
peer := mock.NewPeer(nil)
|
|
addr := peer.SocketAddr()
|
|
|
|
require.NoError(t, book.AddAddress(addr, addr))
|
|
|
|
assert.True(t, book.HasAddress(addr))
|
|
|
|
// imitate maxAttemptsToDial reached
|
|
pexR.attemptsToDial.Store(addr.DialString(), _attemptsToDial{maxAttemptsToDial + 1, time.Now()})
|
|
pexR.crawlPeers([]*p2p.NetAddress{addr})
|
|
|
|
assert.False(t, book.HasAddress(addr))
|
|
}
|
|
|
|
// connect a peer to a seed, wait a bit, then stop it.
|
|
// this should give it time to request addrs and for the seed
|
|
// to call FlushStop, and allows us to test calling Stop concurrently
|
|
// with FlushStop. Before a fix, this non-deterministically reproduced
|
|
// https://github.com/tendermint/tendermint/issues/3231.
|
|
func TestPEXReactorSeedModeFlushStop(t *testing.T) {
|
|
t.Skip("flaky test, will be replaced by new P2P stack")
|
|
N := 2
|
|
switches := make([]*p2p.Switch, N)
|
|
|
|
// directory to store address books
|
|
dir := tempDir(t)
|
|
|
|
books := make([]AddrBook, N)
|
|
logger := log.TestingLogger()
|
|
|
|
// create switches
|
|
for i := 0; i < N; i++ {
|
|
switches[i] = p2p.MakeSwitch(cfg, i, "testing", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch {
|
|
books[i] = NewAddrBook(filepath.Join(dir, fmt.Sprintf("addrbook%d.json", i)), false)
|
|
books[i].SetLogger(logger.With("pex", i))
|
|
sw.SetAddrBook(books[i])
|
|
|
|
sw.SetLogger(logger.With("pex", i))
|
|
|
|
config := &ReactorConfig{}
|
|
if i == 0 {
|
|
// first one is a seed node
|
|
config = &ReactorConfig{SeedMode: true}
|
|
}
|
|
r := NewReactor(books[i], config)
|
|
r.SetLogger(logger.With("pex", i))
|
|
r.SetEnsurePeersPeriod(250 * time.Millisecond)
|
|
sw.AddReactor("pex", r)
|
|
|
|
return sw
|
|
})
|
|
}
|
|
|
|
for _, sw := range switches {
|
|
err := sw.Start() // start switch and reactors
|
|
require.Nil(t, err)
|
|
}
|
|
|
|
reactor := switches[0].Reactors()["pex"].(*Reactor)
|
|
peerID := switches[1].NodeInfo().ID()
|
|
|
|
assert.NoError(t, switches[1].DialPeerWithAddress(switches[0].NetAddress()))
|
|
|
|
// sleep up to a second while waiting for the peer to send us a message.
|
|
// this isn't perfect since it's possible the peer sends us a msg and we FlushStop
|
|
// before this loop catches it. but non-deterministically it works pretty well.
|
|
for i := 0; i < 1000; i++ {
|
|
v := reactor.lastReceivedRequests.Get(string(peerID))
|
|
if v != nil {
|
|
break
|
|
}
|
|
time.Sleep(time.Millisecond)
|
|
}
|
|
|
|
// by now the FlushStop should have happened. Try stopping the peer.
|
|
// it should be safe to do this.
|
|
peers := switches[0].Peers().List()
|
|
for _, peer := range peers {
|
|
err := peer.Stop()
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// stop the switches
|
|
for _, s := range switches {
|
|
err := s.Stop()
|
|
require.NoError(t, err)
|
|
}
|
|
}
|
|
|
|
func TestPEXReactorDoesNotAddPrivatePeersToAddrBook(t *testing.T) {
|
|
peer := p2p.CreateRandomPeer(false)
|
|
|
|
pexR, book := createReactor(t, &ReactorConfig{})
|
|
book.AddPrivateIDs([]string{string(peer.NodeInfo().ID())})
|
|
|
|
// we have to send a request to receive responses
|
|
pexR.RequestAddrs(peer)
|
|
|
|
size := book.Size()
|
|
na, err := peer.NodeInfo().NetAddress()
|
|
require.NoError(t, err)
|
|
msg := mustEncode(&tmp2p.PexResponse{Addresses: []tmp2p.PexAddress{na.ToProto()}})
|
|
pexR.Receive(PexChannel, peer, msg)
|
|
assert.Equal(t, size, book.Size())
|
|
|
|
pexR.AddPeer(peer)
|
|
assert.Equal(t, size, book.Size())
|
|
}
|
|
|
|
func TestPEXReactorDialPeer(t *testing.T) {
|
|
pexR, book := createReactor(t, &ReactorConfig{})
|
|
sw := createSwitchAndAddReactors(pexR)
|
|
|
|
sw.SetAddrBook(book)
|
|
|
|
peer := mock.NewPeer(nil)
|
|
addr := peer.SocketAddr()
|
|
|
|
assert.Equal(t, 0, pexR.AttemptsToDial(addr))
|
|
|
|
// 1st unsuccessful attempt
|
|
err := pexR.dialPeer(addr)
|
|
require.Error(t, err)
|
|
|
|
assert.Equal(t, 1, pexR.AttemptsToDial(addr))
|
|
|
|
// 2nd unsuccessful attempt
|
|
err = pexR.dialPeer(addr)
|
|
require.Error(t, err)
|
|
|
|
// must be skipped because it is too early
|
|
assert.Equal(t, 1, pexR.AttemptsToDial(addr))
|
|
|
|
if !testing.Short() {
|
|
time.Sleep(3 * time.Second)
|
|
|
|
// 3rd attempt
|
|
err = pexR.dialPeer(addr)
|
|
require.Error(t, err)
|
|
|
|
assert.Equal(t, 2, pexR.AttemptsToDial(addr))
|
|
}
|
|
}
|
|
|
|
func assertPeersWithTimeout(
|
|
t *testing.T,
|
|
switches []*p2p.Switch,
|
|
checkPeriod, timeout time.Duration,
|
|
nPeers int,
|
|
) {
|
|
var (
|
|
ticker = time.NewTicker(checkPeriod)
|
|
remaining = timeout
|
|
)
|
|
|
|
for {
|
|
select {
|
|
case <-ticker.C:
|
|
// check peers are connected
|
|
allGood := true
|
|
for _, s := range switches {
|
|
outbound, inbound, _ := s.NumPeers()
|
|
if outbound+inbound < nPeers {
|
|
allGood = false
|
|
break
|
|
}
|
|
}
|
|
remaining -= checkPeriod
|
|
if remaining < 0 {
|
|
remaining = 0
|
|
}
|
|
if allGood {
|
|
return
|
|
}
|
|
case <-time.After(remaining):
|
|
numPeersStr := ""
|
|
for i, s := range switches {
|
|
outbound, inbound, _ := s.NumPeers()
|
|
numPeersStr += fmt.Sprintf("%d => {outbound: %d, inbound: %d}, ", i, outbound, inbound)
|
|
}
|
|
t.Errorf(
|
|
"expected all switches to be connected to at least %d peer(s) (switches: %s)",
|
|
nPeers, numPeersStr,
|
|
)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// Creates a peer with the provided config
|
|
func testCreatePeerWithConfig(dir string, id int, config *ReactorConfig) *p2p.Switch {
|
|
peer := p2p.MakeSwitch(
|
|
cfg,
|
|
id,
|
|
"127.0.0.1",
|
|
"123.123.123",
|
|
func(i int, sw *p2p.Switch) *p2p.Switch {
|
|
book := NewAddrBook(filepath.Join(dir, fmt.Sprintf("addrbook%d.json", id)), false)
|
|
book.SetLogger(log.TestingLogger())
|
|
sw.SetAddrBook(book)
|
|
|
|
sw.SetLogger(log.TestingLogger())
|
|
|
|
r := NewReactor(
|
|
book,
|
|
config,
|
|
)
|
|
r.SetLogger(log.TestingLogger())
|
|
sw.AddReactor("pex", r)
|
|
return sw
|
|
},
|
|
)
|
|
return peer
|
|
}
|
|
|
|
// Creates a peer with the default config
|
|
func testCreateDefaultPeer(dir string, id int) *p2p.Switch {
|
|
return testCreatePeerWithConfig(dir, id, &ReactorConfig{})
|
|
}
|
|
|
|
// Creates a seed which knows about the provided addresses / source address pairs.
|
|
// Starting and stopping the seed is left to the caller
|
|
func testCreateSeed(dir string, id int, knownAddrs, srcAddrs []*p2p.NetAddress) *p2p.Switch {
|
|
seed := p2p.MakeSwitch(
|
|
cfg,
|
|
id,
|
|
"127.0.0.1",
|
|
"123.123.123",
|
|
func(i int, sw *p2p.Switch) *p2p.Switch {
|
|
book := NewAddrBook(filepath.Join(dir, "addrbookSeed.json"), false)
|
|
book.SetLogger(log.TestingLogger())
|
|
for j := 0; j < len(knownAddrs); j++ {
|
|
book.AddAddress(knownAddrs[j], srcAddrs[j]) // nolint:errcheck // ignore for tests
|
|
book.MarkGood(knownAddrs[j].ID)
|
|
}
|
|
sw.SetAddrBook(book)
|
|
|
|
sw.SetLogger(log.TestingLogger())
|
|
|
|
r := NewReactor(book, &ReactorConfig{})
|
|
r.SetLogger(log.TestingLogger())
|
|
sw.AddReactor("pex", r)
|
|
return sw
|
|
},
|
|
)
|
|
return seed
|
|
}
|
|
|
|
// Creates a peer which knows about the provided seed.
|
|
// Starting and stopping the peer is left to the caller
|
|
func testCreatePeerWithSeed(dir string, id int, seed *p2p.Switch) *p2p.Switch {
|
|
conf := &ReactorConfig{
|
|
Seeds: []string{seed.NetAddress().String()},
|
|
}
|
|
return testCreatePeerWithConfig(dir, id, conf)
|
|
}
|
|
|
|
func createReactor(t *testing.T, conf *ReactorConfig) (r *Reactor, book AddrBook) {
|
|
// directory to store address book
|
|
book = NewAddrBook(filepath.Join(tempDir(t), "addrbook.json"), true)
|
|
book.SetLogger(log.TestingLogger())
|
|
|
|
r = NewReactor(book, conf)
|
|
r.SetLogger(log.TestingLogger())
|
|
return
|
|
}
|
|
|
|
func createSwitchAndAddReactors(reactors ...p2p.Reactor) *p2p.Switch {
|
|
sw := p2p.MakeSwitch(cfg, 0, "127.0.0.1", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch {
|
|
for _, r := range reactors {
|
|
sw.AddReactor(r.String(), r)
|
|
}
|
|
return sw
|
|
})
|
|
sw.SetLogger(log.TestingLogger())
|
|
return sw
|
|
}
|
|
|
|
func TestPexVectors(t *testing.T) {
|
|
addr := tmp2p.PexAddress{
|
|
ID: "1",
|
|
IP: "127.0.0.1",
|
|
Port: 9090,
|
|
}
|
|
|
|
testCases := []struct {
|
|
testName string
|
|
msg proto.Message
|
|
expBytes string
|
|
}{
|
|
{"PexRequest", &tmp2p.PexRequest{}, "0a00"},
|
|
{"PexAddrs", &tmp2p.PexResponse{Addresses: []tmp2p.PexAddress{addr}}, "12130a110a013112093132372e302e302e31188247"},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
tc := tc
|
|
|
|
bz := mustEncode(tc.msg)
|
|
|
|
require.Equal(t, tc.expBytes, hex.EncodeToString(bz), tc.testName)
|
|
}
|
|
}
|
|
|
|
// FIXME: This function is used in place of testing.TB.TempDir()
|
|
// as the latter seems to cause test cases to fail when it is
|
|
// unable to remove the temporary directory once the test case
|
|
// execution terminates. This seems to happen often with pex
|
|
// reactor test cases.
|
|
//
|
|
// References:
|
|
// https://github.com/tendermint/tendermint/pull/5733
|
|
// https://github.com/tendermint/tendermint/issues/5732
|
|
func tempDir(t *testing.T) string {
|
|
t.Helper()
|
|
dir, err := ioutil.TempDir("", "")
|
|
require.NoError(t, err)
|
|
t.Cleanup(func() { _ = os.RemoveAll(dir) })
|
|
return dir
|
|
}
|