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.

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