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.

373 lines
11 KiB

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