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) {
|
|
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
|
|
}
|