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.

366 lines
11 KiB

9 years ago
  1. package consensus
  2. import (
  3. "bytes"
  4. "fmt"
  5. "sort"
  6. "testing"
  7. "time"
  8. dbm "github.com/tendermint/go-db"
  9. bc "github.com/tendermint/tendermint/blockchain"
  10. _ "github.com/tendermint/tendermint/config/tendermint_test"
  11. "github.com/tendermint/tendermint/events"
  12. mempl "github.com/tendermint/tendermint/mempool"
  13. "github.com/tendermint/tendermint/proxy"
  14. sm "github.com/tendermint/tendermint/state"
  15. "github.com/tendermint/tendermint/types"
  16. "github.com/tendermint/tmsp/example"
  17. )
  18. var chainID string
  19. var ensureTimeout = time.Duration(2)
  20. func init() {
  21. chainID = config.GetString("chain_id")
  22. }
  23. type validatorStub struct {
  24. Height int
  25. Round int
  26. *types.PrivValidator
  27. }
  28. func NewValidatorStub(privValidator *types.PrivValidator) *validatorStub {
  29. return &validatorStub{
  30. PrivValidator: privValidator,
  31. }
  32. }
  33. func (vs *validatorStub) signVote(voteType byte, hash []byte, header types.PartSetHeader) (*types.Vote, error) {
  34. vote := &types.Vote{
  35. Height: vs.Height,
  36. Round: vs.Round,
  37. Type: voteType,
  38. BlockHash: hash,
  39. BlockPartsHeader: header,
  40. }
  41. err := vs.PrivValidator.SignVote(chainID, vote)
  42. return vote, err
  43. }
  44. // convenienve function for testing
  45. func signVote(vs *validatorStub, voteType byte, hash []byte, header types.PartSetHeader) *types.Vote {
  46. v, err := vs.signVote(voteType, hash, header)
  47. if err != nil {
  48. panic(fmt.Errorf("failed to sign vote: %v", err))
  49. }
  50. return v
  51. }
  52. // create proposal block from cs1 but sign it with vs
  53. func decideProposal(cs1 *ConsensusState, cs2 *validatorStub, height, round int) (proposal *types.Proposal, block *types.Block) {
  54. block, blockParts := cs1.createProposalBlock()
  55. if block == nil { // on error
  56. panic("error creating proposal block")
  57. }
  58. // Make proposal
  59. proposal = types.NewProposal(height, round, blockParts.Header(), cs1.Votes.POLRound())
  60. if err := cs2.SignProposal(chainID, proposal); err != nil {
  61. panic(err)
  62. }
  63. return
  64. }
  65. //-------------------------------------------------------------------------------
  66. // utils
  67. func nilRound(t *testing.T, cs1 *ConsensusState, vss ...*validatorStub) {
  68. cs1.mtx.Lock()
  69. height, round := cs1.Height, cs1.Round
  70. cs1.mtx.Unlock()
  71. waitFor(t, cs1, height, round, RoundStepPrevote)
  72. signAddVoteToFromMany(types.VoteTypePrevote, cs1, nil, cs1.ProposalBlockParts.Header(), vss...)
  73. waitFor(t, cs1, height, round, RoundStepPrecommit)
  74. signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, cs1.ProposalBlockParts.Header(), vss...)
  75. waitFor(t, cs1, height, round+1, RoundStepNewRound)
  76. }
  77. // NOTE: this switches the propser as far as `perspectiveOf` is concerned,
  78. // but for simplicity we return a block it generated.
  79. func changeProposer(t *testing.T, perspectiveOf *ConsensusState, newProposer *validatorStub) *types.Block {
  80. _, v1 := perspectiveOf.Validators.GetByAddress(perspectiveOf.privValidator.Address)
  81. v1.Accum, v1.VotingPower = 0, 0
  82. if updated := perspectiveOf.Validators.Update(v1); !updated {
  83. t.Fatal("failed to update validator")
  84. }
  85. _, v2 := perspectiveOf.Validators.GetByAddress(newProposer.Address)
  86. v2.Accum, v2.VotingPower = 100, 100
  87. if updated := perspectiveOf.Validators.Update(v2); !updated {
  88. t.Fatal("failed to update validator")
  89. }
  90. // make the proposal
  91. propBlock, _ := perspectiveOf.createProposalBlock()
  92. if propBlock == nil {
  93. t.Fatal("Failed to create proposal block with cs2")
  94. }
  95. return propBlock
  96. }
  97. func fixVotingPower(t *testing.T, cs1 *ConsensusState, addr2 []byte) {
  98. _, v1 := cs1.Validators.GetByAddress(cs1.privValidator.Address)
  99. _, v2 := cs1.Validators.GetByAddress(addr2)
  100. v1.Accum, v1.VotingPower = v2.Accum, v2.VotingPower
  101. if updated := cs1.Validators.Update(v1); !updated {
  102. t.Fatal("failed to update validator")
  103. }
  104. }
  105. func addVoteToFromMany(to *ConsensusState, votes []*types.Vote, froms ...*validatorStub) {
  106. if len(votes) != len(froms) {
  107. panic("len(votes) and len(froms) must match")
  108. }
  109. for i, from := range froms {
  110. addVoteToFrom(to, from, votes[i])
  111. }
  112. }
  113. func addVoteToFrom(to *ConsensusState, from *validatorStub, vote *types.Vote) {
  114. valIndex, _ := to.Validators.GetByAddress(from.PrivValidator.Address)
  115. to.peerMsgQueue <- msgInfo{msg: &VoteMessage{valIndex, vote}}
  116. // added, err := to.TryAddVote(valIndex, vote, "")
  117. /*
  118. if _, ok := err.(*types.ErrVoteConflictingSignature); ok {
  119. // let it fly
  120. } else if !added {
  121. fmt.Println("to, from, vote:", to.Height, from.Height, vote.Height)
  122. panic(fmt.Sprintln("Failed to add vote. Err:", err))
  123. } else if err != nil {
  124. panic(fmt.Sprintln("Failed to add vote:", err))
  125. }*/
  126. }
  127. func signVoteMany(voteType byte, hash []byte, header types.PartSetHeader, vss ...*validatorStub) []*types.Vote {
  128. votes := make([]*types.Vote, len(vss))
  129. for i, vs := range vss {
  130. votes[i] = signVote(vs, voteType, hash, header)
  131. }
  132. return votes
  133. }
  134. // add vote to one cs from another
  135. func signAddVoteToFromMany(voteType byte, to *ConsensusState, hash []byte, header types.PartSetHeader, froms ...*validatorStub) {
  136. for _, from := range froms {
  137. vote := signVote(from, voteType, hash, header)
  138. addVoteToFrom(to, from, vote)
  139. }
  140. }
  141. func signAddVoteToFrom(voteType byte, to *ConsensusState, from *validatorStub, hash []byte, header types.PartSetHeader) *types.Vote {
  142. vote := signVote(from, voteType, hash, header)
  143. addVoteToFrom(to, from, vote)
  144. return vote
  145. }
  146. func ensureNoNewStep(t *testing.T, cs *ConsensusState) {
  147. timeout := time.NewTicker(ensureTimeout * time.Second)
  148. select {
  149. case <-timeout.C:
  150. break
  151. case <-cs.NewStepCh():
  152. panic("We should be stuck waiting for more votes, not moving to the next step")
  153. }
  154. }
  155. func ensureNewStep(t *testing.T, cs *ConsensusState) *RoundState {
  156. timeout := time.NewTicker(ensureTimeout * time.Second)
  157. select {
  158. case <-timeout.C:
  159. panic("We should have gone to the next step, not be stuck waiting")
  160. case rs := <-cs.NewStepCh():
  161. return rs
  162. }
  163. }
  164. func waitFor(t *testing.T, cs *ConsensusState, height int, round int, step RoundStepType) {
  165. for {
  166. rs := ensureNewStep(t, cs)
  167. if CompareHRS(rs.Height, rs.Round, rs.Step, height, round, step) < 0 {
  168. continue
  169. } else {
  170. break
  171. }
  172. }
  173. }
  174. func validatePrevote(t *testing.T, cs *ConsensusState, round int, privVal *validatorStub, blockHash []byte) {
  175. prevotes := cs.Votes.Prevotes(round)
  176. var vote *types.Vote
  177. if vote = prevotes.GetByAddress(privVal.Address); vote == nil {
  178. panic("Failed to find prevote from validator")
  179. }
  180. if blockHash == nil {
  181. if vote.BlockHash != nil {
  182. panic(fmt.Sprintf("Expected prevote to be for nil, got %X", vote.BlockHash))
  183. }
  184. } else {
  185. if !bytes.Equal(vote.BlockHash, blockHash) {
  186. panic(fmt.Sprintf("Expected prevote to be for %X, got %X", blockHash, vote.BlockHash))
  187. }
  188. }
  189. }
  190. func incrementHeight(vss ...*validatorStub) {
  191. for _, vs := range vss {
  192. vs.Height += 1
  193. }
  194. }
  195. func incrementRound(vss ...*validatorStub) {
  196. for _, vs := range vss {
  197. vs.Round += 1
  198. }
  199. }
  200. func validatePrecommit(t *testing.T, cs *ConsensusState, thisRound, lockRound int, privVal *validatorStub, votedBlockHash, lockedBlockHash []byte) {
  201. precommits := cs.Votes.Precommits(thisRound)
  202. var vote *types.Vote
  203. if vote = precommits.GetByAddress(privVal.Address); vote == nil {
  204. panic("Failed to find precommit from validator")
  205. }
  206. if votedBlockHash == nil {
  207. if vote.BlockHash != nil {
  208. panic("Expected precommit to be for nil")
  209. }
  210. } else {
  211. if !bytes.Equal(vote.BlockHash, votedBlockHash) {
  212. panic("Expected precommit to be for proposal block")
  213. }
  214. }
  215. if lockedBlockHash == nil {
  216. if cs.LockedRound != lockRound || cs.LockedBlock != nil {
  217. 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))
  218. }
  219. } else {
  220. if cs.LockedRound != lockRound || !bytes.Equal(cs.LockedBlock.Hash(), lockedBlockHash) {
  221. 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))
  222. }
  223. }
  224. }
  225. func validatePrevoteAndPrecommit(t *testing.T, cs *ConsensusState, thisRound, lockRound int, privVal *validatorStub, votedBlockHash, lockedBlockHash []byte) {
  226. // verify the prevote
  227. validatePrevote(t, cs, thisRound, privVal, votedBlockHash)
  228. // verify precommit
  229. cs.mtx.Lock()
  230. validatePrecommit(t, cs, thisRound, lockRound, privVal, votedBlockHash, lockedBlockHash)
  231. cs.mtx.Unlock()
  232. }
  233. func simpleConsensusState(nValidators int) (*ConsensusState, []*validatorStub) {
  234. // Get State
  235. state, privVals := randGenesisState(nValidators, false, 10)
  236. // fmt.Println(state.Validators)
  237. vss := make([]*validatorStub, nValidators)
  238. // make consensus state for lead validator
  239. // Get BlockStore
  240. blockDB := dbm.NewMemDB()
  241. blockStore := bc.NewBlockStore(blockDB)
  242. // one for mempool, one for consensus
  243. app := example.NewCounterApplication()
  244. appCMem := app.Open()
  245. appCCon := app.Open()
  246. proxyAppCtxMem := proxy.NewLocalAppContext(appCMem)
  247. proxyAppCtxCon := proxy.NewLocalAppContext(appCCon)
  248. // Make Mempool
  249. mempool := mempl.NewMempool(proxyAppCtxMem)
  250. // Make ConsensusReactor
  251. cs := NewConsensusState(state, proxyAppCtxCon, blockStore, mempool)
  252. cs.SetPrivValidator(privVals[0])
  253. // from the updateToState in NewConsensusState
  254. <-cs.NewStepCh()
  255. evsw := events.NewEventSwitch()
  256. cs.SetFireable(evsw)
  257. evsw.OnStart()
  258. go func() {
  259. for {
  260. <-cs.NewStepCh()
  261. }
  262. }()
  263. // start the transition routines
  264. // cs.startRoutines()
  265. for i := 0; i < nValidators; i++ {
  266. vss[i] = NewValidatorStub(privVals[i])
  267. }
  268. // since cs1 starts at 1
  269. incrementHeight(vss[1:]...)
  270. return cs, vss
  271. }
  272. func subscribeToEvent(cs *ConsensusState, eventID string) chan interface{} {
  273. evsw := cs.evsw.(*events.EventSwitch)
  274. // listen for new round
  275. ch := make(chan interface{}, 10)
  276. evsw.AddListenerForEvent("tester", eventID, func(data types.EventData) {
  277. ch <- data
  278. })
  279. return ch
  280. }
  281. func randGenesisState(numValidators int, randPower bool, minPower int64) (*sm.State, []*types.PrivValidator) {
  282. db := dbm.NewMemDB()
  283. genDoc, privValidators := randGenesisDoc(numValidators, randPower, minPower)
  284. s0 := sm.MakeGenesisState(db, genDoc)
  285. s0.Save()
  286. return s0, privValidators
  287. }
  288. func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.GenesisDoc, []*types.PrivValidator) {
  289. validators := make([]types.GenesisValidator, numValidators)
  290. privValidators := make([]*types.PrivValidator, numValidators)
  291. for i := 0; i < numValidators; i++ {
  292. val, privVal := types.RandValidator(randPower, minPower)
  293. validators[i] = types.GenesisValidator{
  294. PubKey: val.PubKey,
  295. Amount: val.VotingPower,
  296. }
  297. privValidators[i] = privVal
  298. }
  299. sort.Sort(types.PrivValidatorsByAddress(privValidators))
  300. return &types.GenesisDoc{
  301. GenesisTime: time.Now(),
  302. ChainID: config.GetString("chain_id"),
  303. Validators: validators,
  304. }, privValidators
  305. }
  306. func startTestRound(cs *ConsensusState, height, round int) {
  307. cs.EnterNewRound(height, round)
  308. cs.startRoutines(0)
  309. }