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.

376 lines
11 KiB

6 years ago
6 years ago
  1. package state
  2. import (
  3. "context"
  4. "fmt"
  5. "testing"
  6. "time"
  7. "github.com/stretchr/testify/assert"
  8. "github.com/stretchr/testify/require"
  9. "github.com/tendermint/tendermint/abci/example/kvstore"
  10. abci "github.com/tendermint/tendermint/abci/types"
  11. "github.com/tendermint/tendermint/crypto/ed25519"
  12. cmn "github.com/tendermint/tendermint/libs/common"
  13. dbm "github.com/tendermint/tendermint/libs/db"
  14. "github.com/tendermint/tendermint/libs/log"
  15. tmtime "github.com/tendermint/tendermint/types/time"
  16. "github.com/tendermint/tendermint/proxy"
  17. "github.com/tendermint/tendermint/types"
  18. )
  19. var (
  20. chainID = "execution_chain"
  21. testPartSize = 65536
  22. nTxsPerBlock = 10
  23. )
  24. func TestApplyBlock(t *testing.T) {
  25. cc := proxy.NewLocalClientCreator(kvstore.NewKVStoreApplication())
  26. proxyApp := proxy.NewAppConns(cc, nil)
  27. err := proxyApp.Start()
  28. require.Nil(t, err)
  29. defer proxyApp.Stop()
  30. state, stateDB := state(1, 1)
  31. blockExec := NewBlockExecutor(stateDB, log.TestingLogger(), proxyApp.Consensus(),
  32. MockMempool{}, MockEvidencePool{})
  33. block := makeBlock(state, 1)
  34. blockID := types.BlockID{block.Hash(), block.MakePartSet(testPartSize).Header()}
  35. state, err = blockExec.ApplyBlock(state, blockID, block)
  36. require.Nil(t, err)
  37. // TODO check state and mempool
  38. }
  39. // TestBeginBlockValidators ensures we send absent validators list.
  40. func TestBeginBlockValidators(t *testing.T) {
  41. app := &testApp{}
  42. cc := proxy.NewLocalClientCreator(app)
  43. proxyApp := proxy.NewAppConns(cc, nil)
  44. err := proxyApp.Start()
  45. require.Nil(t, err)
  46. defer proxyApp.Stop()
  47. state, stateDB := state(2, 2)
  48. prevHash := state.LastBlockID.Hash
  49. prevParts := types.PartSetHeader{}
  50. prevBlockID := types.BlockID{prevHash, prevParts}
  51. now := tmtime.Now()
  52. vote0 := &types.Vote{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit}
  53. vote1 := &types.Vote{ValidatorIndex: 1, Timestamp: now}
  54. testCases := []struct {
  55. desc string
  56. lastCommitPrecommits []*types.Vote
  57. expectedAbsentValidators []int
  58. }{
  59. {"none absent", []*types.Vote{vote0, vote1}, []int{}},
  60. {"one absent", []*types.Vote{vote0, nil}, []int{1}},
  61. {"multiple absent", []*types.Vote{nil, nil}, []int{0, 1}},
  62. }
  63. for _, tc := range testCases {
  64. lastCommit := &types.Commit{BlockID: prevBlockID, Precommits: tc.lastCommitPrecommits}
  65. // block for height 2
  66. block, _ := state.MakeBlock(2, makeTxs(2), lastCommit, nil, state.Validators.GetProposer().Address)
  67. _, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), state.Validators, stateDB)
  68. require.Nil(t, err, tc.desc)
  69. // -> app receives a list of validators with a bool indicating if they signed
  70. ctr := 0
  71. for i, v := range app.CommitVotes {
  72. if ctr < len(tc.expectedAbsentValidators) &&
  73. tc.expectedAbsentValidators[ctr] == i {
  74. assert.False(t, v.SignedLastBlock)
  75. ctr++
  76. } else {
  77. assert.True(t, v.SignedLastBlock)
  78. }
  79. }
  80. }
  81. }
  82. // TestBeginBlockByzantineValidators ensures we send byzantine validators list.
  83. func TestBeginBlockByzantineValidators(t *testing.T) {
  84. app := &testApp{}
  85. cc := proxy.NewLocalClientCreator(app)
  86. proxyApp := proxy.NewAppConns(cc, nil)
  87. err := proxyApp.Start()
  88. require.Nil(t, err)
  89. defer proxyApp.Stop()
  90. state, stateDB := state(2, 12)
  91. prevHash := state.LastBlockID.Hash
  92. prevParts := types.PartSetHeader{}
  93. prevBlockID := types.BlockID{prevHash, prevParts}
  94. height1, idx1, val1 := int64(8), 0, state.Validators.Validators[0].Address
  95. height2, idx2, val2 := int64(3), 1, state.Validators.Validators[1].Address
  96. ev1 := types.NewMockGoodEvidence(height1, idx1, val1)
  97. ev2 := types.NewMockGoodEvidence(height2, idx2, val2)
  98. now := tmtime.Now()
  99. valSet := state.Validators
  100. testCases := []struct {
  101. desc string
  102. evidence []types.Evidence
  103. expectedByzantineValidators []abci.Evidence
  104. }{
  105. {"none byzantine", []types.Evidence{}, []abci.Evidence{}},
  106. {"one byzantine", []types.Evidence{ev1}, []abci.Evidence{types.TM2PB.Evidence(ev1, valSet, now)}},
  107. {"multiple byzantine", []types.Evidence{ev1, ev2}, []abci.Evidence{
  108. types.TM2PB.Evidence(ev1, valSet, now),
  109. types.TM2PB.Evidence(ev2, valSet, now)}},
  110. }
  111. vote0 := &types.Vote{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit}
  112. vote1 := &types.Vote{ValidatorIndex: 1, Timestamp: now}
  113. votes := []*types.Vote{vote0, vote1}
  114. lastCommit := &types.Commit{BlockID: prevBlockID, Precommits: votes}
  115. for _, tc := range testCases {
  116. block, _ := state.MakeBlock(10, makeTxs(2), lastCommit, nil, state.Validators.GetProposer().Address)
  117. block.Time = now
  118. block.Evidence.Evidence = tc.evidence
  119. _, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), state.Validators, stateDB)
  120. require.Nil(t, err, tc.desc)
  121. // -> app must receive an index of the byzantine validator
  122. assert.Equal(t, tc.expectedByzantineValidators, app.ByzantineValidators, tc.desc)
  123. }
  124. }
  125. func TestUpdateValidators(t *testing.T) {
  126. pubkey1 := ed25519.GenPrivKey().PubKey()
  127. val1 := types.NewValidator(pubkey1, 10)
  128. pubkey2 := ed25519.GenPrivKey().PubKey()
  129. val2 := types.NewValidator(pubkey2, 20)
  130. testCases := []struct {
  131. name string
  132. currentSet *types.ValidatorSet
  133. abciUpdates []abci.ValidatorUpdate
  134. resultingSet *types.ValidatorSet
  135. shouldErr bool
  136. }{
  137. {
  138. "adding a validator is OK",
  139. types.NewValidatorSet([]*types.Validator{val1}),
  140. []abci.ValidatorUpdate{{PubKey: types.TM2PB.PubKey(pubkey2), Power: 20}},
  141. types.NewValidatorSet([]*types.Validator{val1, val2}),
  142. false,
  143. },
  144. {
  145. "updating a validator is OK",
  146. types.NewValidatorSet([]*types.Validator{val1}),
  147. []abci.ValidatorUpdate{{PubKey: types.TM2PB.PubKey(pubkey1), Power: 20}},
  148. types.NewValidatorSet([]*types.Validator{types.NewValidator(pubkey1, 20)}),
  149. false,
  150. },
  151. {
  152. "removing a validator is OK",
  153. types.NewValidatorSet([]*types.Validator{val1, val2}),
  154. []abci.ValidatorUpdate{{PubKey: types.TM2PB.PubKey(pubkey2), Power: 0}},
  155. types.NewValidatorSet([]*types.Validator{val1}),
  156. false,
  157. },
  158. {
  159. "removing a non-existing validator results in error",
  160. types.NewValidatorSet([]*types.Validator{val1}),
  161. []abci.ValidatorUpdate{{PubKey: types.TM2PB.PubKey(pubkey2), Power: 0}},
  162. types.NewValidatorSet([]*types.Validator{val1}),
  163. true,
  164. },
  165. {
  166. "adding a validator with negative power results in error",
  167. types.NewValidatorSet([]*types.Validator{val1}),
  168. []abci.ValidatorUpdate{{PubKey: types.TM2PB.PubKey(pubkey2), Power: -100}},
  169. types.NewValidatorSet([]*types.Validator{val1}),
  170. true,
  171. },
  172. }
  173. for _, tc := range testCases {
  174. t.Run(tc.name, func(t *testing.T) {
  175. err := updateValidators(tc.currentSet, tc.abciUpdates)
  176. if tc.shouldErr {
  177. assert.Error(t, err)
  178. } else {
  179. require.Equal(t, tc.resultingSet.Size(), tc.currentSet.Size())
  180. assert.Equal(t, tc.resultingSet.TotalVotingPower(), tc.currentSet.TotalVotingPower())
  181. assert.Equal(t, tc.resultingSet.Validators[0].Address, tc.currentSet.Validators[0].Address)
  182. if tc.resultingSet.Size() > 1 {
  183. assert.Equal(t, tc.resultingSet.Validators[1].Address, tc.currentSet.Validators[1].Address)
  184. }
  185. }
  186. })
  187. }
  188. }
  189. // TestEndBlockValidatorUpdates ensures we update validator set and send an event.
  190. func TestEndBlockValidatorUpdates(t *testing.T) {
  191. app := &testApp{}
  192. cc := proxy.NewLocalClientCreator(app)
  193. proxyApp := proxy.NewAppConns(cc, nil)
  194. err := proxyApp.Start()
  195. require.Nil(t, err)
  196. defer proxyApp.Stop()
  197. state, stateDB := state(1, 1)
  198. blockExec := NewBlockExecutor(stateDB, log.TestingLogger(), proxyApp.Consensus(),
  199. MockMempool{}, MockEvidencePool{})
  200. eventBus := types.NewEventBus()
  201. err = eventBus.Start()
  202. require.NoError(t, err)
  203. defer eventBus.Stop()
  204. blockExec.SetEventBus(eventBus)
  205. updatesCh := make(chan interface{}, 1)
  206. err = eventBus.Subscribe(context.Background(), "TestEndBlockValidatorUpdates", types.EventQueryValidatorSetUpdates, updatesCh)
  207. require.NoError(t, err)
  208. block := makeBlock(state, 1)
  209. blockID := types.BlockID{block.Hash(), block.MakePartSet(testPartSize).Header()}
  210. pubkey := ed25519.GenPrivKey().PubKey()
  211. app.ValidatorUpdates = []abci.ValidatorUpdate{
  212. {PubKey: types.TM2PB.PubKey(pubkey), Power: 10},
  213. }
  214. state, err = blockExec.ApplyBlock(state, blockID, block)
  215. require.Nil(t, err)
  216. // test new validator was added to NextValidators
  217. if assert.Equal(t, state.Validators.Size()+1, state.NextValidators.Size()) {
  218. idx, _ := state.NextValidators.GetByAddress(pubkey.Address())
  219. if idx < 0 {
  220. t.Fatalf("can't find address %v in the set %v", pubkey.Address(), state.NextValidators)
  221. }
  222. }
  223. // test we threw an event
  224. select {
  225. case e := <-updatesCh:
  226. event, ok := e.(types.EventDataValidatorSetUpdates)
  227. require.True(t, ok, "Expected event of type EventDataValidatorSetUpdates, got %T", e)
  228. if assert.NotEmpty(t, event.ValidatorUpdates) {
  229. assert.Equal(t, pubkey, event.ValidatorUpdates[0].PubKey)
  230. assert.EqualValues(t, 10, event.ValidatorUpdates[0].VotingPower)
  231. }
  232. case <-time.After(1 * time.Second):
  233. t.Fatal("Did not receive EventValidatorSetUpdates within 1 sec.")
  234. }
  235. }
  236. //----------------------------------------------------------------------------
  237. // make some bogus txs
  238. func makeTxs(height int64) (txs []types.Tx) {
  239. for i := 0; i < nTxsPerBlock; i++ {
  240. txs = append(txs, types.Tx([]byte{byte(height), byte(i)}))
  241. }
  242. return txs
  243. }
  244. func state(nVals, height int) (State, dbm.DB) {
  245. vals := make([]types.GenesisValidator, nVals)
  246. for i := 0; i < nVals; i++ {
  247. secret := []byte(fmt.Sprintf("test%d", i))
  248. pk := ed25519.GenPrivKeyFromSecret(secret)
  249. vals[i] = types.GenesisValidator{
  250. pk.PubKey(), 1000, fmt.Sprintf("test%d", i),
  251. }
  252. }
  253. s, _ := MakeGenesisState(&types.GenesisDoc{
  254. ChainID: chainID,
  255. Validators: vals,
  256. AppHash: nil,
  257. })
  258. // save validators to db for 2 heights
  259. stateDB := dbm.NewMemDB()
  260. SaveState(stateDB, s)
  261. for i := 1; i < height; i++ {
  262. s.LastBlockHeight++
  263. s.LastValidators = s.Validators.Copy()
  264. SaveState(stateDB, s)
  265. }
  266. return s, stateDB
  267. }
  268. func makeBlock(state State, height int64) *types.Block {
  269. block, _ := state.MakeBlock(height, makeTxs(state.LastBlockHeight), new(types.Commit), nil, state.Validators.GetProposer().Address)
  270. return block
  271. }
  272. //----------------------------------------------------------------------------
  273. type testApp struct {
  274. abci.BaseApplication
  275. CommitVotes []abci.VoteInfo
  276. ByzantineValidators []abci.Evidence
  277. ValidatorUpdates []abci.ValidatorUpdate
  278. }
  279. var _ abci.Application = (*testApp)(nil)
  280. func (app *testApp) Info(req abci.RequestInfo) (resInfo abci.ResponseInfo) {
  281. return abci.ResponseInfo{}
  282. }
  283. func (app *testApp) BeginBlock(req abci.RequestBeginBlock) abci.ResponseBeginBlock {
  284. app.CommitVotes = req.LastCommitInfo.Votes
  285. app.ByzantineValidators = req.ByzantineValidators
  286. return abci.ResponseBeginBlock{}
  287. }
  288. func (app *testApp) EndBlock(req abci.RequestEndBlock) abci.ResponseEndBlock {
  289. return abci.ResponseEndBlock{ValidatorUpdates: app.ValidatorUpdates}
  290. }
  291. func (app *testApp) DeliverTx(tx []byte) abci.ResponseDeliverTx {
  292. return abci.ResponseDeliverTx{Tags: []cmn.KVPair{}}
  293. }
  294. func (app *testApp) CheckTx(tx []byte) abci.ResponseCheckTx {
  295. return abci.ResponseCheckTx{}
  296. }
  297. func (app *testApp) Commit() abci.ResponseCommit {
  298. return abci.ResponseCommit{}
  299. }
  300. func (app *testApp) Query(reqQuery abci.RequestQuery) (resQuery abci.ResponseQuery) {
  301. return
  302. }