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.

199 lines
6.0 KiB

7 years ago
  1. package blockchain
  2. import (
  3. "testing"
  4. wire "github.com/tendermint/go-wire"
  5. cmn "github.com/tendermint/tmlibs/common"
  6. dbm "github.com/tendermint/tmlibs/db"
  7. "github.com/tendermint/tmlibs/log"
  8. cfg "github.com/tendermint/tendermint/config"
  9. "github.com/tendermint/tendermint/p2p"
  10. "github.com/tendermint/tendermint/proxy"
  11. sm "github.com/tendermint/tendermint/state"
  12. "github.com/tendermint/tendermint/types"
  13. )
  14. func makeStateAndBlockStore(logger log.Logger) (sm.State, *BlockStore) {
  15. config := cfg.ResetTestRoot("blockchain_reactor_test")
  16. blockStore := NewBlockStore(dbm.NewMemDB())
  17. state, _ := sm.LoadStateFromDBOrGenesisFile(dbm.NewMemDB(), config.GenesisFile())
  18. return state, blockStore
  19. }
  20. func newBlockchainReactor(logger log.Logger, maxBlockHeight int64) *BlockchainReactor {
  21. state, blockStore := makeStateAndBlockStore(logger)
  22. // Make the blockchainReactor itself
  23. fastSync := true
  24. var nilApp proxy.AppConnConsensus
  25. blockExec := sm.NewBlockExecutor(dbm.NewMemDB(), log.TestingLogger(), nilApp,
  26. types.MockMempool{}, types.MockEvidencePool{})
  27. bcReactor := NewBlockchainReactor(state.Copy(), blockExec, blockStore, fastSync)
  28. bcReactor.SetLogger(logger.With("module", "blockchain"))
  29. // Next: we need to set a switch in order for peers to be added in
  30. bcReactor.Switch = p2p.NewSwitch(cfg.DefaultP2PConfig())
  31. // Lastly: let's add some blocks in
  32. for blockHeight := int64(1); blockHeight <= maxBlockHeight; blockHeight++ {
  33. firstBlock := makeBlock(blockHeight, state)
  34. secondBlock := makeBlock(blockHeight+1, state)
  35. firstParts := firstBlock.MakePartSet(state.ConsensusParams.BlockGossip.BlockPartSizeBytes)
  36. blockStore.SaveBlock(firstBlock, firstParts, secondBlock.LastCommit)
  37. }
  38. return bcReactor
  39. }
  40. func TestNoBlockResponse(t *testing.T) {
  41. maxBlockHeight := int64(20)
  42. bcr := newBlockchainReactor(log.TestingLogger(), maxBlockHeight)
  43. bcr.Start()
  44. defer bcr.Stop()
  45. // Add some peers in
  46. peer := newbcrTestPeer(p2p.ID(cmn.RandStr(12)))
  47. bcr.AddPeer(peer)
  48. chID := byte(0x01)
  49. tests := []struct {
  50. height int64
  51. existent bool
  52. }{
  53. {maxBlockHeight + 2, false},
  54. {10, true},
  55. {1, true},
  56. {100, false},
  57. }
  58. // receive a request message from peer,
  59. // wait for our response to be received on the peer
  60. for _, tt := range tests {
  61. reqBlockMsg := &bcBlockRequestMessage{tt.height}
  62. reqBlockBytes := wire.BinaryBytes(struct{ BlockchainMessage }{reqBlockMsg})
  63. bcr.Receive(chID, peer, reqBlockBytes)
  64. value := peer.lastValue()
  65. msg := value.(struct{ BlockchainMessage }).BlockchainMessage
  66. if tt.existent {
  67. if blockMsg, ok := msg.(*bcBlockResponseMessage); !ok {
  68. t.Fatalf("Expected to receive a block response for height %d", tt.height)
  69. } else if blockMsg.Block.Height != tt.height {
  70. t.Fatalf("Expected response to be for height %d, got %d", tt.height, blockMsg.Block.Height)
  71. }
  72. } else {
  73. if noBlockMsg, ok := msg.(*bcNoBlockResponseMessage); !ok {
  74. t.Fatalf("Expected to receive a no block response for height %d", tt.height)
  75. } else if noBlockMsg.Height != tt.height {
  76. t.Fatalf("Expected response to be for height %d, got %d", tt.height, noBlockMsg.Height)
  77. }
  78. }
  79. }
  80. }
  81. /*
  82. // NOTE: This is too hard to test without
  83. // an easy way to add test peer to switch
  84. // or without significant refactoring of the module.
  85. // Alternatively we could actually dial a TCP conn but
  86. // that seems extreme.
  87. func TestBadBlockStopsPeer(t *testing.T) {
  88. maxBlockHeight := int64(20)
  89. bcr := newBlockchainReactor(log.TestingLogger(), maxBlockHeight)
  90. bcr.Start()
  91. defer bcr.Stop()
  92. // Add some peers in
  93. peer := newbcrTestPeer(p2p.ID(cmn.RandStr(12)))
  94. // XXX: This doesn't add the peer to anything,
  95. // so it's hard to check that it's later removed
  96. bcr.AddPeer(peer)
  97. assert.True(t, bcr.Switch.Peers().Size() > 0)
  98. // send a bad block from the peer
  99. // default blocks already dont have commits, so should fail
  100. block := bcr.store.LoadBlock(3)
  101. msg := &bcBlockResponseMessage{Block: block}
  102. peer.Send(BlockchainChannel, struct{ BlockchainMessage }{msg})
  103. ticker := time.NewTicker(time.Millisecond * 10)
  104. timer := time.NewTimer(time.Second * 2)
  105. LOOP:
  106. for {
  107. select {
  108. case <-ticker.C:
  109. if bcr.Switch.Peers().Size() == 0 {
  110. break LOOP
  111. }
  112. case <-timer.C:
  113. t.Fatal("Timed out waiting to disconnect peer")
  114. }
  115. }
  116. }
  117. */
  118. //----------------------------------------------
  119. // utility funcs
  120. func makeTxs(height int64) (txs []types.Tx) {
  121. for i := 0; i < 10; i++ {
  122. txs = append(txs, types.Tx([]byte{byte(height), byte(i)}))
  123. }
  124. return txs
  125. }
  126. func makeBlock(height int64, state sm.State) *types.Block {
  127. block, _ := state.MakeBlock(height, makeTxs(height), new(types.Commit))
  128. return block
  129. }
  130. // The Test peer
  131. type bcrTestPeer struct {
  132. *cmn.BaseService
  133. id p2p.ID
  134. ch chan interface{}
  135. }
  136. var _ p2p.Peer = (*bcrTestPeer)(nil)
  137. func newbcrTestPeer(id p2p.ID) *bcrTestPeer {
  138. bcr := &bcrTestPeer{
  139. id: id,
  140. ch: make(chan interface{}, 2),
  141. }
  142. bcr.BaseService = cmn.NewBaseService(nil, "bcrTestPeer", bcr)
  143. return bcr
  144. }
  145. func (tp *bcrTestPeer) lastValue() interface{} { return <-tp.ch }
  146. func (tp *bcrTestPeer) TrySend(chID byte, value interface{}) bool {
  147. if _, ok := value.(struct{ BlockchainMessage }).
  148. BlockchainMessage.(*bcStatusResponseMessage); ok {
  149. // Discard status response messages since they skew our results
  150. // We only want to deal with:
  151. // + bcBlockResponseMessage
  152. // + bcNoBlockResponseMessage
  153. } else {
  154. tp.ch <- value
  155. }
  156. return true
  157. }
  158. func (tp *bcrTestPeer) Send(chID byte, data interface{}) bool { return tp.TrySend(chID, data) }
  159. func (tp *bcrTestPeer) NodeInfo() p2p.NodeInfo { return p2p.NodeInfo{} }
  160. func (tp *bcrTestPeer) Status() p2p.ConnectionStatus { return p2p.ConnectionStatus{} }
  161. func (tp *bcrTestPeer) ID() p2p.ID { return tp.id }
  162. func (tp *bcrTestPeer) IsOutbound() bool { return false }
  163. func (tp *bcrTestPeer) IsPersistent() bool { return true }
  164. func (tp *bcrTestPeer) Get(s string) interface{} { return s }
  165. func (tp *bcrTestPeer) Set(string, interface{}) {}
  166. func (tp *bcrTestPeer) QuitChan() <-chan struct{} { return tp.Quit }