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.

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