mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 06:42:16 +00:00
* close peer's connection to avoid fd leak Fixes #2967 * rename peer#Addr to RemoteAddr * fix test * fixes after Ethan's review * bring back the check * changelog entry * write a test for switch#acceptRoutine * increase timeouts? :( * remove extra assertNPeersWithTimeout * simplify test * assert number of peers (just to be safe) * Cleanup in OnStop * run tests with verbose flag on CircleCI * spawn a reading routine to prevent connection from closing * get port from the listener random port is faster, but often results in ``` panic: listen tcp 127.0.0.1:44068: bind: address already in use [recovered] panic: listen tcp 127.0.0.1:44068: bind: address already in use goroutine 79 [running]: testing.tRunner.func1(0xc0001bd600) /usr/local/go/src/testing/testing.go:792 +0x387 panic(0x974d20, 0xc0001b0500) /usr/local/go/src/runtime/panic.go:513 +0x1b9 github.com/tendermint/tendermint/p2p.MakeSwitch(0xc0000f42a0, 0x0, 0x9fb9cc, 0x9, 0x9fc346, 0xb, 0xb42128, 0x0, 0x0, 0x0, ...) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/test_util.go:182 +0xa28 github.com/tendermint/tendermint/p2p.MakeConnectedSwitches(0xc0000f42a0, 0x2, 0xb42128, 0xb41eb8, 0x4f1205, 0xc0001bed80, 0x4f16ed) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/test_util.go:75 +0xf9 github.com/tendermint/tendermint/p2p.MakeSwitchPair(0xbb8d20, 0xc0001bd600, 0xb42128, 0x2f7, 0x4f16c0) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/switch_test.go:94 +0x4c github.com/tendermint/tendermint/p2p.TestSwitches(0xc0001bd600) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/switch_test.go:117 +0x58 testing.tRunner(0xc0001bd600, 0xb42038) /usr/local/go/src/testing/testing.go:827 +0xbf created by testing.(*T).Run /usr/local/go/src/testing/testing.go:878 +0x353 exit status 2 FAIL github.com/tendermint/tendermint/p2p 0.350s ```
228 lines
5.2 KiB
Go
228 lines
5.2 KiB
Go
package p2p
|
|
|
|
import (
|
|
"fmt"
|
|
golog "log"
|
|
"net"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/tendermint/tendermint/crypto"
|
|
"github.com/tendermint/tendermint/crypto/ed25519"
|
|
cmn "github.com/tendermint/tendermint/libs/common"
|
|
"github.com/tendermint/tendermint/libs/log"
|
|
|
|
"github.com/tendermint/tendermint/config"
|
|
tmconn "github.com/tendermint/tendermint/p2p/conn"
|
|
)
|
|
|
|
func TestPeerBasic(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
|
|
// simulate remote peer
|
|
rp := &remotePeer{PrivKey: ed25519.GenPrivKey(), Config: cfg}
|
|
rp.Start()
|
|
defer rp.Stop()
|
|
|
|
p, err := createOutboundPeerAndPerformHandshake(rp.Addr(), cfg, tmconn.DefaultMConnConfig())
|
|
require.Nil(err)
|
|
|
|
err = p.Start()
|
|
require.Nil(err)
|
|
defer p.Stop()
|
|
|
|
assert.True(p.IsRunning())
|
|
assert.True(p.IsOutbound())
|
|
assert.False(p.IsPersistent())
|
|
p.persistent = true
|
|
assert.True(p.IsPersistent())
|
|
assert.Equal(rp.Addr().DialString(), p.RemoteAddr().String())
|
|
assert.Equal(rp.ID(), p.ID())
|
|
}
|
|
|
|
func TestPeerSend(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
|
|
config := cfg
|
|
|
|
// simulate remote peer
|
|
rp := &remotePeer{PrivKey: ed25519.GenPrivKey(), Config: config}
|
|
rp.Start()
|
|
defer rp.Stop()
|
|
|
|
p, err := createOutboundPeerAndPerformHandshake(rp.Addr(), config, tmconn.DefaultMConnConfig())
|
|
require.Nil(err)
|
|
|
|
err = p.Start()
|
|
require.Nil(err)
|
|
|
|
defer p.Stop()
|
|
|
|
assert.True(p.CanSend(testCh))
|
|
assert.True(p.Send(testCh, []byte("Asylum")))
|
|
}
|
|
|
|
func createOutboundPeerAndPerformHandshake(
|
|
addr *NetAddress,
|
|
config *config.P2PConfig,
|
|
mConfig tmconn.MConnConfig,
|
|
) (*peer, error) {
|
|
chDescs := []*tmconn.ChannelDescriptor{
|
|
{ID: testCh, Priority: 1},
|
|
}
|
|
reactorsByCh := map[byte]Reactor{testCh: NewTestReactor(chDescs, true)}
|
|
pk := ed25519.GenPrivKey()
|
|
pc, err := testOutboundPeerConn(addr, config, false, pk)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
timeout := 1 * time.Second
|
|
ourNodeInfo := testNodeInfo(addr.ID, "host_peer")
|
|
peerNodeInfo, err := handshake(pc.conn, timeout, ourNodeInfo)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
p := newPeer(pc, mConfig, peerNodeInfo, reactorsByCh, chDescs, func(p Peer, r interface{}) {})
|
|
p.SetLogger(log.TestingLogger().With("peer", addr))
|
|
return p, nil
|
|
}
|
|
|
|
func testDial(addr *NetAddress, cfg *config.P2PConfig) (net.Conn, error) {
|
|
if cfg.TestDialFail {
|
|
return nil, fmt.Errorf("dial err (peerConfig.DialFail == true)")
|
|
}
|
|
|
|
conn, err := addr.DialTimeout(cfg.DialTimeout)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return conn, nil
|
|
}
|
|
|
|
func testOutboundPeerConn(
|
|
addr *NetAddress,
|
|
config *config.P2PConfig,
|
|
persistent bool,
|
|
ourNodePrivKey crypto.PrivKey,
|
|
) (peerConn, error) {
|
|
conn, err := testDial(addr, config)
|
|
if err != nil {
|
|
return peerConn{}, cmn.ErrorWrap(err, "Error creating peer")
|
|
}
|
|
|
|
pc, err := testPeerConn(conn, config, true, persistent, ourNodePrivKey, addr)
|
|
if err != nil {
|
|
if cerr := conn.Close(); cerr != nil {
|
|
return peerConn{}, cmn.ErrorWrap(err, cerr.Error())
|
|
}
|
|
return peerConn{}, err
|
|
}
|
|
|
|
// ensure dialed ID matches connection ID
|
|
if addr.ID != pc.ID() {
|
|
if cerr := conn.Close(); cerr != nil {
|
|
return peerConn{}, cmn.ErrorWrap(err, cerr.Error())
|
|
}
|
|
return peerConn{}, ErrSwitchAuthenticationFailure{addr, pc.ID()}
|
|
}
|
|
|
|
return pc, nil
|
|
}
|
|
|
|
type remotePeer struct {
|
|
PrivKey crypto.PrivKey
|
|
Config *config.P2PConfig
|
|
addr *NetAddress
|
|
channels cmn.HexBytes
|
|
listenAddr string
|
|
listener net.Listener
|
|
}
|
|
|
|
func (rp *remotePeer) Addr() *NetAddress {
|
|
return rp.addr
|
|
}
|
|
|
|
func (rp *remotePeer) ID() ID {
|
|
return PubKeyToID(rp.PrivKey.PubKey())
|
|
}
|
|
|
|
func (rp *remotePeer) Start() {
|
|
if rp.listenAddr == "" {
|
|
rp.listenAddr = "127.0.0.1:0"
|
|
}
|
|
|
|
l, e := net.Listen("tcp", rp.listenAddr) // any available address
|
|
if e != nil {
|
|
golog.Fatalf("net.Listen tcp :0: %+v", e)
|
|
}
|
|
rp.listener = l
|
|
rp.addr = NewNetAddress(PubKeyToID(rp.PrivKey.PubKey()), l.Addr())
|
|
if rp.channels == nil {
|
|
rp.channels = []byte{testCh}
|
|
}
|
|
go rp.accept()
|
|
}
|
|
|
|
func (rp *remotePeer) Stop() {
|
|
rp.listener.Close()
|
|
}
|
|
|
|
func (rp *remotePeer) Dial(addr *NetAddress) (net.Conn, error) {
|
|
conn, err := addr.DialTimeout(1 * time.Second)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
pc, err := testInboundPeerConn(conn, rp.Config, rp.PrivKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
_, err = handshake(pc.conn, time.Second, rp.nodeInfo())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return conn, err
|
|
}
|
|
|
|
func (rp *remotePeer) accept() {
|
|
conns := []net.Conn{}
|
|
|
|
for {
|
|
conn, err := rp.listener.Accept()
|
|
if err != nil {
|
|
golog.Printf("Failed to accept conn: %+v", err)
|
|
for _, conn := range conns {
|
|
_ = conn.Close()
|
|
}
|
|
return
|
|
}
|
|
|
|
pc, err := testInboundPeerConn(conn, rp.Config, rp.PrivKey)
|
|
if err != nil {
|
|
golog.Fatalf("Failed to create a peer: %+v", err)
|
|
}
|
|
|
|
_, err = handshake(pc.conn, time.Second, rp.nodeInfo())
|
|
if err != nil {
|
|
golog.Fatalf("Failed to perform handshake: %+v", err)
|
|
}
|
|
|
|
conns = append(conns, conn)
|
|
}
|
|
}
|
|
|
|
func (rp *remotePeer) nodeInfo() NodeInfo {
|
|
return DefaultNodeInfo{
|
|
ProtocolVersion: defaultProtocolVersion,
|
|
ID_: rp.Addr().ID,
|
|
ListenAddr: rp.listener.Addr().String(),
|
|
Network: "testing",
|
|
Version: "1.2.3-rc0-deadbeef",
|
|
Channels: rp.channels,
|
|
Moniker: "remote_peer",
|
|
}
|
|
}
|