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.

1058 lines
34 KiB

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