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.

327 lines
10 KiB

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