github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/peer/peer_test.go (about) 1 // Copyright (c) 2015-2016 The btcsuite developers 2 // Copyright (c) 2016 The Dash developers 3 // Use of this source code is governed by an ISC 4 // license that can be found in the LICENSE file. 5 6 package peer_test 7 8 import ( 9 "errors" 10 "io" 11 "net" 12 "strconv" 13 "testing" 14 "time" 15 16 "github.com/btcsuite/go-socks/socks" 17 "github.com/BlockABC/godash/chaincfg" 18 "github.com/BlockABC/godash/peer" 19 "github.com/BlockABC/godash/wire" 20 ) 21 22 // conn mocks a network connection by implementing the net.Conn interface. It 23 // is used to test peer connection without actually opening a network 24 // connection. 25 type conn struct { 26 io.Reader 27 io.Writer 28 io.Closer 29 30 // local network, address for the connection. 31 lnet, laddr string 32 33 // remote network, address for the connection. 34 rnet, raddr string 35 36 // mocks socks proxy if true 37 proxy bool 38 } 39 40 // LocalAddr returns the local address for the connection. 41 func (c conn) LocalAddr() net.Addr { 42 return &addr{c.lnet, c.laddr} 43 } 44 45 // Remote returns the remote address for the connection. 46 func (c conn) RemoteAddr() net.Addr { 47 if !c.proxy { 48 return &addr{c.rnet, c.raddr} 49 } 50 host, strPort, _ := net.SplitHostPort(c.raddr) 51 port, _ := strconv.Atoi(strPort) 52 return &socks.ProxiedAddr{ 53 Net: c.rnet, 54 Host: host, 55 Port: port, 56 } 57 } 58 59 // Close handles closing the connection. 60 func (c conn) Close() error { 61 return nil 62 } 63 64 func (c conn) SetDeadline(t time.Time) error { return nil } 65 func (c conn) SetReadDeadline(t time.Time) error { return nil } 66 func (c conn) SetWriteDeadline(t time.Time) error { return nil } 67 68 // addr mocks a network address 69 type addr struct { 70 net, address string 71 } 72 73 func (m addr) Network() string { return m.net } 74 func (m addr) String() string { return m.address } 75 76 // pipe turns two mock connections into a full-duplex connection similar to 77 // net.Pipe to allow pipe's with (fake) addresses. 78 func pipe(c1, c2 *conn) (*conn, *conn) { 79 r1, w1 := io.Pipe() 80 r2, w2 := io.Pipe() 81 82 c1.Writer = w1 83 c2.Reader = r1 84 c1.Reader = r2 85 c2.Writer = w2 86 87 return c1, c2 88 } 89 90 // peerStats holds the expected peer stats used for testing peer. 91 type peerStats struct { 92 wantUserAgent string 93 wantServices wire.ServiceFlag 94 wantProtocolVersion uint32 95 wantConnected bool 96 wantVersionKnown bool 97 wantVerAckReceived bool 98 wantLastBlock int32 99 wantStartingHeight int32 100 wantLastPingTime time.Time 101 wantLastPingNonce uint64 102 wantLastPingMicros int64 103 wantTimeOffset int64 104 wantBytesSent uint64 105 wantBytesReceived uint64 106 } 107 108 // testPeer tests the given peer's flags and stats 109 func testPeer(t *testing.T, p *peer.Peer, s peerStats) { 110 if p.UserAgent() != s.wantUserAgent { 111 t.Errorf("testPeer: wrong UserAgent - got %v, want %v", p.UserAgent(), s.wantUserAgent) 112 return 113 } 114 115 if p.Services() != s.wantServices { 116 t.Errorf("testPeer: wrong Services - got %v, want %v", p.Services(), s.wantServices) 117 return 118 } 119 120 if !p.LastPingTime().Equal(s.wantLastPingTime) { 121 t.Errorf("testPeer: wrong LastPingTime - got %v, want %v", p.LastPingTime(), s.wantLastPingTime) 122 return 123 } 124 125 if p.LastPingNonce() != s.wantLastPingNonce { 126 t.Errorf("testPeer: wrong LastPingNonce - got %v, want %v", p.LastPingNonce(), s.wantLastPingNonce) 127 return 128 } 129 130 if p.LastPingMicros() != s.wantLastPingMicros { 131 t.Errorf("testPeer: wrong LastPingMicros - got %v, want %v", p.LastPingMicros(), s.wantLastPingMicros) 132 return 133 } 134 135 if p.VerAckReceived() != s.wantVerAckReceived { 136 t.Errorf("testPeer: wrong VerAckReceived - got %v, want %v", p.VerAckReceived(), s.wantVerAckReceived) 137 return 138 } 139 140 if p.VersionKnown() != s.wantVersionKnown { 141 t.Errorf("testPeer: wrong VersionKnown - got %v, want %v", p.VersionKnown(), s.wantVersionKnown) 142 return 143 } 144 145 if p.ProtocolVersion() != s.wantProtocolVersion { 146 t.Errorf("testPeer: wrong ProtocolVersion - got %v, want %v", p.ProtocolVersion(), s.wantProtocolVersion) 147 return 148 } 149 150 if p.LastBlock() != s.wantLastBlock { 151 t.Errorf("testPeer: wrong LastBlock - got %v, want %v", p.LastBlock(), s.wantLastBlock) 152 return 153 } 154 155 // Allow for a deviation of 1s, as the second may tick when the message is 156 // in transit and the protocol doesn't support any further precision. 157 if p.TimeOffset() != s.wantTimeOffset && p.TimeOffset() != s.wantTimeOffset-1 { 158 t.Errorf("testPeer: wrong TimeOffset - got %v, want %v or %v", p.TimeOffset(), 159 s.wantTimeOffset, s.wantTimeOffset-1) 160 return 161 } 162 163 if p.BytesSent() != s.wantBytesSent { 164 t.Errorf("testPeer: wrong BytesSent - got %v, want %v", p.BytesSent(), s.wantBytesSent) 165 return 166 } 167 168 if p.BytesReceived() != s.wantBytesReceived { 169 t.Errorf("testPeer: wrong BytesReceived - got %v, want %v", p.BytesReceived(), s.wantBytesReceived) 170 return 171 } 172 173 if p.StartingHeight() != s.wantStartingHeight { 174 t.Errorf("testPeer: wrong StartingHeight - got %v, want %v", p.StartingHeight(), s.wantStartingHeight) 175 return 176 } 177 178 if p.Connected() != s.wantConnected { 179 t.Errorf("testPeer: wrong Connected - got %v, want %v", p.Connected(), s.wantConnected) 180 return 181 } 182 183 stats := p.StatsSnapshot() 184 185 if p.ID() != stats.ID { 186 t.Errorf("testPeer: wrong ID - got %v, want %v", p.ID(), stats.ID) 187 return 188 } 189 190 if p.Addr() != stats.Addr { 191 t.Errorf("testPeer: wrong Addr - got %v, want %v", p.Addr(), stats.Addr) 192 return 193 } 194 195 if p.LastSend() != stats.LastSend { 196 t.Errorf("testPeer: wrong LastSend - got %v, want %v", p.LastSend(), stats.LastSend) 197 return 198 } 199 200 if p.LastRecv() != stats.LastRecv { 201 t.Errorf("testPeer: wrong LastRecv - got %v, want %v", p.LastRecv(), stats.LastRecv) 202 return 203 } 204 } 205 206 // TestPeerConnection tests connection between inbound and outbound peers. 207 func TestPeerConnection(t *testing.T) { 208 verack := make(chan struct{}) 209 peerCfg := &peer.Config{ 210 Listeners: peer.MessageListeners{ 211 OnVerAck: func(p *peer.Peer, msg *wire.MsgVerAck) { 212 verack <- struct{}{} 213 }, 214 OnWrite: func(p *peer.Peer, bytesWritten int, msg wire.Message, 215 err error) { 216 if _, ok := msg.(*wire.MsgVerAck); ok { 217 verack <- struct{}{} 218 } 219 }, 220 }, 221 UserAgentName: "peer", 222 UserAgentVersion: "1.0", 223 ChainParams: &chaincfg.MainNetParams, 224 Services: 0, 225 } 226 wantStats := peerStats{ 227 wantUserAgent: wire.DefaultUserAgent + "peer:1.0/", 228 wantServices: 0, 229 wantProtocolVersion: peer.MaxProtocolVersion, 230 wantConnected: true, 231 wantVersionKnown: true, 232 wantVerAckReceived: true, 233 wantLastPingTime: time.Time{}, 234 wantLastPingNonce: uint64(0), 235 wantLastPingMicros: int64(0), 236 wantTimeOffset: int64(0), 237 wantBytesSent: 158, // 134 version + 24 verack 238 wantBytesReceived: 158, 239 } 240 tests := []struct { 241 name string 242 setup func() (*peer.Peer, *peer.Peer, error) 243 }{ 244 { 245 "basic handshake", 246 func() (*peer.Peer, *peer.Peer, error) { 247 inConn, outConn := pipe( 248 &conn{raddr: "10.0.0.1:8333"}, 249 &conn{raddr: "10.0.0.2:8333"}, 250 ) 251 inPeer := peer.NewInboundPeer(peerCfg) 252 inPeer.Connect(inConn) 253 254 outPeer, err := peer.NewOutboundPeer(peerCfg, "10.0.0.2:8333") 255 if err != nil { 256 return nil, nil, err 257 } 258 outPeer.Connect(outConn) 259 260 for i := 0; i < 4; i++ { 261 select { 262 case <-verack: 263 case <-time.After(time.Second): 264 return nil, nil, errors.New("verack timeout") 265 } 266 } 267 return inPeer, outPeer, nil 268 }, 269 }, 270 { 271 "socks proxy", 272 func() (*peer.Peer, *peer.Peer, error) { 273 inConn, outConn := pipe( 274 &conn{raddr: "10.0.0.1:8333", proxy: true}, 275 &conn{raddr: "10.0.0.2:8333"}, 276 ) 277 inPeer := peer.NewInboundPeer(peerCfg) 278 inPeer.Connect(inConn) 279 280 outPeer, err := peer.NewOutboundPeer(peerCfg, "10.0.0.2:8333") 281 if err != nil { 282 return nil, nil, err 283 } 284 outPeer.Connect(outConn) 285 286 for i := 0; i < 4; i++ { 287 select { 288 case <-verack: 289 case <-time.After(time.Second): 290 return nil, nil, errors.New("verack timeout") 291 } 292 } 293 return inPeer, outPeer, nil 294 }, 295 }, 296 } 297 t.Logf("Running %d tests", len(tests)) 298 for i, test := range tests { 299 inPeer, outPeer, err := test.setup() 300 if err != nil { 301 t.Errorf("TestPeerConnection setup #%d: unexpected err %v", i, err) 302 return 303 } 304 testPeer(t, inPeer, wantStats) 305 testPeer(t, outPeer, wantStats) 306 307 inPeer.Disconnect() 308 outPeer.Disconnect() 309 inPeer.WaitForDisconnect() 310 outPeer.WaitForDisconnect() 311 } 312 } 313 314 // TestPeerListeners tests that the peer listeners are called as expected. 315 func TestPeerListeners(t *testing.T) { 316 verack := make(chan struct{}, 1) 317 ok := make(chan wire.Message, 20) 318 peerCfg := &peer.Config{ 319 Listeners: peer.MessageListeners{ 320 OnGetAddr: func(p *peer.Peer, msg *wire.MsgGetAddr) { 321 ok <- msg 322 }, 323 OnAddr: func(p *peer.Peer, msg *wire.MsgAddr) { 324 ok <- msg 325 }, 326 OnPing: func(p *peer.Peer, msg *wire.MsgPing) { 327 ok <- msg 328 }, 329 OnPong: func(p *peer.Peer, msg *wire.MsgPong) { 330 ok <- msg 331 }, 332 OnAlert: func(p *peer.Peer, msg *wire.MsgAlert) { 333 ok <- msg 334 }, 335 OnMemPool: func(p *peer.Peer, msg *wire.MsgMemPool) { 336 ok <- msg 337 }, 338 OnTx: func(p *peer.Peer, msg *wire.MsgTx) { 339 ok <- msg 340 }, 341 OnBlock: func(p *peer.Peer, msg *wire.MsgBlock, buf []byte) { 342 ok <- msg 343 }, 344 OnInv: func(p *peer.Peer, msg *wire.MsgInv) { 345 ok <- msg 346 }, 347 OnHeaders: func(p *peer.Peer, msg *wire.MsgHeaders) { 348 ok <- msg 349 }, 350 OnNotFound: func(p *peer.Peer, msg *wire.MsgNotFound) { 351 ok <- msg 352 }, 353 OnGetData: func(p *peer.Peer, msg *wire.MsgGetData) { 354 ok <- msg 355 }, 356 OnGetBlocks: func(p *peer.Peer, msg *wire.MsgGetBlocks) { 357 ok <- msg 358 }, 359 OnGetHeaders: func(p *peer.Peer, msg *wire.MsgGetHeaders) { 360 ok <- msg 361 }, 362 OnFilterAdd: func(p *peer.Peer, msg *wire.MsgFilterAdd) { 363 ok <- msg 364 }, 365 OnFilterClear: func(p *peer.Peer, msg *wire.MsgFilterClear) { 366 ok <- msg 367 }, 368 OnFilterLoad: func(p *peer.Peer, msg *wire.MsgFilterLoad) { 369 ok <- msg 370 }, 371 OnMerkleBlock: func(p *peer.Peer, msg *wire.MsgMerkleBlock) { 372 ok <- msg 373 }, 374 OnVersion: func(p *peer.Peer, msg *wire.MsgVersion) { 375 ok <- msg 376 }, 377 OnVerAck: func(p *peer.Peer, msg *wire.MsgVerAck) { 378 verack <- struct{}{} 379 }, 380 OnReject: func(p *peer.Peer, msg *wire.MsgReject) { 381 ok <- msg 382 }, 383 OnSendHeaders: func(p *peer.Peer, msg *wire.MsgSendHeaders) { 384 ok <- msg 385 }, 386 }, 387 UserAgentName: "peer", 388 UserAgentVersion: "1.0", 389 ChainParams: &chaincfg.MainNetParams, 390 Services: wire.SFNodeBloom, 391 } 392 inConn, outConn := pipe( 393 &conn{raddr: "10.0.0.1:8333"}, 394 &conn{raddr: "10.0.0.2:8333"}, 395 ) 396 inPeer := peer.NewInboundPeer(peerCfg) 397 inPeer.Connect(inConn) 398 399 peerCfg.Listeners = peer.MessageListeners{ 400 OnVerAck: func(p *peer.Peer, msg *wire.MsgVerAck) { 401 verack <- struct{}{} 402 }, 403 } 404 outPeer, err := peer.NewOutboundPeer(peerCfg, "10.0.0.1:8333") 405 if err != nil { 406 t.Errorf("NewOutboundPeer: unexpected err %v\n", err) 407 return 408 } 409 outPeer.Connect(outConn) 410 411 for i := 0; i < 2; i++ { 412 select { 413 case <-verack: 414 case <-time.After(time.Second * 1): 415 t.Errorf("TestPeerListeners: verack timeout\n") 416 return 417 } 418 } 419 420 tests := []struct { 421 listener string 422 msg wire.Message 423 }{ 424 { 425 "OnGetAddr", 426 wire.NewMsgGetAddr(), 427 }, 428 { 429 "OnAddr", 430 wire.NewMsgAddr(), 431 }, 432 { 433 "OnPing", 434 wire.NewMsgPing(42), 435 }, 436 { 437 "OnPong", 438 wire.NewMsgPong(42), 439 }, 440 { 441 "OnAlert", 442 wire.NewMsgAlert([]byte("payload"), []byte("signature")), 443 }, 444 { 445 "OnMemPool", 446 wire.NewMsgMemPool(), 447 }, 448 { 449 "OnTx", 450 wire.NewMsgTx(), 451 }, 452 { 453 "OnBlock", 454 wire.NewMsgBlock(wire.NewBlockHeader(&wire.ShaHash{}, &wire.ShaHash{}, 1, 1)), 455 }, 456 { 457 "OnInv", 458 wire.NewMsgInv(), 459 }, 460 { 461 "OnHeaders", 462 wire.NewMsgHeaders(), 463 }, 464 { 465 "OnNotFound", 466 wire.NewMsgNotFound(), 467 }, 468 { 469 "OnGetData", 470 wire.NewMsgGetData(), 471 }, 472 { 473 "OnGetBlocks", 474 wire.NewMsgGetBlocks(&wire.ShaHash{}), 475 }, 476 { 477 "OnGetHeaders", 478 wire.NewMsgGetHeaders(), 479 }, 480 { 481 "OnFilterAdd", 482 wire.NewMsgFilterAdd([]byte{0x01}), 483 }, 484 { 485 "OnFilterClear", 486 wire.NewMsgFilterClear(), 487 }, 488 { 489 "OnFilterLoad", 490 wire.NewMsgFilterLoad([]byte{0x01}, 10, 0, wire.BloomUpdateNone), 491 }, 492 { 493 "OnMerkleBlock", 494 wire.NewMsgMerkleBlock(wire.NewBlockHeader(&wire.ShaHash{}, &wire.ShaHash{}, 1, 1)), 495 }, 496 // only one version message is allowed 497 // only one verack message is allowed 498 { 499 "OnReject", 500 wire.NewMsgReject("block", wire.RejectDuplicate, "dupe block"), 501 }, 502 { 503 "OnSendHeaders", 504 wire.NewMsgSendHeaders(), 505 }, 506 } 507 t.Logf("Running %d tests", len(tests)) 508 for _, test := range tests { 509 // Queue the test message 510 outPeer.QueueMessage(test.msg, nil) 511 select { 512 case <-ok: 513 case <-time.After(time.Second * 1): 514 t.Errorf("TestPeerListeners: %s timeout", test.listener) 515 return 516 } 517 } 518 inPeer.Disconnect() 519 outPeer.Disconnect() 520 } 521 522 // TestOutboundPeer tests that the outbound peer works as expected. 523 func TestOutboundPeer(t *testing.T) { 524 525 peerCfg := &peer.Config{ 526 NewestBlock: func() (*wire.ShaHash, int32, error) { 527 return nil, 0, errors.New("newest block not found") 528 }, 529 UserAgentName: "peer", 530 UserAgentVersion: "1.0", 531 ChainParams: &chaincfg.MainNetParams, 532 Services: 0, 533 } 534 535 r, w := io.Pipe() 536 c := &conn{raddr: "10.0.0.1:8333", Writer: w, Reader: r} 537 538 p, err := peer.NewOutboundPeer(peerCfg, "10.0.0.1:8333") 539 if err != nil { 540 t.Errorf("NewOutboundPeer: unexpected err - %v\n", err) 541 return 542 } 543 544 // Test trying to connect twice. 545 p.Connect(c) 546 p.Connect(c) 547 548 disconnected := make(chan struct{}) 549 go func() { 550 p.WaitForDisconnect() 551 disconnected <- struct{}{} 552 }() 553 554 select { 555 case <-disconnected: 556 close(disconnected) 557 case <-time.After(time.Second): 558 t.Fatal("Peer did not automatically disconnect.") 559 } 560 561 if p.Connected() { 562 t.Fatalf("Should not be connected as NewestBlock produces error.") 563 } 564 565 // Test Queue Inv 566 fakeBlockHash := &wire.ShaHash{0: 0x00, 1: 0x01} 567 fakeInv := wire.NewInvVect(wire.InvTypeBlock, fakeBlockHash) 568 569 // Should be noops as the peer could not connect. 570 p.QueueInventory(fakeInv) 571 p.AddKnownInventory(fakeInv) 572 p.QueueInventory(fakeInv) 573 574 fakeMsg := wire.NewMsgVerAck() 575 p.QueueMessage(fakeMsg, nil) 576 done := make(chan struct{}) 577 p.QueueMessage(fakeMsg, done) 578 <-done 579 p.Disconnect() 580 581 // Test NewestBlock 582 var newestBlock = func() (*wire.ShaHash, int32, error) { 583 hashStr := "14a0810ac680a3eb3f82edc878cea25ec41d6b790744e5daeef" 584 hash, err := wire.NewShaHashFromStr(hashStr) 585 if err != nil { 586 return nil, 0, err 587 } 588 return hash, 234439, nil 589 } 590 591 peerCfg.NewestBlock = newestBlock 592 r1, w1 := io.Pipe() 593 c1 := &conn{raddr: "10.0.0.1:8333", Writer: w1, Reader: r1} 594 p1, err := peer.NewOutboundPeer(peerCfg, "10.0.0.1:8333") 595 if err != nil { 596 t.Errorf("NewOutboundPeer: unexpected err - %v\n", err) 597 return 598 } 599 p1.Connect(c1) 600 601 // Test update latest block 602 latestBlockSha, err := wire.NewShaHashFromStr("1a63f9cdff1752e6375c8c76e543a71d239e1a2e5c6db1aa679") 603 if err != nil { 604 t.Errorf("NewShaHashFromStr: unexpected err %v\n", err) 605 return 606 } 607 p1.UpdateLastAnnouncedBlock(latestBlockSha) 608 p1.UpdateLastBlockHeight(234440) 609 if p1.LastAnnouncedBlock() != latestBlockSha { 610 t.Errorf("LastAnnouncedBlock: wrong block - got %v, want %v", 611 p1.LastAnnouncedBlock(), latestBlockSha) 612 return 613 } 614 615 // Test Queue Inv after connection 616 p1.QueueInventory(fakeInv) 617 p1.Disconnect() 618 619 // Test regression 620 peerCfg.ChainParams = &chaincfg.RegressionNetParams 621 peerCfg.Services = wire.SFNodeBloom 622 r2, w2 := io.Pipe() 623 c2 := &conn{raddr: "10.0.0.1:8333", Writer: w2, Reader: r2} 624 p2, err := peer.NewOutboundPeer(peerCfg, "10.0.0.1:8333") 625 if err != nil { 626 t.Errorf("NewOutboundPeer: unexpected err - %v\n", err) 627 return 628 } 629 p2.Connect(c2) 630 631 // Test PushXXX 632 var addrs []*wire.NetAddress 633 for i := 0; i < 5; i++ { 634 na := wire.NetAddress{} 635 addrs = append(addrs, &na) 636 } 637 if _, err := p2.PushAddrMsg(addrs); err != nil { 638 t.Errorf("PushAddrMsg: unexpected err %v\n", err) 639 return 640 } 641 if err := p2.PushGetBlocksMsg(nil, &wire.ShaHash{}); err != nil { 642 t.Errorf("PushGetBlocksMsg: unexpected err %v\n", err) 643 return 644 } 645 if err := p2.PushGetHeadersMsg(nil, &wire.ShaHash{}); err != nil { 646 t.Errorf("PushGetHeadersMsg: unexpected err %v\n", err) 647 return 648 } 649 650 p2.PushRejectMsg("block", wire.RejectMalformed, "malformed", nil, false) 651 p2.PushRejectMsg("block", wire.RejectInvalid, "invalid", nil, false) 652 653 // Test Queue Messages 654 p2.QueueMessage(wire.NewMsgGetAddr(), nil) 655 p2.QueueMessage(wire.NewMsgPing(1), nil) 656 p2.QueueMessage(wire.NewMsgMemPool(), nil) 657 p2.QueueMessage(wire.NewMsgGetData(), nil) 658 p2.QueueMessage(wire.NewMsgGetHeaders(), nil) 659 660 p2.Disconnect() 661 } 662 663 func init() { 664 // Allow self connection when running the tests. 665 peer.TstAllowSelfConns() 666 }