github.com/pure-x-eth/consensus_tm@v0.0.0-20230502163723-e3c2ff987250/p2p/peer_test.go (about)

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