github.com/klaytn/klaytn@v1.12.1/networks/p2p/peer_test.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2014 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from p2p/peer_test.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package p2p 22 23 import ( 24 "errors" 25 "fmt" 26 "math/rand" 27 "net" 28 "reflect" 29 "testing" 30 "time" 31 32 "github.com/klaytn/klaytn/common/math" 33 "github.com/stretchr/testify/assert" 34 ) 35 36 var discard = Protocol{ 37 Name: "discard", 38 Length: 1, 39 Run: func(p *Peer, rw MsgReadWriter) error { 40 for { 41 msg, err := rw.ReadMsg() 42 if err != nil { 43 return err 44 } 45 fmt.Printf("discarding %d\n", msg.Code) 46 if err = msg.Discard(); err != nil { 47 return err 48 } 49 } 50 }, 51 } 52 53 func testPeer(protos []Protocol) (func(), *conn, *Peer, <-chan error) { 54 var ( 55 fd1, fd2 = net.Pipe() 56 id1, id2 = randomID(), randomID() 57 pubkey1, _ = id1.Pubkey() 58 t1 = newTestTransport(id2, fd1, nil, true) 59 t2 = newTestTransport(id1, fd2, pubkey1, true) 60 ) 61 c1 := &conn{fd: fd1, transport: t1} 62 c2 := &conn{fd: fd2, transport: t2} 63 for _, p := range protos { 64 c1.caps = append(c1.caps, p.cap()) 65 c2.caps = append(c2.caps, p.cap()) 66 } 67 68 peer, _ := newPeer([]*conn{c1}, protos, defaultRWTimerConfig) 69 errc := make(chan error, 1) 70 go func() { 71 _, err := peer.run() 72 errc <- err 73 }() 74 75 closer := func() { c2.close(errors.New("close func called")) } 76 return closer, c2, peer, errc 77 } 78 79 func testPeerWithRWs(protos []Protocol, channelSize int) (func(), []*conn, *Peer, <-chan error) { 80 serverSideConn := make([]*conn, 0, channelSize) 81 peerSideConn := make([]*conn, 0, channelSize) 82 83 for i := 0; i < channelSize; i++ { 84 var ( 85 fd1, fd2 = net.Pipe() 86 id1, id2 = randomID(), randomID() 87 pubkey1, _ = id1.Pubkey() 88 t1 = newTestTransport(id2, fd1, nil, true) 89 t2 = newTestTransport(id1, fd2, pubkey1, true) 90 ) 91 c1 := &conn{fd: fd1, transport: t1} 92 c2 := &conn{fd: fd2, transport: t2} 93 for _, p := range protos { 94 c1.caps = append(c1.caps, p.cap()) 95 c2.caps = append(c2.caps, p.cap()) 96 } 97 serverSideConn = append(serverSideConn, c1) 98 peerSideConn = append(peerSideConn, c2) 99 } 100 101 peer, _ := newPeer(serverSideConn, protos, defaultRWTimerConfig) 102 errc := make(chan error, 1) 103 go func() { 104 _, err := peer.runWithRWs() 105 errc <- err 106 }() 107 108 closer := func() { 109 for _, conn := range peerSideConn { 110 conn.close(errors.New("close func called")) 111 } 112 } 113 return closer, peerSideConn, peer, errc 114 } 115 116 func TestPeerProtoReadMsg(t *testing.T) { 117 proto := Protocol{ 118 Name: "a", 119 Length: 5, 120 Run: func(peer *Peer, rw MsgReadWriter) error { 121 if err := ExpectMsg(rw, 2, []uint{1}); err != nil { 122 t.Error(err) 123 } 124 if err := ExpectMsg(rw, 3, []uint{2}); err != nil { 125 t.Error(err) 126 } 127 if err := ExpectMsg(rw, 4, []uint{3}); err != nil { 128 t.Error(err) 129 } 130 return nil 131 }, 132 } 133 134 closer, rw, _, errc := testPeer([]Protocol{proto}) 135 defer closer() 136 137 Send(rw, baseProtocolLength+2, []uint{1}) 138 Send(rw, baseProtocolLength+3, []uint{2}) 139 Send(rw, baseProtocolLength+4, []uint{3}) 140 141 select { 142 case err := <-errc: 143 if err != errProtocolReturned { 144 t.Errorf("peer returned error: %v", err) 145 } 146 case <-time.After(2 * time.Second): 147 t.Errorf("receive timeout") 148 } 149 } 150 151 func TestPeerProtoEncodeMsg(t *testing.T) { 152 proto := Protocol{ 153 Name: "a", 154 Length: 2, 155 Run: func(peer *Peer, rw MsgReadWriter) error { 156 if err := SendItems(rw, 2); err == nil { 157 t.Error("expected error for out-of-range msg code, got nil") 158 } 159 if err := SendItems(rw, 1, "foo", "bar"); err != nil { 160 t.Errorf("write error: %v", err) 161 } 162 return nil 163 }, 164 } 165 closer, rw, _, _ := testPeer([]Protocol{proto}) 166 defer closer() 167 168 if err := ExpectMsg(rw, 17, []string{"foo", "bar"}); err != nil { 169 t.Error(err) 170 } 171 } 172 173 func TestPeerPing(t *testing.T) { 174 closer, rw, _, _ := testPeer(nil) 175 defer closer() 176 if err := SendItems(rw, pingMsg); err != nil { 177 t.Fatal(err) 178 } 179 if err := ExpectMsg(rw, pongMsg, nil); err != nil { 180 t.Error(err) 181 } 182 } 183 184 func TestPeerDisconnect(t *testing.T) { 185 for _, tc := range []struct { 186 dc DiscReason 187 error string 188 }{ 189 {DiscQuitting, "client quitting"}, 190 {DiscSubprotocolError, "subprotocol error"}, 191 {17, "unknown disconnect reason 17"}, 192 {18, "unknown disconnect reason 18"}, 193 {math.MaxUint8, "unknown disconnect reason 255"}, 194 } { 195 closer, rw, _, disc := testPeer(nil) 196 if err := SendItems(rw, discMsg, tc.dc); err != nil { 197 t.Fatal(err) 198 } 199 select { 200 case reason := <-disc: 201 assert.Equal(t, tc.dc, reason) 202 assert.Equal(t, tc.error, reason.Error()) 203 case <-time.After(500 * time.Millisecond): 204 t.Error("peer did not return") 205 } 206 closer() 207 } 208 } 209 210 // This test is supposed to verify that Peer can reliably handle 211 // multiple causes of disconnection occurring at the same time. 212 func TestPeerDisconnectRace(t *testing.T) { 213 maybe := func() bool { return rand.Intn(2) == 1 } 214 215 for i := 0; i < 1000; i++ { 216 protoclose := make(chan error) 217 protodisc := make(chan DiscReason) 218 closer, rw, p, disc := testPeer([]Protocol{ 219 { 220 Name: "closereq", 221 Run: func(p *Peer, rw MsgReadWriter) error { return <-protoclose }, 222 Length: 1, 223 }, 224 { 225 Name: "disconnect", 226 Run: func(p *Peer, rw MsgReadWriter) error { p.Disconnect(<-protodisc); return nil }, 227 Length: 1, 228 }, 229 }) 230 231 // Simulate incoming messages. 232 go SendItems(rw, baseProtocolLength+1) 233 go SendItems(rw, baseProtocolLength+2) 234 // Close the network connection. 235 go closer() 236 // Make protocol "closereq" return. 237 protoclose <- errors.New("protocol closed") 238 // Make protocol "disconnect" call peer.Disconnect 239 protodisc <- DiscAlreadyConnected 240 // In some cases, simulate something else calling peer.Disconnect. 241 if maybe() { 242 go p.Disconnect(DiscInvalidIdentity) 243 } 244 // In some cases, simulate remote requesting a disconnect. 245 if maybe() { 246 go SendItems(rw, discMsg, DiscQuitting) 247 } 248 249 select { 250 case <-disc: 251 case <-time.After(2 * time.Second): 252 // Peer.run should return quickly. If it doesn't the Peer 253 // goroutines are probably deadlocked. Call panic in order to 254 // show the stacks. 255 panic("Peer.run took to long to return.") 256 } 257 } 258 } 259 260 func TestMultiChannelPeerProtoReadMsg(t *testing.T) { 261 proto := Protocol{ 262 Name: "a", 263 Length: 5, 264 RunWithRWs: func(peer *Peer, rws []MsgReadWriter) error { 265 for _, rw := range rws { 266 if err := ExpectMsg(rw, 2, []uint{1}); err != nil { 267 t.Error(err) 268 } 269 if err := ExpectMsg(rw, 3, []uint{2}); err != nil { 270 t.Error(err) 271 } 272 if err := ExpectMsg(rw, 4, []uint{3}); err != nil { 273 t.Error(err) 274 } 275 } 276 return nil 277 }, 278 } 279 280 closer, rws, _, errc := testPeerWithRWs([]Protocol{proto}, 2) 281 defer closer() 282 283 for _, rw := range rws { 284 Send(rw, baseProtocolLength+2, []uint{1}) 285 Send(rw, baseProtocolLength+3, []uint{2}) 286 Send(rw, baseProtocolLength+4, []uint{3}) 287 } 288 289 select { 290 case err := <-errc: 291 if err != errProtocolReturned { 292 t.Errorf("peer returned error: %v", err) 293 } 294 case <-time.After(2 * time.Second): 295 t.Errorf("receive timeout") 296 } 297 } 298 299 func TestMultiChannelPeerProtoEncodeMsg(t *testing.T) { 300 proto := Protocol{ 301 Name: "a", 302 Length: 2, 303 RunWithRWs: func(peer *Peer, rws []MsgReadWriter) error { 304 for _, rw := range rws { 305 if err := SendItems(rw, 2); err == nil { 306 t.Error("expected error for out-of-range msg code, got nil") 307 } 308 if err := SendItems(rw, 1, "foo", "bar"); err != nil { 309 t.Errorf("write error: %v", err) 310 } 311 } 312 return nil 313 }, 314 } 315 closer, rws, _, _ := testPeerWithRWs([]Protocol{proto}, 2) 316 defer closer() 317 318 for _, rw := range rws { 319 if err := ExpectMsg(rw, 17, []string{"foo", "bar"}); err != nil { 320 t.Error(err) 321 } 322 } 323 } 324 325 func TestMultiChannelPeerPing(t *testing.T) { 326 closer, rws, _, _ := testPeerWithRWs(nil, 2) 327 defer closer() 328 329 for _, rw := range rws { 330 if err := SendItems(rw, pingMsg); err != nil { 331 t.Fatal(err) 332 } 333 if err := ExpectMsg(rw, pongMsg, nil); err != nil { 334 t.Error(err) 335 } 336 } 337 } 338 339 func TestMultiChannelPeerDisconnect(t *testing.T) { 340 channelSize := 2 341 for i := 0; i < channelSize; i++ { 342 closer, rws, _, disc := testPeerWithRWs(nil, channelSize) 343 defer closer() 344 345 if err := SendItems(rws[i], discMsg, DiscQuitting); err != nil { 346 t.Fatal(err) 347 } 348 349 select { 350 case reason := <-disc: 351 if reason != DiscQuitting { 352 t.Errorf("run returned wrong reason: got %v, want %v", reason, DiscQuitting) 353 } 354 case <-time.After(500 * time.Millisecond): 355 t.Error("peer did not return") 356 } 357 } 358 } 359 360 // This test is supposed to verify that Peer can reliably handle 361 // multiple causes of disconnection occurring at the same time. 362 func TestMultiChannelPeerDisconnectRace(t *testing.T) { 363 maybe := func() bool { return rand.Intn(2) == 1 } 364 channelSize := 2 365 366 for i := 0; i < 1000; i++ { 367 protoclose := make(chan error) 368 protodisc := make(chan DiscReason) 369 closer, rws, p, disc := testPeerWithRWs([]Protocol{ 370 { 371 Name: "closereq", 372 RunWithRWs: func(p *Peer, rw []MsgReadWriter) error { return <-protoclose }, 373 Length: 1, 374 }, 375 { 376 Name: "disconnect", 377 RunWithRWs: func(p *Peer, rw []MsgReadWriter) error { p.Disconnect(<-protodisc); return nil }, 378 Length: 1, 379 }, 380 }, channelSize) 381 382 // Simulate incoming messages. 383 for _, rw := range rws { 384 go SendItems(rw, baseProtocolLength+1) 385 go SendItems(rw, baseProtocolLength+2) 386 } 387 // Close the network connection. 388 go closer() 389 // Make protocol "closereq" return. 390 protoclose <- errors.New("protocol closed") 391 // Make protocol "disconnect" call peer.Disconnect 392 protodisc <- DiscAlreadyConnected 393 // In some cases, simulate something else calling peer.Disconnect. 394 if maybe() { 395 go p.Disconnect(DiscInvalidIdentity) 396 } 397 // In some cases, simulate remote requesting a disconnect. 398 if maybe() { 399 go SendItems(rws[rand.Intn(channelSize)], discMsg, DiscQuitting) 400 } 401 402 select { 403 case <-disc: 404 case <-time.After(2 * time.Second): 405 // Peer.run should return quickly. If it doesn't the Peer 406 // goroutines are probably deadlocked. Call panic in order to 407 // show the stacks. 408 panic("Peer.run took to long to return.") 409 } 410 } 411 } 412 413 func TestNewPeer(t *testing.T) { 414 name := "nodename" 415 caps := []Cap{{"foo", 2}, {"bar", 3}} 416 id := randomID() 417 p := NewPeer(id, name, caps) 418 if p.ID() != id { 419 t.Errorf("ID mismatch: got %v, expected %v", p.ID(), id) 420 } 421 if p.Name() != name { 422 t.Errorf("Name mismatch: got %v, expected %v", p.Name(), name) 423 } 424 if !reflect.DeepEqual(p.Caps(), caps) { 425 t.Errorf("Caps mismatch: got %v, expected %v", p.Caps(), caps) 426 } 427 428 p.Disconnect(DiscAlreadyConnected) // Should not hang 429 } 430 431 func TestMatchProtocols(t *testing.T) { 432 tests := []struct { 433 Remote []Cap 434 Local []Protocol 435 Match map[string]protoRW 436 }{ 437 { 438 // No remote capabilities 439 Local: []Protocol{{Name: "a"}}, 440 }, 441 { 442 // No local protocols 443 Remote: []Cap{{Name: "a"}}, 444 }, 445 { 446 // No mutual protocols 447 Remote: []Cap{{Name: "a"}}, 448 Local: []Protocol{{Name: "b"}}, 449 }, 450 { 451 // Some matches, some differences 452 Remote: []Cap{{Name: "local"}, {Name: "match1"}, {Name: "match2"}}, 453 Local: []Protocol{{Name: "match1"}, {Name: "match2"}, {Name: "remote"}}, 454 Match: map[string]protoRW{ 455 "match1": {Protocol: Protocol{Name: "match1"}, tc: defaultRWTimerConfig}, 456 "match2": {Protocol: Protocol{Name: "match2"}, tc: defaultRWTimerConfig}, 457 }, 458 }, 459 { 460 // Various alphabetical ordering 461 Remote: []Cap{{Name: "aa"}, {Name: "ab"}, {Name: "bb"}, {Name: "ba"}}, 462 Local: []Protocol{{Name: "ba"}, {Name: "bb"}, {Name: "ab"}, {Name: "aa"}}, 463 Match: map[string]protoRW{ 464 "aa": {Protocol: Protocol{Name: "aa"}, tc: defaultRWTimerConfig}, 465 "ab": {Protocol: Protocol{Name: "ab"}, tc: defaultRWTimerConfig}, 466 "ba": {Protocol: Protocol{Name: "ba"}, tc: defaultRWTimerConfig}, 467 "bb": {Protocol: Protocol{Name: "bb"}, tc: defaultRWTimerConfig}, 468 }, 469 }, 470 { 471 // No mutual versions 472 Remote: []Cap{{Version: 1}}, 473 Local: []Protocol{{Version: 2}}, 474 }, 475 { 476 // Multiple versions, single common 477 Remote: []Cap{{Version: 1}, {Version: 2}}, 478 Local: []Protocol{{Version: 2}, {Version: 3}}, 479 Match: map[string]protoRW{"": {Protocol: Protocol{Version: 2}, tc: defaultRWTimerConfig}}, 480 }, 481 { 482 // Multiple versions, multiple common 483 Remote: []Cap{{Version: 1}, {Version: 2}, {Version: 3}, {Version: 4}}, 484 Local: []Protocol{{Version: 2}, {Version: 3}}, 485 Match: map[string]protoRW{"": {Protocol: Protocol{Version: 3}, tc: defaultRWTimerConfig}}, 486 }, 487 { 488 // Various version orderings 489 Remote: []Cap{{Version: 4}, {Version: 1}, {Version: 3}, {Version: 2}}, 490 Local: []Protocol{{Version: 2}, {Version: 3}, {Version: 1}}, 491 Match: map[string]protoRW{"": {Protocol: Protocol{Version: 3}, tc: defaultRWTimerConfig}}, 492 }, 493 { 494 // Versions overriding sub-protocol lengths 495 Remote: []Cap{{Version: 1}, {Version: 2}, {Version: 3}, {Name: "a"}}, 496 Local: []Protocol{{Version: 1, Length: 1}, {Version: 2, Length: 2}, {Version: 3, Length: 3}, {Name: "a"}}, 497 Match: map[string]protoRW{ 498 "": {Protocol: Protocol{Version: 3}, tc: defaultRWTimerConfig}, 499 "a": {Protocol: Protocol{Name: "a"}, offset: 3, tc: defaultRWTimerConfig}, 500 }, 501 }, 502 } 503 504 for i, tt := range tests { 505 result := matchProtocols(tt.Local, tt.Remote, nil, defaultRWTimerConfig) 506 if len(result) != len(tt.Match) { 507 t.Errorf("test %d: negotiation mismatch: have %v, want %v", i, len(result), len(tt.Match)) 508 continue 509 } 510 // Make sure all negotiated protocols are needed and correct 511 for name, proto := range result { 512 match, ok := tt.Match[name] 513 if !ok { 514 t.Errorf("test %d, protobuf '%s': negotiated but shouldn't have", i, name) 515 continue 516 } 517 if proto[ConnDefault].Name != match.Name { 518 t.Errorf("test %d, protobuf '%s': name mismatch: have %v, want %v", i, name, proto[ConnDefault].Name, match.Name) 519 } 520 if proto[ConnDefault].Version != match.Version { 521 t.Errorf("test %d, protobuf '%s': version mismatch: have %v, want %v", i, name, proto[ConnDefault].Version, match.Version) 522 } 523 if proto[ConnDefault].offset-baseProtocolLength != match.offset { 524 t.Errorf("test %d, protobuf '%s': offset mismatch: have %v, want %v", i, name, proto[ConnDefault].offset-baseProtocolLength, match.offset) 525 } 526 } 527 // Make sure no protocols missed negotiation 528 for name := range tt.Match { 529 if _, ok := result[name]; !ok { 530 t.Errorf("test %d, protobuf '%s': not negotiated, should have", i, name) 531 continue 532 } 533 } 534 } 535 }