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.

1148 lines
38 KiB

9 years ago
9 years ago
9 years ago
  1. package consensus
  2. import (
  3. "bytes"
  4. "fmt"
  5. "testing"
  6. "time"
  7. _ "github.com/tendermint/tendermint/config/tendermint_test"
  8. "github.com/tendermint/tendermint/events"
  9. "github.com/tendermint/tendermint/types"
  10. )
  11. /*
  12. ProposeSuite
  13. x * TestEnterProposeNoValidator - timeout into prevote round
  14. x * TestEnterPropose - finish propose without timing out (we have the proposal)
  15. x * TestBadProposal - 2 vals, bad proposal (bad block state hash), should prevote and precommit nil
  16. FullRoundSuite
  17. x * TestFullRound1 - 1 val, full successful round
  18. x * TestFullRoundNil - 1 val, full round of nil
  19. x * TestFullRound2 - 2 vals, both required for fuill round
  20. LockSuite
  21. x * TestLockNoPOL - 2 vals, 4 rounds. one val locked, precommits nil every round except first.
  22. x * TestLockPOLRelock - 4 vals, one precommits, other 3 polka at next round, so we unlock and precomit the polka
  23. x * TestLockPOLUnlock - 4 vals, one precommits, other 3 polka nil at next round, so we unlock and precomit nil
  24. x * TestLockPOLSafety1 - 4 vals. We shouldn't change lock based on polka at earlier round
  25. x * TestLockPOLSafety2 - 4 vals. After unlocking, we shouldn't relock based on polka at earlier round
  26. * TestNetworkLock - once +1/3 precommits, network should be locked
  27. * TestNetworkLockPOL - once +1/3 precommits, the block with more recent polka is committed
  28. SlashingSuite
  29. x * TestSlashingPrevotes - a validator prevoting twice in a round gets slashed
  30. x * TestSlashingPrecommits - a validator precomitting twice in a round gets slashed
  31. CatchupSuite
  32. * TestCatchup - if we might be behind and we've seen any 2/3 prevotes, round skip to new round, precommit, or prevote
  33. HaltSuite
  34. x * TestHalt1 - if we see +2/3 precommits after timing out into new round, we should still commit
  35. */
  36. //----------------------------------------------------------------------------------------------------
  37. // ProposeSuite
  38. func init() {
  39. fmt.Println("")
  40. timeoutPropose = 1000 * time.Millisecond
  41. }
  42. // a non-validator should timeout into the prevote round
  43. func TestEnterProposeNoPrivValidator(t *testing.T) {
  44. css, _ := simpleConsensusState(1)
  45. cs := css[0]
  46. cs.SetPrivValidator(nil)
  47. timeoutChan := make(chan struct{})
  48. evsw := events.NewEventSwitch()
  49. evsw.OnStart()
  50. evsw.AddListenerForEvent("tester", types.EventStringTimeoutPropose(), func(data types.EventData) {
  51. timeoutChan <- struct{}{}
  52. })
  53. cs.SetFireable(evsw)
  54. // starts a go routine for EnterPropose
  55. cs.EnterNewRound(cs.Height, 0, false)
  56. // go to prevote
  57. <-cs.NewStepCh()
  58. // if we're not a validator, EnterPropose should timeout
  59. select {
  60. case rs := <-cs.NewStepCh():
  61. log.Info(rs.String())
  62. t.Fatal("Expected EnterPropose to timeout")
  63. case <-timeoutChan:
  64. rs := cs.GetRoundState()
  65. if rs.Proposal != nil {
  66. t.Error("Expected to make no proposal, since no privValidator")
  67. }
  68. break
  69. }
  70. }
  71. // a validator should not timeout of the prevote round (TODO: unless the block is really big!)
  72. func TestEnterPropose(t *testing.T) {
  73. css, _ := simpleConsensusState(1)
  74. cs := css[0]
  75. timeoutChan := make(chan struct{})
  76. evsw := events.NewEventSwitch()
  77. evsw.OnStart()
  78. evsw.AddListenerForEvent("tester", types.EventStringTimeoutPropose(), func(data types.EventData) {
  79. timeoutChan <- struct{}{}
  80. })
  81. cs.SetFireable(evsw)
  82. // starts a go routine for EnterPropose
  83. cs.EnterNewRound(cs.Height, 0, false)
  84. // go to prevote
  85. <-cs.NewStepCh()
  86. // if we are a validator, we expect it not to timeout
  87. select {
  88. case <-cs.NewStepCh():
  89. rs := cs.GetRoundState()
  90. // Check that Proposal, ProposalBlock, ProposalBlockParts are set.
  91. if rs.Proposal == nil {
  92. t.Error("rs.Proposal should be set")
  93. }
  94. if rs.ProposalBlock == nil {
  95. t.Error("rs.ProposalBlock should be set")
  96. }
  97. if rs.ProposalBlockParts.Total() == 0 {
  98. t.Error("rs.ProposalBlockParts should be set")
  99. }
  100. break
  101. case <-timeoutChan:
  102. t.Fatal("Expected EnterPropose not to timeout")
  103. }
  104. }
  105. func TestBadProposal(t *testing.T) {
  106. css, privVals := simpleConsensusState(2)
  107. cs1, cs2 := css[0], css[1]
  108. cs1.newStepCh = make(chan *RoundState) // so it blocks
  109. timeoutChan := make(chan struct{})
  110. evsw := events.NewEventSwitch()
  111. evsw.OnStart()
  112. evsw.AddListenerForEvent("tester", types.EventStringTimeoutPropose(), func(data types.EventData) {
  113. timeoutChan <- struct{}{}
  114. })
  115. evsw.AddListenerForEvent("tester", types.EventStringTimeoutWait(), func(data types.EventData) {
  116. timeoutChan <- struct{}{}
  117. })
  118. cs1.SetFireable(evsw)
  119. // make the second validator the proposer
  120. propBlock := changeProposer(t, cs1, cs2)
  121. // make the block bad by tampering with statehash
  122. stateHash := propBlock.StateHash
  123. stateHash[0] = byte((stateHash[0] + 1) % 255)
  124. propBlock.StateHash = stateHash
  125. propBlockParts := propBlock.MakePartSet()
  126. proposal := types.NewProposal(cs2.Height, cs2.Round, propBlockParts.Header(), cs2.Votes.POLRound())
  127. if err := cs2.privValidator.SignProposal(cs2.state.ChainID, proposal); err != nil {
  128. t.Fatal("failed to sign bad proposal", err)
  129. }
  130. // start round
  131. cs1.EnterNewRound(cs1.Height, 0, false)
  132. // now we're on a new round and not the proposer
  133. <-cs1.NewStepCh()
  134. // so set the proposal block (and fix voting power)
  135. cs1.mtx.Lock()
  136. cs1.Proposal, cs1.ProposalBlock, cs1.ProposalBlockParts = proposal, propBlock, propBlockParts
  137. fixVotingPower(t, cs1, privVals[1].Address)
  138. cs1.mtx.Unlock()
  139. // and wait for timeout
  140. <-timeoutChan
  141. // go to prevote, prevote for nil (proposal is bad)
  142. <-cs1.NewStepCh()
  143. validatePrevote(t, cs1, 0, privVals[0], nil)
  144. // add bad prevote from cs2. we should precommit nil
  145. signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, propBlock.Hash(), propBlock.MakePartSet().Header())
  146. _, _, _ = <-cs1.NewStepCh(), <-timeoutChan, <-cs1.NewStepCh()
  147. validatePrecommit(t, cs1, 0, 0, privVals[0], nil, nil)
  148. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, propBlock.Hash(), propBlock.MakePartSet().Header())
  149. }
  150. //----------------------------------------------------------------------------------------------------
  151. // FulLRoundSuite
  152. // propose, prevote, and precommit a block
  153. func TestFullRound1(t *testing.T) {
  154. css, privVals := simpleConsensusState(1)
  155. cs := css[0]
  156. // starts a go routine for EnterPropose
  157. cs.EnterNewRound(cs.Height, 0, false)
  158. // wait to finish propose and prevote
  159. _, _ = <-cs.NewStepCh(), <-cs.NewStepCh()
  160. // we should now be in precommit
  161. // verify our prevote is there
  162. cs.mtx.Lock()
  163. propBlockHash := cs.ProposalBlock.Hash()
  164. cs.mtx.Unlock()
  165. // the proposed block should be prevoted, precommitted, and locked
  166. validatePrevoteAndPrecommit(t, cs, 0, 0, privVals[0], propBlockHash, propBlockHash, nil)
  167. }
  168. // nil is proposed, so prevote and precommit nil
  169. func TestFullRoundNil(t *testing.T) {
  170. css, privVals := simpleConsensusState(1)
  171. cs := css[0]
  172. cs.newStepCh = make(chan *RoundState) // so it blocks
  173. cs.SetPrivValidator(nil)
  174. timeoutChan := make(chan struct{})
  175. evsw := events.NewEventSwitch()
  176. evsw.OnStart()
  177. evsw.AddListenerForEvent("tester", types.EventStringTimeoutPropose(), func(data types.EventData) {
  178. timeoutChan <- struct{}{}
  179. })
  180. cs.SetFireable(evsw)
  181. // starts a go routine for EnterPropose
  182. cs.EnterNewRound(cs.Height, 0, false)
  183. // wait to finish propose (we should time out)
  184. <-cs.NewStepCh()
  185. cs.SetPrivValidator(privVals[0]) // this might be a race condition (uses the mutex that EnterPropose has just released and EnterPrevote is about to grab)
  186. <-timeoutChan
  187. // wait to finish prevote
  188. <-cs.NewStepCh()
  189. // should prevote and precommit nil
  190. validatePrevoteAndPrecommit(t, cs, 0, 0, privVals[0], nil, nil, nil)
  191. }
  192. // run through propose, prevote, precommit commit with two validators
  193. // where the first validator has to wait for votes from the second
  194. func TestFullRound2(t *testing.T) {
  195. css, privVals := simpleConsensusState(2)
  196. cs1, cs2 := css[0], css[1]
  197. cs1.newStepCh = make(chan *RoundState) // so it blocks
  198. cs2.newStepCh = make(chan *RoundState) // so it blocks
  199. // start round and wait for propose and prevote
  200. cs1.EnterNewRound(cs1.Height, 0, false)
  201. _, _ = <-cs1.NewStepCh(), <-cs1.NewStepCh()
  202. // we should now be stuck in limbo forever, waiting for more prevotes
  203. ensureNoNewStep(t, cs1)
  204. propBlockHash, propPartsHeader := cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header()
  205. // prevote arrives from cs2:
  206. signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, propBlockHash, propPartsHeader)
  207. // wait to finish precommit
  208. <-cs1.NewStepCh()
  209. // the proposed block should now be locked and our precommit added
  210. validatePrecommit(t, cs1, 0, 0, privVals[0], propBlockHash, propBlockHash)
  211. // we should now be stuck in limbo forever, waiting for more precommits
  212. ensureNoNewStep(t, cs1)
  213. // precommit arrives from cs2:
  214. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, propBlockHash, propPartsHeader)
  215. // wait to finish commit, propose in next height
  216. _, rs := <-cs1.NewStepCh(), <-cs1.NewStepCh()
  217. if rs.Height != 2 {
  218. t.Fatal("Expected height to increment")
  219. }
  220. }
  221. //------------------------------------------------------------------------------------------
  222. // LockSuite
  223. // two validators, 4 rounds.
  224. // val1 proposes the first 2 rounds, and is locked in the first.
  225. // val2 proposes the next two. val1 should precommit nil on all (except first where he locks)
  226. func TestLockNoPOL(t *testing.T) {
  227. css, privVals := simpleConsensusState(2)
  228. cs1, cs2 := css[0], css[1]
  229. cs1.newStepCh = make(chan *RoundState) // so it blocks
  230. timeoutChan := make(chan struct{})
  231. evsw := events.NewEventSwitch()
  232. evsw.OnStart()
  233. evsw.AddListenerForEvent("tester", types.EventStringTimeoutPropose(), func(data types.EventData) {
  234. timeoutChan <- struct{}{}
  235. })
  236. evsw.AddListenerForEvent("tester", types.EventStringTimeoutWait(), func(data types.EventData) {
  237. timeoutChan <- struct{}{}
  238. })
  239. cs1.SetFireable(evsw)
  240. /*
  241. Round1 (cs1, B) // B B // B B2
  242. */
  243. // start round and wait for propose and prevote
  244. cs1.EnterNewRound(cs1.Height, 0, false)
  245. _, _ = <-cs1.NewStepCh(), <-cs1.NewStepCh()
  246. // we should now be stuck in limbo forever, waiting for more prevotes
  247. // prevote arrives from cs2:
  248. signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header())
  249. cs1.mtx.Lock() // XXX: sigh
  250. theBlockHash := cs1.ProposalBlock.Hash()
  251. cs1.mtx.Unlock()
  252. // wait to finish precommit
  253. <-cs1.NewStepCh()
  254. // the proposed block should now be locked and our precommit added
  255. validatePrecommit(t, cs1, 0, 0, privVals[0], theBlockHash, theBlockHash)
  256. // we should now be stuck in limbo forever, waiting for more precommits
  257. // lets add one for a different block
  258. // NOTE: in practice we should never get to a point where there are precommits for different blocks at the same round
  259. hash := cs1.ProposalBlock.Hash()
  260. hash[0] = byte((hash[0] + 1) % 255)
  261. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, hash, cs1.ProposalBlockParts.Header())
  262. // (note we're entering precommit for a second time this round)
  263. // but with invalid args. then we EnterPrecommitWait, and the timeout to new round
  264. _, _ = <-cs1.NewStepCh(), <-timeoutChan
  265. log.Info("#### ONTO ROUND 2")
  266. /*
  267. Round2 (cs1, B) // B B2
  268. */
  269. incrementRound(cs2)
  270. // go to prevote
  271. <-cs1.NewStepCh()
  272. // now we're on a new round and the proposer
  273. if cs1.ProposalBlock != cs1.LockedBlock {
  274. t.Fatalf("Expected proposal block to be locked block. Got %v, Expected %v", cs1.ProposalBlock, cs1.LockedBlock)
  275. }
  276. // wait to finish prevote
  277. <-cs1.NewStepCh()
  278. // we should have prevoted our locked block
  279. validatePrevote(t, cs1, 1, privVals[0], cs1.LockedBlock.Hash())
  280. // add a conflicting prevote from the other validator
  281. signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, hash, cs1.ProposalBlockParts.Header())
  282. // now we're going to enter prevote again, but with invalid args
  283. // and then prevote wait, which should timeout. then wait for precommit
  284. _, _, _ = <-cs1.NewStepCh(), <-timeoutChan, <-cs1.NewStepCh()
  285. // the proposed block should still be locked and our precommit added
  286. // we should precommit nil and be locked on the proposal
  287. validatePrecommit(t, cs1, 1, 0, privVals[0], nil, theBlockHash)
  288. // add conflicting precommit from cs2
  289. // NOTE: in practice we should never get to a point where there are precommits for different blocks at the same round
  290. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, hash, cs1.ProposalBlockParts.Header())
  291. // (note we're entering precommit for a second time this round, but with invalid args
  292. // then we EnterPrecommitWait and timeout into NewRound
  293. _, _ = <-cs1.NewStepCh(), <-timeoutChan
  294. log.Info("#### ONTO ROUND 3")
  295. /*
  296. Round3 (cs2, _) // B, B2
  297. */
  298. incrementRound(cs2)
  299. // now we're on a new round and not the proposer, so wait for timeout
  300. _, _ = <-cs1.NewStepCh(), <-timeoutChan
  301. if cs1.ProposalBlock != nil {
  302. t.Fatal("Expected proposal block to be nil")
  303. }
  304. // go to prevote, prevote for locked block
  305. <-cs1.NewStepCh()
  306. validatePrevote(t, cs1, 0, privVals[0], cs1.LockedBlock.Hash())
  307. // TODO: quick fastforward to new round, set proposer
  308. signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, hash, cs1.ProposalBlockParts.Header())
  309. _, _, _ = <-cs1.NewStepCh(), <-timeoutChan, <-cs1.NewStepCh()
  310. validatePrecommit(t, cs1, 2, 0, privVals[0], nil, theBlockHash) // precommit nil but be locked on proposal
  311. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, hash, cs1.ProposalBlockParts.Header()) // NOTE: conflicting precommits at same height
  312. <-cs1.NewStepCh()
  313. // before we time out into new round, set next proposer
  314. // and next proposal block
  315. _, v1 := cs1.Validators.GetByAddress(privVals[0].Address)
  316. v1.VotingPower = 1
  317. if updated := cs1.Validators.Update(v1); !updated {
  318. t.Fatal("failed to update validator")
  319. }
  320. cs2.decideProposal(cs2.Height, cs2.Round+1)
  321. prop, propBlock := cs2.Proposal, cs2.ProposalBlock
  322. if prop == nil || propBlock == nil {
  323. t.Fatal("Failed to create proposal block with cs2")
  324. }
  325. incrementRound(cs2)
  326. <-timeoutChan
  327. log.Info("#### ONTO ROUND 4")
  328. /*
  329. Round4 (cs2, C) // B C // B C
  330. */
  331. // now we're on a new round and not the proposer
  332. <-cs1.NewStepCh()
  333. // so set the proposal block
  334. cs1.mtx.Lock()
  335. cs1.Proposal, cs1.ProposalBlock = prop, propBlock
  336. cs1.mtx.Unlock()
  337. // and wait for timeout
  338. <-timeoutChan
  339. // go to prevote, prevote for locked block (not proposal)
  340. <-cs1.NewStepCh()
  341. validatePrevote(t, cs1, 0, privVals[0], cs1.LockedBlock.Hash())
  342. signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, propBlock.Hash(), propBlock.MakePartSet().Header())
  343. _, _, _ = <-cs1.NewStepCh(), <-timeoutChan, <-cs1.NewStepCh()
  344. validatePrecommit(t, cs1, 2, 0, privVals[0], nil, theBlockHash) // precommit nil but locked on proposal
  345. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, propBlock.Hash(), propBlock.MakePartSet().Header()) // NOTE: conflicting precommits at same height
  346. }
  347. // 4 vals, one precommits, other 3 polka at next round, so we unlock and precomit the polka
  348. func TestLockPOLRelock(t *testing.T) {
  349. css, privVals := simpleConsensusState(4)
  350. cs1, cs2, cs3, cs4 := css[0], css[1], css[2], css[3]
  351. cs1.newStepCh = make(chan *RoundState) // so it blocks
  352. timeoutChan := make(chan *types.EventDataRoundState)
  353. voteChan := make(chan *types.EventDataVote)
  354. evsw := events.NewEventSwitch()
  355. evsw.OnStart()
  356. evsw.AddListenerForEvent("tester", types.EventStringTimeoutPropose(), func(data types.EventData) {
  357. timeoutChan <- data.(*types.EventDataRoundState)
  358. })
  359. evsw.AddListenerForEvent("tester", types.EventStringTimeoutWait(), func(data types.EventData) {
  360. timeoutChan <- data.(*types.EventDataRoundState)
  361. })
  362. evsw.AddListenerForEvent("tester", types.EventStringVote(), func(data types.EventData) {
  363. vote := data.(*types.EventDataVote)
  364. // we only fire for our own votes
  365. if bytes.Equal(cs1.privValidator.Address, vote.Address) {
  366. voteChan <- vote
  367. }
  368. })
  369. cs1.SetFireable(evsw)
  370. // everything done from perspective of cs1
  371. /*
  372. Round1 (cs1, B) // B B B B// B nil B nil
  373. eg. cs2 and cs4 didn't see the 2/3 prevotes
  374. */
  375. // start round and wait for propose and prevote
  376. cs1.EnterNewRound(cs1.Height, 0, false)
  377. _, _, _ = <-cs1.NewStepCh(), <-voteChan, <-cs1.NewStepCh()
  378. theBlockHash := cs1.ProposalBlock.Hash()
  379. // wait to finish precommit after prevotes done
  380. // we do this in a go routine with another channel since otherwise
  381. // we may get deadlock with EnterPrecommit waiting to send on newStepCh and the final
  382. // signAddVoteToFrom waiting for the cs.mtx.Lock
  383. donePrecommit := make(chan struct{})
  384. go func() {
  385. <-voteChan
  386. <-cs1.NewStepCh()
  387. donePrecommit <- struct{}{}
  388. }()
  389. signAddVoteToFromMany(types.VoteTypePrevote, cs1, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header(), cs2, cs3, cs4)
  390. <-donePrecommit
  391. // the proposed block should now be locked and our precommit added
  392. validatePrecommit(t, cs1, 0, 0, privVals[0], theBlockHash, theBlockHash)
  393. donePrecommitWait := make(chan struct{})
  394. go func() {
  395. // (note we're entering precommit for a second time this round)
  396. // but with invalid args. then we EnterPrecommitWait, twice (?)
  397. <-cs1.NewStepCh()
  398. donePrecommitWait <- struct{}{}
  399. }()
  400. // add precommits from the rest
  401. signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, cs2, cs4)
  402. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs3, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header())
  403. <-donePrecommitWait
  404. // before we time out into new round, set next proposer
  405. // and next proposal block
  406. _, v1 := cs1.Validators.GetByAddress(privVals[0].Address)
  407. v1.VotingPower = 1
  408. if updated := cs1.Validators.Update(v1); !updated {
  409. t.Fatal("failed to update validator")
  410. }
  411. cs2.decideProposal(cs2.Height, cs2.Round+1)
  412. prop, propBlock := cs2.Proposal, cs2.ProposalBlock
  413. if prop == nil || propBlock == nil {
  414. t.Fatal("Failed to create proposal block with cs2")
  415. }
  416. incrementRound(cs2, cs3, cs4)
  417. // timeout to new round
  418. te := <-timeoutChan
  419. if te.Step != RoundStepPrecommitWait.String() {
  420. t.Fatalf("expected to timeout of precommit into new round. got %v", te.Step)
  421. }
  422. log.Info("### ONTO ROUND 2")
  423. /*
  424. Round2 (cs2, C) // B C C C // C C C _)
  425. cs1 changes lock!
  426. */
  427. // now we're on a new round and not the proposer
  428. <-cs1.NewStepCh()
  429. cs1.mtx.Lock()
  430. // so set the proposal block
  431. propBlockHash, propBlockParts := propBlock.Hash(), propBlock.MakePartSet()
  432. cs1.Proposal, cs1.ProposalBlock, cs1.ProposalBlockParts = prop, propBlock, propBlockParts
  433. cs1.mtx.Unlock()
  434. // and wait for timeout
  435. te = <-timeoutChan
  436. if te.Step != RoundStepPropose.String() {
  437. t.Fatalf("expected to timeout of propose. got %v", te.Step)
  438. }
  439. // go to prevote, prevote for locked block (not proposal), move on
  440. _, _ = <-voteChan, <-cs1.NewStepCh()
  441. validatePrevote(t, cs1, 0, privVals[0], theBlockHash)
  442. donePrecommit = make(chan struct{})
  443. go func() {
  444. // we need this go routine because if we go into PrevoteWait it has to pull on newStepCh
  445. // before the final vote will get added (because it holds the mutex).
  446. select {
  447. case <-cs1.NewStepCh(): // we're in PrevoteWait, go to Precommit
  448. <-voteChan
  449. case <-voteChan: // we went straight to Precommit
  450. }
  451. donePrecommit <- struct{}{}
  452. }()
  453. // now lets add prevotes from everyone else for the new block
  454. signAddVoteToFromMany(types.VoteTypePrevote, cs1, propBlockHash, propBlockParts.Header(), cs2, cs3, cs4)
  455. <-donePrecommit
  456. // we should have unlocked and locked on the new block
  457. validatePrecommit(t, cs1, 1, 1, privVals[0], propBlockHash, propBlockHash)
  458. donePrecommitWait = make(chan struct{})
  459. go func() {
  460. // (note we're entering precommit for a second time this round)
  461. // but with invalid args. then we EnterPrecommitWait,
  462. <-cs1.NewStepCh()
  463. donePrecommitWait <- struct{}{}
  464. }()
  465. signAddVoteToFromMany(types.VoteTypePrecommit, cs1, propBlockHash, propBlockParts.Header(), cs2, cs3)
  466. <-donePrecommitWait
  467. <-cs1.NewStepCh()
  468. rs := <-cs1.NewStepCh()
  469. if rs.Height != 2 {
  470. t.Fatal("Expected height to increment")
  471. }
  472. if hash, _, ok := rs.LastCommit.TwoThirdsMajority(); !ok || !bytes.Equal(hash, propBlockHash) {
  473. t.Fatal("Expected block to get committed")
  474. }
  475. }
  476. // 4 vals, one precommits, other 3 polka at next round, so we unlock and precomit the polka
  477. func TestLockPOLUnlock(t *testing.T) {
  478. css, privVals := simpleConsensusState(4)
  479. cs1, cs2, cs3, cs4 := css[0], css[1], css[2], css[3]
  480. cs1.newStepCh = make(chan *RoundState) // so it blocks
  481. timeoutChan := make(chan *types.EventDataRoundState)
  482. voteChan := make(chan *types.EventDataVote)
  483. evsw := events.NewEventSwitch()
  484. evsw.OnStart()
  485. evsw.AddListenerForEvent("tester", types.EventStringTimeoutPropose(), func(data types.EventData) {
  486. timeoutChan <- data.(*types.EventDataRoundState)
  487. })
  488. evsw.AddListenerForEvent("tester", types.EventStringTimeoutWait(), func(data types.EventData) {
  489. timeoutChan <- data.(*types.EventDataRoundState)
  490. })
  491. evsw.AddListenerForEvent("tester", types.EventStringVote(), func(data types.EventData) {
  492. vote := data.(*types.EventDataVote)
  493. // we only fire for our own votes
  494. if bytes.Equal(cs1.privValidator.Address, vote.Address) {
  495. voteChan <- vote
  496. }
  497. })
  498. cs1.SetFireable(evsw)
  499. // everything done from perspective of cs1
  500. /*
  501. Round1 (cs1, B) // B B B B // B nil B nil
  502. eg. didn't see the 2/3 prevotes
  503. */
  504. // start round and wait for propose and prevote
  505. cs1.EnterNewRound(cs1.Height, 0, false)
  506. _, _, _ = <-cs1.NewStepCh(), <-voteChan, <-cs1.NewStepCh()
  507. theBlockHash := cs1.ProposalBlock.Hash()
  508. donePrecommit := make(chan struct{})
  509. go func() {
  510. <-voteChan
  511. <-cs1.NewStepCh()
  512. donePrecommit <- struct{}{}
  513. }()
  514. signAddVoteToFromMany(types.VoteTypePrevote, cs1, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header(), cs2, cs3, cs4)
  515. <-donePrecommit
  516. // the proposed block should now be locked and our precommit added
  517. validatePrecommit(t, cs1, 0, 0, privVals[0], theBlockHash, theBlockHash)
  518. donePrecommitWait := make(chan struct{})
  519. go func() {
  520. <-cs1.NewStepCh()
  521. donePrecommitWait <- struct{}{}
  522. }()
  523. // add precommits from the rest
  524. signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, cs2, cs4)
  525. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs3, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header())
  526. <-donePrecommitWait
  527. // before we time out into new round, set next proposer
  528. // and next proposal block
  529. _, v1 := cs1.Validators.GetByAddress(privVals[0].Address)
  530. v1.VotingPower = 1
  531. if updated := cs1.Validators.Update(v1); !updated {
  532. t.Fatal("failed to update validator")
  533. }
  534. cs2.decideProposal(cs2.Height, cs2.Round+1)
  535. prop, propBlock := cs2.Proposal, cs2.ProposalBlock
  536. if prop == nil || propBlock == nil {
  537. t.Fatal("Failed to create proposal block with cs2")
  538. }
  539. incrementRound(cs2, cs3, cs4)
  540. // timeout to new round
  541. <-timeoutChan
  542. log.Info("#### ONTO ROUND 2")
  543. /*
  544. Round2 (cs2, C) // B nil nil nil // nil nil nil _
  545. cs1 unlocks!
  546. */
  547. // now we're on a new round and not the proposer,
  548. <-cs1.NewStepCh()
  549. cs1.mtx.Lock()
  550. // so set the proposal block
  551. cs1.Proposal, cs1.ProposalBlock, cs1.ProposalBlockParts = prop, propBlock, propBlock.MakePartSet()
  552. lockedBlockHash := cs1.LockedBlock.Hash()
  553. cs1.mtx.Unlock()
  554. // and wait for timeout
  555. <-timeoutChan
  556. // go to prevote, prevote for locked block (not proposal)
  557. _, _ = <-voteChan, <-cs1.NewStepCh()
  558. validatePrevote(t, cs1, 0, privVals[0], lockedBlockHash)
  559. donePrecommit = make(chan struct{})
  560. go func() {
  561. select {
  562. case <-cs1.NewStepCh(): // we're in PrevoteWait, go to Precommit
  563. <-voteChan
  564. case <-voteChan: // we went straight to Precommit
  565. }
  566. donePrecommit <- struct{}{}
  567. }()
  568. // now lets add prevotes from everyone else for the new block
  569. signAddVoteToFromMany(types.VoteTypePrevote, cs1, nil, types.PartSetHeader{}, cs2, cs3, cs4)
  570. <-donePrecommit
  571. // we should have unlocked
  572. // NOTE: we don't lock on nil, so LockedRound is still 0
  573. validatePrecommit(t, cs1, 1, 0, privVals[0], nil, nil)
  574. donePrecommitWait = make(chan struct{})
  575. go func() {
  576. // the votes will bring us to new round right away
  577. // we should timeout of it
  578. _, _, _ = <-cs1.NewStepCh(), <-cs1.NewStepCh(), <-timeoutChan
  579. donePrecommitWait <- struct{}{}
  580. }()
  581. signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, cs2, cs3)
  582. <-donePrecommitWait
  583. }
  584. // 4 vals
  585. // a polka at round 1 but we miss it
  586. // then a polka at round 2 that we lock on
  587. // then we see the polka from round 1 but shouldn't unlock
  588. func TestLockPOLSafety1(t *testing.T) {
  589. css, privVals := simpleConsensusState(4)
  590. cs1, cs2, cs3, cs4 := css[0], css[1], css[2], css[3]
  591. cs1.newStepCh = make(chan *RoundState) // so it blocks
  592. timeoutChan := make(chan *types.EventDataRoundState)
  593. voteChan := make(chan *types.EventDataVote)
  594. evsw := events.NewEventSwitch()
  595. evsw.OnStart()
  596. evsw.AddListenerForEvent("tester", types.EventStringTimeoutPropose(), func(data types.EventData) {
  597. timeoutChan <- data.(*types.EventDataRoundState)
  598. })
  599. evsw.AddListenerForEvent("tester", types.EventStringTimeoutWait(), func(data types.EventData) {
  600. timeoutChan <- data.(*types.EventDataRoundState)
  601. })
  602. evsw.AddListenerForEvent("tester", types.EventStringVote(), func(data types.EventData) {
  603. vote := data.(*types.EventDataVote)
  604. // we only fire for our own votes
  605. if bytes.Equal(cs1.privValidator.Address, vote.Address) {
  606. voteChan <- vote
  607. }
  608. })
  609. cs1.SetFireable(evsw)
  610. // start round and wait for propose and prevote
  611. cs1.EnterNewRound(cs1.Height, 0, false)
  612. _, _, _ = <-cs1.NewStepCh(), <-voteChan, <-cs1.NewStepCh()
  613. propBlock := cs1.ProposalBlock
  614. validatePrevote(t, cs1, 0, privVals[0], cs1.ProposalBlock.Hash())
  615. // the others sign a polka but we don't see it
  616. prevotes := signVoteMany(types.VoteTypePrevote, propBlock.Hash(), propBlock.MakePartSet().Header(), cs2, cs3, cs4)
  617. // before we time out into new round, set next proposer
  618. // and next proposal block
  619. _, v1 := cs1.Validators.GetByAddress(privVals[0].Address)
  620. v1.VotingPower = 1
  621. if updated := cs1.Validators.Update(v1); !updated {
  622. t.Fatal("failed to update validator")
  623. }
  624. log.Warn("old prop", "hash", fmt.Sprintf("%X", propBlock.Hash()))
  625. // we do see them precommit nil
  626. signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, cs2, cs3, cs4)
  627. cs2.decideProposal(cs2.Height, cs2.Round+1)
  628. prop, propBlock := cs2.Proposal, cs2.ProposalBlock
  629. if prop == nil || propBlock == nil {
  630. t.Fatal("Failed to create proposal block with cs2")
  631. }
  632. incrementRound(cs2, cs3, cs4)
  633. log.Info("### ONTO ROUND 2")
  634. /*Round2
  635. // we timeout and prevote our lock
  636. // a polka happened but we didn't see it!
  637. */
  638. // now we're on a new round and not the proposer,
  639. <-cs1.NewStepCh()
  640. // so set proposal
  641. cs1.mtx.Lock()
  642. propBlockHash, propBlockParts := propBlock.Hash(), propBlock.MakePartSet()
  643. cs1.Proposal, cs1.ProposalBlock, cs1.ProposalBlockParts = prop, propBlock, propBlockParts
  644. cs1.mtx.Unlock()
  645. // and wait for timeout
  646. <-timeoutChan
  647. if cs1.LockedBlock != nil {
  648. t.Fatal("we should not be locked!")
  649. }
  650. log.Warn("new prop", "hash", fmt.Sprintf("%X", propBlockHash))
  651. // go to prevote, prevote for proposal block
  652. _, _ = <-voteChan, <-cs1.NewStepCh()
  653. validatePrevote(t, cs1, 1, privVals[0], propBlockHash)
  654. // now we see the others prevote for it, so we should lock on it
  655. donePrecommit := make(chan struct{})
  656. go func() {
  657. select {
  658. case <-cs1.NewStepCh(): // we're in PrevoteWait, go to Precommit
  659. <-voteChan
  660. case <-voteChan: // we went straight to Precommit
  661. }
  662. <-cs1.NewStepCh()
  663. donePrecommit <- struct{}{}
  664. }()
  665. // now lets add prevotes from everyone else for nil
  666. signAddVoteToFromMany(types.VoteTypePrevote, cs1, propBlockHash, propBlockParts.Header(), cs2, cs3, cs4)
  667. <-donePrecommit
  668. // we should have precommitted
  669. validatePrecommit(t, cs1, 1, 1, privVals[0], propBlockHash, propBlockHash)
  670. // now we see precommits for nil
  671. donePrecommitWait := make(chan struct{})
  672. go func() {
  673. // the votes will bring us to new round
  674. // we should timeut of it and go to prevote
  675. <-cs1.NewStepCh()
  676. <-timeoutChan
  677. donePrecommitWait <- struct{}{}
  678. }()
  679. signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, cs2, cs3)
  680. <-donePrecommitWait
  681. incrementRound(cs2, cs3, cs4)
  682. log.Info("### ONTO ROUND 3")
  683. /*Round3
  684. we see the polka from round 1 but we shouldn't unlock!
  685. */
  686. // timeout of propose
  687. _, _ = <-cs1.NewStepCh(), <-timeoutChan
  688. // finish prevote
  689. _, _ = <-voteChan, <-cs1.NewStepCh()
  690. // we should prevote what we're locked on
  691. validatePrevote(t, cs1, 2, privVals[0], propBlockHash)
  692. // add prevotes from the earlier round
  693. addVoteToFromMany(cs1, prevotes, cs2, cs3, cs4)
  694. log.Warn("Done adding prevotes!")
  695. ensureNoNewStep(t, cs1)
  696. }
  697. // 4 vals.
  698. // polka P1 at R1, P2 at R2, and P3 at R3,
  699. // we lock on P1 at R1, don't see P2, and unlock using P3 at R3
  700. // then we should make sure we don't lock using P2
  701. func TestLockPOLSafety2(t *testing.T) {
  702. css, privVals := simpleConsensusState(4)
  703. cs1, cs2, cs3, cs4 := css[0], css[1], css[2], css[3]
  704. cs1.newStepCh = make(chan *RoundState) // so it blocks
  705. timeoutChan := make(chan *types.EventDataRoundState)
  706. voteChan := make(chan *types.EventDataVote)
  707. evsw := events.NewEventSwitch()
  708. evsw.OnStart()
  709. evsw.AddListenerForEvent("tester", types.EventStringTimeoutPropose(), func(data types.EventData) {
  710. timeoutChan <- data.(*types.EventDataRoundState)
  711. })
  712. evsw.AddListenerForEvent("tester", types.EventStringTimeoutWait(), func(data types.EventData) {
  713. timeoutChan <- data.(*types.EventDataRoundState)
  714. })
  715. evsw.AddListenerForEvent("tester", types.EventStringVote(), func(data types.EventData) {
  716. vote := data.(*types.EventDataVote)
  717. // we only fire for our own votes
  718. if bytes.Equal(cs1.privValidator.Address, vote.Address) {
  719. voteChan <- vote
  720. }
  721. })
  722. cs1.SetFireable(evsw)
  723. // start round and wait for propose and prevote
  724. cs1.EnterNewRound(cs1.Height, 0, false)
  725. _, _, _ = <-cs1.NewStepCh(), <-voteChan, <-cs1.NewStepCh()
  726. theBlockHash := cs1.ProposalBlock.Hash()
  727. donePrecommit := make(chan struct{})
  728. go func() {
  729. <-voteChan
  730. <-cs1.NewStepCh()
  731. donePrecommit <- struct{}{}
  732. }()
  733. signAddVoteToFromMany(types.VoteTypePrevote, cs1, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header(), cs2, cs3, cs4)
  734. <-donePrecommit
  735. // the proposed block should now be locked and our precommit added
  736. validatePrecommit(t, cs1, 0, 0, privVals[0], theBlockHash, theBlockHash)
  737. donePrecommitWait := make(chan struct{})
  738. go func() {
  739. <-cs1.NewStepCh()
  740. donePrecommitWait <- struct{}{}
  741. }()
  742. // add precommits from the rest
  743. signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, cs2, cs4)
  744. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs3, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header())
  745. <-donePrecommitWait
  746. // before we time out into new round, set next proposer
  747. // and next proposal block
  748. _, v1 := cs1.Validators.GetByAddress(privVals[0].Address)
  749. v1.VotingPower = 1
  750. if updated := cs1.Validators.Update(v1); !updated {
  751. t.Fatal("failed to update validator")
  752. }
  753. cs2.decideProposal(cs2.Height, cs2.Round+1)
  754. prop, propBlock := cs2.Proposal, cs2.ProposalBlock
  755. if prop == nil || propBlock == nil {
  756. t.Fatal("Failed to create proposal block with cs2")
  757. }
  758. incrementRound(cs2, cs3, cs4)
  759. // timeout to new round
  760. <-timeoutChan
  761. log.Info("### ONTO Round 2")
  762. /*Round2
  763. // we timeout and prevote our lock
  764. // a polka happened but we didn't see it!
  765. */
  766. // now we're on a new round and not the proposer, so wait for timeout
  767. _, _ = <-cs1.NewStepCh(), <-timeoutChan
  768. // go to prevote, prevote for locked block
  769. _, _ = <-voteChan, <-cs1.NewStepCh()
  770. validatePrevote(t, cs1, 0, privVals[0], cs1.LockedBlock.Hash())
  771. // the others sign a polka but we don't see it
  772. prevotes := signVoteMany(types.VoteTypePrevote, propBlock.Hash(), propBlock.MakePartSet().Header(), cs2, cs3, cs4)
  773. // once we see prevotes for the next round we'll skip ahead
  774. incrementRound(cs2, cs3, cs4)
  775. log.Info("### ONTO Round 3")
  776. /*Round3
  777. a polka for nil causes us to unlock
  778. */
  779. // these prevotes will send us straight to precommit at the higher round
  780. donePrecommit = make(chan struct{})
  781. go func() {
  782. select {
  783. case <-cs1.NewStepCh(): // we're in PrevoteWait, go to Precommit
  784. <-voteChan
  785. case <-voteChan: // we went straight to Precommit
  786. }
  787. <-cs1.NewStepCh()
  788. donePrecommit <- struct{}{}
  789. }()
  790. // now lets add prevotes from everyone else for nil
  791. signAddVoteToFromMany(types.VoteTypePrevote, cs1, nil, types.PartSetHeader{}, cs2, cs3, cs4)
  792. <-donePrecommit
  793. // we should have unlocked
  794. // NOTE: we don't lock on nil, so LockedRound is still 0
  795. validatePrecommit(t, cs1, 2, 0, privVals[0], nil, nil)
  796. donePrecommitWait = make(chan struct{})
  797. go func() {
  798. // the votes will bring us to new round right away
  799. // we should timeut of it and go to prevote
  800. <-cs1.NewStepCh()
  801. // set the proposal block to be that which got a polka in R2
  802. cs1.mtx.Lock()
  803. cs1.Proposal, cs1.ProposalBlock, cs1.ProposalBlockParts = prop, propBlock, propBlock.MakePartSet()
  804. cs1.mtx.Unlock()
  805. // timeout into prevote, finish prevote
  806. _, _, _ = <-timeoutChan, <-voteChan, <-cs1.NewStepCh()
  807. donePrecommitWait <- struct{}{}
  808. }()
  809. signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, cs2, cs3)
  810. <-donePrecommitWait
  811. log.Info("### ONTO ROUND 4")
  812. /*Round4
  813. we see the polka from R2
  814. make sure we don't lock because of it!
  815. */
  816. // new round and not proposer
  817. // (we already timed out and stepped into prevote)
  818. log.Warn("adding prevotes from round 2")
  819. addVoteToFromMany(cs1, prevotes, cs2, cs3, cs4)
  820. log.Warn("Done adding prevotes!")
  821. // we should prevote it now
  822. validatePrevote(t, cs1, 3, privVals[0], cs1.ProposalBlock.Hash())
  823. // but we shouldn't precommit it
  824. precommits := cs1.Votes.Precommits(3)
  825. vote := precommits.GetByIndex(0)
  826. if vote != nil {
  827. t.Fatal("validator precommitted at round 4 based on an old polka")
  828. }
  829. }
  830. //------------------------------------------------------------------------------------------
  831. // SlashingSuite
  832. func TestSlashingPrevotes(t *testing.T) {
  833. css, _ := simpleConsensusState(2)
  834. cs1, cs2 := css[0], css[1]
  835. cs1.newStepCh = make(chan *RoundState) // so it blocks
  836. // start round and wait for propose and prevote
  837. cs1.EnterNewRound(cs1.Height, 0, false)
  838. _, _ = <-cs1.NewStepCh(), <-cs1.NewStepCh()
  839. // we should now be stuck in limbo forever, waiting for more prevotes
  840. // add one for a different block should cause us to go into prevote wait
  841. hash := cs1.ProposalBlock.Hash()
  842. hash[0] = byte(hash[0]+1) % 255
  843. signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, hash, cs1.ProposalBlockParts.Header())
  844. // pass prevote wait
  845. <-cs1.NewStepCh()
  846. // NOTE: we have to send the vote for different block first so we don't just go into precommit round right
  847. // away and ignore more prevotes (and thus fail to slash!)
  848. // add the conflicting vote
  849. signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header())
  850. // XXX: Check for existence of Dupeout info
  851. }
  852. func TestSlashingPrecommits(t *testing.T) {
  853. css, _ := simpleConsensusState(2)
  854. cs1, cs2 := css[0], css[1]
  855. cs1.newStepCh = make(chan *RoundState) // so it blocks
  856. // start round and wait for propose and prevote
  857. cs1.EnterNewRound(cs1.Height, 0, false)
  858. _, _ = <-cs1.NewStepCh(), <-cs1.NewStepCh()
  859. // add prevote from cs2
  860. signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header())
  861. // wait to finish precommit
  862. <-cs1.NewStepCh()
  863. // we should now be stuck in limbo forever, waiting for more prevotes
  864. // add one for a different block should cause us to go into prevote wait
  865. hash := cs1.ProposalBlock.Hash()
  866. hash[0] = byte(hash[0]+1) % 255
  867. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, hash, cs1.ProposalBlockParts.Header())
  868. // pass prevote wait
  869. <-cs1.NewStepCh()
  870. // NOTE: we have to send the vote for different block first so we don't just go into precommit round right
  871. // away and ignore more prevotes (and thus fail to slash!)
  872. // add precommit from cs2
  873. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header())
  874. // XXX: Check for existence of Dupeout info
  875. }
  876. //------------------------------------------------------------------------------------------
  877. // CatchupSuite
  878. //------------------------------------------------------------------------------------------
  879. // HaltSuite
  880. // 4 vals.
  881. // we receive a final precommit after going into next round, but others might have gone to commit already!
  882. func TestHalt1(t *testing.T) {
  883. css, privVals := simpleConsensusState(4)
  884. cs1, cs2, cs3, cs4 := css[0], css[1], css[2], css[3]
  885. cs1.newStepCh = make(chan *RoundState) // so it blocks
  886. timeoutChan := make(chan struct{})
  887. evsw := events.NewEventSwitch()
  888. evsw.OnStart()
  889. evsw.AddListenerForEvent("tester", types.EventStringTimeoutWait(), func(data types.EventData) {
  890. timeoutChan <- struct{}{}
  891. })
  892. cs1.SetFireable(evsw)
  893. // start round and wait for propose and prevote
  894. cs1.EnterNewRound(cs1.Height, 0, false)
  895. _, _ = <-cs1.NewStepCh(), <-cs1.NewStepCh()
  896. theBlockHash := cs1.ProposalBlock.Hash()
  897. donePrecommit := make(chan struct{})
  898. go func() {
  899. <-cs1.NewStepCh()
  900. donePrecommit <- struct{}{}
  901. }()
  902. signAddVoteToFromMany(types.VoteTypePrevote, cs1, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header(), cs3, cs4)
  903. <-donePrecommit
  904. // the proposed block should now be locked and our precommit added
  905. validatePrecommit(t, cs1, 0, 0, privVals[0], theBlockHash, theBlockHash)
  906. donePrecommitWait := make(chan struct{})
  907. go func() {
  908. <-cs1.NewStepCh()
  909. donePrecommitWait <- struct{}{}
  910. }()
  911. // add precommits from the rest
  912. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, nil, types.PartSetHeader{}) // didnt receive proposal
  913. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs3, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header())
  914. // we receive this later, but cs3 might receive it earlier and with ours will go to commit!
  915. precommit4 := signVote(cs4, types.VoteTypePrecommit, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header())
  916. <-donePrecommitWait
  917. incrementRound(cs2, cs3, cs4)
  918. // timeout to new round
  919. <-timeoutChan
  920. log.Info("### ONTO ROUND 2")
  921. /*Round2
  922. // we timeout and prevote our lock
  923. // a polka happened but we didn't see it!
  924. */
  925. // go to prevote, prevote for locked block
  926. _, _ = <-cs1.NewStepCh(), <-cs1.NewStepCh()
  927. validatePrevote(t, cs1, 0, privVals[0], cs1.LockedBlock.Hash())
  928. // now we receive the precommit from the previous round
  929. addVoteToFrom(cs1, cs4, precommit4)
  930. // receiving that precommit should take us straight to commit
  931. ensureNewStep(t, cs1)
  932. log.Warn("done enter commit!")
  933. // update to state
  934. ensureNewStep(t, cs1)
  935. if cs1.Height != 2 {
  936. t.Fatal("expected height to increment")
  937. }
  938. }