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.

1186 lines
39 KiB

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