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.

222 lines
4.7 KiB

7 years ago
7 years ago
9 years ago
7 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. package blockchain
  2. import (
  3. "fmt"
  4. "testing"
  5. "time"
  6. "github.com/stretchr/testify/assert"
  7. "github.com/stretchr/testify/require"
  8. cmn "github.com/tendermint/tendermint/libs/common"
  9. "github.com/tendermint/tendermint/libs/log"
  10. "github.com/tendermint/tendermint/p2p"
  11. "github.com/tendermint/tendermint/types"
  12. )
  13. func init() {
  14. peerTimeout = 2 * time.Second
  15. }
  16. type testPeer struct {
  17. id p2p.ID
  18. height int64
  19. inputChan chan inputData //make sure each peer's data is sequential
  20. }
  21. type inputData struct {
  22. t *testing.T
  23. pool *BlockPool
  24. request BlockRequest
  25. }
  26. func (p testPeer) runInputRoutine() {
  27. go func() {
  28. for input := range p.inputChan {
  29. p.simulateInput(input)
  30. }
  31. }()
  32. }
  33. // Request desired, pretend like we got the block immediately.
  34. func (p testPeer) simulateInput(input inputData) {
  35. block := &types.Block{Header: types.Header{Height: input.request.Height}}
  36. input.pool.AddBlock(input.request.PeerID, block, 123)
  37. input.t.Logf("Added block from peer %v (height: %v)", input.request.PeerID, input.request.Height)
  38. }
  39. type testPeers map[p2p.ID]testPeer
  40. func (ps testPeers) start() {
  41. for _, v := range ps {
  42. v.runInputRoutine()
  43. }
  44. }
  45. func (ps testPeers) stop() {
  46. for _, v := range ps {
  47. close(v.inputChan)
  48. }
  49. }
  50. func makePeers(numPeers int, minHeight, maxHeight int64) testPeers {
  51. peers := make(testPeers, numPeers)
  52. for i := 0; i < numPeers; i++ {
  53. peerID := p2p.ID(cmn.RandStr(12))
  54. height := minHeight + cmn.RandInt63n(maxHeight-minHeight)
  55. peers[peerID] = testPeer{peerID, height, make(chan inputData, 10)}
  56. }
  57. return peers
  58. }
  59. func TestBlockPoolBasic(t *testing.T) {
  60. start := int64(42)
  61. peers := makePeers(10, start+1, 1000)
  62. errorsCh := make(chan peerError, 1000)
  63. requestsCh := make(chan BlockRequest, 1000)
  64. pool := NewBlockPool(start, requestsCh, errorsCh)
  65. pool.SetLogger(log.TestingLogger())
  66. err := pool.Start()
  67. if err != nil {
  68. t.Error(err)
  69. }
  70. defer pool.Stop()
  71. peers.start()
  72. defer peers.stop()
  73. // Introduce each peer.
  74. go func() {
  75. for _, peer := range peers {
  76. pool.SetPeerHeight(peer.id, peer.height)
  77. }
  78. }()
  79. // Start a goroutine to pull blocks
  80. go func() {
  81. for {
  82. if !pool.IsRunning() {
  83. return
  84. }
  85. first, second := pool.PeekTwoBlocks()
  86. if first != nil && second != nil {
  87. pool.PopRequest()
  88. } else {
  89. time.Sleep(1 * time.Second)
  90. }
  91. }
  92. }()
  93. // Pull from channels
  94. for {
  95. select {
  96. case err := <-errorsCh:
  97. t.Error(err)
  98. case request := <-requestsCh:
  99. t.Logf("Pulled new BlockRequest %v", request)
  100. if request.Height == 300 {
  101. return // Done!
  102. }
  103. peers[request.PeerID].inputChan <- inputData{t, pool, request}
  104. }
  105. }
  106. }
  107. func TestBlockPoolTimeout(t *testing.T) {
  108. start := int64(42)
  109. peers := makePeers(10, start+1, 1000)
  110. errorsCh := make(chan peerError, 1000)
  111. requestsCh := make(chan BlockRequest, 1000)
  112. pool := NewBlockPool(start, requestsCh, errorsCh)
  113. pool.SetLogger(log.TestingLogger())
  114. err := pool.Start()
  115. if err != nil {
  116. t.Error(err)
  117. }
  118. defer pool.Stop()
  119. for _, peer := range peers {
  120. t.Logf("Peer %v", peer.id)
  121. }
  122. // Introduce each peer.
  123. go func() {
  124. for _, peer := range peers {
  125. pool.SetPeerHeight(peer.id, peer.height)
  126. }
  127. }()
  128. // Start a goroutine to pull blocks
  129. go func() {
  130. for {
  131. if !pool.IsRunning() {
  132. return
  133. }
  134. first, second := pool.PeekTwoBlocks()
  135. if first != nil && second != nil {
  136. pool.PopRequest()
  137. } else {
  138. time.Sleep(1 * time.Second)
  139. }
  140. }
  141. }()
  142. // Pull from channels
  143. counter := 0
  144. timedOut := map[p2p.ID]struct{}{}
  145. for {
  146. select {
  147. case err := <-errorsCh:
  148. t.Log(err)
  149. // consider error to be always timeout here
  150. if _, ok := timedOut[err.peerID]; !ok {
  151. counter++
  152. if counter == len(peers) {
  153. return // Done!
  154. }
  155. }
  156. case request := <-requestsCh:
  157. t.Logf("Pulled new BlockRequest %+v", request)
  158. }
  159. }
  160. }
  161. func TestBlockPoolRemovePeer(t *testing.T) {
  162. peers := make(testPeers, 10)
  163. for i := 0; i < 10; i++ {
  164. peerID := p2p.ID(fmt.Sprintf("%d", i+1))
  165. height := int64(i + 1)
  166. peers[peerID] = testPeer{peerID, height, make(chan inputData)}
  167. }
  168. requestsCh := make(chan BlockRequest)
  169. errorsCh := make(chan peerError)
  170. pool := NewBlockPool(1, requestsCh, errorsCh)
  171. pool.SetLogger(log.TestingLogger())
  172. err := pool.Start()
  173. require.NoError(t, err)
  174. defer pool.Stop()
  175. // add peers
  176. for peerID, peer := range peers {
  177. pool.SetPeerHeight(peerID, peer.height)
  178. }
  179. assert.EqualValues(t, 10, pool.MaxPeerHeight())
  180. // remove not-existing peer
  181. assert.NotPanics(t, func() { pool.RemovePeer(p2p.ID("Superman")) })
  182. // remove peer with biggest height
  183. pool.RemovePeer(p2p.ID("10"))
  184. assert.EqualValues(t, 9, pool.MaxPeerHeight())
  185. // remove all peers
  186. for peerID := range peers {
  187. pool.RemovePeer(peerID)
  188. }
  189. assert.EqualValues(t, 0, pool.MaxPeerHeight())
  190. }