github.com/Oyster-zx/tendermint@v0.34.24-fork/p2p/conn/connection_test.go (about) 1 package conn 2 3 import ( 4 "encoding/hex" 5 "net" 6 "testing" 7 "time" 8 9 "github.com/fortytw2/leaktest" 10 "github.com/gogo/protobuf/proto" 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 14 "github.com/tendermint/tendermint/libs/log" 15 "github.com/tendermint/tendermint/libs/protoio" 16 tmp2p "github.com/tendermint/tendermint/proto/tendermint/p2p" 17 "github.com/tendermint/tendermint/proto/tendermint/types" 18 ) 19 20 const maxPingPongPacketSize = 1024 // bytes 21 22 func createTestMConnection(conn net.Conn) *MConnection { 23 onReceive := func(chID byte, msgBytes []byte) { 24 } 25 onError := func(r interface{}) { 26 } 27 c := createMConnectionWithCallbacks(conn, onReceive, onError) 28 c.SetLogger(log.TestingLogger()) 29 return c 30 } 31 32 func createMConnectionWithCallbacks( 33 conn net.Conn, 34 onReceive func(chID byte, msgBytes []byte), 35 onError func(r interface{}), 36 ) *MConnection { 37 cfg := DefaultMConnConfig() 38 cfg.PingInterval = 90 * time.Millisecond 39 cfg.PongTimeout = 45 * time.Millisecond 40 chDescs := []*ChannelDescriptor{{ID: 0x01, Priority: 1, SendQueueCapacity: 1}} 41 c := NewMConnectionWithConfig(conn, chDescs, onReceive, onError, cfg) 42 c.SetLogger(log.TestingLogger()) 43 return c 44 } 45 46 func TestMConnectionSendFlushStop(t *testing.T) { 47 server, client := NetPipe() 48 defer server.Close() 49 defer client.Close() 50 51 clientConn := createTestMConnection(client) 52 err := clientConn.Start() 53 require.Nil(t, err) 54 defer clientConn.Stop() //nolint:errcheck // ignore for tests 55 56 msg := []byte("abc") 57 assert.True(t, clientConn.Send(0x01, msg)) 58 59 msgLength := 14 60 61 // start the reader in a new routine, so we can flush 62 errCh := make(chan error) 63 go func() { 64 msgB := make([]byte, msgLength) 65 _, err := server.Read(msgB) 66 if err != nil { 67 t.Error(err) 68 return 69 } 70 errCh <- err 71 }() 72 73 // stop the conn - it should flush all conns 74 clientConn.FlushStop() 75 76 timer := time.NewTimer(3 * time.Second) 77 select { 78 case <-errCh: 79 case <-timer.C: 80 t.Error("timed out waiting for msgs to be read") 81 } 82 } 83 84 func TestMConnectionSend(t *testing.T) { 85 server, client := NetPipe() 86 defer server.Close() 87 defer client.Close() 88 89 mconn := createTestMConnection(client) 90 err := mconn.Start() 91 require.Nil(t, err) 92 defer mconn.Stop() //nolint:errcheck // ignore for tests 93 94 msg := []byte("Ant-Man") 95 assert.True(t, mconn.Send(0x01, msg)) 96 // Note: subsequent Send/TrySend calls could pass because we are reading from 97 // the send queue in a separate goroutine. 98 _, err = server.Read(make([]byte, len(msg))) 99 if err != nil { 100 t.Error(err) 101 } 102 assert.True(t, mconn.CanSend(0x01)) 103 104 msg = []byte("Spider-Man") 105 assert.True(t, mconn.TrySend(0x01, msg)) 106 _, err = server.Read(make([]byte, len(msg))) 107 if err != nil { 108 t.Error(err) 109 } 110 111 assert.False(t, mconn.CanSend(0x05), "CanSend should return false because channel is unknown") 112 assert.False(t, mconn.Send(0x05, []byte("Absorbing Man")), "Send should return false because channel is unknown") 113 } 114 115 func TestMConnectionReceive(t *testing.T) { 116 server, client := NetPipe() 117 defer server.Close() 118 defer client.Close() 119 120 receivedCh := make(chan []byte) 121 errorsCh := make(chan interface{}) 122 onReceive := func(chID byte, msgBytes []byte) { 123 receivedCh <- msgBytes 124 } 125 onError := func(r interface{}) { 126 errorsCh <- r 127 } 128 mconn1 := createMConnectionWithCallbacks(client, onReceive, onError) 129 err := mconn1.Start() 130 require.Nil(t, err) 131 defer mconn1.Stop() //nolint:errcheck // ignore for tests 132 133 mconn2 := createTestMConnection(server) 134 err = mconn2.Start() 135 require.Nil(t, err) 136 defer mconn2.Stop() //nolint:errcheck // ignore for tests 137 138 msg := []byte("Cyclops") 139 assert.True(t, mconn2.Send(0x01, msg)) 140 141 select { 142 case receivedBytes := <-receivedCh: 143 assert.Equal(t, msg, receivedBytes) 144 case err := <-errorsCh: 145 t.Fatalf("Expected %s, got %+v", msg, err) 146 case <-time.After(500 * time.Millisecond): 147 t.Fatalf("Did not receive %s message in 500ms", msg) 148 } 149 } 150 151 func TestMConnectionStatus(t *testing.T) { 152 server, client := NetPipe() 153 defer server.Close() 154 defer client.Close() 155 156 mconn := createTestMConnection(client) 157 err := mconn.Start() 158 require.Nil(t, err) 159 defer mconn.Stop() //nolint:errcheck // ignore for tests 160 161 status := mconn.Status() 162 assert.NotNil(t, status) 163 assert.Zero(t, status.Channels[0].SendQueueSize) 164 } 165 166 func TestMConnectionPongTimeoutResultsInError(t *testing.T) { 167 server, client := net.Pipe() 168 defer server.Close() 169 defer client.Close() 170 171 receivedCh := make(chan []byte) 172 errorsCh := make(chan interface{}) 173 onReceive := func(chID byte, msgBytes []byte) { 174 receivedCh <- msgBytes 175 } 176 onError := func(r interface{}) { 177 errorsCh <- r 178 } 179 mconn := createMConnectionWithCallbacks(client, onReceive, onError) 180 err := mconn.Start() 181 require.Nil(t, err) 182 defer mconn.Stop() //nolint:errcheck // ignore for tests 183 184 serverGotPing := make(chan struct{}) 185 go func() { 186 // read ping 187 var pkt tmp2p.Packet 188 _, err := protoio.NewDelimitedReader(server, maxPingPongPacketSize).ReadMsg(&pkt) 189 require.NoError(t, err) 190 serverGotPing <- struct{}{} 191 }() 192 <-serverGotPing 193 194 pongTimerExpired := mconn.config.PongTimeout + 200*time.Millisecond 195 select { 196 case msgBytes := <-receivedCh: 197 t.Fatalf("Expected error, but got %v", msgBytes) 198 case err := <-errorsCh: 199 assert.NotNil(t, err) 200 case <-time.After(pongTimerExpired): 201 t.Fatalf("Expected to receive error after %v", pongTimerExpired) 202 } 203 } 204 205 func TestMConnectionMultiplePongsInTheBeginning(t *testing.T) { 206 server, client := net.Pipe() 207 defer server.Close() 208 defer client.Close() 209 210 receivedCh := make(chan []byte) 211 errorsCh := make(chan interface{}) 212 onReceive := func(chID byte, msgBytes []byte) { 213 receivedCh <- msgBytes 214 } 215 onError := func(r interface{}) { 216 errorsCh <- r 217 } 218 mconn := createMConnectionWithCallbacks(client, onReceive, onError) 219 err := mconn.Start() 220 require.Nil(t, err) 221 defer mconn.Stop() //nolint:errcheck // ignore for tests 222 223 // sending 3 pongs in a row (abuse) 224 protoWriter := protoio.NewDelimitedWriter(server) 225 226 _, err = protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketPong{})) 227 require.NoError(t, err) 228 229 _, err = protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketPong{})) 230 require.NoError(t, err) 231 232 _, err = protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketPong{})) 233 require.NoError(t, err) 234 235 serverGotPing := make(chan struct{}) 236 go func() { 237 // read ping (one byte) 238 var packet tmp2p.Packet 239 _, err := protoio.NewDelimitedReader(server, maxPingPongPacketSize).ReadMsg(&packet) 240 require.NoError(t, err) 241 serverGotPing <- struct{}{} 242 243 // respond with pong 244 _, err = protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketPong{})) 245 require.NoError(t, err) 246 }() 247 <-serverGotPing 248 249 pongTimerExpired := mconn.config.PongTimeout + 20*time.Millisecond 250 select { 251 case msgBytes := <-receivedCh: 252 t.Fatalf("Expected no data, but got %v", msgBytes) 253 case err := <-errorsCh: 254 t.Fatalf("Expected no error, but got %v", err) 255 case <-time.After(pongTimerExpired): 256 assert.True(t, mconn.IsRunning()) 257 } 258 } 259 260 func TestMConnectionMultiplePings(t *testing.T) { 261 server, client := net.Pipe() 262 defer server.Close() 263 defer client.Close() 264 265 receivedCh := make(chan []byte) 266 errorsCh := make(chan interface{}) 267 onReceive := func(chID byte, msgBytes []byte) { 268 receivedCh <- msgBytes 269 } 270 onError := func(r interface{}) { 271 errorsCh <- r 272 } 273 mconn := createMConnectionWithCallbacks(client, onReceive, onError) 274 err := mconn.Start() 275 require.Nil(t, err) 276 defer mconn.Stop() //nolint:errcheck // ignore for tests 277 278 // sending 3 pings in a row (abuse) 279 // see https://github.com/tendermint/tendermint/issues/1190 280 protoReader := protoio.NewDelimitedReader(server, maxPingPongPacketSize) 281 protoWriter := protoio.NewDelimitedWriter(server) 282 var pkt tmp2p.Packet 283 284 _, err = protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketPing{})) 285 require.NoError(t, err) 286 287 _, err = protoReader.ReadMsg(&pkt) 288 require.NoError(t, err) 289 290 _, err = protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketPing{})) 291 require.NoError(t, err) 292 293 _, err = protoReader.ReadMsg(&pkt) 294 require.NoError(t, err) 295 296 _, err = protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketPing{})) 297 require.NoError(t, err) 298 299 _, err = protoReader.ReadMsg(&pkt) 300 require.NoError(t, err) 301 302 assert.True(t, mconn.IsRunning()) 303 } 304 305 func TestMConnectionPingPongs(t *testing.T) { 306 // check that we are not leaking any go-routines 307 defer leaktest.CheckTimeout(t, 10*time.Second)() 308 309 server, client := net.Pipe() 310 311 defer server.Close() 312 defer client.Close() 313 314 receivedCh := make(chan []byte) 315 errorsCh := make(chan interface{}) 316 onReceive := func(chID byte, msgBytes []byte) { 317 receivedCh <- msgBytes 318 } 319 onError := func(r interface{}) { 320 errorsCh <- r 321 } 322 mconn := createMConnectionWithCallbacks(client, onReceive, onError) 323 err := mconn.Start() 324 require.Nil(t, err) 325 defer mconn.Stop() //nolint:errcheck // ignore for tests 326 327 serverGotPing := make(chan struct{}) 328 go func() { 329 protoReader := protoio.NewDelimitedReader(server, maxPingPongPacketSize) 330 protoWriter := protoio.NewDelimitedWriter(server) 331 var pkt tmp2p.PacketPing 332 333 // read ping 334 _, err = protoReader.ReadMsg(&pkt) 335 require.NoError(t, err) 336 serverGotPing <- struct{}{} 337 338 // respond with pong 339 _, err = protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketPong{})) 340 require.NoError(t, err) 341 342 time.Sleep(mconn.config.PingInterval) 343 344 // read ping 345 _, err = protoReader.ReadMsg(&pkt) 346 require.NoError(t, err) 347 serverGotPing <- struct{}{} 348 349 // respond with pong 350 _, err = protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketPong{})) 351 require.NoError(t, err) 352 }() 353 <-serverGotPing 354 <-serverGotPing 355 356 pongTimerExpired := (mconn.config.PongTimeout + 20*time.Millisecond) * 2 357 select { 358 case msgBytes := <-receivedCh: 359 t.Fatalf("Expected no data, but got %v", msgBytes) 360 case err := <-errorsCh: 361 t.Fatalf("Expected no error, but got %v", err) 362 case <-time.After(2 * pongTimerExpired): 363 assert.True(t, mconn.IsRunning()) 364 } 365 } 366 367 func TestMConnectionStopsAndReturnsError(t *testing.T) { 368 server, client := NetPipe() 369 defer server.Close() 370 defer client.Close() 371 372 receivedCh := make(chan []byte) 373 errorsCh := make(chan interface{}) 374 onReceive := func(chID byte, msgBytes []byte) { 375 receivedCh <- msgBytes 376 } 377 onError := func(r interface{}) { 378 errorsCh <- r 379 } 380 mconn := createMConnectionWithCallbacks(client, onReceive, onError) 381 err := mconn.Start() 382 require.Nil(t, err) 383 defer mconn.Stop() //nolint:errcheck // ignore for tests 384 385 if err := client.Close(); err != nil { 386 t.Error(err) 387 } 388 389 select { 390 case receivedBytes := <-receivedCh: 391 t.Fatalf("Expected error, got %v", receivedBytes) 392 case err := <-errorsCh: 393 assert.NotNil(t, err) 394 assert.False(t, mconn.IsRunning()) 395 case <-time.After(500 * time.Millisecond): 396 t.Fatal("Did not receive error in 500ms") 397 } 398 } 399 400 func newClientAndServerConnsForReadErrors(t *testing.T, chOnErr chan struct{}) (*MConnection, *MConnection) { 401 server, client := NetPipe() 402 403 onReceive := func(chID byte, msgBytes []byte) {} 404 onError := func(r interface{}) {} 405 406 // create client conn with two channels 407 chDescs := []*ChannelDescriptor{ 408 {ID: 0x01, Priority: 1, SendQueueCapacity: 1}, 409 {ID: 0x02, Priority: 1, SendQueueCapacity: 1}, 410 } 411 mconnClient := NewMConnection(client, chDescs, onReceive, onError) 412 mconnClient.SetLogger(log.TestingLogger().With("module", "client")) 413 err := mconnClient.Start() 414 require.Nil(t, err) 415 416 // create server conn with 1 channel 417 // it fires on chOnErr when there's an error 418 serverLogger := log.TestingLogger().With("module", "server") 419 onError = func(r interface{}) { 420 chOnErr <- struct{}{} 421 } 422 mconnServer := createMConnectionWithCallbacks(server, onReceive, onError) 423 mconnServer.SetLogger(serverLogger) 424 err = mconnServer.Start() 425 require.Nil(t, err) 426 return mconnClient, mconnServer 427 } 428 429 func expectSend(ch chan struct{}) bool { 430 after := time.After(time.Second * 5) 431 select { 432 case <-ch: 433 return true 434 case <-after: 435 return false 436 } 437 } 438 439 func TestMConnectionReadErrorBadEncoding(t *testing.T) { 440 chOnErr := make(chan struct{}) 441 mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr) 442 443 client := mconnClient.conn 444 445 // Write it. 446 _, err := client.Write([]byte{1, 2, 3, 4, 5}) 447 require.NoError(t, err) 448 assert.True(t, expectSend(chOnErr), "badly encoded msgPacket") 449 450 t.Cleanup(func() { 451 if err := mconnClient.Stop(); err != nil { 452 t.Log(err) 453 } 454 }) 455 456 t.Cleanup(func() { 457 if err := mconnServer.Stop(); err != nil { 458 t.Log(err) 459 } 460 }) 461 } 462 463 func TestMConnectionReadErrorUnknownChannel(t *testing.T) { 464 chOnErr := make(chan struct{}) 465 mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr) 466 467 msg := []byte("Ant-Man") 468 469 // fail to send msg on channel unknown by client 470 assert.False(t, mconnClient.Send(0x03, msg)) 471 472 // send msg on channel unknown by the server. 473 // should cause an error 474 assert.True(t, mconnClient.Send(0x02, msg)) 475 assert.True(t, expectSend(chOnErr), "unknown channel") 476 477 t.Cleanup(func() { 478 if err := mconnClient.Stop(); err != nil { 479 t.Log(err) 480 } 481 }) 482 483 t.Cleanup(func() { 484 if err := mconnServer.Stop(); err != nil { 485 t.Log(err) 486 } 487 }) 488 } 489 490 func TestMConnectionReadErrorLongMessage(t *testing.T) { 491 chOnErr := make(chan struct{}) 492 chOnRcv := make(chan struct{}) 493 494 mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr) 495 defer mconnClient.Stop() //nolint:errcheck // ignore for tests 496 defer mconnServer.Stop() //nolint:errcheck // ignore for tests 497 498 mconnServer.onReceive = func(chID byte, msgBytes []byte) { 499 chOnRcv <- struct{}{} 500 } 501 502 client := mconnClient.conn 503 protoWriter := protoio.NewDelimitedWriter(client) 504 505 // send msg thats just right 506 var packet = tmp2p.PacketMsg{ 507 ChannelID: 0x01, 508 EOF: true, 509 Data: make([]byte, mconnClient.config.MaxPacketMsgPayloadSize), 510 } 511 512 _, err := protoWriter.WriteMsg(mustWrapPacket(&packet)) 513 require.NoError(t, err) 514 assert.True(t, expectSend(chOnRcv), "msg just right") 515 516 // send msg thats too long 517 packet = tmp2p.PacketMsg{ 518 ChannelID: 0x01, 519 EOF: true, 520 Data: make([]byte, mconnClient.config.MaxPacketMsgPayloadSize+100), 521 } 522 523 _, err = protoWriter.WriteMsg(mustWrapPacket(&packet)) 524 require.Error(t, err) 525 assert.True(t, expectSend(chOnErr), "msg too long") 526 } 527 528 func TestMConnectionReadErrorUnknownMsgType(t *testing.T) { 529 chOnErr := make(chan struct{}) 530 mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr) 531 defer mconnClient.Stop() //nolint:errcheck // ignore for tests 532 defer mconnServer.Stop() //nolint:errcheck // ignore for tests 533 534 // send msg with unknown msg type 535 _, err := protoio.NewDelimitedWriter(mconnClient.conn).WriteMsg(&types.Header{ChainID: "x"}) 536 require.NoError(t, err) 537 assert.True(t, expectSend(chOnErr), "unknown msg type") 538 } 539 540 func TestMConnectionTrySend(t *testing.T) { 541 server, client := NetPipe() 542 defer server.Close() 543 defer client.Close() 544 545 mconn := createTestMConnection(client) 546 err := mconn.Start() 547 require.Nil(t, err) 548 defer mconn.Stop() //nolint:errcheck // ignore for tests 549 550 msg := []byte("Semicolon-Woman") 551 resultCh := make(chan string, 2) 552 assert.True(t, mconn.TrySend(0x01, msg)) 553 _, err = server.Read(make([]byte, len(msg))) 554 require.NoError(t, err) 555 assert.True(t, mconn.CanSend(0x01)) 556 assert.True(t, mconn.TrySend(0x01, msg)) 557 assert.False(t, mconn.CanSend(0x01)) 558 go func() { 559 mconn.TrySend(0x01, msg) 560 resultCh <- "TrySend" 561 }() 562 assert.False(t, mconn.CanSend(0x01)) 563 assert.False(t, mconn.TrySend(0x01, msg)) 564 assert.Equal(t, "TrySend", <-resultCh) 565 } 566 567 //nolint:lll //ignore line length for tests 568 func TestConnVectors(t *testing.T) { 569 570 testCases := []struct { 571 testName string 572 msg proto.Message 573 expBytes string 574 }{ 575 {"PacketPing", &tmp2p.PacketPing{}, "0a00"}, 576 {"PacketPong", &tmp2p.PacketPong{}, "1200"}, 577 {"PacketMsg", &tmp2p.PacketMsg{ChannelID: 1, EOF: false, Data: []byte("data transmitted over the wire")}, "1a2208011a1e64617461207472616e736d6974746564206f766572207468652077697265"}, 578 } 579 580 for _, tc := range testCases { 581 tc := tc 582 583 pm := mustWrapPacket(tc.msg) 584 bz, err := pm.Marshal() 585 require.NoError(t, err, tc.testName) 586 587 require.Equal(t, tc.expBytes, hex.EncodeToString(bz), tc.testName) 588 } 589 } 590 591 func TestMConnectionChannelOverflow(t *testing.T) { 592 chOnErr := make(chan struct{}) 593 chOnRcv := make(chan struct{}) 594 595 mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr) 596 t.Cleanup(stopAll(t, mconnClient, mconnServer)) 597 598 mconnServer.onReceive = func(chID byte, msgBytes []byte) { 599 chOnRcv <- struct{}{} 600 } 601 602 client := mconnClient.conn 603 protoWriter := protoio.NewDelimitedWriter(client) 604 605 var packet = tmp2p.PacketMsg{ 606 ChannelID: 0x01, 607 EOF: true, 608 Data: []byte(`42`), 609 } 610 _, err := protoWriter.WriteMsg(mustWrapPacket(&packet)) 611 require.NoError(t, err) 612 assert.True(t, expectSend(chOnRcv)) 613 614 packet.ChannelID = int32(1025) 615 _, err = protoWriter.WriteMsg(mustWrapPacket(&packet)) 616 require.NoError(t, err) 617 assert.False(t, expectSend(chOnRcv)) 618 619 } 620 621 type stopper interface { 622 Stop() error 623 } 624 625 func stopAll(t *testing.T, stoppers ...stopper) func() { 626 return func() { 627 for _, s := range stoppers { 628 if err := s.Stop(); err != nil { 629 t.Log(err) 630 } 631 } 632 } 633 }