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.

1044 lines
34 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
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/go-common"
  8. "github.com/tendermint/tendermint/config/tendermint_test"
  9. "github.com/tendermint/tendermint/types"
  10. )
  11. func init() {
  12. config = tendermint_test.ResetConfig("consensus_state_test")
  13. }
  14. func (tp *TimeoutParams) ensureProposeTimeout() time.Duration {
  15. return time.Duration(tp.Propose0*2) * time.Millisecond
  16. }
  17. /*
  18. ProposeSuite
  19. x * TestProposerSelection0 - round robin ordering, round 0
  20. x * TestProposerSelection2 - round robin ordering, round 2++
  21. x * TestEnterProposeNoValidator - timeout into prevote round
  22. x * TestEnterPropose - finish propose without timing out (we have the proposal)
  23. x * TestBadProposal - 2 vals, bad proposal (bad block state hash), should prevote and precommit nil
  24. FullRoundSuite
  25. x * TestFullRound1 - 1 val, full successful round
  26. x * TestFullRoundNil - 1 val, full round of nil
  27. x * TestFullRound2 - 2 vals, both required for full round
  28. LockSuite
  29. x * TestLockNoPOL - 2 vals, 4 rounds. one val locked, precommits nil every round except first.
  30. x * TestLockPOLRelock - 4 vals, one precommits, other 3 polka at next round, so we unlock and precomit the polka
  31. x * TestLockPOLUnlock - 4 vals, one precommits, other 3 polka nil at next round, so we unlock and precomit nil
  32. x * TestLockPOLSafety1 - 4 vals. We shouldn't change lock based on polka at earlier round
  33. x * TestLockPOLSafety2 - 4 vals. After unlocking, we shouldn't relock based on polka at earlier round
  34. * TestNetworkLock - once +1/3 precommits, network should be locked
  35. * TestNetworkLockPOL - once +1/3 precommits, the block with more recent polka is committed
  36. SlashingSuite
  37. x * TestSlashingPrevotes - a validator prevoting twice in a round gets slashed
  38. x * TestSlashingPrecommits - a validator precomitting twice in a round gets slashed
  39. CatchupSuite
  40. * TestCatchup - if we might be behind and we've seen any 2/3 prevotes, round skip to new round, precommit, or prevote
  41. HaltSuite
  42. x * TestHalt1 - if we see +2/3 precommits after timing out into new round, we should still commit
  43. */
  44. //----------------------------------------------------------------------------------------------------
  45. // ProposeSuite
  46. func TestProposerSelection0(t *testing.T) {
  47. cs1, vss := randConsensusState(4)
  48. height, round := cs1.Height, cs1.Round
  49. newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
  50. proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
  51. startTestRound(cs1, height, round)
  52. // wait for new round so proposer is set
  53. <-newRoundCh
  54. // lets commit a block and ensure proposer for the next height is correct
  55. prop := cs1.GetRoundState().Validators.Proposer()
  56. if !bytes.Equal(prop.Address, cs1.privValidator.GetAddress()) {
  57. t.Fatalf("expected proposer to be validator %d. Got %X", 0, prop.Address)
  58. }
  59. // wait for complete proposal
  60. <-proposalCh
  61. rs := cs1.GetRoundState()
  62. signAddVotes(cs1, types.VoteTypePrecommit, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), vss[1:]...)
  63. // wait for new round so next validator is set
  64. <-newRoundCh
  65. prop = cs1.GetRoundState().Validators.Proposer()
  66. if !bytes.Equal(prop.Address, vss[1].Address) {
  67. panic(Fmt("expected proposer to be validator %d. Got %X", 1, prop.Address))
  68. }
  69. }
  70. // Now let's do it all again, but starting from round 2 instead of 0
  71. func TestProposerSelection2(t *testing.T) {
  72. cs1, vss := randConsensusState(4) // test needs more work for more than 3 validators
  73. newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
  74. // this time we jump in at round 2
  75. incrementRound(vss[1:]...)
  76. incrementRound(vss[1:]...)
  77. startTestRound(cs1, cs1.Height, 2)
  78. <-newRoundCh // wait for the new round
  79. // everyone just votes nil. we get a new proposer each round
  80. for i := 0; i < len(vss); i++ {
  81. prop := cs1.GetRoundState().Validators.Proposer()
  82. if !bytes.Equal(prop.Address, vss[(i+2)%len(vss)].Address) {
  83. panic(Fmt("expected proposer to be validator %d. Got %X", (i+2)%len(vss), prop.Address))
  84. }
  85. rs := cs1.GetRoundState()
  86. signAddVotes(cs1, types.VoteTypePrecommit, nil, rs.ProposalBlockParts.Header(), vss[1:]...)
  87. <-newRoundCh // wait for the new round event each round
  88. incrementRound(vss[1:]...)
  89. }
  90. }
  91. // a non-validator should timeout into the prevote round
  92. func TestEnterProposeNoPrivValidator(t *testing.T) {
  93. cs, _ := randConsensusState(1)
  94. cs.SetPrivValidator(nil)
  95. height, round := cs.Height, cs.Round
  96. // Listen for propose timeout event
  97. timeoutCh := subscribeToEvent(cs.evsw, "tester", types.EventStringTimeoutPropose(), 1)
  98. startTestRound(cs, height, round)
  99. // if we're not a validator, EnterPropose should timeout
  100. ticker := time.NewTicker(cs.timeoutParams.ensureProposeTimeout())
  101. select {
  102. case <-timeoutCh:
  103. case <-ticker.C:
  104. panic("Expected EnterPropose to timeout")
  105. }
  106. if cs.GetRoundState().Proposal != nil {
  107. t.Error("Expected to make no proposal, since no privValidator")
  108. }
  109. }
  110. // a validator should not timeout of the prevote round (TODO: unless the block is really big!)
  111. func TestEnterProposeYesPrivValidator(t *testing.T) {
  112. cs, _ := randConsensusState(1)
  113. height, round := cs.Height, cs.Round
  114. // Listen for propose timeout event
  115. timeoutCh := subscribeToEvent(cs.evsw, "tester", types.EventStringTimeoutPropose(), 1)
  116. proposalCh := subscribeToEvent(cs.evsw, "tester", types.EventStringCompleteProposal(), 1)
  117. cs.enterNewRound(height, round)
  118. cs.startRoutines(3)
  119. <-proposalCh
  120. // Check that Proposal, ProposalBlock, ProposalBlockParts are set.
  121. rs := cs.GetRoundState()
  122. if rs.Proposal == nil {
  123. t.Error("rs.Proposal should be set")
  124. }
  125. if rs.ProposalBlock == nil {
  126. t.Error("rs.ProposalBlock should be set")
  127. }
  128. if rs.ProposalBlockParts.Total() == 0 {
  129. t.Error("rs.ProposalBlockParts should be set")
  130. }
  131. // if we're a validator, enterPropose should not timeout
  132. ticker := time.NewTicker(cs.timeoutParams.ensureProposeTimeout())
  133. select {
  134. case <-timeoutCh:
  135. panic("Expected EnterPropose not to timeout")
  136. case <-ticker.C:
  137. }
  138. }
  139. func TestBadProposal(t *testing.T) {
  140. cs1, vss := randConsensusState(2)
  141. height, round := cs1.Height, cs1.Round
  142. vs2 := vss[1]
  143. proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
  144. voteCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringVote(), 1)
  145. propBlock, _ := cs1.createProposalBlock() //changeProposer(t, cs1, vs2)
  146. // make the second validator the proposer by incrementing round
  147. round = round + 1
  148. incrementRound(vss[1:]...)
  149. // make the block bad by tampering with statehash
  150. stateHash := propBlock.AppHash
  151. if len(stateHash) == 0 {
  152. stateHash = make([]byte, 32)
  153. }
  154. stateHash[0] = byte((stateHash[0] + 1) % 255)
  155. propBlock.AppHash = stateHash
  156. propBlockParts := propBlock.MakePartSet()
  157. proposal := types.NewProposal(vs2.Height, round, propBlockParts.Header(), -1, types.BlockID{})
  158. if err := vs2.SignProposal(config.GetString("chain_id"), proposal); err != nil {
  159. t.Fatal("failed to sign bad proposal", err)
  160. }
  161. // set the proposal block
  162. cs1.SetProposalAndBlock(proposal, propBlock, propBlockParts, "some peer")
  163. // start the machine
  164. startTestRound(cs1, height, round)
  165. // wait for proposal
  166. <-proposalCh
  167. // wait for prevote
  168. <-voteCh
  169. validatePrevote(t, cs1, round, vss[0], nil)
  170. // add bad prevote from vs2 and wait for it
  171. signAddVotes(cs1, types.VoteTypePrevote, propBlock.Hash(), propBlock.MakePartSet().Header(), vs2)
  172. <-voteCh
  173. // wait for precommit
  174. <-voteCh
  175. validatePrecommit(t, cs1, round, 0, vss[0], nil, nil)
  176. signAddVotes(cs1, types.VoteTypePrecommit, propBlock.Hash(), propBlock.MakePartSet().Header(), vs2)
  177. }
  178. //----------------------------------------------------------------------------------------------------
  179. // FullRoundSuite
  180. // propose, prevote, and precommit a block
  181. func TestFullRound1(t *testing.T) {
  182. cs, vss := randConsensusState(1)
  183. height, round := cs.Height, cs.Round
  184. voteCh := subscribeToEvent(cs.evsw, "tester", types.EventStringVote(), 0)
  185. propCh := subscribeToEvent(cs.evsw, "tester", types.EventStringCompleteProposal(), 1)
  186. newRoundCh := subscribeToEvent(cs.evsw, "tester", types.EventStringNewRound(), 1)
  187. startTestRound(cs, height, round)
  188. <-newRoundCh
  189. // grab proposal
  190. re := <-propCh
  191. propBlockHash := re.(types.EventDataRoundState).RoundState.(*RoundState).ProposalBlock.Hash()
  192. <-voteCh // wait for prevote
  193. // NOTE: voteChan cap of 0 ensures we can complete this
  194. // before consensus can move to the next height (and cause a race condition)
  195. validatePrevote(t, cs, round, vss[0], propBlockHash)
  196. <-voteCh // wait for precommit
  197. // we're going to roll right into new height
  198. <-newRoundCh
  199. validateLastPrecommit(t, cs, vss[0], propBlockHash)
  200. }
  201. // nil is proposed, so prevote and precommit nil
  202. func TestFullRoundNil(t *testing.T) {
  203. cs, vss := randConsensusState(1)
  204. height, round := cs.Height, cs.Round
  205. voteCh := subscribeToEvent(cs.evsw, "tester", types.EventStringVote(), 1)
  206. cs.enterPrevote(height, round)
  207. cs.startRoutines(4)
  208. <-voteCh // prevote
  209. <-voteCh // precommit
  210. // should prevote and precommit nil
  211. validatePrevoteAndPrecommit(t, cs, round, 0, vss[0], nil, nil)
  212. }
  213. // run through propose, prevote, precommit commit with two validators
  214. // where the first validator has to wait for votes from the second
  215. func TestFullRound2(t *testing.T) {
  216. cs1, vss := randConsensusState(2)
  217. vs2 := vss[1]
  218. height, round := cs1.Height, cs1.Round
  219. voteCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringVote(), 1)
  220. newBlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewBlock(), 1)
  221. // start round and wait for propose and prevote
  222. startTestRound(cs1, height, round)
  223. <-voteCh // prevote
  224. // we should be stuck in limbo waiting for more prevotes
  225. rs := cs1.GetRoundState()
  226. propBlockHash, propPartsHeader := rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header()
  227. // prevote arrives from vs2:
  228. signAddVotes(cs1, types.VoteTypePrevote, propBlockHash, propPartsHeader, vs2)
  229. <-voteCh
  230. <-voteCh //precommit
  231. // the proposed block should now be locked and our precommit added
  232. validatePrecommit(t, cs1, 0, 0, vss[0], propBlockHash, propBlockHash)
  233. // we should be stuck in limbo waiting for more precommits
  234. // precommit arrives from vs2:
  235. signAddVotes(cs1, types.VoteTypePrecommit, propBlockHash, propPartsHeader, vs2)
  236. <-voteCh
  237. // wait to finish commit, propose in next height
  238. <-newBlockCh
  239. }
  240. //------------------------------------------------------------------------------------------
  241. // LockSuite
  242. // two validators, 4 rounds.
  243. // two vals take turns proposing. val1 locks on first one, precommits nil on everything else
  244. func TestLockNoPOL(t *testing.T) {
  245. cs1, vss := randConsensusState(2)
  246. vs2 := vss[1]
  247. height := cs1.Height
  248. timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
  249. timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
  250. voteCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringVote(), 1)
  251. proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
  252. newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
  253. /*
  254. Round1 (cs1, B) // B B // B B2
  255. */
  256. // start round and wait for prevote
  257. cs1.enterNewRound(height, 0)
  258. cs1.startRoutines(0)
  259. re := <-proposalCh
  260. rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
  261. theBlockHash := rs.ProposalBlock.Hash()
  262. <-voteCh // prevote
  263. // we should now be stuck in limbo forever, waiting for more prevotes
  264. // prevote arrives from vs2:
  265. signAddVotes(cs1, types.VoteTypePrevote, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header(), vs2)
  266. <-voteCh // prevote
  267. <-voteCh // precommit
  268. // the proposed block should now be locked and our precommit added
  269. validatePrecommit(t, cs1, 0, 0, vss[0], theBlockHash, theBlockHash)
  270. // we should now be stuck in limbo forever, waiting for more precommits
  271. // lets add one for a different block
  272. // NOTE: in practice we should never get to a point where there are precommits for different blocks at the same round
  273. hash := make([]byte, len(theBlockHash))
  274. copy(hash, theBlockHash)
  275. hash[0] = byte((hash[0] + 1) % 255)
  276. signAddVotes(cs1, types.VoteTypePrecommit, hash, rs.ProposalBlock.MakePartSet().Header(), vs2)
  277. <-voteCh // precommit
  278. // (note we're entering precommit for a second time this round)
  279. // but with invalid args. then we enterPrecommitWait, and the timeout to new round
  280. <-timeoutWaitCh
  281. ///
  282. <-newRoundCh
  283. log.Notice("#### ONTO ROUND 1")
  284. /*
  285. Round2 (cs1, B) // B B2
  286. */
  287. incrementRound(vs2)
  288. // now we're on a new round and not the proposer, so wait for timeout
  289. re = <-timeoutProposeCh
  290. rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
  291. if rs.ProposalBlock != nil {
  292. panic("Expected proposal block to be nil")
  293. }
  294. // wait to finish prevote
  295. <-voteCh
  296. // we should have prevoted our locked block
  297. validatePrevote(t, cs1, 1, vss[0], rs.LockedBlock.Hash())
  298. // add a conflicting prevote from the other validator
  299. signAddVotes(cs1, types.VoteTypePrevote, hash, rs.ProposalBlock.MakePartSet().Header(), vs2)
  300. <-voteCh
  301. // now we're going to enter prevote again, but with invalid args
  302. // and then prevote wait, which should timeout. then wait for precommit
  303. <-timeoutWaitCh
  304. <-voteCh // precommit
  305. // the proposed block should still be locked and our precommit added
  306. // we should precommit nil and be locked on the proposal
  307. validatePrecommit(t, cs1, 1, 0, vss[0], nil, theBlockHash)
  308. // add conflicting precommit from vs2
  309. // NOTE: in practice we should never get to a point where there are precommits for different blocks at the same round
  310. signAddVotes(cs1, types.VoteTypePrecommit, hash, rs.ProposalBlock.MakePartSet().Header(), vs2)
  311. <-voteCh
  312. // (note we're entering precommit for a second time this round, but with invalid args
  313. // then we enterPrecommitWait and timeout into NewRound
  314. <-timeoutWaitCh
  315. <-newRoundCh
  316. log.Notice("#### ONTO ROUND 2")
  317. /*
  318. Round3 (vs2, _) // B, B2
  319. */
  320. incrementRound(vs2)
  321. re = <-proposalCh
  322. rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
  323. // now we're on a new round and are the proposer
  324. if !bytes.Equal(rs.ProposalBlock.Hash(), rs.LockedBlock.Hash()) {
  325. panic(Fmt("Expected proposal block to be locked block. Got %v, Expected %v", rs.ProposalBlock, rs.LockedBlock))
  326. }
  327. <-voteCh // prevote
  328. validatePrevote(t, cs1, 2, vss[0], rs.LockedBlock.Hash())
  329. signAddVotes(cs1, types.VoteTypePrevote, hash, rs.ProposalBlock.MakePartSet().Header(), vs2)
  330. <-voteCh
  331. <-timeoutWaitCh // prevote wait
  332. <-voteCh // precommit
  333. validatePrecommit(t, cs1, 2, 0, vss[0], nil, theBlockHash) // precommit nil but be locked on proposal
  334. signAddVotes(cs1, types.VoteTypePrecommit, hash, rs.ProposalBlock.MakePartSet().Header(), vs2) // NOTE: conflicting precommits at same height
  335. <-voteCh
  336. <-timeoutWaitCh
  337. // before we time out into new round, set next proposal block
  338. prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1)
  339. if prop == nil || propBlock == nil {
  340. t.Fatal("Failed to create proposal block with vs2")
  341. }
  342. incrementRound(vs2)
  343. <-newRoundCh
  344. log.Notice("#### ONTO ROUND 3")
  345. /*
  346. Round4 (vs2, C) // B C // B C
  347. */
  348. // now we're on a new round and not the proposer
  349. // so set the proposal block
  350. cs1.SetProposalAndBlock(prop, propBlock, propBlock.MakePartSet(), "")
  351. <-proposalCh
  352. <-voteCh // prevote
  353. // prevote for locked block (not proposal)
  354. validatePrevote(t, cs1, 0, vss[0], cs1.LockedBlock.Hash())
  355. signAddVotes(cs1, types.VoteTypePrevote, propBlock.Hash(), propBlock.MakePartSet().Header(), vs2)
  356. <-voteCh
  357. <-timeoutWaitCh
  358. <-voteCh
  359. validatePrecommit(t, cs1, 2, 0, vss[0], nil, theBlockHash) // precommit nil but locked on proposal
  360. signAddVotes(cs1, types.VoteTypePrecommit, propBlock.Hash(), propBlock.MakePartSet().Header(), vs2) // NOTE: conflicting precommits at same height
  361. <-voteCh
  362. }
  363. // 4 vals, one precommits, other 3 polka at next round, so we unlock and precomit the polka
  364. func TestLockPOLRelock(t *testing.T) {
  365. cs1, vss := randConsensusState(4)
  366. vs2, vs3, vs4 := vss[1], vss[2], vss[3]
  367. timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
  368. timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
  369. proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
  370. voteCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringVote(), 1)
  371. newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
  372. newBlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewBlockHeader(), 1)
  373. log.Debug("vs2 last round", "lr", vs2.PrivValidator.LastRound)
  374. // everything done from perspective of cs1
  375. /*
  376. Round1 (cs1, B) // B B B B// B nil B nil
  377. eg. vs2 and vs4 didn't see the 2/3 prevotes
  378. */
  379. // start round and wait for propose and prevote
  380. startTestRound(cs1, cs1.Height, 0)
  381. <-newRoundCh
  382. re := <-proposalCh
  383. rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
  384. theBlockHash := rs.ProposalBlock.Hash()
  385. <-voteCh // prevote
  386. signAddVotes(cs1, types.VoteTypePrevote, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header(), vs2, vs3, vs4)
  387. _, _, _ = <-voteCh, <-voteCh, <-voteCh // prevotes
  388. <-voteCh // our precommit
  389. // the proposed block should now be locked and our precommit added
  390. validatePrecommit(t, cs1, 0, 0, vss[0], theBlockHash, theBlockHash)
  391. // add precommits from the rest
  392. signAddVotes(cs1, types.VoteTypePrecommit, nil, types.PartSetHeader{}, vs2, vs4)
  393. signAddVotes(cs1, types.VoteTypePrecommit, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header(), vs3)
  394. _, _, _ = <-voteCh, <-voteCh, <-voteCh // precommits
  395. // before we timeout to the new round set the new proposal
  396. prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1)
  397. propBlockParts := propBlock.MakePartSet()
  398. propBlockHash := propBlock.Hash()
  399. incrementRound(vs2, vs3, vs4)
  400. // timeout to new round
  401. <-timeoutWaitCh
  402. //XXX: this isnt gauranteed to get there before the timeoutPropose ...
  403. cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer")
  404. <-newRoundCh
  405. log.Notice("### ONTO ROUND 1")
  406. /*
  407. Round2 (vs2, C) // B C C C // C C C _)
  408. cs1 changes lock!
  409. */
  410. // now we're on a new round and not the proposer
  411. // but we should receive the proposal
  412. select {
  413. case <-proposalCh:
  414. case <-timeoutProposeCh:
  415. <-proposalCh
  416. }
  417. // go to prevote, prevote for locked block (not proposal), move on
  418. <-voteCh
  419. validatePrevote(t, cs1, 0, vss[0], theBlockHash)
  420. // now lets add prevotes from everyone else for the new block
  421. signAddVotes(cs1, types.VoteTypePrevote, propBlockHash, propBlockParts.Header(), vs2, vs3, vs4)
  422. _, _, _ = <-voteCh, <-voteCh, <-voteCh // prevotes
  423. // now either we go to PrevoteWait or Precommit
  424. select {
  425. case <-timeoutWaitCh: // we're in PrevoteWait, go to Precommit
  426. // XXX: there's no guarantee we see the polka, this might be a precommit for nil,
  427. // in which case the test fails!
  428. <-voteCh
  429. case <-voteCh: // we went straight to Precommit
  430. }
  431. // we should have unlocked and locked on the new block
  432. validatePrecommit(t, cs1, 1, 1, vss[0], propBlockHash, propBlockHash)
  433. signAddVotes(cs1, types.VoteTypePrecommit, propBlockHash, propBlockParts.Header(), vs2, vs3)
  434. _, _ = <-voteCh, <-voteCh
  435. be := <-newBlockCh
  436. b := be.(types.EventDataNewBlockHeader)
  437. re = <-newRoundCh
  438. rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
  439. if rs.Height != 2 {
  440. panic("Expected height to increment")
  441. }
  442. if !bytes.Equal(b.Header.Hash(), propBlockHash) {
  443. panic("Expected new block to be proposal block")
  444. }
  445. }
  446. // 4 vals, one precommits, other 3 polka at next round, so we unlock and precomit the polka
  447. func TestLockPOLUnlock(t *testing.T) {
  448. cs1, vss := randConsensusState(4)
  449. vs2, vs3, vs4 := vss[1], vss[2], vss[3]
  450. proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
  451. timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
  452. timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
  453. newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
  454. unlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringUnlock(), 1)
  455. voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
  456. // everything done from perspective of cs1
  457. /*
  458. Round1 (cs1, B) // B B B B // B nil B nil
  459. eg. didn't see the 2/3 prevotes
  460. */
  461. // start round and wait for propose and prevote
  462. startTestRound(cs1, cs1.Height, 0)
  463. <-newRoundCh
  464. re := <-proposalCh
  465. rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
  466. theBlockHash := rs.ProposalBlock.Hash()
  467. <-voteCh // prevote
  468. signAddVotes(cs1, types.VoteTypePrevote, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header(), vs2, vs3, vs4)
  469. <-voteCh //precommit
  470. // the proposed block should now be locked and our precommit added
  471. validatePrecommit(t, cs1, 0, 0, vss[0], theBlockHash, theBlockHash)
  472. rs = cs1.GetRoundState()
  473. // add precommits from the rest
  474. signAddVotes(cs1, types.VoteTypePrecommit, nil, types.PartSetHeader{}, vs2, vs4)
  475. signAddVotes(cs1, types.VoteTypePrecommit, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header(), vs3)
  476. // before we time out into new round, set next proposal block
  477. prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1)
  478. propBlockParts := propBlock.MakePartSet()
  479. incrementRound(vs2, vs3, vs4)
  480. // timeout to new round
  481. re = <-timeoutWaitCh
  482. rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
  483. lockedBlockHash := rs.LockedBlock.Hash()
  484. //XXX: this isnt gauranteed to get there before the timeoutPropose ...
  485. cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer")
  486. <-newRoundCh
  487. log.Notice("#### ONTO ROUND 1")
  488. /*
  489. Round2 (vs2, C) // B nil nil nil // nil nil nil _
  490. cs1 unlocks!
  491. */
  492. // now we're on a new round and not the proposer,
  493. // but we should receive the proposal
  494. select {
  495. case <-proposalCh:
  496. case <-timeoutProposeCh:
  497. <-proposalCh
  498. }
  499. // go to prevote, prevote for locked block (not proposal)
  500. <-voteCh
  501. validatePrevote(t, cs1, 0, vss[0], lockedBlockHash)
  502. // now lets add prevotes from everyone else for nil (a polka!)
  503. signAddVotes(cs1, types.VoteTypePrevote, nil, types.PartSetHeader{}, vs2, vs3, vs4)
  504. // the polka makes us unlock and precommit nil
  505. <-unlockCh
  506. <-voteCh // precommit
  507. // we should have unlocked and committed nil
  508. // NOTE: since we don't relock on nil, the lock round is 0
  509. validatePrecommit(t, cs1, 1, 0, vss[0], nil, nil)
  510. signAddVotes(cs1, types.VoteTypePrecommit, nil, types.PartSetHeader{}, vs2, vs3)
  511. <-newRoundCh
  512. }
  513. // 4 vals
  514. // a polka at round 1 but we miss it
  515. // then a polka at round 2 that we lock on
  516. // then we see the polka from round 1 but shouldn't unlock
  517. func TestLockPOLSafety1(t *testing.T) {
  518. cs1, vss := randConsensusState(4)
  519. vs2, vs3, vs4 := vss[1], vss[2], vss[3]
  520. proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
  521. timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
  522. timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
  523. newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
  524. voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
  525. // start round and wait for propose and prevote
  526. startTestRound(cs1, cs1.Height, 0)
  527. <-newRoundCh
  528. re := <-proposalCh
  529. rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
  530. propBlock := rs.ProposalBlock
  531. <-voteCh // prevote
  532. validatePrevote(t, cs1, 0, vss[0], propBlock.Hash())
  533. // the others sign a polka but we don't see it
  534. prevotes := signVotes(types.VoteTypePrevote, propBlock.Hash(), propBlock.MakePartSet().Header(), vs2, vs3, vs4)
  535. // before we time out into new round, set next proposer
  536. // and next proposal block
  537. /*
  538. _, v1 := cs1.Validators.GetByAddress(vss[0].Address)
  539. v1.VotingPower = 1
  540. if updated := cs1.Validators.Update(v1); !updated {
  541. panic("failed to update validator")
  542. }*/
  543. log.Warn("old prop", "hash", fmt.Sprintf("%X", propBlock.Hash()))
  544. // we do see them precommit nil
  545. signAddVotes(cs1, types.VoteTypePrecommit, nil, types.PartSetHeader{}, vs2, vs3, vs4)
  546. prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1)
  547. propBlockHash := propBlock.Hash()
  548. propBlockParts := propBlock.MakePartSet()
  549. incrementRound(vs2, vs3, vs4)
  550. //XXX: this isnt gauranteed to get there before the timeoutPropose ...
  551. cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer")
  552. <-newRoundCh
  553. log.Notice("### ONTO ROUND 1")
  554. /*Round2
  555. // we timeout and prevote our lock
  556. // a polka happened but we didn't see it!
  557. */
  558. // now we're on a new round and not the proposer,
  559. // but we should receive the proposal
  560. select {
  561. case re = <-proposalCh:
  562. case <-timeoutProposeCh:
  563. re = <-proposalCh
  564. }
  565. rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
  566. if rs.LockedBlock != nil {
  567. panic("we should not be locked!")
  568. }
  569. log.Warn("new prop", "hash", fmt.Sprintf("%X", propBlockHash))
  570. // go to prevote, prevote for proposal block
  571. <-voteCh
  572. validatePrevote(t, cs1, 1, vss[0], propBlockHash)
  573. // now we see the others prevote for it, so we should lock on it
  574. signAddVotes(cs1, types.VoteTypePrevote, propBlockHash, propBlockParts.Header(), vs2, vs3, vs4)
  575. <-voteCh // precommit
  576. // we should have precommitted
  577. validatePrecommit(t, cs1, 1, 1, vss[0], propBlockHash, propBlockHash)
  578. signAddVotes(cs1, types.VoteTypePrecommit, nil, types.PartSetHeader{}, vs2, vs3)
  579. <-timeoutWaitCh
  580. incrementRound(vs2, vs3, vs4)
  581. <-newRoundCh
  582. log.Notice("### ONTO ROUND 2")
  583. /*Round3
  584. we see the polka from round 1 but we shouldn't unlock!
  585. */
  586. // timeout of propose
  587. <-timeoutProposeCh
  588. // finish prevote
  589. <-voteCh
  590. // we should prevote what we're locked on
  591. validatePrevote(t, cs1, 2, vss[0], propBlockHash)
  592. newStepCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRoundStep(), 1)
  593. // add prevotes from the earlier round
  594. addVotes(cs1, prevotes...)
  595. log.Warn("Done adding prevotes!")
  596. ensureNoNewStep(newStepCh)
  597. }
  598. // 4 vals.
  599. // polka P0 at R0, P1 at R1, and P2 at R2,
  600. // we lock on P0 at R0, don't see P1, and unlock using P2 at R2
  601. // then we should make sure we don't lock using P1
  602. // What we want:
  603. // dont see P0, lock on P1 at R1, dont unlock using P0 at R2
  604. func TestLockPOLSafety2(t *testing.T) {
  605. cs1, vss := randConsensusState(4)
  606. vs2, vs3, vs4 := vss[1], vss[2], vss[3]
  607. proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
  608. timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
  609. timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
  610. newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
  611. unlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringUnlock(), 1)
  612. voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
  613. // the block for R0: gets polkad but we miss it
  614. // (even though we signed it, shhh)
  615. _, propBlock0 := decideProposal(cs1, vss[0], cs1.Height, cs1.Round)
  616. propBlockHash0 := propBlock0.Hash()
  617. propBlockParts0 := propBlock0.MakePartSet()
  618. // the others sign a polka but we don't see it
  619. prevotes := signVotes(types.VoteTypePrevote, propBlockHash0, propBlockParts0.Header(), vs2, vs3, vs4)
  620. // the block for round 1
  621. prop1, propBlock1 := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1)
  622. propBlockHash1 := propBlock1.Hash()
  623. propBlockParts1 := propBlock1.MakePartSet()
  624. propBlockID1 := types.BlockID{propBlockHash1, propBlockParts1.Header()}
  625. incrementRound(vs2, vs3, vs4)
  626. cs1.updateRoundStep(0, RoundStepPrecommitWait)
  627. log.Notice("### ONTO Round 1")
  628. // jump in at round 1
  629. height := cs1.Height
  630. startTestRound(cs1, height, 1)
  631. <-newRoundCh
  632. cs1.SetProposalAndBlock(prop1, propBlock1, propBlockParts1, "some peer")
  633. <-proposalCh
  634. <-voteCh // prevote
  635. signAddVotes(cs1, types.VoteTypePrevote, propBlockHash1, propBlockParts1.Header(), vs2, vs3, vs4)
  636. <-voteCh // precommit
  637. // the proposed block should now be locked and our precommit added
  638. validatePrecommit(t, cs1, 1, 1, vss[0], propBlockHash1, propBlockHash1)
  639. // add precommits from the rest
  640. signAddVotes(cs1, types.VoteTypePrecommit, nil, types.PartSetHeader{}, vs2, vs4)
  641. signAddVotes(cs1, types.VoteTypePrecommit, propBlockHash1, propBlockParts1.Header(), vs3)
  642. incrementRound(vs2, vs3, vs4)
  643. // timeout of precommit wait to new round
  644. <-timeoutWaitCh
  645. // in round 2 we see the polkad block from round 0
  646. newProp := types.NewProposal(height, 2, propBlockParts0.Header(), 0, propBlockID1)
  647. if err := vs3.SignProposal(config.GetString("chain_id"), newProp); err != nil {
  648. t.Fatal(err)
  649. }
  650. cs1.SetProposalAndBlock(newProp, propBlock0, propBlockParts0, "some peer")
  651. // Add the pol votes
  652. addVotes(cs1, prevotes...)
  653. <-newRoundCh
  654. log.Notice("### ONTO Round 2")
  655. /*Round2
  656. // now we see the polka from round 1, but we shouldnt unlock
  657. */
  658. select {
  659. case <-timeoutProposeCh:
  660. <-proposalCh
  661. case <-proposalCh:
  662. }
  663. select {
  664. case <-unlockCh:
  665. panic("validator unlocked using an old polka")
  666. case <-voteCh:
  667. // prevote our locked block
  668. }
  669. validatePrevote(t, cs1, 2, vss[0], propBlockHash1)
  670. }
  671. //------------------------------------------------------------------------------------------
  672. // SlashingSuite
  673. // TODO: Slashing
  674. /*
  675. func TestSlashingPrevotes(t *testing.T) {
  676. cs1, vss := randConsensusState(2)
  677. vs2 := vss[1]
  678. proposalCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringCompleteProposal() , 1)
  679. timeoutWaitCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringTimeoutWait() , 1)
  680. newRoundCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringNewRound() , 1)
  681. voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
  682. // start round and wait for propose and prevote
  683. startTestRound(cs1, cs1.Height, 0)
  684. <-newRoundCh
  685. re := <-proposalCh
  686. <-voteCh // prevote
  687. rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
  688. // we should now be stuck in limbo forever, waiting for more prevotes
  689. // add one for a different block should cause us to go into prevote wait
  690. hash := rs.ProposalBlock.Hash()
  691. hash[0] = byte(hash[0]+1) % 255
  692. signAddVotes(cs1, types.VoteTypePrevote, hash, rs.ProposalBlockParts.Header(), vs2)
  693. <-timeoutWaitCh
  694. // NOTE: we have to send the vote for different block first so we don't just go into precommit round right
  695. // away and ignore more prevotes (and thus fail to slash!)
  696. // add the conflicting vote
  697. signAddVotes(cs1, types.VoteTypePrevote, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), vs2)
  698. // XXX: Check for existence of Dupeout info
  699. }
  700. func TestSlashingPrecommits(t *testing.T) {
  701. cs1, vss := randConsensusState(2)
  702. vs2 := vss[1]
  703. proposalCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringCompleteProposal() , 1)
  704. timeoutWaitCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringTimeoutWait() , 1)
  705. newRoundCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringNewRound() , 1)
  706. voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
  707. // start round and wait for propose and prevote
  708. startTestRound(cs1, cs1.Height, 0)
  709. <-newRoundCh
  710. re := <-proposalCh
  711. <-voteCh // prevote
  712. // add prevote from vs2
  713. signAddVotes(cs1, types.VoteTypePrevote, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), vs2)
  714. <-voteCh // precommit
  715. // we should now be stuck in limbo forever, waiting for more prevotes
  716. // add one for a different block should cause us to go into prevote wait
  717. hash := rs.ProposalBlock.Hash()
  718. hash[0] = byte(hash[0]+1) % 255
  719. signAddVotes(cs1, types.VoteTypePrecommit, hash, rs.ProposalBlockParts.Header(), vs2)
  720. // NOTE: we have to send the vote for different block first so we don't just go into precommit round right
  721. // away and ignore more prevotes (and thus fail to slash!)
  722. // add precommit from vs2
  723. signAddVotes(cs1, types.VoteTypePrecommit, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), vs2)
  724. // XXX: Check for existence of Dupeout info
  725. }
  726. */
  727. //------------------------------------------------------------------------------------------
  728. // CatchupSuite
  729. //------------------------------------------------------------------------------------------
  730. // HaltSuite
  731. // 4 vals.
  732. // we receive a final precommit after going into next round, but others might have gone to commit already!
  733. func TestHalt1(t *testing.T) {
  734. cs1, vss := randConsensusState(4)
  735. vs2, vs3, vs4 := vss[1], vss[2], vss[3]
  736. proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
  737. timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
  738. newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
  739. newBlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewBlock(), 1)
  740. voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
  741. // start round and wait for propose and prevote
  742. startTestRound(cs1, cs1.Height, 0)
  743. <-newRoundCh
  744. re := <-proposalCh
  745. rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
  746. propBlock := rs.ProposalBlock
  747. propBlockParts := propBlock.MakePartSet()
  748. <-voteCh // prevote
  749. signAddVotes(cs1, types.VoteTypePrevote, propBlock.Hash(), propBlockParts.Header(), vs3, vs4)
  750. <-voteCh // precommit
  751. // the proposed block should now be locked and our precommit added
  752. validatePrecommit(t, cs1, 0, 0, vss[0], propBlock.Hash(), propBlock.Hash())
  753. // add precommits from the rest
  754. signAddVotes(cs1, types.VoteTypePrecommit, nil, types.PartSetHeader{}, vs2) // didnt receive proposal
  755. signAddVotes(cs1, types.VoteTypePrecommit, propBlock.Hash(), propBlockParts.Header(), vs3)
  756. // we receive this later, but vs3 might receive it earlier and with ours will go to commit!
  757. precommit4 := signVote(vs4, types.VoteTypePrecommit, propBlock.Hash(), propBlockParts.Header())
  758. incrementRound(vs2, vs3, vs4)
  759. // timeout to new round
  760. <-timeoutWaitCh
  761. re = <-newRoundCh
  762. rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
  763. log.Notice("### ONTO ROUND 1")
  764. /*Round2
  765. // we timeout and prevote our lock
  766. // a polka happened but we didn't see it!
  767. */
  768. // go to prevote, prevote for locked block
  769. <-voteCh // prevote
  770. validatePrevote(t, cs1, 0, vss[0], rs.LockedBlock.Hash())
  771. // now we receive the precommit from the previous round
  772. addVotes(cs1, precommit4)
  773. // receiving that precommit should take us straight to commit
  774. <-newBlockCh
  775. re = <-newRoundCh
  776. rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
  777. if rs.Height != 2 {
  778. panic("expected height to increment")
  779. }
  780. }