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.

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