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.

471 lines
14 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
9 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. package consensus
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io/ioutil"
  6. "os"
  7. "path"
  8. "sort"
  9. "sync"
  10. "testing"
  11. "time"
  12. abcicli "github.com/tendermint/abci/client"
  13. abci "github.com/tendermint/abci/types"
  14. bc "github.com/tendermint/tendermint/blockchain"
  15. cfg "github.com/tendermint/tendermint/config"
  16. mempl "github.com/tendermint/tendermint/mempool"
  17. "github.com/tendermint/tendermint/p2p"
  18. sm "github.com/tendermint/tendermint/state"
  19. "github.com/tendermint/tendermint/types"
  20. . "github.com/tendermint/tmlibs/common"
  21. dbm "github.com/tendermint/tmlibs/db"
  22. "github.com/tendermint/tmlibs/log"
  23. "github.com/tendermint/abci/example/counter"
  24. "github.com/tendermint/abci/example/dummy"
  25. )
  26. // genesis, chain_id, priv_val
  27. var config *cfg.Config // NOTE: must be reset for each _test.go file
  28. var ensureTimeout = time.Duration(2)
  29. func ensureDir(dir string, mode os.FileMode) {
  30. if err := EnsureDir(dir, mode); err != nil {
  31. panic(err)
  32. }
  33. }
  34. func ResetConfig(name string) *cfg.Config {
  35. return cfg.ResetTestRoot(name)
  36. }
  37. //-------------------------------------------------------------------------------
  38. // validator stub (a dummy consensus peer we control)
  39. type validatorStub struct {
  40. Index int // Validator index. NOTE: we don't assume validator set changes.
  41. Height int
  42. Round int
  43. *types.PrivValidator
  44. }
  45. var testMinPower = 10
  46. func NewValidatorStub(privValidator *types.PrivValidator, valIndex int) *validatorStub {
  47. return &validatorStub{
  48. Index: valIndex,
  49. PrivValidator: privValidator,
  50. }
  51. }
  52. func (vs *validatorStub) signVote(voteType byte, hash []byte, header types.PartSetHeader) (*types.Vote, error) {
  53. vote := &types.Vote{
  54. ValidatorIndex: vs.Index,
  55. ValidatorAddress: vs.PrivValidator.Address,
  56. Height: vs.Height,
  57. Round: vs.Round,
  58. Type: voteType,
  59. BlockID: types.BlockID{hash, header},
  60. }
  61. err := vs.PrivValidator.SignVote(config.ChainID, vote)
  62. return vote, err
  63. }
  64. // Sign vote for type/hash/header
  65. func signVote(vs *validatorStub, voteType byte, hash []byte, header types.PartSetHeader) *types.Vote {
  66. v, err := vs.signVote(voteType, hash, header)
  67. if err != nil {
  68. panic(fmt.Errorf("failed to sign vote: %v", err))
  69. }
  70. return v
  71. }
  72. func signVotes(voteType byte, hash []byte, header types.PartSetHeader, vss ...*validatorStub) []*types.Vote {
  73. votes := make([]*types.Vote, len(vss))
  74. for i, vs := range vss {
  75. votes[i] = signVote(vs, voteType, hash, header)
  76. }
  77. return votes
  78. }
  79. func incrementHeight(vss ...*validatorStub) {
  80. for _, vs := range vss {
  81. vs.Height += 1
  82. }
  83. }
  84. func incrementRound(vss ...*validatorStub) {
  85. for _, vs := range vss {
  86. vs.Round += 1
  87. }
  88. }
  89. //-------------------------------------------------------------------------------
  90. // Functions for transitioning the consensus state
  91. func startTestRound(cs *ConsensusState, height, round int) {
  92. cs.enterNewRound(height, round)
  93. cs.startRoutines(0)
  94. }
  95. // Create proposal block from cs1 but sign it with vs
  96. func decideProposal(cs1 *ConsensusState, vs *validatorStub, height, round int) (proposal *types.Proposal, block *types.Block) {
  97. block, blockParts := cs1.createProposalBlock()
  98. if block == nil { // on error
  99. panic("error creating proposal block")
  100. }
  101. // Make proposal
  102. polRound, polBlockID := cs1.Votes.POLInfo()
  103. proposal = types.NewProposal(height, round, blockParts.Header(), polRound, polBlockID)
  104. if err := vs.SignProposal(config.ChainID, proposal); err != nil {
  105. panic(err)
  106. }
  107. return
  108. }
  109. func addVotes(to *ConsensusState, votes ...*types.Vote) {
  110. for _, vote := range votes {
  111. to.peerMsgQueue <- msgInfo{Msg: &VoteMessage{vote}}
  112. }
  113. }
  114. func signAddVotes(to *ConsensusState, voteType byte, hash []byte, header types.PartSetHeader, vss ...*validatorStub) {
  115. votes := signVotes(voteType, hash, header, vss...)
  116. addVotes(to, votes...)
  117. }
  118. func validatePrevote(t *testing.T, cs *ConsensusState, round int, privVal *validatorStub, blockHash []byte) {
  119. prevotes := cs.Votes.Prevotes(round)
  120. var vote *types.Vote
  121. if vote = prevotes.GetByAddress(privVal.Address); vote == nil {
  122. panic("Failed to find prevote from validator")
  123. }
  124. if blockHash == nil {
  125. if vote.BlockID.Hash != nil {
  126. panic(fmt.Sprintf("Expected prevote to be for nil, got %X", vote.BlockID.Hash))
  127. }
  128. } else {
  129. if !bytes.Equal(vote.BlockID.Hash, blockHash) {
  130. panic(fmt.Sprintf("Expected prevote to be for %X, got %X", blockHash, vote.BlockID.Hash))
  131. }
  132. }
  133. }
  134. func validateLastPrecommit(t *testing.T, cs *ConsensusState, privVal *validatorStub, blockHash []byte) {
  135. votes := cs.LastCommit
  136. var vote *types.Vote
  137. if vote = votes.GetByAddress(privVal.Address); vote == nil {
  138. panic("Failed to find precommit from validator")
  139. }
  140. if !bytes.Equal(vote.BlockID.Hash, blockHash) {
  141. panic(fmt.Sprintf("Expected precommit to be for %X, got %X", blockHash, vote.BlockID.Hash))
  142. }
  143. }
  144. func validatePrecommit(t *testing.T, cs *ConsensusState, thisRound, lockRound int, privVal *validatorStub, votedBlockHash, lockedBlockHash []byte) {
  145. precommits := cs.Votes.Precommits(thisRound)
  146. var vote *types.Vote
  147. if vote = precommits.GetByAddress(privVal.Address); vote == nil {
  148. panic("Failed to find precommit from validator")
  149. }
  150. if votedBlockHash == nil {
  151. if vote.BlockID.Hash != nil {
  152. panic("Expected precommit to be for nil")
  153. }
  154. } else {
  155. if !bytes.Equal(vote.BlockID.Hash, votedBlockHash) {
  156. panic("Expected precommit to be for proposal block")
  157. }
  158. }
  159. if lockedBlockHash == nil {
  160. if cs.LockedRound != lockRound || cs.LockedBlock != nil {
  161. 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))
  162. }
  163. } else {
  164. if cs.LockedRound != lockRound || !bytes.Equal(cs.LockedBlock.Hash(), lockedBlockHash) {
  165. 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))
  166. }
  167. }
  168. }
  169. func validatePrevoteAndPrecommit(t *testing.T, cs *ConsensusState, thisRound, lockRound int, privVal *validatorStub, votedBlockHash, lockedBlockHash []byte) {
  170. // verify the prevote
  171. validatePrevote(t, cs, thisRound, privVal, votedBlockHash)
  172. // verify precommit
  173. cs.mtx.Lock()
  174. validatePrecommit(t, cs, thisRound, lockRound, privVal, votedBlockHash, lockedBlockHash)
  175. cs.mtx.Unlock()
  176. }
  177. // genesis
  178. func subscribeToVoter(cs *ConsensusState, addr []byte) chan interface{} {
  179. voteCh0 := subscribeToEvent(cs.evsw, "tester", types.EventStringVote(), 1)
  180. voteCh := make(chan interface{})
  181. go func() {
  182. for {
  183. v := <-voteCh0
  184. vote := v.(types.TMEventData).Unwrap().(types.EventDataVote)
  185. // we only fire for our own votes
  186. if bytes.Equal(addr, vote.Vote.ValidatorAddress) {
  187. voteCh <- v
  188. }
  189. }
  190. }()
  191. return voteCh
  192. }
  193. func readVotes(ch chan interface{}, reads int) chan struct{} {
  194. wg := make(chan struct{})
  195. go func() {
  196. for i := 0; i < reads; i++ {
  197. <-ch // read the precommit event
  198. }
  199. close(wg)
  200. }()
  201. return wg
  202. }
  203. //-------------------------------------------------------------------------------
  204. // consensus states
  205. func newConsensusState(state *sm.State, pv *types.PrivValidator, app abci.Application) *ConsensusState {
  206. return newConsensusStateWithConfig(config, state, pv, app)
  207. }
  208. func newConsensusStateWithConfig(thisConfig *cfg.Config, state *sm.State, pv *types.PrivValidator, app abci.Application) *ConsensusState {
  209. // Get BlockStore
  210. blockDB := dbm.NewMemDB()
  211. blockStore := bc.NewBlockStore(blockDB)
  212. // one for mempool, one for consensus
  213. mtx := new(sync.Mutex)
  214. proxyAppConnMem := abcicli.NewLocalClient(mtx, app)
  215. proxyAppConnCon := abcicli.NewLocalClient(mtx, app)
  216. // Make Mempool
  217. mempool := mempl.NewMempool(thisConfig.Mempool, proxyAppConnMem)
  218. mempool.SetLogger(log.TestingLogger().With("module", "mempool"))
  219. // Make ConsensusReactor
  220. cs := NewConsensusState(thisConfig.Consensus, state, proxyAppConnCon, blockStore, mempool)
  221. cs.SetLogger(log.TestingLogger())
  222. cs.SetPrivValidator(pv)
  223. evsw := types.NewEventSwitch()
  224. evsw.SetLogger(log.TestingLogger().With("module", "events"))
  225. cs.SetEventSwitch(evsw)
  226. evsw.Start()
  227. return cs
  228. }
  229. func loadPrivValidator(config *cfg.Config) *types.PrivValidator {
  230. privValidatorFile := config.PrivValidatorFile()
  231. ensureDir(path.Dir(privValidatorFile), 0700)
  232. privValidator := types.LoadOrGenPrivValidator(privValidatorFile, log.TestingLogger())
  233. privValidator.Reset()
  234. return privValidator
  235. }
  236. func fixedConsensusState() *ConsensusState {
  237. stateDB := dbm.NewMemDB()
  238. state := sm.MakeGenesisStateFromFile(stateDB, config.GenesisFile())
  239. state.SetLogger(log.TestingLogger().With("module", "state"))
  240. privValidator := loadPrivValidator(config)
  241. cs := newConsensusState(state, privValidator, counter.NewCounterApplication(true))
  242. cs.SetLogger(log.TestingLogger())
  243. return cs
  244. }
  245. func fixedConsensusStateDummy() *ConsensusState {
  246. stateDB := dbm.NewMemDB()
  247. state := sm.MakeGenesisStateFromFile(stateDB, config.GenesisFile())
  248. state.SetLogger(log.TestingLogger().With("module", "state"))
  249. privValidator := loadPrivValidator(config)
  250. cs := newConsensusState(state, privValidator, dummy.NewDummyApplication())
  251. cs.SetLogger(log.TestingLogger())
  252. return cs
  253. }
  254. func randConsensusState(nValidators int) (*ConsensusState, []*validatorStub) {
  255. // Get State
  256. state, privVals := randGenesisState(nValidators, false, 10)
  257. vss := make([]*validatorStub, nValidators)
  258. cs := newConsensusState(state, privVals[0], counter.NewCounterApplication(true))
  259. cs.SetLogger(log.TestingLogger())
  260. for i := 0; i < nValidators; i++ {
  261. vss[i] = NewValidatorStub(privVals[i], i)
  262. }
  263. // since cs1 starts at 1
  264. incrementHeight(vss[1:]...)
  265. return cs, vss
  266. }
  267. //-------------------------------------------------------------------------------
  268. func ensureNoNewStep(stepCh chan interface{}) {
  269. timeout := time.NewTicker(ensureTimeout * time.Second)
  270. select {
  271. case <-timeout.C:
  272. break
  273. case <-stepCh:
  274. panic("We should be stuck waiting for more votes, not moving to the next step")
  275. }
  276. }
  277. //-------------------------------------------------------------------------------
  278. // consensus nets
  279. func randConsensusNet(nValidators int, testName string, tickerFunc func() TimeoutTicker, appFunc func() abci.Application) []*ConsensusState {
  280. genDoc, privVals := randGenesisDoc(nValidators, false, 10)
  281. css := make([]*ConsensusState, nValidators)
  282. for i := 0; i < nValidators; i++ {
  283. db := dbm.NewMemDB() // each state needs its own db
  284. state := sm.MakeGenesisState(db, genDoc)
  285. state.SetLogger(log.TestingLogger().With("module", "state"))
  286. state.Save()
  287. thisConfig := ResetConfig(Fmt("%s_%d", testName, i))
  288. ensureDir(path.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
  289. css[i] = newConsensusStateWithConfig(thisConfig, state, privVals[i], appFunc())
  290. css[i].SetLogger(log.TestingLogger())
  291. css[i].SetTimeoutTicker(tickerFunc())
  292. }
  293. return css
  294. }
  295. // nPeers = nValidators + nNotValidator
  296. func randConsensusNetWithPeers(nValidators, nPeers int, testName string, tickerFunc func() TimeoutTicker, appFunc func() abci.Application) []*ConsensusState {
  297. genDoc, privVals := randGenesisDoc(nValidators, false, int64(testMinPower))
  298. css := make([]*ConsensusState, nPeers)
  299. for i := 0; i < nPeers; i++ {
  300. db := dbm.NewMemDB() // each state needs its own db
  301. state := sm.MakeGenesisState(db, genDoc)
  302. state.SetLogger(log.TestingLogger().With("module", "state"))
  303. state.Save()
  304. thisConfig := ResetConfig(Fmt("%s_%d", testName, i))
  305. ensureDir(path.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
  306. var privVal *types.PrivValidator
  307. if i < nValidators {
  308. privVal = privVals[i]
  309. } else {
  310. privVal = types.GenPrivValidator()
  311. _, tempFilePath := Tempfile("priv_validator_")
  312. privVal.SetFile(tempFilePath)
  313. }
  314. css[i] = newConsensusStateWithConfig(thisConfig, state, privVal, appFunc())
  315. css[i].SetLogger(log.TestingLogger())
  316. css[i].SetTimeoutTicker(tickerFunc())
  317. }
  318. return css
  319. }
  320. func getSwitchIndex(switches []*p2p.Switch, peer *p2p.Peer) int {
  321. for i, s := range switches {
  322. if bytes.Equal(peer.NodeInfo.PubKey.Address(), s.NodeInfo().PubKey.Address()) {
  323. return i
  324. }
  325. }
  326. panic("didnt find peer in switches")
  327. return -1
  328. }
  329. //-------------------------------------------------------------------------------
  330. // genesis
  331. func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.GenesisDoc, []*types.PrivValidator) {
  332. validators := make([]types.GenesisValidator, numValidators)
  333. privValidators := make([]*types.PrivValidator, numValidators)
  334. for i := 0; i < numValidators; i++ {
  335. val, privVal := types.RandValidator(randPower, minPower)
  336. validators[i] = types.GenesisValidator{
  337. PubKey: val.PubKey,
  338. Amount: val.VotingPower,
  339. }
  340. privValidators[i] = privVal
  341. }
  342. sort.Sort(types.PrivValidatorsByAddress(privValidators))
  343. return &types.GenesisDoc{
  344. GenesisTime: time.Now(),
  345. ChainID: config.ChainID,
  346. Validators: validators,
  347. }, privValidators
  348. }
  349. func randGenesisState(numValidators int, randPower bool, minPower int64) (*sm.State, []*types.PrivValidator) {
  350. genDoc, privValidators := randGenesisDoc(numValidators, randPower, minPower)
  351. db := dbm.NewMemDB()
  352. s0 := sm.MakeGenesisState(db, genDoc)
  353. s0.SetLogger(log.TestingLogger().With("module", "state"))
  354. s0.Save()
  355. return s0, privValidators
  356. }
  357. //------------------------------------
  358. // mock ticker
  359. func newMockTickerFunc(onlyOnce bool) func() TimeoutTicker {
  360. return func() TimeoutTicker {
  361. return &mockTicker{
  362. c: make(chan timeoutInfo, 10),
  363. onlyOnce: onlyOnce,
  364. }
  365. }
  366. }
  367. // mock ticker only fires on RoundStepNewHeight
  368. // and only once if onlyOnce=true
  369. type mockTicker struct {
  370. c chan timeoutInfo
  371. mtx sync.Mutex
  372. onlyOnce bool
  373. fired bool
  374. }
  375. func (m *mockTicker) Start() (bool, error) {
  376. return true, nil
  377. }
  378. func (m *mockTicker) Stop() bool {
  379. return true
  380. }
  381. func (m *mockTicker) ScheduleTimeout(ti timeoutInfo) {
  382. m.mtx.Lock()
  383. defer m.mtx.Unlock()
  384. if m.onlyOnce && m.fired {
  385. return
  386. }
  387. if ti.Step == RoundStepNewHeight {
  388. m.c <- ti
  389. m.fired = true
  390. }
  391. }
  392. func (m *mockTicker) Chan() <-chan timeoutInfo {
  393. return m.c
  394. }
  395. func (mockTicker) SetLogger(log.Logger) {
  396. }
  397. //------------------------------------
  398. func newCounter() abci.Application {
  399. return counter.NewCounterApplication(true)
  400. }
  401. func newPersistentDummy() abci.Application {
  402. dir, _ := ioutil.TempDir("/tmp", "persistent-dummy")
  403. return dummy.NewPersistentDummyApplication(dir)
  404. }