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.

193 lines
5.5 KiB

  1. package state
  2. import (
  3. "bytes"
  4. "fmt"
  5. "path"
  6. "testing"
  7. "github.com/tendermint/tendermint/config/tendermint_test"
  8. // . "github.com/tendermint/go-common"
  9. "github.com/tendermint/go-crypto"
  10. dbm "github.com/tendermint/go-db"
  11. "github.com/tendermint/tendermint/proxy"
  12. "github.com/tendermint/tendermint/types"
  13. "github.com/tendermint/tmsp/example/dummy"
  14. )
  15. var (
  16. privKey = crypto.GenPrivKeyEd25519FromSecret([]byte("handshake_test"))
  17. chainID = "handshake_chain"
  18. nBlocks = 5
  19. mempool = mockMempool{}
  20. testPartSize = 65536
  21. )
  22. func TestExecBlock(t *testing.T) {
  23. // TODO
  24. }
  25. // Sync from scratch
  26. func TestHandshakeReplayAll(t *testing.T) {
  27. testHandshakeReplay(t, 0)
  28. }
  29. // Sync many, not from scratch
  30. func TestHandshakeReplaySome(t *testing.T) {
  31. testHandshakeReplay(t, 1)
  32. }
  33. // Sync from lagging by one
  34. func TestHandshakeReplayOne(t *testing.T) {
  35. testHandshakeReplay(t, nBlocks-1)
  36. }
  37. // Sync from caught up
  38. func TestHandshakeReplayNone(t *testing.T) {
  39. testHandshakeReplay(t, nBlocks)
  40. }
  41. // Make some blocks. Start a fresh app and apply n blocks. Then restart the app and sync it up with the remaining blocks
  42. func testHandshakeReplay(t *testing.T, n int) {
  43. config := tendermint_test.ResetConfig("proxy_test_")
  44. state, store := stateAndStore()
  45. clientCreator := proxy.NewLocalClientCreator(dummy.NewPersistentDummyApplication(path.Join(config.GetString("db_dir"), "1")))
  46. clientCreator2 := proxy.NewLocalClientCreator(dummy.NewPersistentDummyApplication(path.Join(config.GetString("db_dir"), "2")))
  47. proxyApp := proxy.NewAppConns(config, clientCreator, NewHandshaker(config, state, store))
  48. if _, err := proxyApp.Start(); err != nil {
  49. t.Fatalf("Error starting proxy app connections: %v", err)
  50. }
  51. chain := makeBlockchain(t, proxyApp, state)
  52. store.chain = chain //
  53. latestAppHash := state.AppHash
  54. proxyApp.Stop()
  55. if n > 0 {
  56. // start a new app without handshake, play n blocks
  57. proxyApp = proxy.NewAppConns(config, clientCreator2, nil)
  58. if _, err := proxyApp.Start(); err != nil {
  59. t.Fatalf("Error starting proxy app connections: %v", err)
  60. }
  61. state2, _ := stateAndStore()
  62. for i := 0; i < n; i++ {
  63. block := chain[i]
  64. err := state2.ApplyBlock(nil, proxyApp.Consensus(), block, block.MakePartSet(testPartSize).Header(), mempool)
  65. if err != nil {
  66. t.Fatal(err)
  67. }
  68. }
  69. proxyApp.Stop()
  70. }
  71. // now start it with the handshake
  72. handshaker := NewHandshaker(config, state, store)
  73. proxyApp = proxy.NewAppConns(config, clientCreator2, handshaker)
  74. if _, err := proxyApp.Start(); err != nil {
  75. t.Fatalf("Error starting proxy app connections: %v", err)
  76. }
  77. // get the latest app hash from the app
  78. r, _, blockInfo, _ := proxyApp.Query().InfoSync()
  79. if r.IsErr() {
  80. t.Fatal(r)
  81. }
  82. // the app hash should be synced up
  83. if !bytes.Equal(latestAppHash, blockInfo.AppHash) {
  84. t.Fatalf("Expected app hashes to match after handshake/replay. got %X, expected %X", blockInfo.AppHash, latestAppHash)
  85. }
  86. if handshaker.nBlocks != nBlocks-n {
  87. t.Fatalf("Expected handshake to sync %d blocks, got %d", nBlocks-n, handshaker.nBlocks)
  88. }
  89. }
  90. //--------------------------
  91. // make some bogus txs
  92. func txsFunc(blockNum int) (txs []types.Tx) {
  93. for i := 0; i < 10; i++ {
  94. txs = append(txs, types.Tx([]byte{byte(blockNum), byte(i)}))
  95. }
  96. return txs
  97. }
  98. // sign a commit vote
  99. func signCommit(height, round int, hash []byte, header types.PartSetHeader) *types.Vote {
  100. vote := &types.Vote{
  101. ValidatorIndex: 0,
  102. ValidatorAddress: privKey.PubKey().Address(),
  103. Height: height,
  104. Round: round,
  105. Type: types.VoteTypePrecommit,
  106. BlockID: types.BlockID{hash, header},
  107. }
  108. sig := privKey.Sign(types.SignBytes(chainID, vote))
  109. vote.Signature = sig.(crypto.SignatureEd25519)
  110. return vote
  111. }
  112. // make a blockchain with one validator
  113. func makeBlockchain(t *testing.T, proxyApp proxy.AppConns, state *State) (blockchain []*types.Block) {
  114. prevHash := state.LastBlockID.Hash
  115. lastCommit := new(types.Commit)
  116. prevParts := types.PartSetHeader{}
  117. valHash := state.Validators.Hash()
  118. prevBlockID := types.BlockID{prevHash, prevParts}
  119. for i := 1; i < nBlocks+1; i++ {
  120. block, parts := types.MakeBlock(i, chainID, txsFunc(i), lastCommit,
  121. prevBlockID, valHash, state.AppHash, testPartSize)
  122. fmt.Println(i)
  123. fmt.Println(prevBlockID)
  124. fmt.Println(block.LastBlockID)
  125. err := state.ApplyBlock(nil, proxyApp.Consensus(), block, block.MakePartSet(testPartSize).Header(), mempool)
  126. if err != nil {
  127. t.Fatal(i, err)
  128. }
  129. voteSet := types.NewVoteSet(chainID, i, 0, types.VoteTypePrecommit, state.Validators)
  130. vote := signCommit(i, 0, block.Hash(), parts.Header())
  131. _, err = voteSet.AddVote(vote)
  132. if err != nil {
  133. t.Fatal(err)
  134. }
  135. blockchain = append(blockchain, block)
  136. prevHash = block.Hash()
  137. prevParts = parts.Header()
  138. lastCommit = voteSet.MakeCommit()
  139. prevBlockID = types.BlockID{prevHash, prevParts}
  140. }
  141. return blockchain
  142. }
  143. // fresh state and mock store
  144. func stateAndStore() (*State, *mockBlockStore) {
  145. stateDB := dbm.NewMemDB()
  146. return MakeGenesisState(stateDB, &types.GenesisDoc{
  147. ChainID: chainID,
  148. Validators: []types.GenesisValidator{
  149. types.GenesisValidator{privKey.PubKey(), 10000, "test"},
  150. },
  151. AppHash: nil,
  152. }), NewMockBlockStore(nil)
  153. }
  154. //----------------------------------
  155. // mock block store
  156. type mockBlockStore struct {
  157. chain []*types.Block
  158. }
  159. func NewMockBlockStore(chain []*types.Block) *mockBlockStore {
  160. return &mockBlockStore{chain}
  161. }
  162. func (bs *mockBlockStore) Height() int { return len(bs.chain) }
  163. func (bs *mockBlockStore) LoadBlock(height int) *types.Block { return bs.chain[height-1] }