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.

307 lines
9.2 KiB

9 years ago
  1. package consensus
  2. import (
  3. "bytes"
  4. "fmt"
  5. "sort"
  6. "sync"
  7. "testing"
  8. "time"
  9. cfg "github.com/tendermint/go-config"
  10. dbm "github.com/tendermint/go-db"
  11. bc "github.com/tendermint/tendermint/blockchain"
  12. mempl "github.com/tendermint/tendermint/mempool"
  13. sm "github.com/tendermint/tendermint/state"
  14. "github.com/tendermint/tendermint/types"
  15. tmspcli "github.com/tendermint/tmsp/client"
  16. tmsp "github.com/tendermint/tmsp/types"
  17. "github.com/tendermint/tmsp/example/counter"
  18. "github.com/tendermint/tmsp/example/dummy"
  19. )
  20. var config cfg.Config // NOTE: must be reset for each _test.go file
  21. var ensureTimeout = time.Duration(2)
  22. type validatorStub struct {
  23. Index int // Validator index. NOTE: we don't assume validator set changes.
  24. Height int
  25. Round int
  26. *types.PrivValidator
  27. }
  28. func NewValidatorStub(privValidator *types.PrivValidator, valIndex int) *validatorStub {
  29. return &validatorStub{
  30. Index: valIndex,
  31. PrivValidator: privValidator,
  32. }
  33. }
  34. func (vs *validatorStub) signVote(voteType byte, hash []byte, header types.PartSetHeader) (*types.Vote, error) {
  35. vote := &types.Vote{
  36. ValidatorIndex: vs.Index,
  37. ValidatorAddress: vs.PrivValidator.Address,
  38. Height: vs.Height,
  39. Round: vs.Round,
  40. Type: voteType,
  41. BlockHash: hash,
  42. BlockPartsHeader: header,
  43. }
  44. err := vs.PrivValidator.SignVote(config.GetString("chain_id"), vote)
  45. return vote, err
  46. }
  47. //-------------------------------------------------------------------------------
  48. // Convenience functions
  49. // Sign vote for type/hash/header
  50. func signVote(vs *validatorStub, voteType byte, hash []byte, header types.PartSetHeader) *types.Vote {
  51. v, err := vs.signVote(voteType, hash, header)
  52. if err != nil {
  53. panic(fmt.Errorf("failed to sign vote: %v", err))
  54. }
  55. return v
  56. }
  57. // Create proposal block from cs1 but sign it with vs
  58. func decideProposal(cs1 *ConsensusState, vs *validatorStub, height, round int) (proposal *types.Proposal, block *types.Block) {
  59. block, blockParts := cs1.createProposalBlock()
  60. if block == nil { // on error
  61. panic("error creating proposal block")
  62. }
  63. // Make proposal
  64. proposal = types.NewProposal(height, round, blockParts.Header(), cs1.Votes.POLRound())
  65. if err := vs.SignProposal(config.GetString("chain_id"), proposal); err != nil {
  66. panic(err)
  67. }
  68. return
  69. }
  70. func addVotes(to *ConsensusState, votes ...*types.Vote) {
  71. for _, vote := range votes {
  72. to.peerMsgQueue <- msgInfo{Msg: &VoteMessage{vote}}
  73. }
  74. }
  75. func signVotes(voteType byte, hash []byte, header types.PartSetHeader, vss ...*validatorStub) []*types.Vote {
  76. votes := make([]*types.Vote, len(vss))
  77. for i, vs := range vss {
  78. votes[i] = signVote(vs, voteType, hash, header)
  79. }
  80. return votes
  81. }
  82. func signAddVotes(to *ConsensusState, voteType byte, hash []byte, header types.PartSetHeader, vss ...*validatorStub) {
  83. votes := signVotes(voteType, hash, header, vss...)
  84. addVotes(to, votes...)
  85. }
  86. func ensureNoNewStep(stepCh chan interface{}) {
  87. timeout := time.NewTicker(ensureTimeout * time.Second)
  88. select {
  89. case <-timeout.C:
  90. break
  91. case <-stepCh:
  92. panic("We should be stuck waiting for more votes, not moving to the next step")
  93. }
  94. }
  95. func incrementHeight(vss ...*validatorStub) {
  96. for _, vs := range vss {
  97. vs.Height += 1
  98. }
  99. }
  100. func incrementRound(vss ...*validatorStub) {
  101. for _, vs := range vss {
  102. vs.Round += 1
  103. }
  104. }
  105. func validatePrevote(t *testing.T, cs *ConsensusState, round int, privVal *validatorStub, blockHash []byte) {
  106. prevotes := cs.Votes.Prevotes(round)
  107. var vote *types.Vote
  108. if vote = prevotes.GetByAddress(privVal.Address); vote == nil {
  109. panic("Failed to find prevote from validator")
  110. }
  111. if blockHash == nil {
  112. if vote.BlockHash != nil {
  113. panic(fmt.Sprintf("Expected prevote to be for nil, got %X", vote.BlockHash))
  114. }
  115. } else {
  116. if !bytes.Equal(vote.BlockHash, blockHash) {
  117. panic(fmt.Sprintf("Expected prevote to be for %X, got %X", blockHash, vote.BlockHash))
  118. }
  119. }
  120. }
  121. func validateLastPrecommit(t *testing.T, cs *ConsensusState, privVal *validatorStub, blockHash []byte) {
  122. votes := cs.LastCommit
  123. var vote *types.Vote
  124. if vote = votes.GetByAddress(privVal.Address); vote == nil {
  125. panic("Failed to find precommit from validator")
  126. }
  127. if !bytes.Equal(vote.BlockHash, blockHash) {
  128. panic(fmt.Sprintf("Expected precommit to be for %X, got %X", blockHash, vote.BlockHash))
  129. }
  130. }
  131. func validatePrecommit(t *testing.T, cs *ConsensusState, thisRound, lockRound int, privVal *validatorStub, votedBlockHash, lockedBlockHash []byte) {
  132. precommits := cs.Votes.Precommits(thisRound)
  133. var vote *types.Vote
  134. if vote = precommits.GetByAddress(privVal.Address); vote == nil {
  135. panic("Failed to find precommit from validator")
  136. }
  137. if votedBlockHash == nil {
  138. if vote.BlockHash != nil {
  139. panic("Expected precommit to be for nil")
  140. }
  141. } else {
  142. if !bytes.Equal(vote.BlockHash, votedBlockHash) {
  143. panic("Expected precommit to be for proposal block")
  144. }
  145. }
  146. if lockedBlockHash == nil {
  147. if cs.LockedRound != lockRound || cs.LockedBlock != nil {
  148. panic(fmt.Sprintf("Expected to be locked on nil at round %d. Got locked at round %d with block %v", lockRound, cs.LockedRound, cs.LockedBlock))
  149. }
  150. } else {
  151. if cs.LockedRound != lockRound || !bytes.Equal(cs.LockedBlock.Hash(), lockedBlockHash) {
  152. panic(fmt.Sprintf("Expected block to be locked on round %d, got %d. Got locked block %X, expected %X", lockRound, cs.LockedRound, cs.LockedBlock.Hash(), lockedBlockHash))
  153. }
  154. }
  155. }
  156. func validatePrevoteAndPrecommit(t *testing.T, cs *ConsensusState, thisRound, lockRound int, privVal *validatorStub, votedBlockHash, lockedBlockHash []byte) {
  157. // verify the prevote
  158. validatePrevote(t, cs, thisRound, privVal, votedBlockHash)
  159. // verify precommit
  160. cs.mtx.Lock()
  161. validatePrecommit(t, cs, thisRound, lockRound, privVal, votedBlockHash, lockedBlockHash)
  162. cs.mtx.Unlock()
  163. }
  164. func fixedConsensusState() *ConsensusState {
  165. stateDB := dbm.NewMemDB()
  166. state := sm.MakeGenesisStateFromFile(stateDB, config.GetString("genesis_file"))
  167. privValidatorFile := config.GetString("priv_validator_file")
  168. privValidator := types.LoadOrGenPrivValidator(privValidatorFile)
  169. privValidator.Reset()
  170. cs := newConsensusState(state, privValidator, counter.NewCounterApplication(true))
  171. return cs
  172. }
  173. func fixedConsensusStateDummy() *ConsensusState {
  174. stateDB := dbm.NewMemDB()
  175. state := sm.MakeGenesisStateFromFile(stateDB, config.GetString("genesis_file"))
  176. privValidatorFile := config.GetString("priv_validator_file")
  177. privValidator := types.LoadOrGenPrivValidator(privValidatorFile)
  178. privValidator.Reset()
  179. cs := newConsensusState(state, privValidator, dummy.NewDummyApplication())
  180. return cs
  181. }
  182. func newConsensusState(state *sm.State, pv *types.PrivValidator, app tmsp.Application) *ConsensusState {
  183. // Get BlockStore
  184. blockDB := dbm.NewMemDB()
  185. blockStore := bc.NewBlockStore(blockDB)
  186. // one for mempool, one for consensus
  187. mtx := new(sync.Mutex)
  188. proxyAppConnMem := tmspcli.NewLocalClient(mtx, app)
  189. proxyAppConnCon := tmspcli.NewLocalClient(mtx, app)
  190. // Make Mempool
  191. mempool := mempl.NewMempool(config, proxyAppConnMem)
  192. // Make ConsensusReactor
  193. cs := NewConsensusState(config, state, proxyAppConnCon, blockStore, mempool)
  194. cs.SetPrivValidator(pv)
  195. evsw := types.NewEventSwitch()
  196. cs.SetEventSwitch(evsw)
  197. evsw.Start()
  198. return cs
  199. }
  200. func randConsensusState(nValidators int) (*ConsensusState, []*validatorStub) {
  201. // Get State
  202. state, privVals := randGenesisState(nValidators, false, 10)
  203. vss := make([]*validatorStub, nValidators)
  204. cs := newConsensusState(state, privVals[0], counter.NewCounterApplication(true))
  205. for i := 0; i < nValidators; i++ {
  206. vss[i] = NewValidatorStub(privVals[i], i)
  207. }
  208. // since cs1 starts at 1
  209. incrementHeight(vss[1:]...)
  210. return cs, vss
  211. }
  212. func subscribeToVoter(cs *ConsensusState, addr []byte) chan interface{} {
  213. voteCh0 := subscribeToEvent(cs.evsw, "tester", types.EventStringVote(), 1)
  214. voteCh := make(chan interface{})
  215. go func() {
  216. for {
  217. v := <-voteCh0
  218. vote := v.(types.EventDataVote)
  219. // we only fire for our own votes
  220. if bytes.Equal(addr, vote.Vote.ValidatorAddress) {
  221. voteCh <- v
  222. }
  223. }
  224. }()
  225. return voteCh
  226. }
  227. func readVotes(ch chan interface{}, reads int) chan struct{} {
  228. wg := make(chan struct{})
  229. go func() {
  230. for i := 0; i < reads; i++ {
  231. <-ch // read the precommit event
  232. }
  233. close(wg)
  234. }()
  235. return wg
  236. }
  237. func randGenesisState(numValidators int, randPower bool, minPower int64) (*sm.State, []*types.PrivValidator) {
  238. db := dbm.NewMemDB()
  239. genDoc, privValidators := randGenesisDoc(numValidators, randPower, minPower)
  240. s0 := sm.MakeGenesisState(db, genDoc)
  241. s0.Save()
  242. return s0, privValidators
  243. }
  244. func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.GenesisDoc, []*types.PrivValidator) {
  245. validators := make([]types.GenesisValidator, numValidators)
  246. privValidators := make([]*types.PrivValidator, numValidators)
  247. for i := 0; i < numValidators; i++ {
  248. val, privVal := types.RandValidator(randPower, minPower)
  249. validators[i] = types.GenesisValidator{
  250. PubKey: val.PubKey,
  251. Amount: val.VotingPower,
  252. }
  253. privValidators[i] = privVal
  254. }
  255. sort.Sort(types.PrivValidatorsByAddress(privValidators))
  256. return &types.GenesisDoc{
  257. GenesisTime: time.Now(),
  258. ChainID: config.GetString("chain_id"),
  259. Validators: validators,
  260. }, privValidators
  261. }
  262. func startTestRound(cs *ConsensusState, height, round int) {
  263. cs.enterNewRound(height, round)
  264. cs.startRoutines(0)
  265. }