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