You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 lines
3.0 KiB

  1. package blockchain
  2. import (
  3. "math/rand"
  4. "testing"
  5. "time"
  6. cmn "github.com/tendermint/tmlibs/common"
  7. "github.com/tendermint/tmlibs/log"
  8. "github.com/tendermint/tendermint/p2p"
  9. "github.com/tendermint/tendermint/types"
  10. )
  11. func init() {
  12. peerTimeout = 2 * time.Second
  13. }
  14. type testPeer struct {
  15. id p2p.ID
  16. height int64
  17. }
  18. func makePeers(numPeers int, minHeight, maxHeight int64) map[p2p.ID]testPeer {
  19. peers := make(map[p2p.ID]testPeer, numPeers)
  20. for i := 0; i < numPeers; i++ {
  21. peerID := p2p.ID(cmn.RandStr(12))
  22. height := minHeight + rand.Int63n(maxHeight-minHeight)
  23. peers[peerID] = testPeer{peerID, height}
  24. }
  25. return peers
  26. }
  27. func TestBasic(t *testing.T) {
  28. start := int64(42)
  29. peers := makePeers(10, start+1, 1000)
  30. errorsCh := make(chan peerError, 1000)
  31. requestsCh := make(chan BlockRequest, 1000)
  32. pool := NewBlockPool(start, requestsCh, errorsCh)
  33. pool.SetLogger(log.TestingLogger())
  34. err := pool.Start()
  35. if err != nil {
  36. t.Error(err)
  37. }
  38. defer pool.Stop()
  39. // Introduce each peer.
  40. go func() {
  41. for _, peer := range peers {
  42. pool.SetPeerHeight(peer.id, peer.height)
  43. }
  44. }()
  45. // Start a goroutine to pull blocks
  46. go func() {
  47. for {
  48. if !pool.IsRunning() {
  49. return
  50. }
  51. first, second := pool.PeekTwoBlocks()
  52. if first != nil && second != nil {
  53. pool.PopRequest()
  54. } else {
  55. time.Sleep(1 * time.Second)
  56. }
  57. }
  58. }()
  59. // Pull from channels
  60. for {
  61. select {
  62. case err := <-errorsCh:
  63. t.Error(err)
  64. case request := <-requestsCh:
  65. t.Logf("Pulled new BlockRequest %v", request)
  66. if request.Height == 300 {
  67. return // Done!
  68. }
  69. // Request desired, pretend like we got the block immediately.
  70. go func() {
  71. block := &types.Block{Header: &types.Header{Height: request.Height}}
  72. pool.AddBlock(request.PeerID, block, 123)
  73. t.Logf("Added block from peer %v (height: %v)", request.PeerID, request.Height)
  74. }()
  75. }
  76. }
  77. }
  78. func TestTimeout(t *testing.T) {
  79. start := int64(42)
  80. peers := makePeers(10, start+1, 1000)
  81. errorsCh := make(chan peerError, 1000)
  82. requestsCh := make(chan BlockRequest, 1000)
  83. pool := NewBlockPool(start, requestsCh, errorsCh)
  84. pool.SetLogger(log.TestingLogger())
  85. err := pool.Start()
  86. if err != nil {
  87. t.Error(err)
  88. }
  89. defer pool.Stop()
  90. for _, peer := range peers {
  91. t.Logf("Peer %v", peer.id)
  92. }
  93. // Introduce each peer.
  94. go func() {
  95. for _, peer := range peers {
  96. pool.SetPeerHeight(peer.id, peer.height)
  97. }
  98. }()
  99. // Start a goroutine to pull blocks
  100. go func() {
  101. for {
  102. if !pool.IsRunning() {
  103. return
  104. }
  105. first, second := pool.PeekTwoBlocks()
  106. if first != nil && second != nil {
  107. pool.PopRequest()
  108. } else {
  109. time.Sleep(1 * time.Second)
  110. }
  111. }
  112. }()
  113. // Pull from channels
  114. counter := 0
  115. timedOut := map[p2p.ID]struct{}{}
  116. for {
  117. select {
  118. case err := <-errorsCh:
  119. t.Log(err)
  120. // consider error to be always timeout here
  121. if _, ok := timedOut[err.peerID]; !ok {
  122. counter++
  123. if counter == len(peers) {
  124. return // Done!
  125. }
  126. }
  127. case request := <-requestsCh:
  128. t.Logf("Pulled new BlockRequest %+v", request)
  129. }
  130. }
  131. }