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.

1025 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
  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 fuill 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.Address) {
  57. panic(Fmt("expected proposer to be validator %d. Got %X", 0, prop.Address))
  58. }
  59. // wait for complete proposal
  60. <-proposalCh
  61. rs := cs1.GetRoundState()
  62. signAddVoteToFromMany(types.VoteTypePrecommit, cs1, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), nil, 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. signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, rs.ProposalBlockParts.Header(), nil, 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. cs2 := 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, cs2)
  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(cs2.Height, round, propBlockParts.Header(), -1)
  158. if err := cs2.SignProposal(config.GetString("chain_id"), proposal); err != nil {
  159. panic("failed to sign bad proposal: " + err.Error())
  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 cs2 and wait for it
  171. signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, propBlock.Hash(), propBlock.MakePartSet().Header(), voteCh)
  172. // wait for precommit
  173. <-voteCh
  174. validatePrecommit(t, cs1, round, 0, vss[0], nil, nil)
  175. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, propBlock.Hash(), propBlock.MakePartSet().Header(), voteCh)
  176. }
  177. //----------------------------------------------------------------------------------------------------
  178. // FullRoundSuite
  179. // propose, prevote, and precommit a block
  180. func TestFullRound1(t *testing.T) {
  181. cs, vss := randConsensusState(1)
  182. height, round := cs.Height, cs.Round
  183. voteCh := subscribeToEvent(cs.evsw, "tester", types.EventStringVote(), 0)
  184. propCh := subscribeToEvent(cs.evsw, "tester", types.EventStringCompleteProposal(), 1)
  185. newRoundCh := subscribeToEvent(cs.evsw, "tester", types.EventStringNewRound(), 1)
  186. startTestRound(cs, height, round)
  187. <-newRoundCh
  188. // grab proposal
  189. re := <-propCh
  190. propBlockHash := re.(types.EventDataRoundState).RoundState.(*RoundState).ProposalBlock.Hash()
  191. <-voteCh // wait for prevote
  192. // NOTE: voteChan cap of 0 ensures we can complete this
  193. // before consensus can move to the next height (and cause a race condition)
  194. validatePrevote(t, cs, round, vss[0], propBlockHash)
  195. <-voteCh // wait for precommit
  196. // we're going to roll right into new height
  197. <-newRoundCh
  198. validateLastPrecommit(t, cs, vss[0], propBlockHash)
  199. }
  200. // nil is proposed, so prevote and precommit nil
  201. func TestFullRoundNil(t *testing.T) {
  202. cs, vss := randConsensusState(1)
  203. height, round := cs.Height, cs.Round
  204. voteCh := subscribeToEvent(cs.evsw, "tester", types.EventStringVote(), 1)
  205. cs.enterPrevote(height, round)
  206. cs.startRoutines(4)
  207. <-voteCh // prevote
  208. <-voteCh // precommit
  209. // should prevote and precommit nil
  210. validatePrevoteAndPrecommit(t, cs, round, 0, vss[0], nil, nil)
  211. }
  212. // run through propose, prevote, precommit commit with two validators
  213. // where the first validator has to wait for votes from the second
  214. func TestFullRound2(t *testing.T) {
  215. cs1, vss := randConsensusState(2)
  216. cs2 := vss[1]
  217. height, round := cs1.Height, cs1.Round
  218. voteCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringVote(), 1)
  219. newBlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewBlock(), 1)
  220. // start round and wait for propose and prevote
  221. startTestRound(cs1, height, round)
  222. <-voteCh // prevote
  223. // we should be stuck in limbo waiting for more prevotes
  224. rs := cs1.GetRoundState()
  225. propBlockHash, propPartsHeader := rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header()
  226. // prevote arrives from cs2:
  227. signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, propBlockHash, propPartsHeader, voteCh)
  228. <-voteCh //precommit
  229. // the proposed block should now be locked and our precommit added
  230. validatePrecommit(t, cs1, 0, 0, vss[0], propBlockHash, propBlockHash)
  231. // we should be stuck in limbo waiting for more precommits
  232. // precommit arrives from cs2:
  233. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, propBlockHash, propPartsHeader, voteCh)
  234. // wait to finish commit, propose in next height
  235. <-newBlockCh
  236. }
  237. //------------------------------------------------------------------------------------------
  238. // LockSuite
  239. // two validators, 4 rounds.
  240. // two vals take turns proposing. val1 locks on first one, precommits nil on everything else
  241. func TestLockNoPOL(t *testing.T) {
  242. cs1, vss := randConsensusState(2)
  243. cs2 := vss[1]
  244. height := cs1.Height
  245. timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
  246. timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
  247. voteCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringVote(), 1)
  248. proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
  249. newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
  250. /*
  251. Round1 (cs1, B) // B B // B B2
  252. */
  253. // start round and wait for prevote
  254. cs1.enterNewRound(height, 0)
  255. cs1.startRoutines(0)
  256. re := <-proposalCh
  257. rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
  258. theBlockHash := rs.ProposalBlock.Hash()
  259. <-voteCh // prevote
  260. // we should now be stuck in limbo forever, waiting for more prevotes
  261. // prevote arrives from cs2:
  262. signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), voteCh)
  263. <-voteCh // precommit
  264. // the proposed block should now be locked and our precommit added
  265. validatePrecommit(t, cs1, 0, 0, vss[0], theBlockHash, theBlockHash)
  266. // we should now be stuck in limbo forever, waiting for more precommits
  267. // lets add one for a different block
  268. // NOTE: in practice we should never get to a point where there are precommits for different blocks at the same round
  269. hash := make([]byte, len(theBlockHash))
  270. copy(hash, theBlockHash)
  271. hash[0] = byte((hash[0] + 1) % 255)
  272. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, hash, rs.ProposalBlock.MakePartSet().Header(), voteCh)
  273. // (note we're entering precommit for a second time this round)
  274. // but with invalid args. then we enterPrecommitWait, and the timeout to new round
  275. <-timeoutWaitCh
  276. ///
  277. <-newRoundCh
  278. log.Notice("#### ONTO ROUND 1")
  279. /*
  280. Round2 (cs1, B) // B B2
  281. */
  282. incrementRound(cs2)
  283. // now we're on a new round and not the proposer, so wait for timeout
  284. re = <-timeoutProposeCh
  285. rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
  286. if rs.ProposalBlock != nil {
  287. panic("Expected proposal block to be nil")
  288. }
  289. // wait to finish prevote
  290. <-voteCh
  291. // we should have prevoted our locked block
  292. validatePrevote(t, cs1, 1, vss[0], rs.LockedBlock.Hash())
  293. // add a conflicting prevote from the other validator
  294. signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, hash, rs.ProposalBlock.MakePartSet().Header(), voteCh)
  295. // now we're going to enter prevote again, but with invalid args
  296. // and then prevote wait, which should timeout. then wait for precommit
  297. <-timeoutWaitCh
  298. <-voteCh // precommit
  299. // the proposed block should still be locked and our precommit added
  300. // we should precommit nil and be locked on the proposal
  301. validatePrecommit(t, cs1, 1, 0, vss[0], nil, theBlockHash)
  302. // add conflicting precommit from cs2
  303. // NOTE: in practice we should never get to a point where there are precommits for different blocks at the same round
  304. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, hash, rs.ProposalBlock.MakePartSet().Header(), voteCh)
  305. // (note we're entering precommit for a second time this round, but with invalid args
  306. // then we enterPrecommitWait and timeout into NewRound
  307. <-timeoutWaitCh
  308. <-newRoundCh
  309. log.Notice("#### ONTO ROUND 2")
  310. /*
  311. Round3 (cs2, _) // B, B2
  312. */
  313. incrementRound(cs2)
  314. re = <-proposalCh
  315. rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
  316. // now we're on a new round and are the proposer
  317. if !bytes.Equal(rs.ProposalBlock.Hash(), rs.LockedBlock.Hash()) {
  318. panic(Fmt("Expected proposal block to be locked block. Got %v, Expected %v", rs.ProposalBlock, rs.LockedBlock))
  319. }
  320. <-voteCh // prevote
  321. validatePrevote(t, cs1, 2, vss[0], rs.LockedBlock.Hash())
  322. signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, hash, rs.ProposalBlock.MakePartSet().Header(), voteCh)
  323. <-timeoutWaitCh // prevote wait
  324. <-voteCh // precommit
  325. validatePrecommit(t, cs1, 2, 0, vss[0], nil, theBlockHash) // precommit nil but be locked on proposal
  326. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, hash, rs.ProposalBlock.MakePartSet().Header(), voteCh) // NOTE: conflicting precommits at same height
  327. <-timeoutWaitCh
  328. // before we time out into new round, set next proposal block
  329. prop, propBlock := decideProposal(cs1, cs2, cs2.Height, cs2.Round+1)
  330. if prop == nil || propBlock == nil {
  331. panic("Failed to create proposal block with cs2")
  332. }
  333. incrementRound(cs2)
  334. <-newRoundCh
  335. log.Notice("#### ONTO ROUND 3")
  336. /*
  337. Round4 (cs2, C) // B C // B C
  338. */
  339. // now we're on a new round and not the proposer
  340. // so set the proposal block
  341. cs1.SetProposalAndBlock(prop, propBlock, propBlock.MakePartSet(), "")
  342. <-proposalCh
  343. <-voteCh // prevote
  344. // prevote for locked block (not proposal)
  345. validatePrevote(t, cs1, 0, vss[0], cs1.LockedBlock.Hash())
  346. signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, propBlock.Hash(), propBlock.MakePartSet().Header(), voteCh)
  347. <-timeoutWaitCh
  348. <-voteCh
  349. validatePrecommit(t, cs1, 2, 0, vss[0], nil, theBlockHash) // precommit nil but locked on proposal
  350. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, propBlock.Hash(), propBlock.MakePartSet().Header(), voteCh) // NOTE: conflicting precommits at same height
  351. }
  352. // 4 vals, one precommits, other 3 polka at next round, so we unlock and precomit the polka
  353. func TestLockPOLRelock(t *testing.T) {
  354. cs1, vss := randConsensusState(4)
  355. cs2, cs3, cs4 := vss[1], vss[2], vss[3]
  356. timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
  357. timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
  358. proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
  359. voteCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringVote(), 1)
  360. newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
  361. newBlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewBlockHeader(), 1)
  362. log.Debug("cs2 last round", "lr", cs2.PrivValidator.LastRound)
  363. // everything done from perspective of cs1
  364. /*
  365. Round1 (cs1, B) // B B B B// B nil B nil
  366. eg. cs2 and cs4 didn't see the 2/3 prevotes
  367. */
  368. // start round and wait for propose and prevote
  369. startTestRound(cs1, cs1.Height, 0)
  370. <-newRoundCh
  371. re := <-proposalCh
  372. rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
  373. theBlockHash := rs.ProposalBlock.Hash()
  374. theBlockPartsHeader := rs.ProposalBlockParts.Header()
  375. <-voteCh // prevote
  376. signAddVoteToFromMany(types.VoteTypePrevote, cs1, theBlockHash, theBlockPartsHeader, voteCh, cs2, cs3, cs4)
  377. <-voteCh // our precommit
  378. // the proposed block should now be locked and our precommit added
  379. validatePrecommit(t, cs1, 0, 0, vss[0], theBlockHash, theBlockHash)
  380. // add precommits from the rest
  381. signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, voteCh, cs2, cs4)
  382. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs3, theBlockHash, theBlockPartsHeader, voteCh)
  383. // before we timeout to the new round set the new proposal
  384. prop, propBlock := decideProposal(cs1, cs2, cs2.Height, cs2.Round+1)
  385. propBlockParts := propBlock.MakePartSet()
  386. propBlockHash := propBlock.Hash()
  387. incrementRound(cs2, cs3, cs4)
  388. // timeout to new round
  389. <-timeoutWaitCh
  390. //XXX: this isnt gauranteed to get there before the timeoutPropose ...
  391. cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer")
  392. <-newRoundCh
  393. log.Notice("### ONTO ROUND 1")
  394. /*
  395. Round2 (cs2, C) // B C C C // C C C _)
  396. cs1 changes lock!
  397. */
  398. // now we're on a new round and not the proposer
  399. // but we should receive the proposal
  400. select {
  401. case <-proposalCh:
  402. case <-timeoutProposeCh:
  403. <-proposalCh
  404. }
  405. // go to prevote, prevote for locked block (not proposal), move on
  406. <-voteCh
  407. validatePrevote(t, cs1, 0, vss[0], theBlockHash)
  408. // now lets add prevotes from everyone else for the new block
  409. signAddVoteToFromMany(types.VoteTypePrevote, cs1, propBlockHash, propBlockParts.Header(), voteCh, cs2, cs3, cs4)
  410. // now either we go to PrevoteWait or Precommit
  411. select {
  412. case <-timeoutWaitCh: // we're in PrevoteWait, go to Precommit
  413. // XXX: there's no guarantee we see the polka, this might be a precommit for nil,
  414. // in which case the test fails!
  415. <-voteCh
  416. case <-voteCh: // we went straight to Precommit
  417. }
  418. // we should have unlocked and locked on the new block
  419. validatePrecommit(t, cs1, 1, 1, vss[0], propBlockHash, propBlockHash)
  420. signAddVoteToFromMany(types.VoteTypePrecommit, cs1, propBlockHash, propBlockParts.Header(), voteCh, cs2, cs3)
  421. be := <-newBlockCh
  422. b := be.(types.EventDataNewBlockHeader)
  423. re = <-newRoundCh
  424. rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
  425. if rs.Height != 2 {
  426. panic("Expected height to increment")
  427. }
  428. if !bytes.Equal(b.Header.Hash(), propBlockHash) {
  429. panic("Expected new block to be proposal block")
  430. }
  431. }
  432. // 4 vals, one precommits, other 3 polka at next round, so we unlock and precomit the polka
  433. func TestLockPOLUnlock(t *testing.T) {
  434. cs1, vss := randConsensusState(4)
  435. cs2, cs3, cs4 := vss[1], vss[2], vss[3]
  436. proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
  437. timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
  438. timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
  439. newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
  440. unlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringUnlock(), 1)
  441. voteCh := subscribeToVoter(cs1, cs1.privValidator.Address)
  442. // everything done from perspective of cs1
  443. /*
  444. Round1 (cs1, B) // B B B B // B nil B nil
  445. eg. didn't see the 2/3 prevotes
  446. */
  447. // start round and wait for propose and prevote
  448. startTestRound(cs1, cs1.Height, 0)
  449. <-newRoundCh
  450. re := <-proposalCh
  451. rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
  452. theBlockHash := rs.ProposalBlock.Hash()
  453. <-voteCh // prevote
  454. signAddVoteToFromMany(types.VoteTypePrevote, cs1, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), nil, cs2, cs3, cs4)
  455. <-voteCh //precommit
  456. // the proposed block should now be locked and our precommit added
  457. validatePrecommit(t, cs1, 0, 0, vss[0], theBlockHash, theBlockHash)
  458. rs = cs1.GetRoundState()
  459. // add precommits from the rest
  460. signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, nil, cs2, cs4)
  461. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs3, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), nil)
  462. // before we time out into new round, set next proposal block
  463. prop, propBlock := decideProposal(cs1, cs2, cs2.Height, cs2.Round+1)
  464. propBlockParts := propBlock.MakePartSet()
  465. incrementRound(cs2, cs3, cs4)
  466. // timeout to new round
  467. re = <-timeoutWaitCh
  468. rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
  469. lockedBlockHash := rs.LockedBlock.Hash()
  470. //XXX: this isnt gauranteed to get there before the timeoutPropose ...
  471. cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer")
  472. <-newRoundCh
  473. log.Notice("#### ONTO ROUND 1")
  474. /*
  475. Round2 (cs2, C) // B nil nil nil // nil nil nil _
  476. cs1 unlocks!
  477. */
  478. // now we're on a new round and not the proposer,
  479. // but we should receive the proposal
  480. select {
  481. case <-proposalCh:
  482. case <-timeoutProposeCh:
  483. <-proposalCh
  484. }
  485. // go to prevote, prevote for locked block (not proposal)
  486. <-voteCh
  487. validatePrevote(t, cs1, 0, vss[0], lockedBlockHash)
  488. // now lets add prevotes from everyone else for nil (a polka!)
  489. signAddVoteToFromMany(types.VoteTypePrevote, cs1, nil, types.PartSetHeader{}, nil, cs2, cs3, cs4)
  490. // the polka makes us unlock and precommit nil
  491. <-unlockCh
  492. <-voteCh // precommit
  493. // we should have unlocked and committed nil
  494. // NOTE: since we don't relock on nil, the lock round is 0
  495. validatePrecommit(t, cs1, 1, 0, vss[0], nil, nil)
  496. signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, nil, cs2, cs3)
  497. <-newRoundCh
  498. }
  499. // 4 vals
  500. // a polka at round 1 but we miss it
  501. // then a polka at round 2 that we lock on
  502. // then we see the polka from round 1 but shouldn't unlock
  503. func TestLockPOLSafety1(t *testing.T) {
  504. cs1, vss := randConsensusState(4)
  505. cs2, cs3, cs4 := vss[1], vss[2], vss[3]
  506. proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
  507. timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
  508. timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
  509. newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
  510. voteCh := subscribeToVoter(cs1, cs1.privValidator.Address)
  511. // start round and wait for propose and prevote
  512. startTestRound(cs1, cs1.Height, 0)
  513. <-newRoundCh
  514. re := <-proposalCh
  515. rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
  516. propBlock := rs.ProposalBlock
  517. <-voteCh // prevote
  518. validatePrevote(t, cs1, 0, vss[0], propBlock.Hash())
  519. // the others sign a polka but we don't see it
  520. prevotes := signVoteMany(types.VoteTypePrevote, propBlock.Hash(), propBlock.MakePartSet().Header(), cs2, cs3, cs4)
  521. // before we time out into new round, set next proposer
  522. // and next proposal block
  523. /*
  524. _, v1 := cs1.Validators.GetByAddress(vss[0].Address)
  525. v1.VotingPower = 1
  526. if updated := cs1.Validators.Update(v1); !updated {
  527. panic("failed to update validator")
  528. }*/
  529. log.Warn("old prop", "hash", fmt.Sprintf("%X", propBlock.Hash()))
  530. // we do see them precommit nil
  531. signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, nil, cs2, cs3, cs4)
  532. prop, propBlock := decideProposal(cs1, cs2, cs2.Height, cs2.Round+1)
  533. propBlockHash := propBlock.Hash()
  534. propBlockParts := propBlock.MakePartSet()
  535. incrementRound(cs2, cs3, cs4)
  536. //XXX: this isnt gauranteed to get there before the timeoutPropose ...
  537. cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer")
  538. <-newRoundCh
  539. log.Notice("### ONTO ROUND 1")
  540. /*Round2
  541. // we timeout and prevote our lock
  542. // a polka happened but we didn't see it!
  543. */
  544. // now we're on a new round and not the proposer,
  545. // but we should receive the proposal
  546. select {
  547. case re = <-proposalCh:
  548. case <-timeoutProposeCh:
  549. re = <-proposalCh
  550. }
  551. rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
  552. if rs.LockedBlock != nil {
  553. panic("we should not be locked!")
  554. }
  555. log.Warn("new prop", "hash", fmt.Sprintf("%X", propBlockHash))
  556. // go to prevote, prevote for proposal block
  557. <-voteCh
  558. validatePrevote(t, cs1, 1, vss[0], propBlockHash)
  559. // now we see the others prevote for it, so we should lock on it
  560. signAddVoteToFromMany(types.VoteTypePrevote, cs1, propBlockHash, propBlockParts.Header(), nil, cs2, cs3, cs4)
  561. <-voteCh // precommit
  562. // we should have precommitted
  563. validatePrecommit(t, cs1, 1, 1, vss[0], propBlockHash, propBlockHash)
  564. signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, nil, cs2, cs3)
  565. <-timeoutWaitCh
  566. incrementRound(cs2, cs3, cs4)
  567. <-newRoundCh
  568. log.Notice("### ONTO ROUND 2")
  569. /*Round3
  570. we see the polka from round 1 but we shouldn't unlock!
  571. */
  572. // timeout of propose
  573. <-timeoutProposeCh
  574. // finish prevote
  575. <-voteCh
  576. // we should prevote what we're locked on
  577. validatePrevote(t, cs1, 2, vss[0], propBlockHash)
  578. newStepCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRoundStep(), 1)
  579. // add prevotes from the earlier round
  580. addVoteToFromMany(cs1, prevotes, cs2, cs3, cs4)
  581. log.Warn("Done adding prevotes!")
  582. ensureNoNewStep(newStepCh)
  583. }
  584. // 4 vals.
  585. // polka P0 at R0, P1 at R1, and P2 at R2,
  586. // we lock on P0 at R0, don't see P1, and unlock using P2 at R2
  587. // then we should make sure we don't lock using P1
  588. // What we want:
  589. // dont see P0, lock on P1 at R1, dont unlock using P0 at R2
  590. func TestLockPOLSafety2(t *testing.T) {
  591. cs1, vss := randConsensusState(4)
  592. cs2, cs3, cs4 := vss[1], vss[2], vss[3]
  593. proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
  594. timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
  595. timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
  596. newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
  597. unlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringUnlock(), 1)
  598. voteCh := subscribeToVoter(cs1, cs1.privValidator.Address)
  599. // the block for R0: gets polkad but we miss it
  600. // (even though we signed it, shhh)
  601. _, propBlock0 := decideProposal(cs1, vss[0], cs1.Height, cs1.Round)
  602. propBlockHash0 := propBlock0.Hash()
  603. propBlockParts0 := propBlock0.MakePartSet()
  604. // the others sign a polka but we don't see it
  605. prevotes := signVoteMany(types.VoteTypePrevote, propBlockHash0, propBlockParts0.Header(), cs2, cs3, cs4)
  606. // the block for round 1
  607. prop1, propBlock1 := decideProposal(cs1, cs2, cs2.Height, cs2.Round+1)
  608. propBlockHash1 := propBlock1.Hash()
  609. propBlockParts1 := propBlock1.MakePartSet()
  610. incrementRound(cs2, cs3, cs4)
  611. cs1.updateRoundStep(0, RoundStepPrecommitWait)
  612. log.Notice("### ONTO Round 1")
  613. // jump in at round 1
  614. height := cs1.Height
  615. startTestRound(cs1, height, 1)
  616. <-newRoundCh
  617. cs1.SetProposalAndBlock(prop1, propBlock1, propBlockParts1, "some peer")
  618. <-proposalCh
  619. <-voteCh // prevote
  620. signAddVoteToFromMany(types.VoteTypePrevote, cs1, propBlockHash1, propBlockParts1.Header(), nil, cs2, cs3, cs4)
  621. <-voteCh // precommit
  622. // the proposed block should now be locked and our precommit added
  623. validatePrecommit(t, cs1, 1, 1, vss[0], propBlockHash1, propBlockHash1)
  624. // add precommits from the rest
  625. signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, nil, cs2, cs4)
  626. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs3, propBlockHash1, propBlockParts1.Header(), nil)
  627. incrementRound(cs2, cs3, cs4)
  628. // timeout of precommit wait to new round
  629. <-timeoutWaitCh
  630. // in round 2 we see the polkad block from round 0
  631. newProp := types.NewProposal(height, 2, propBlockParts0.Header(), 0)
  632. if err := cs3.SignProposal(config.GetString("chain_id"), newProp); err != nil {
  633. panic(err)
  634. }
  635. cs1.SetProposalAndBlock(newProp, propBlock0, propBlockParts0, "some peer")
  636. addVoteToFromMany(cs1, prevotes, cs2, cs3, cs4) // add the pol votes
  637. <-newRoundCh
  638. log.Notice("### ONTO Round 2")
  639. /*Round2
  640. // now we see the polka from round 1, but we shouldnt unlock
  641. */
  642. select {
  643. case <-timeoutProposeCh:
  644. <-proposalCh
  645. case <-proposalCh:
  646. }
  647. select {
  648. case <-unlockCh:
  649. panic("validator unlocked using an old polka")
  650. case <-voteCh:
  651. // prevote our locked block
  652. }
  653. validatePrevote(t, cs1, 2, vss[0], propBlockHash1)
  654. }
  655. //------------------------------------------------------------------------------------------
  656. // SlashingSuite
  657. // TODO: Slashing
  658. /*
  659. func TestSlashingPrevotes(t *testing.T) {
  660. cs1, vss := randConsensusState(2)
  661. cs2 := vss[1]
  662. proposalCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringCompleteProposal() , 1)
  663. timeoutWaitCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringTimeoutWait() , 1)
  664. newRoundCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringNewRound() , 1)
  665. voteCh := subscribeToVoter(cs1, cs1.privValidator.Address)
  666. // start round and wait for propose and prevote
  667. startTestRound(cs1, cs1.Height, 0)
  668. <-newRoundCh
  669. re := <-proposalCh
  670. <-voteCh // prevote
  671. rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
  672. // we should now be stuck in limbo forever, waiting for more prevotes
  673. // add one for a different block should cause us to go into prevote wait
  674. hash := rs.ProposalBlock.Hash()
  675. hash[0] = byte(hash[0]+1) % 255
  676. signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, hash, rs.ProposalBlockParts.Header(), nil)
  677. <-timeoutWaitCh
  678. // NOTE: we have to send the vote for different block first so we don't just go into precommit round right
  679. // away and ignore more prevotes (and thus fail to slash!)
  680. // add the conflicting vote
  681. signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(),nil)
  682. // XXX: Check for existence of Dupeout info
  683. }
  684. func TestSlashingPrecommits(t *testing.T) {
  685. cs1, vss := randConsensusState(2)
  686. cs2 := vss[1]
  687. proposalCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringCompleteProposal() , 1)
  688. timeoutWaitCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringTimeoutWait() , 1)
  689. newRoundCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringNewRound() , 1)
  690. voteCh := subscribeToVoter(cs1, cs1.privValidator.Address)
  691. // start round and wait for propose and prevote
  692. startTestRound(cs1, cs1.Height, 0)
  693. <-newRoundCh
  694. re := <-proposalCh
  695. <-voteCh // prevote
  696. // add prevote from cs2
  697. signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), nil)
  698. <-voteCh // precommit
  699. // we should now be stuck in limbo forever, waiting for more prevotes
  700. // add one for a different block should cause us to go into prevote wait
  701. hash := rs.ProposalBlock.Hash()
  702. hash[0] = byte(hash[0]+1) % 255
  703. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, hash, rs.ProposalBlockParts.Header(),nil)
  704. // NOTE: we have to send the vote for different block first so we don't just go into precommit round right
  705. // away and ignore more prevotes (and thus fail to slash!)
  706. // add precommit from cs2
  707. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(),nil)
  708. // XXX: Check for existence of Dupeout info
  709. }
  710. */
  711. //------------------------------------------------------------------------------------------
  712. // CatchupSuite
  713. //------------------------------------------------------------------------------------------
  714. // HaltSuite
  715. // 4 vals.
  716. // we receive a final precommit after going into next round, but others might have gone to commit already!
  717. func TestHalt1(t *testing.T) {
  718. cs1, vss := randConsensusState(4)
  719. cs2, cs3, cs4 := vss[1], vss[2], vss[3]
  720. proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
  721. timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
  722. newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
  723. newBlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewBlock(), 1)
  724. voteCh := subscribeToVoter(cs1, cs1.privValidator.Address)
  725. // start round and wait for propose and prevote
  726. startTestRound(cs1, cs1.Height, 0)
  727. <-newRoundCh
  728. re := <-proposalCh
  729. rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
  730. propBlock := rs.ProposalBlock
  731. propBlockParts := propBlock.MakePartSet()
  732. <-voteCh // prevote
  733. signAddVoteToFromMany(types.VoteTypePrevote, cs1, propBlock.Hash(), propBlockParts.Header(), nil, cs3, cs4)
  734. <-voteCh // precommit
  735. // the proposed block should now be locked and our precommit added
  736. validatePrecommit(t, cs1, 0, 0, vss[0], propBlock.Hash(), propBlock.Hash())
  737. // add precommits from the rest
  738. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, nil, types.PartSetHeader{}, nil) // didnt receive proposal
  739. signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs3, propBlock.Hash(), propBlockParts.Header(), nil)
  740. // we receive this later, but cs3 might receive it earlier and with ours will go to commit!
  741. precommit4 := signVote(cs4, types.VoteTypePrecommit, propBlock.Hash(), propBlockParts.Header())
  742. incrementRound(cs2, cs3, cs4)
  743. // timeout to new round
  744. <-timeoutWaitCh
  745. re = <-newRoundCh
  746. rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
  747. log.Notice("### ONTO ROUND 1")
  748. /*Round2
  749. // we timeout and prevote our lock
  750. // a polka happened but we didn't see it!
  751. */
  752. // go to prevote, prevote for locked block
  753. <-voteCh // prevote
  754. validatePrevote(t, cs1, 0, vss[0], rs.LockedBlock.Hash())
  755. // now we receive the precommit from the previous round
  756. addVoteToFrom(cs1, cs4, precommit4)
  757. // receiving that precommit should take us straight to commit
  758. <-newBlockCh
  759. re = <-newRoundCh
  760. rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
  761. if rs.Height != 2 {
  762. panic("expected height to increment")
  763. }
  764. }