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.

466 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
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
  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.Duration(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.Address,
  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.Address); 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.Address); 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.Address); 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)
  209. mempool.SetLogger(log.TestingLogger().With("module", "mempool"))
  210. // Make ConsensusReactor
  211. cs := NewConsensusState(thisConfig.Consensus, state, proxyAppConnCon, blockStore, mempool)
  212. cs.SetLogger(log.TestingLogger())
  213. cs.SetPrivValidator(pv)
  214. evsw := types.NewEventSwitch()
  215. evsw.SetLogger(log.TestingLogger().With("module", "events"))
  216. cs.SetEventSwitch(evsw)
  217. evsw.Start()
  218. return cs
  219. }
  220. func loadPrivValidator(config *cfg.Config) *types.PrivValidator {
  221. privValidatorFile := config.PrivValidatorFile()
  222. ensureDir(path.Dir(privValidatorFile), 0700)
  223. privValidator := types.LoadOrGenPrivValidator(privValidatorFile, log.TestingLogger())
  224. privValidator.Reset()
  225. return privValidator
  226. }
  227. func fixedConsensusStateDummy() *ConsensusState {
  228. stateDB := dbm.NewMemDB()
  229. state := sm.MakeGenesisStateFromFile(stateDB, config.GenesisFile())
  230. state.SetLogger(log.TestingLogger().With("module", "state"))
  231. privValidator := loadPrivValidator(config)
  232. cs := newConsensusState(state, privValidator, dummy.NewDummyApplication())
  233. cs.SetLogger(log.TestingLogger())
  234. return cs
  235. }
  236. func randConsensusState(nValidators int) (*ConsensusState, []*validatorStub) {
  237. // Get State
  238. state, privVals := randGenesisState(nValidators, false, 10)
  239. vss := make([]*validatorStub, nValidators)
  240. cs := newConsensusState(state, privVals[0], counter.NewCounterApplication(true))
  241. cs.SetLogger(log.TestingLogger())
  242. for i := 0; i < nValidators; i++ {
  243. vss[i] = NewValidatorStub(privVals[i], i)
  244. }
  245. // since cs1 starts at 1
  246. incrementHeight(vss[1:]...)
  247. return cs, vss
  248. }
  249. //-------------------------------------------------------------------------------
  250. func ensureNoNewStep(stepCh chan interface{}) {
  251. timeout := time.NewTicker(ensureTimeout * time.Second)
  252. select {
  253. case <-timeout.C:
  254. break
  255. case <-stepCh:
  256. panic("We should be stuck waiting for more votes, not moving to the next step")
  257. }
  258. }
  259. //-------------------------------------------------------------------------------
  260. // consensus nets
  261. // consensusLogger is a TestingLogger which uses a different
  262. // color for each validator ("validator" key must exist).
  263. func consensusLogger() log.Logger {
  264. return log.TestingLoggerWithColorFn(func(keyvals ...interface{}) term.FgBgColor {
  265. for i := 0; i < len(keyvals)-1; i += 2 {
  266. if keyvals[i] == "validator" {
  267. return term.FgBgColor{Fg: term.Color(uint8(keyvals[i+1].(int) + 1))}
  268. }
  269. }
  270. return term.FgBgColor{}
  271. })
  272. }
  273. func randConsensusNet(nValidators int, testName string, tickerFunc func() TimeoutTicker, appFunc func() abci.Application) []*ConsensusState {
  274. genDoc, privVals := randGenesisDoc(nValidators, false, 10)
  275. css := make([]*ConsensusState, nValidators)
  276. logger := consensusLogger()
  277. for i := 0; i < nValidators; i++ {
  278. db := dbm.NewMemDB() // each state needs its own db
  279. state := sm.MakeGenesisState(db, genDoc)
  280. state.SetLogger(logger.With("module", "state", "validator", i))
  281. state.Save()
  282. thisConfig := ResetConfig(Fmt("%s_%d", testName, i))
  283. ensureDir(path.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
  284. css[i] = newConsensusStateWithConfig(thisConfig, state, privVals[i], appFunc())
  285. css[i].SetLogger(logger.With("validator", i))
  286. css[i].SetTimeoutTicker(tickerFunc())
  287. }
  288. return css
  289. }
  290. // nPeers = nValidators + nNotValidator
  291. func randConsensusNetWithPeers(nValidators, nPeers int, testName string, tickerFunc func() TimeoutTicker, appFunc func() abci.Application) []*ConsensusState {
  292. genDoc, privVals := randGenesisDoc(nValidators, false, int64(testMinPower))
  293. css := make([]*ConsensusState, nPeers)
  294. for i := 0; i < nPeers; i++ {
  295. db := dbm.NewMemDB() // each state needs its own db
  296. state := sm.MakeGenesisState(db, genDoc)
  297. state.SetLogger(log.TestingLogger().With("module", "state"))
  298. state.Save()
  299. thisConfig := ResetConfig(Fmt("%s_%d", testName, i))
  300. ensureDir(path.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
  301. var privVal *types.PrivValidator
  302. if i < nValidators {
  303. privVal = privVals[i]
  304. } else {
  305. privVal = types.GenPrivValidator()
  306. _, tempFilePath := Tempfile("priv_validator_")
  307. privVal.SetFile(tempFilePath)
  308. }
  309. css[i] = newConsensusStateWithConfig(thisConfig, state, privVal, appFunc())
  310. css[i].SetLogger(log.TestingLogger())
  311. css[i].SetTimeoutTicker(tickerFunc())
  312. }
  313. return css
  314. }
  315. func getSwitchIndex(switches []*p2p.Switch, peer *p2p.Peer) int {
  316. for i, s := range switches {
  317. if bytes.Equal(peer.NodeInfo.PubKey.Address(), s.NodeInfo().PubKey.Address()) {
  318. return i
  319. }
  320. }
  321. panic("didnt find peer in switches")
  322. return -1
  323. }
  324. //-------------------------------------------------------------------------------
  325. // genesis
  326. func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.GenesisDoc, []*types.PrivValidator) {
  327. validators := make([]types.GenesisValidator, numValidators)
  328. privValidators := make([]*types.PrivValidator, numValidators)
  329. for i := 0; i < numValidators; i++ {
  330. val, privVal := types.RandValidator(randPower, minPower)
  331. validators[i] = types.GenesisValidator{
  332. PubKey: val.PubKey,
  333. Amount: val.VotingPower,
  334. }
  335. privValidators[i] = privVal
  336. }
  337. sort.Sort(types.PrivValidatorsByAddress(privValidators))
  338. return &types.GenesisDoc{
  339. GenesisTime: time.Now(),
  340. ChainID: config.ChainID,
  341. Validators: validators,
  342. }, privValidators
  343. }
  344. func randGenesisState(numValidators int, randPower bool, minPower int64) (*sm.State, []*types.PrivValidator) {
  345. genDoc, privValidators := randGenesisDoc(numValidators, randPower, minPower)
  346. db := dbm.NewMemDB()
  347. s0 := sm.MakeGenesisState(db, genDoc)
  348. s0.SetLogger(log.TestingLogger().With("module", "state"))
  349. s0.Save()
  350. return s0, privValidators
  351. }
  352. //------------------------------------
  353. // mock ticker
  354. func newMockTickerFunc(onlyOnce bool) func() TimeoutTicker {
  355. return func() TimeoutTicker {
  356. return &mockTicker{
  357. c: make(chan timeoutInfo, 10),
  358. onlyOnce: onlyOnce,
  359. }
  360. }
  361. }
  362. // mock ticker only fires on RoundStepNewHeight
  363. // and only once if onlyOnce=true
  364. type mockTicker struct {
  365. c chan timeoutInfo
  366. mtx sync.Mutex
  367. onlyOnce bool
  368. fired bool
  369. }
  370. func (m *mockTicker) Start() (bool, error) {
  371. return true, nil
  372. }
  373. func (m *mockTicker) Stop() bool {
  374. return true
  375. }
  376. func (m *mockTicker) ScheduleTimeout(ti timeoutInfo) {
  377. m.mtx.Lock()
  378. defer m.mtx.Unlock()
  379. if m.onlyOnce && m.fired {
  380. return
  381. }
  382. if ti.Step == RoundStepNewHeight {
  383. m.c <- ti
  384. m.fired = true
  385. }
  386. }
  387. func (m *mockTicker) Chan() <-chan timeoutInfo {
  388. return m.c
  389. }
  390. func (mockTicker) SetLogger(log.Logger) {
  391. }
  392. //------------------------------------
  393. func newCounter() abci.Application {
  394. return counter.NewCounterApplication(true)
  395. }
  396. func newPersistentDummy() abci.Application {
  397. dir, _ := ioutil.TempDir("/tmp", "persistent-dummy")
  398. return dummy.NewPersistentDummyApplication(dir)
  399. }