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.

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