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.

481 lines
14 KiB

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