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 }