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.

1026 lines
34 KiB

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