github.com/okex/exchain@v1.8.0/libs/tendermint/p2p/peer_test.go (about)

     1  package p2p
     2  
     3  import (
     4  	"fmt"
     5  	golog "log"
     6  	"math"
     7  	"net"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/tendermint/go-amino"
    12  
    13  	"github.com/pkg/errors"
    14  	"github.com/stretchr/testify/assert"
    15  	"github.com/stretchr/testify/require"
    16  
    17  	"github.com/okex/exchain/libs/tendermint/crypto"
    18  	"github.com/okex/exchain/libs/tendermint/crypto/ed25519"
    19  	"github.com/okex/exchain/libs/tendermint/libs/bytes"
    20  	"github.com/okex/exchain/libs/tendermint/libs/log"
    21  
    22  	"github.com/okex/exchain/libs/tendermint/config"
    23  	tmconn "github.com/okex/exchain/libs/tendermint/p2p/conn"
    24  )
    25  
    26  func TestPeerBasic(t *testing.T) {
    27  	assert, require := assert.New(t), require.New(t)
    28  
    29  	// simulate remote peer
    30  	rp := &remotePeer{PrivKey: ed25519.GenPrivKey(), Config: cfg}
    31  	rp.Start()
    32  	defer rp.Stop()
    33  
    34  	p, err := createOutboundPeerAndPerformHandshake(rp.Addr(), cfg, tmconn.DefaultMConnConfig())
    35  	require.Nil(err)
    36  
    37  	err = p.Start()
    38  	require.Nil(err)
    39  	defer p.Stop()
    40  
    41  	assert.True(p.IsRunning())
    42  	assert.True(p.IsOutbound())
    43  	assert.False(p.IsPersistent())
    44  	p.persistent = true
    45  	assert.True(p.IsPersistent())
    46  	assert.Equal(rp.Addr().DialString(), p.RemoteAddr().String())
    47  	assert.Equal(rp.ID(), p.ID())
    48  }
    49  
    50  func TestPeerSend(t *testing.T) {
    51  	assert, require := assert.New(t), require.New(t)
    52  
    53  	config := cfg
    54  
    55  	// simulate remote peer
    56  	rp := &remotePeer{PrivKey: ed25519.GenPrivKey(), Config: config}
    57  	rp.Start()
    58  	defer rp.Stop()
    59  
    60  	p, err := createOutboundPeerAndPerformHandshake(rp.Addr(), config, tmconn.DefaultMConnConfig())
    61  	require.Nil(err)
    62  
    63  	err = p.Start()
    64  	require.Nil(err)
    65  
    66  	defer p.Stop()
    67  
    68  	assert.True(p.CanSend(testCh))
    69  	assert.True(p.Send(testCh, []byte("Asylum")))
    70  }
    71  
    72  func createOutboundPeerAndPerformHandshake(
    73  	addr *NetAddress,
    74  	config *config.P2PConfig,
    75  	mConfig tmconn.MConnConfig,
    76  ) (*peer, error) {
    77  	chDescs := []*tmconn.ChannelDescriptor{
    78  		{ID: testCh, Priority: 1},
    79  	}
    80  	reactorsByCh := map[byte]Reactor{testCh: NewTestReactor(chDescs, true)}
    81  	pk := ed25519.GenPrivKey()
    82  	pc, err := testOutboundPeerConn(addr, config, false, pk)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  	timeout := 1 * time.Second
    87  	ourNodeInfo := testNodeInfo(addr.ID, "host_peer")
    88  	peerNodeInfo, err := handshake(pc.conn, timeout, ourNodeInfo)
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  
    93  	p := newPeer(pc, mConfig, peerNodeInfo, reactorsByCh, chDescs, func(p Peer, r interface{}) {})
    94  	p.SetLogger(log.TestingLogger().With("peer", addr))
    95  	return p, nil
    96  }
    97  
    98  func testDial(addr *NetAddress, cfg *config.P2PConfig) (net.Conn, error) {
    99  	if cfg.TestDialFail {
   100  		return nil, fmt.Errorf("dial err (peerConfig.DialFail == true)")
   101  	}
   102  
   103  	conn, err := addr.DialTimeout(cfg.DialTimeout)
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  	return conn, nil
   108  }
   109  
   110  func testOutboundPeerConn(
   111  	addr *NetAddress,
   112  	config *config.P2PConfig,
   113  	persistent bool,
   114  	ourNodePrivKey crypto.PrivKey,
   115  ) (peerConn, error) {
   116  
   117  	var pc peerConn
   118  	conn, err := testDial(addr, config)
   119  	if err != nil {
   120  		return pc, errors.Wrap(err, "Error creating peer")
   121  	}
   122  
   123  	pc, err = testPeerConn(conn, config, true, persistent, ourNodePrivKey, addr)
   124  	if err != nil {
   125  		if cerr := conn.Close(); cerr != nil {
   126  			return pc, errors.Wrap(err, cerr.Error())
   127  		}
   128  		return pc, err
   129  	}
   130  
   131  	// ensure dialed ID matches connection ID
   132  	if addr.ID != pc.ID() {
   133  		if cerr := conn.Close(); cerr != nil {
   134  			return pc, errors.Wrap(err, cerr.Error())
   135  		}
   136  		return pc, ErrSwitchAuthenticationFailure{addr, pc.ID()}
   137  	}
   138  
   139  	return pc, nil
   140  }
   141  
   142  type remotePeer struct {
   143  	PrivKey    crypto.PrivKey
   144  	Config     *config.P2PConfig
   145  	addr       *NetAddress
   146  	channels   bytes.HexBytes
   147  	listenAddr string
   148  	listener   net.Listener
   149  }
   150  
   151  func (rp *remotePeer) Addr() *NetAddress {
   152  	return rp.addr
   153  }
   154  
   155  func (rp *remotePeer) ID() ID {
   156  	return PubKeyToID(rp.PrivKey.PubKey())
   157  }
   158  
   159  func (rp *remotePeer) Start() {
   160  	if rp.listenAddr == "" {
   161  		rp.listenAddr = "127.0.0.1:0"
   162  	}
   163  
   164  	l, e := net.Listen("tcp", rp.listenAddr) // any available address
   165  	if e != nil {
   166  		golog.Fatalf("net.Listen tcp :0: %+v", e)
   167  	}
   168  	rp.listener = l
   169  	rp.addr = NewNetAddress(PubKeyToID(rp.PrivKey.PubKey()), l.Addr())
   170  	if rp.channels == nil {
   171  		rp.channels = []byte{testCh}
   172  	}
   173  	go rp.accept()
   174  }
   175  
   176  func (rp *remotePeer) Stop() {
   177  	rp.listener.Close()
   178  }
   179  
   180  func (rp *remotePeer) Dial(addr *NetAddress) (net.Conn, error) {
   181  	conn, err := addr.DialTimeout(1 * time.Second)
   182  	if err != nil {
   183  		return nil, err
   184  	}
   185  	pc, err := testInboundPeerConn(conn, rp.Config, rp.PrivKey)
   186  	if err != nil {
   187  		return nil, err
   188  	}
   189  	_, err = handshake(pc.conn, time.Second, rp.nodeInfo())
   190  	if err != nil {
   191  		return nil, err
   192  	}
   193  	return conn, err
   194  }
   195  
   196  func (rp *remotePeer) accept() {
   197  	conns := []net.Conn{}
   198  
   199  	for {
   200  		conn, err := rp.listener.Accept()
   201  		if err != nil {
   202  			golog.Printf("Failed to accept conn: %+v", err)
   203  			for _, conn := range conns {
   204  				_ = conn.Close()
   205  			}
   206  			return
   207  		}
   208  
   209  		pc, err := testInboundPeerConn(conn, rp.Config, rp.PrivKey)
   210  		if err != nil {
   211  			golog.Fatalf("Failed to create a peer: %+v", err)
   212  		}
   213  
   214  		_, err = handshake(pc.conn, time.Second, rp.nodeInfo())
   215  		if err != nil {
   216  			golog.Fatalf("Failed to perform handshake: %+v", err)
   217  		}
   218  
   219  		conns = append(conns, conn)
   220  	}
   221  }
   222  
   223  func (rp *remotePeer) nodeInfo() NodeInfo {
   224  	return DefaultNodeInfo{
   225  		ProtocolVersion: defaultProtocolVersion,
   226  		DefaultNodeID:   rp.Addr().ID,
   227  		ListenAddr:      rp.listener.Addr().String(),
   228  		Network:         "testing",
   229  		Version:         "1.2.3-rc0-deadbeef",
   230  		Channels:        rp.channels,
   231  		Moniker:         "remote_peer",
   232  	}
   233  }
   234  
   235  func TestGetChIdStr(t *testing.T) {
   236  	var i byte
   237  	for ; i < math.MaxUint8; i++ {
   238  		require.EqualValues(t, fmt.Sprintf("%#x", i), getChIdStr(i))
   239  	}
   240  }
   241  
   242  const hextable = "0123456789abcdef"
   243  
   244  func chidToHex(v byte) string {
   245  	size := 3
   246  	if v > 15 {
   247  		size += 1
   248  	}
   249  	ret := make([]byte, size)
   250  	ret[0] = '0'
   251  	ret[1] = 'x'
   252  	if v > 15 {
   253  		ret[2] = hextable[v>>4]
   254  		ret[3] = hextable[v&0x0f]
   255  	} else {
   256  		ret[2] = hextable[v]
   257  	}
   258  	return amino.BytesToStr(ret)
   259  }
   260  
   261  func BenchmarkChIdFormat(b *testing.B) {
   262  	b.Run("fmt", func(b *testing.B) {
   263  		b.ReportAllocs()
   264  		for i := 0; i < b.N; i++ {
   265  			_ = fmt.Sprintf("%#x", byte(i))
   266  		}
   267  	})
   268  	b.Run("hex", func(b *testing.B) {
   269  		b.ReportAllocs()
   270  		for i := 0; i < b.N; i++ {
   271  			_ = chidToHex(byte(i))
   272  		}
   273  	})
   274  	b.Run("table", func(b *testing.B) {
   275  		b.ReportAllocs()
   276  		for i := 0; i < b.N; i++ {
   277  			_ = getChIdStr(byte(i))
   278  		}
   279  	})
   280  }