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.

208 lines
6.3 KiB

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