- package p2p
-
- import (
- "fmt"
- "math/rand"
- "net"
- "reflect"
- "runtime"
- "strings"
- "testing"
- "time"
-
- "github.com/tendermint/tendermint/crypto/ed25519"
- "github.com/tendermint/tendermint/libs/protoio"
- "github.com/tendermint/tendermint/p2p/conn"
- tmp2p "github.com/tendermint/tendermint/proto/tendermint/p2p"
- )
-
- var defaultNodeName = "host_peer"
-
- func emptyNodeInfo() NodeInfo {
- return DefaultNodeInfo{}
- }
-
- // newMultiplexTransport returns a tcp connected multiplexed peer
- // using the default MConnConfig. It's a convenience function used
- // for testing.
- func newMultiplexTransport(
- nodeInfo NodeInfo,
- nodeKey NodeKey,
- ) *MultiplexTransport {
- return NewMultiplexTransport(
- nodeInfo, nodeKey, conn.DefaultMConnConfig(),
- )
- }
-
- func TestTransportMultiplexConnFilter(t *testing.T) {
- mt := newMultiplexTransport(
- emptyNodeInfo(),
- NodeKey{
- PrivKey: ed25519.GenPrivKey(),
- },
- )
- id := mt.nodeKey.ID()
-
- MultiplexTransportConnFilters(
- func(_ ConnSet, _ net.Conn, _ []net.IP) error { return nil },
- func(_ ConnSet, _ net.Conn, _ []net.IP) error { return nil },
- func(_ ConnSet, _ net.Conn, _ []net.IP) error {
- return fmt.Errorf("rejected")
- },
- )(mt)
-
- addr, err := NewNetAddressString(IDAddressString(id, "127.0.0.1:0"))
- if err != nil {
- t.Fatal(err)
- }
-
- if err := mt.Listen(*addr); err != nil {
- t.Fatal(err)
- }
-
- errc := make(chan error)
-
- go func() {
- addr := NewNetAddress(id, mt.listener.Addr())
-
- _, err := addr.Dial()
- if err != nil {
- errc <- err
- return
- }
-
- close(errc)
- }()
-
- if err := <-errc; err != nil {
- t.Errorf("connection failed: %v", err)
- }
-
- _, err = mt.Accept(peerConfig{})
- if err, ok := err.(ErrRejected); ok {
- if !err.IsFiltered() {
- t.Errorf("expected peer to be filtered, got %v", err)
- }
- } else {
- t.Errorf("expected ErrRejected, got %v", err)
- }
- }
-
- func TestTransportMultiplexConnFilterTimeout(t *testing.T) {
- mt := newMultiplexTransport(
- emptyNodeInfo(),
- NodeKey{
- PrivKey: ed25519.GenPrivKey(),
- },
- )
- id := mt.nodeKey.ID()
-
- MultiplexTransportFilterTimeout(5 * time.Millisecond)(mt)
- MultiplexTransportConnFilters(
- func(_ ConnSet, _ net.Conn, _ []net.IP) error {
- time.Sleep(1 * time.Second)
- return nil
- },
- )(mt)
-
- addr, err := NewNetAddressString(IDAddressString(id, "127.0.0.1:0"))
- if err != nil {
- t.Fatal(err)
- }
-
- if err := mt.Listen(*addr); err != nil {
- t.Fatal(err)
- }
-
- errc := make(chan error)
- go func() {
- addr := NewNetAddress(id, mt.listener.Addr())
-
- _, err := addr.Dial()
- if err != nil {
- errc <- err
- return
- }
-
- close(errc)
- }()
-
- if err := <-errc; err != nil {
- t.Errorf("connection failed: %v", err)
- }
-
- _, err = mt.Accept(peerConfig{})
- if _, ok := err.(ErrFilterTimeout); !ok {
- t.Errorf("expected ErrFilterTimeout, got %v", err)
- }
- }
-
- func TestTransportMultiplexMaxIncomingConnections(t *testing.T) {
- pv := ed25519.GenPrivKey()
- id := PubKeyToID(pv.PubKey())
- mt := newMultiplexTransport(
- testNodeInfo(
- id, "transport",
- ),
- NodeKey{
- PrivKey: pv,
- },
- )
-
- MultiplexTransportMaxIncomingConnections(0)(mt)
-
- addr, err := NewNetAddressString(IDAddressString(id, "127.0.0.1:0"))
- if err != nil {
- t.Fatal(err)
- }
- const maxIncomingConns = 2
- MultiplexTransportMaxIncomingConnections(maxIncomingConns)(mt)
- if err := mt.Listen(*addr); err != nil {
- t.Fatal(err)
- }
-
- laddr := NewNetAddress(mt.nodeKey.ID(), mt.listener.Addr())
-
- // Connect more peers than max
- for i := 0; i <= maxIncomingConns; i++ {
- errc := make(chan error)
- go testDialer(*laddr, errc)
-
- err = <-errc
- if i < maxIncomingConns {
- if err != nil {
- t.Errorf("dialer connection failed: %v", err)
- }
- _, err = mt.Accept(peerConfig{})
- if err != nil {
- t.Errorf("connection failed: %v", err)
- }
- } else if err == nil || !strings.Contains(err.Error(), "i/o timeout") {
- // mt actually blocks forever on trying to accept a new peer into a full channel so
- // expect the dialer to encounter a timeout error. Calling mt.Accept will block until
- // mt is closed.
- t.Errorf("expected i/o timeout error, got %v", err)
- }
- }
- }
-
- func TestTransportMultiplexAcceptMultiple(t *testing.T) {
- mt := testSetupMultiplexTransport(t)
- laddr := NewNetAddress(mt.nodeKey.ID(), mt.listener.Addr())
-
- var (
- seed = rand.New(rand.NewSource(time.Now().UnixNano()))
- nDialers = seed.Intn(64) + 64
- errc = make(chan error, nDialers)
- )
-
- // Setup dialers.
- for i := 0; i < nDialers; i++ {
- go testDialer(*laddr, errc)
- }
-
- // Catch connection errors.
- for i := 0; i < nDialers; i++ {
- if err := <-errc; err != nil {
- t.Fatal(err)
- }
- }
-
- ps := []Peer{}
-
- // Accept all peers.
- for i := 0; i < cap(errc); i++ {
- p, err := mt.Accept(peerConfig{})
- if err != nil {
- t.Fatal(err)
- }
-
- if err := p.Start(); err != nil {
- t.Fatal(err)
- }
-
- ps = append(ps, p)
- }
-
- if have, want := len(ps), cap(errc); have != want {
- t.Errorf("have %v, want %v", have, want)
- }
-
- // Stop all peers.
- for _, p := range ps {
- if err := p.Stop(); err != nil {
- t.Fatal(err)
- }
- }
-
- if err := mt.Close(); err != nil {
- t.Errorf("close errored: %v", err)
- }
- }
-
- func testDialer(dialAddr NetAddress, errc chan error) {
- var (
- pv = ed25519.GenPrivKey()
- dialer = newMultiplexTransport(
- testNodeInfo(PubKeyToID(pv.PubKey()), defaultNodeName),
- NodeKey{
- PrivKey: pv,
- },
- )
- )
-
- _, err := dialer.Dial(dialAddr, peerConfig{})
- if err != nil {
- errc <- err
- return
- }
-
- // Signal that the connection was established.
- errc <- nil
- }
-
- func TestTransportMultiplexAcceptNonBlocking(t *testing.T) {
- mt := testSetupMultiplexTransport(t)
-
- var (
- fastNodePV = ed25519.GenPrivKey()
- fastNodeInfo = testNodeInfo(PubKeyToID(fastNodePV.PubKey()), "fastnode")
- errc = make(chan error)
- fastc = make(chan struct{})
- slowc = make(chan struct{})
- slowdonec = make(chan struct{})
- )
-
- // Simulate slow Peer.
- go func() {
- addr := NewNetAddress(mt.nodeKey.ID(), mt.listener.Addr())
-
- c, err := addr.Dial()
- if err != nil {
- errc <- err
- return
- }
-
- close(slowc)
- defer func() {
- close(slowdonec)
- }()
-
- // Make sure we switch to fast peer goroutine.
- runtime.Gosched()
-
- select {
- case <-fastc:
- // Fast peer connected.
- case <-time.After(200 * time.Millisecond):
- // We error if the fast peer didn't succeed.
- errc <- fmt.Errorf("fast peer timed out")
- }
-
- sc, err := upgradeSecretConn(c, 200*time.Millisecond, ed25519.GenPrivKey())
- if err != nil {
- errc <- err
- return
- }
-
- _, err = handshake(sc, 200*time.Millisecond,
- testNodeInfo(
- PubKeyToID(ed25519.GenPrivKey().PubKey()),
- "slow_peer",
- ))
- if err != nil {
- errc <- err
- }
- }()
-
- // Simulate fast Peer.
- go func() {
- <-slowc
-
- var (
- dialer = newMultiplexTransport(
- fastNodeInfo,
- NodeKey{
- PrivKey: fastNodePV,
- },
- )
- )
- addr := NewNetAddress(mt.nodeKey.ID(), mt.listener.Addr())
-
- _, err := dialer.Dial(*addr, peerConfig{})
- if err != nil {
- errc <- err
- return
- }
-
- close(fastc)
- <-slowdonec
- close(errc)
- }()
-
- if err := <-errc; err != nil {
- t.Logf("connection failed: %v", err)
- }
-
- p, err := mt.Accept(peerConfig{})
- if err != nil {
- t.Fatal(err)
- }
-
- if have, want := p.NodeInfo(), fastNodeInfo; !reflect.DeepEqual(have, want) {
- t.Errorf("have %v, want %v", have, want)
- }
- }
-
- func TestTransportMultiplexValidateNodeInfo(t *testing.T) {
- mt := testSetupMultiplexTransport(t)
-
- errc := make(chan error)
-
- go func() {
- var (
- pv = ed25519.GenPrivKey()
- dialer = newMultiplexTransport(
- testNodeInfo(PubKeyToID(pv.PubKey()), ""), // Should not be empty
- NodeKey{
- PrivKey: pv,
- },
- )
- )
-
- addr := NewNetAddress(mt.nodeKey.ID(), mt.listener.Addr())
-
- _, err := dialer.Dial(*addr, peerConfig{})
- if err != nil {
- errc <- err
- return
- }
-
- close(errc)
- }()
-
- if err := <-errc; err != nil {
- t.Errorf("connection failed: %v", err)
- }
-
- _, err := mt.Accept(peerConfig{})
- if err, ok := err.(ErrRejected); ok {
- if !err.IsNodeInfoInvalid() {
- t.Errorf("expected NodeInfo to be invalid, got %v", err)
- }
- } else {
- t.Errorf("expected ErrRejected, got %v", err)
- }
- }
-
- func TestTransportMultiplexRejectMissmatchID(t *testing.T) {
- mt := testSetupMultiplexTransport(t)
-
- errc := make(chan error)
-
- go func() {
- dialer := newMultiplexTransport(
- testNodeInfo(
- PubKeyToID(ed25519.GenPrivKey().PubKey()), "dialer",
- ),
- NodeKey{
- PrivKey: ed25519.GenPrivKey(),
- },
- )
- addr := NewNetAddress(mt.nodeKey.ID(), mt.listener.Addr())
-
- _, err := dialer.Dial(*addr, peerConfig{})
- if err != nil {
- errc <- err
- return
- }
-
- close(errc)
- }()
-
- if err := <-errc; err != nil {
- t.Errorf("connection failed: %v", err)
- }
-
- _, err := mt.Accept(peerConfig{})
- if err, ok := err.(ErrRejected); ok {
- if !err.IsAuthFailure() {
- t.Errorf("expected auth failure, got %v", err)
- }
- } else {
- t.Errorf("expected ErrRejected, got %v", err)
- }
- }
-
- func TestTransportMultiplexDialRejectWrongID(t *testing.T) {
- mt := testSetupMultiplexTransport(t)
-
- var (
- pv = ed25519.GenPrivKey()
- dialer = newMultiplexTransport(
- testNodeInfo(PubKeyToID(pv.PubKey()), ""), // Should not be empty
- NodeKey{
- PrivKey: pv,
- },
- )
- )
-
- wrongID := PubKeyToID(ed25519.GenPrivKey().PubKey())
- addr := NewNetAddress(wrongID, mt.listener.Addr())
-
- _, err := dialer.Dial(*addr, peerConfig{})
- if err != nil {
- t.Logf("connection failed: %v", err)
- if err, ok := err.(ErrRejected); ok {
- if !err.IsAuthFailure() {
- t.Errorf("expected auth failure, got %v", err)
- }
- } else {
- t.Errorf("expected ErrRejected, got %v", err)
- }
- }
- }
-
- func TestTransportMultiplexRejectIncompatible(t *testing.T) {
- mt := testSetupMultiplexTransport(t)
-
- errc := make(chan error)
-
- go func() {
- var (
- pv = ed25519.GenPrivKey()
- dialer = newMultiplexTransport(
- testNodeInfoWithNetwork(PubKeyToID(pv.PubKey()), "dialer", "incompatible-network"),
- NodeKey{
- PrivKey: pv,
- },
- )
- )
- addr := NewNetAddress(mt.nodeKey.ID(), mt.listener.Addr())
-
- _, err := dialer.Dial(*addr, peerConfig{})
- if err != nil {
- errc <- err
- return
- }
-
- close(errc)
- }()
-
- _, err := mt.Accept(peerConfig{})
- if err, ok := err.(ErrRejected); ok {
- if !err.IsIncompatible() {
- t.Errorf("expected to reject incompatible, got %v", err)
- }
- } else {
- t.Errorf("expected ErrRejected, got %v", err)
- }
- }
-
- func TestTransportMultiplexRejectSelf(t *testing.T) {
- mt := testSetupMultiplexTransport(t)
-
- errc := make(chan error)
-
- go func() {
- addr := NewNetAddress(mt.nodeKey.ID(), mt.listener.Addr())
-
- _, err := mt.Dial(*addr, peerConfig{})
- if err != nil {
- errc <- err
- return
- }
-
- close(errc)
- }()
-
- if err := <-errc; err != nil {
- if err, ok := err.(ErrRejected); ok {
- if !err.IsSelf() {
- t.Errorf("expected to reject self, got: %v", err)
- }
- } else {
- t.Errorf("expected ErrRejected, got %v", err)
- }
- } else {
- t.Errorf("expected connection failure")
- }
-
- _, err := mt.Accept(peerConfig{})
- if err, ok := err.(ErrRejected); ok {
- if !err.IsSelf() {
- t.Errorf("expected to reject self, got: %v", err)
- }
- } else {
- t.Errorf("expected ErrRejected, got %v", nil)
- }
- }
-
- func TestTransportConnDuplicateIPFilter(t *testing.T) {
- filter := ConnDuplicateIPFilter()
-
- if err := filter(nil, &testTransportConn{}, nil); err != nil {
- t.Fatal(err)
- }
-
- var (
- c = &testTransportConn{}
- cs = NewConnSet()
- )
-
- cs.Set(c, []net.IP{
- {10, 0, 10, 1},
- {10, 0, 10, 2},
- {10, 0, 10, 3},
- })
-
- if err := filter(cs, c, []net.IP{
- {10, 0, 10, 2},
- }); err == nil {
- t.Errorf("expected Peer to be rejected as duplicate")
- }
- }
-
- func TestTransportHandshake(t *testing.T) {
- ln, err := net.Listen("tcp", "127.0.0.1:0")
- if err != nil {
- t.Fatal(err)
- }
-
- var (
- peerPV = ed25519.GenPrivKey()
- peerNodeInfo = testNodeInfo(PubKeyToID(peerPV.PubKey()), defaultNodeName)
- )
-
- go func() {
- c, err := net.Dial(ln.Addr().Network(), ln.Addr().String())
- if err != nil {
- t.Error(err)
- return
- }
-
- go func(c net.Conn) {
- _, err := protoio.NewDelimitedWriter(c).WriteMsg(peerNodeInfo.(DefaultNodeInfo).ToProto())
- if err != nil {
- t.Error(err)
- }
- }(c)
- go func(c net.Conn) {
- var (
- // ni DefaultNodeInfo
- pbni tmp2p.DefaultNodeInfo
- )
-
- protoReader := protoio.NewDelimitedReader(c, MaxNodeInfoSize())
- err := protoReader.ReadMsg(&pbni)
- if err != nil {
- t.Error(err)
- }
-
- _, err = DefaultNodeInfoFromToProto(&pbni)
- if err != nil {
- t.Error(err)
- }
- }(c)
- }()
-
- c, err := ln.Accept()
- if err != nil {
- t.Fatal(err)
- }
-
- ni, err := handshake(c, 20*time.Millisecond, emptyNodeInfo())
- if err != nil {
- t.Fatal(err)
- }
-
- if have, want := ni, peerNodeInfo; !reflect.DeepEqual(have, want) {
- t.Errorf("have %v, want %v", have, want)
- }
- }
-
- // create listener
- func testSetupMultiplexTransport(t *testing.T) *MultiplexTransport {
- var (
- pv = ed25519.GenPrivKey()
- id = PubKeyToID(pv.PubKey())
- mt = newMultiplexTransport(
- testNodeInfo(
- id, "transport",
- ),
- NodeKey{
- PrivKey: pv,
- },
- )
- )
-
- addr, err := NewNetAddressString(IDAddressString(id, "127.0.0.1:0"))
- if err != nil {
- t.Fatal(err)
- }
-
- if err := mt.Listen(*addr); err != nil {
- t.Fatal(err)
- }
-
- // give the listener some time to get ready
- time.Sleep(20 * time.Millisecond)
-
- return mt
- }
-
- type testTransportAddr struct{}
-
- func (a *testTransportAddr) Network() string { return "tcp" }
- func (a *testTransportAddr) String() string { return "test.local:1234" }
-
- type testTransportConn struct{}
-
- func (c *testTransportConn) Close() error {
- return fmt.Errorf("close() not implemented")
- }
-
- func (c *testTransportConn) LocalAddr() net.Addr {
- return &testTransportAddr{}
- }
-
- func (c *testTransportConn) RemoteAddr() net.Addr {
- return &testTransportAddr{}
- }
-
- func (c *testTransportConn) Read(_ []byte) (int, error) {
- return -1, fmt.Errorf("read() not implemented")
- }
-
- func (c *testTransportConn) SetDeadline(_ time.Time) error {
- return fmt.Errorf("setDeadline() not implemented")
- }
-
- func (c *testTransportConn) SetReadDeadline(_ time.Time) error {
- return fmt.Errorf("setReadDeadline() not implemented")
- }
-
- func (c *testTransportConn) SetWriteDeadline(_ time.Time) error {
- return fmt.Errorf("setWriteDeadline() not implemented")
- }
-
- func (c *testTransportConn) Write(_ []byte) (int, error) {
- return -1, fmt.Errorf("write() not implemented")
- }
|