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.

315 lines
8.8 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/tendermint/abci/example/kvstore"
  9. abci "github.com/tendermint/tendermint/abci/types"
  10. "github.com/tendermint/tendermint/crypto/ed25519"
  11. cmn "github.com/tendermint/tendermint/libs/common"
  12. dbm "github.com/tendermint/tendermint/libs/db"
  13. "github.com/tendermint/tendermint/libs/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. func TestUpdateValidators(t *testing.T) {
  124. pubkey1 := ed25519.GenPrivKey().PubKey()
  125. val1 := types.NewValidator(pubkey1, 10)
  126. pubkey2 := ed25519.GenPrivKey().PubKey()
  127. val2 := types.NewValidator(pubkey2, 20)
  128. testCases := []struct {
  129. name string
  130. currentSet *types.ValidatorSet
  131. abciUpdates []abci.Validator
  132. resultingSet *types.ValidatorSet
  133. shouldErr bool
  134. }{
  135. {
  136. "adding a validator is OK",
  137. types.NewValidatorSet([]*types.Validator{val1}),
  138. []abci.Validator{{[]byte{}, types.TM2PB.PubKey(pubkey2), 20}},
  139. types.NewValidatorSet([]*types.Validator{val1, val2}),
  140. false,
  141. },
  142. {
  143. "updating a validator is OK",
  144. types.NewValidatorSet([]*types.Validator{val1}),
  145. []abci.Validator{{[]byte{}, types.TM2PB.PubKey(pubkey1), 20}},
  146. types.NewValidatorSet([]*types.Validator{types.NewValidator(pubkey1, 20)}),
  147. false,
  148. },
  149. {
  150. "removing a validator is OK",
  151. types.NewValidatorSet([]*types.Validator{val1, val2}),
  152. []abci.Validator{{[]byte{}, types.TM2PB.PubKey(pubkey2), 0}},
  153. types.NewValidatorSet([]*types.Validator{val1}),
  154. false,
  155. },
  156. {
  157. "removing a non-existing validator results in error",
  158. types.NewValidatorSet([]*types.Validator{val1}),
  159. []abci.Validator{{[]byte{}, types.TM2PB.PubKey(pubkey2), 0}},
  160. types.NewValidatorSet([]*types.Validator{val1}),
  161. true,
  162. },
  163. {
  164. "adding a validator with negative power results in error",
  165. types.NewValidatorSet([]*types.Validator{val1}),
  166. []abci.Validator{{[]byte{}, types.TM2PB.PubKey(pubkey2), -100}},
  167. types.NewValidatorSet([]*types.Validator{val1}),
  168. true,
  169. },
  170. }
  171. for _, tc := range testCases {
  172. t.Run(tc.name, func(t *testing.T) {
  173. err := updateValidators(tc.currentSet, tc.abciUpdates)
  174. if tc.shouldErr {
  175. assert.Error(t, err)
  176. } else {
  177. require.Equal(t, tc.resultingSet.Size(), tc.currentSet.Size())
  178. assert.Equal(t, tc.resultingSet.TotalVotingPower(), tc.currentSet.TotalVotingPower())
  179. assert.Equal(t, tc.resultingSet.Validators[0].Address, tc.currentSet.Validators[0].Address)
  180. if tc.resultingSet.Size() > 1 {
  181. assert.Equal(t, tc.resultingSet.Validators[1].Address, tc.currentSet.Validators[1].Address)
  182. }
  183. }
  184. })
  185. }
  186. }
  187. //----------------------------------------------------------------------------
  188. // make some bogus txs
  189. func makeTxs(height int64) (txs []types.Tx) {
  190. for i := 0; i < nTxsPerBlock; i++ {
  191. txs = append(txs, types.Tx([]byte{byte(height), byte(i)}))
  192. }
  193. return txs
  194. }
  195. func state(nVals, height int) (State, dbm.DB) {
  196. vals := make([]types.GenesisValidator, nVals)
  197. for i := 0; i < nVals; i++ {
  198. secret := []byte(fmt.Sprintf("test%d", i))
  199. pk := ed25519.GenPrivKeyFromSecret(secret)
  200. vals[i] = types.GenesisValidator{
  201. pk.PubKey(), 1000, fmt.Sprintf("test%d", i),
  202. }
  203. }
  204. s, _ := MakeGenesisState(&types.GenesisDoc{
  205. ChainID: chainID,
  206. Validators: vals,
  207. AppHash: nil,
  208. })
  209. // save validators to db for 2 heights
  210. stateDB := dbm.NewMemDB()
  211. SaveState(stateDB, s)
  212. for i := 1; i < height; i++ {
  213. s.LastBlockHeight += 1
  214. SaveState(stateDB, s)
  215. }
  216. return s, stateDB
  217. }
  218. func makeBlock(state State, height int64) *types.Block {
  219. block, _ := state.MakeBlock(height, makeTxs(state.LastBlockHeight), new(types.Commit))
  220. return block
  221. }
  222. //----------------------------------------------------------------------------
  223. var _ abci.Application = (*testApp)(nil)
  224. type testApp struct {
  225. abci.BaseApplication
  226. Validators []abci.SigningValidator
  227. ByzantineValidators []abci.Evidence
  228. }
  229. func NewKVStoreApplication() *testApp {
  230. return &testApp{}
  231. }
  232. func (app *testApp) Info(req abci.RequestInfo) (resInfo abci.ResponseInfo) {
  233. return abci.ResponseInfo{}
  234. }
  235. func (app *testApp) BeginBlock(req abci.RequestBeginBlock) abci.ResponseBeginBlock {
  236. app.Validators = req.Validators
  237. app.ByzantineValidators = req.ByzantineValidators
  238. return abci.ResponseBeginBlock{}
  239. }
  240. func (app *testApp) DeliverTx(tx []byte) abci.ResponseDeliverTx {
  241. return abci.ResponseDeliverTx{Tags: []cmn.KVPair{}}
  242. }
  243. func (app *testApp) CheckTx(tx []byte) abci.ResponseCheckTx {
  244. return abci.ResponseCheckTx{}
  245. }
  246. func (app *testApp) Commit() abci.ResponseCommit {
  247. return abci.ResponseCommit{}
  248. }
  249. func (app *testApp) Query(reqQuery abci.RequestQuery) (resQuery abci.ResponseQuery) {
  250. return
  251. }