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