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.

232 lines
6.6 KiB

  1. package state
  2. import (
  3. "fmt"
  4. "testing"
  5. "time"
  6. "github.com/stretchr/testify/assert"
  7. "github.com/stretchr/testify/require"
  8. "github.com/tendermint/abci/example/kvstore"
  9. abci "github.com/tendermint/abci/types"
  10. crypto "github.com/tendermint/tendermint/crypto"
  11. cmn "github.com/tendermint/tmlibs/common"
  12. dbm "github.com/tendermint/tmlibs/db"
  13. "github.com/tendermint/tmlibs/log"
  14. "github.com/tendermint/tendermint/proxy"
  15. "github.com/tendermint/tendermint/types"
  16. )
  17. var (
  18. chainID = "execution_chain"
  19. testPartSize = 65536
  20. nTxsPerBlock = 10
  21. )
  22. func TestApplyBlock(t *testing.T) {
  23. cc := proxy.NewLocalClientCreator(kvstore.NewKVStoreApplication())
  24. proxyApp := proxy.NewAppConns(cc, nil)
  25. err := proxyApp.Start()
  26. require.Nil(t, err)
  27. defer proxyApp.Stop()
  28. state, stateDB := state(1, 1)
  29. blockExec := NewBlockExecutor(stateDB, log.TestingLogger(), proxyApp.Consensus(),
  30. MockMempool{}, MockEvidencePool{})
  31. block := makeBlock(state, 1)
  32. blockID := types.BlockID{block.Hash(), block.MakePartSet(testPartSize).Header()}
  33. state, err = blockExec.ApplyBlock(state, blockID, block)
  34. require.Nil(t, err)
  35. // TODO check state and mempool
  36. }
  37. // TestBeginBlockValidators ensures we send absent validators list.
  38. func TestBeginBlockValidators(t *testing.T) {
  39. app := &testApp{}
  40. cc := proxy.NewLocalClientCreator(app)
  41. proxyApp := proxy.NewAppConns(cc, nil)
  42. err := proxyApp.Start()
  43. require.Nil(t, err)
  44. defer proxyApp.Stop()
  45. state, stateDB := state(2, 2)
  46. prevHash := state.LastBlockID.Hash
  47. prevParts := types.PartSetHeader{}
  48. prevBlockID := types.BlockID{prevHash, prevParts}
  49. now := time.Now().UTC()
  50. vote0 := &types.Vote{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit}
  51. vote1 := &types.Vote{ValidatorIndex: 1, Timestamp: now}
  52. testCases := []struct {
  53. desc string
  54. lastCommitPrecommits []*types.Vote
  55. expectedAbsentValidators []int
  56. }{
  57. {"none absent", []*types.Vote{vote0, vote1}, []int{}},
  58. {"one absent", []*types.Vote{vote0, nil}, []int{1}},
  59. {"multiple absent", []*types.Vote{nil, nil}, []int{0, 1}},
  60. }
  61. for _, tc := range testCases {
  62. lastCommit := &types.Commit{BlockID: prevBlockID, Precommits: tc.lastCommitPrecommits}
  63. // block for height 2
  64. block, _ := state.MakeBlock(2, makeTxs(2), lastCommit)
  65. _, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), state.Validators, stateDB)
  66. require.Nil(t, err, tc.desc)
  67. // -> app receives a list of validators with a bool indicating if they signed
  68. ctr := 0
  69. for i, v := range app.Validators {
  70. if ctr < len(tc.expectedAbsentValidators) &&
  71. tc.expectedAbsentValidators[ctr] == i {
  72. assert.False(t, v.SignedLastBlock)
  73. ctr++
  74. } else {
  75. assert.True(t, v.SignedLastBlock)
  76. }
  77. }
  78. }
  79. }
  80. // TestBeginBlockByzantineValidators ensures we send byzantine validators list.
  81. func TestBeginBlockByzantineValidators(t *testing.T) {
  82. app := &testApp{}
  83. cc := proxy.NewLocalClientCreator(app)
  84. proxyApp := proxy.NewAppConns(cc, nil)
  85. err := proxyApp.Start()
  86. require.Nil(t, err)
  87. defer proxyApp.Stop()
  88. state, stateDB := state(2, 12)
  89. prevHash := state.LastBlockID.Hash
  90. prevParts := types.PartSetHeader{}
  91. prevBlockID := types.BlockID{prevHash, prevParts}
  92. height1, idx1, val1 := int64(8), 0, state.Validators.Validators[0].Address
  93. height2, idx2, val2 := int64(3), 1, state.Validators.Validators[1].Address
  94. ev1 := types.NewMockGoodEvidence(height1, idx1, val1)
  95. ev2 := types.NewMockGoodEvidence(height2, idx2, val2)
  96. now := time.Now()
  97. valSet := state.Validators
  98. testCases := []struct {
  99. desc string
  100. evidence []types.Evidence
  101. expectedByzantineValidators []abci.Evidence
  102. }{
  103. {"none byzantine", []types.Evidence{}, []abci.Evidence{}},
  104. {"one byzantine", []types.Evidence{ev1}, []abci.Evidence{types.TM2PB.Evidence(ev1, valSet, now)}},
  105. {"multiple byzantine", []types.Evidence{ev1, ev2}, []abci.Evidence{
  106. types.TM2PB.Evidence(ev1, valSet, now),
  107. types.TM2PB.Evidence(ev2, valSet, now)}},
  108. }
  109. vote0 := &types.Vote{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit}
  110. vote1 := &types.Vote{ValidatorIndex: 1, Timestamp: now}
  111. votes := []*types.Vote{vote0, vote1}
  112. lastCommit := &types.Commit{BlockID: prevBlockID, Precommits: votes}
  113. for _, tc := range testCases {
  114. block, _ := state.MakeBlock(10, makeTxs(2), lastCommit)
  115. block.Time = now
  116. block.Evidence.Evidence = tc.evidence
  117. _, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), state.Validators, stateDB)
  118. require.Nil(t, err, tc.desc)
  119. // -> app must receive an index of the byzantine validator
  120. assert.Equal(t, tc.expectedByzantineValidators, app.ByzantineValidators, tc.desc)
  121. }
  122. }
  123. //----------------------------------------------------------------------------
  124. // make some bogus txs
  125. func makeTxs(height int64) (txs []types.Tx) {
  126. for i := 0; i < nTxsPerBlock; i++ {
  127. txs = append(txs, types.Tx([]byte{byte(height), byte(i)}))
  128. }
  129. return txs
  130. }
  131. func state(nVals, height int) (State, dbm.DB) {
  132. vals := make([]types.GenesisValidator, nVals)
  133. for i := 0; i < nVals; i++ {
  134. secret := []byte(fmt.Sprintf("test%d", i))
  135. pk := crypto.GenPrivKeyEd25519FromSecret(secret)
  136. vals[i] = types.GenesisValidator{
  137. pk.PubKey(), 1000, fmt.Sprintf("test%d", i),
  138. }
  139. }
  140. s, _ := MakeGenesisState(&types.GenesisDoc{
  141. ChainID: chainID,
  142. Validators: vals,
  143. AppHash: nil,
  144. })
  145. // save validators to db for 2 heights
  146. stateDB := dbm.NewMemDB()
  147. SaveState(stateDB, s)
  148. for i := 1; i < height; i++ {
  149. s.LastBlockHeight += 1
  150. SaveState(stateDB, s)
  151. }
  152. return s, stateDB
  153. }
  154. func makeBlock(state State, height int64) *types.Block {
  155. block, _ := state.MakeBlock(height, makeTxs(state.LastBlockHeight), new(types.Commit))
  156. return block
  157. }
  158. //----------------------------------------------------------------------------
  159. var _ abci.Application = (*testApp)(nil)
  160. type testApp struct {
  161. abci.BaseApplication
  162. Validators []abci.SigningValidator
  163. ByzantineValidators []abci.Evidence
  164. }
  165. func NewKVStoreApplication() *testApp {
  166. return &testApp{}
  167. }
  168. func (app *testApp) Info(req abci.RequestInfo) (resInfo abci.ResponseInfo) {
  169. return abci.ResponseInfo{}
  170. }
  171. func (app *testApp) BeginBlock(req abci.RequestBeginBlock) abci.ResponseBeginBlock {
  172. app.Validators = req.Validators
  173. app.ByzantineValidators = req.ByzantineValidators
  174. return abci.ResponseBeginBlock{}
  175. }
  176. func (app *testApp) DeliverTx(tx []byte) abci.ResponseDeliverTx {
  177. return abci.ResponseDeliverTx{Tags: []cmn.KVPair{}}
  178. }
  179. func (app *testApp) CheckTx(tx []byte) abci.ResponseCheckTx {
  180. return abci.ResponseCheckTx{}
  181. }
  182. func (app *testApp) Commit() abci.ResponseCommit {
  183. return abci.ResponseCommit{}
  184. }
  185. func (app *testApp) Query(reqQuery abci.RequestQuery) (resQuery abci.ResponseQuery) {
  186. return
  187. }