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.

567 lines
17 KiB

  1. package types
  2. import (
  3. "bytes"
  4. "testing"
  5. "github.com/stretchr/testify/assert"
  6. "github.com/stretchr/testify/require"
  7. "github.com/tendermint/tendermint/crypto"
  8. tmrand "github.com/tendermint/tendermint/libs/rand"
  9. tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
  10. tmtime "github.com/tendermint/tendermint/types/time"
  11. )
  12. func TestVoteSet_AddVote_Good(t *testing.T) {
  13. height, round := int64(1), int32(0)
  14. voteSet, _, privValidators := randVoteSet(height, round, tmproto.PrevoteType, 10, 1)
  15. val0 := privValidators[0]
  16. val0p, err := val0.GetPubKey()
  17. require.NoError(t, err)
  18. val0Addr := val0p.Address()
  19. assert.Nil(t, voteSet.GetByAddress(val0Addr))
  20. assert.False(t, voteSet.BitArray().GetIndex(0))
  21. blockID, ok := voteSet.TwoThirdsMajority()
  22. assert.False(t, ok || !blockID.IsZero(), "there should be no 2/3 majority")
  23. vote := &Vote{
  24. ValidatorAddress: val0Addr,
  25. ValidatorIndex: 0, // since privValidators are in order
  26. Height: height,
  27. Round: round,
  28. Type: tmproto.PrevoteType,
  29. Timestamp: tmtime.Now(),
  30. BlockID: BlockID{nil, PartSetHeader{}},
  31. }
  32. _, err = signAddVote(val0, vote, voteSet)
  33. require.NoError(t, err)
  34. assert.NotNil(t, voteSet.GetByAddress(val0Addr))
  35. assert.True(t, voteSet.BitArray().GetIndex(0))
  36. blockID, ok = voteSet.TwoThirdsMajority()
  37. assert.False(t, ok || !blockID.IsZero(), "there should be no 2/3 majority")
  38. }
  39. func TestVoteSet_AddVote_Bad(t *testing.T) {
  40. height, round := int64(1), int32(0)
  41. voteSet, _, privValidators := randVoteSet(height, round, tmproto.PrevoteType, 10, 1)
  42. voteProto := &Vote{
  43. ValidatorAddress: nil,
  44. ValidatorIndex: -1,
  45. Height: height,
  46. Round: round,
  47. Timestamp: tmtime.Now(),
  48. Type: tmproto.PrevoteType,
  49. BlockID: BlockID{nil, PartSetHeader{}},
  50. }
  51. // val0 votes for nil.
  52. {
  53. pubKey, err := privValidators[0].GetPubKey()
  54. require.NoError(t, err)
  55. addr := pubKey.Address()
  56. vote := withValidator(voteProto, addr, 0)
  57. added, err := signAddVote(privValidators[0], vote, voteSet)
  58. if !added || err != nil {
  59. t.Errorf("expected VoteSet.Add to succeed")
  60. }
  61. }
  62. // val0 votes again for some block.
  63. {
  64. pubKey, err := privValidators[0].GetPubKey()
  65. require.NoError(t, err)
  66. addr := pubKey.Address()
  67. vote := withValidator(voteProto, addr, 0)
  68. added, err := signAddVote(privValidators[0], withBlockHash(vote, tmrand.Bytes(32)), voteSet)
  69. if added || err == nil {
  70. t.Errorf("expected VoteSet.Add to fail, conflicting vote.")
  71. }
  72. }
  73. // val1 votes on another height
  74. {
  75. pubKey, err := privValidators[1].GetPubKey()
  76. require.NoError(t, err)
  77. addr := pubKey.Address()
  78. vote := withValidator(voteProto, addr, 1)
  79. added, err := signAddVote(privValidators[1], withHeight(vote, height+1), voteSet)
  80. if added || err == nil {
  81. t.Errorf("expected VoteSet.Add to fail, wrong height")
  82. }
  83. }
  84. // val2 votes on another round
  85. {
  86. pubKey, err := privValidators[2].GetPubKey()
  87. require.NoError(t, err)
  88. addr := pubKey.Address()
  89. vote := withValidator(voteProto, addr, 2)
  90. added, err := signAddVote(privValidators[2], withRound(vote, round+1), voteSet)
  91. if added || err == nil {
  92. t.Errorf("expected VoteSet.Add to fail, wrong round")
  93. }
  94. }
  95. // val3 votes of another type.
  96. {
  97. pubKey, err := privValidators[3].GetPubKey()
  98. require.NoError(t, err)
  99. addr := pubKey.Address()
  100. vote := withValidator(voteProto, addr, 3)
  101. added, err := signAddVote(privValidators[3], withType(vote, byte(tmproto.PrecommitType)), voteSet)
  102. if added || err == nil {
  103. t.Errorf("expected VoteSet.Add to fail, wrong type")
  104. }
  105. }
  106. }
  107. func TestVoteSet_2_3Majority(t *testing.T) {
  108. height, round := int64(1), int32(0)
  109. voteSet, _, privValidators := randVoteSet(height, round, tmproto.PrevoteType, 10, 1)
  110. voteProto := &Vote{
  111. ValidatorAddress: nil, // NOTE: must fill in
  112. ValidatorIndex: -1, // NOTE: must fill in
  113. Height: height,
  114. Round: round,
  115. Type: tmproto.PrevoteType,
  116. Timestamp: tmtime.Now(),
  117. BlockID: BlockID{nil, PartSetHeader{}},
  118. }
  119. // 6 out of 10 voted for nil.
  120. for i := int32(0); i < 6; i++ {
  121. pubKey, err := privValidators[i].GetPubKey()
  122. require.NoError(t, err)
  123. addr := pubKey.Address()
  124. vote := withValidator(voteProto, addr, i)
  125. _, err = signAddVote(privValidators[i], vote, voteSet)
  126. require.NoError(t, err)
  127. }
  128. blockID, ok := voteSet.TwoThirdsMajority()
  129. assert.False(t, ok || !blockID.IsZero(), "there should be no 2/3 majority")
  130. // 7th validator voted for some blockhash
  131. {
  132. pubKey, err := privValidators[6].GetPubKey()
  133. require.NoError(t, err)
  134. addr := pubKey.Address()
  135. vote := withValidator(voteProto, addr, 6)
  136. _, err = signAddVote(privValidators[6], withBlockHash(vote, tmrand.Bytes(32)), voteSet)
  137. require.NoError(t, err)
  138. blockID, ok = voteSet.TwoThirdsMajority()
  139. assert.False(t, ok || !blockID.IsZero(), "there should be no 2/3 majority")
  140. }
  141. // 8th validator voted for nil.
  142. {
  143. pubKey, err := privValidators[7].GetPubKey()
  144. require.NoError(t, err)
  145. addr := pubKey.Address()
  146. vote := withValidator(voteProto, addr, 7)
  147. _, err = signAddVote(privValidators[7], vote, voteSet)
  148. require.NoError(t, err)
  149. blockID, ok = voteSet.TwoThirdsMajority()
  150. assert.True(t, ok || blockID.IsZero(), "there should be 2/3 majority for nil")
  151. }
  152. }
  153. func TestVoteSet_2_3MajorityRedux(t *testing.T) {
  154. height, round := int64(1), int32(0)
  155. voteSet, _, privValidators := randVoteSet(height, round, tmproto.PrevoteType, 100, 1)
  156. blockHash := crypto.CRandBytes(32)
  157. blockPartsTotal := uint32(123)
  158. blockPartSetHeader := PartSetHeader{blockPartsTotal, crypto.CRandBytes(32)}
  159. voteProto := &Vote{
  160. ValidatorAddress: nil, // NOTE: must fill in
  161. ValidatorIndex: -1, // NOTE: must fill in
  162. Height: height,
  163. Round: round,
  164. Timestamp: tmtime.Now(),
  165. Type: tmproto.PrevoteType,
  166. BlockID: BlockID{blockHash, blockPartSetHeader},
  167. }
  168. // 66 out of 100 voted for nil.
  169. for i := int32(0); i < 66; i++ {
  170. pubKey, err := privValidators[i].GetPubKey()
  171. require.NoError(t, err)
  172. addr := pubKey.Address()
  173. vote := withValidator(voteProto, addr, i)
  174. _, err = signAddVote(privValidators[i], vote, voteSet)
  175. require.NoError(t, err)
  176. }
  177. blockID, ok := voteSet.TwoThirdsMajority()
  178. assert.False(t, ok || !blockID.IsZero(),
  179. "there should be no 2/3 majority")
  180. // 67th validator voted for nil
  181. {
  182. pubKey, err := privValidators[66].GetPubKey()
  183. require.NoError(t, err)
  184. adrr := pubKey.Address()
  185. vote := withValidator(voteProto, adrr, 66)
  186. _, err = signAddVote(privValidators[66], withBlockHash(vote, nil), voteSet)
  187. require.NoError(t, err)
  188. blockID, ok = voteSet.TwoThirdsMajority()
  189. assert.False(t, ok || !blockID.IsZero(),
  190. "there should be no 2/3 majority: last vote added was nil")
  191. }
  192. // 68th validator voted for a different BlockParts PartSetHeader
  193. {
  194. pubKey, err := privValidators[67].GetPubKey()
  195. require.NoError(t, err)
  196. addr := pubKey.Address()
  197. vote := withValidator(voteProto, addr, 67)
  198. blockPartsHeader := PartSetHeader{blockPartsTotal, crypto.CRandBytes(32)}
  199. _, err = signAddVote(privValidators[67], withBlockPartSetHeader(vote, blockPartsHeader), voteSet)
  200. require.NoError(t, err)
  201. blockID, ok = voteSet.TwoThirdsMajority()
  202. assert.False(t, ok || !blockID.IsZero(),
  203. "there should be no 2/3 majority: last vote added had different PartSetHeader Hash")
  204. }
  205. // 69th validator voted for different BlockParts Total
  206. {
  207. pubKey, err := privValidators[68].GetPubKey()
  208. require.NoError(t, err)
  209. addr := pubKey.Address()
  210. vote := withValidator(voteProto, addr, 68)
  211. blockPartsHeader := PartSetHeader{blockPartsTotal + 1, blockPartSetHeader.Hash}
  212. _, err = signAddVote(privValidators[68], withBlockPartSetHeader(vote, blockPartsHeader), voteSet)
  213. require.NoError(t, err)
  214. blockID, ok = voteSet.TwoThirdsMajority()
  215. assert.False(t, ok || !blockID.IsZero(),
  216. "there should be no 2/3 majority: last vote added had different PartSetHeader Total")
  217. }
  218. // 70th validator voted for different BlockHash
  219. {
  220. pubKey, err := privValidators[69].GetPubKey()
  221. require.NoError(t, err)
  222. addr := pubKey.Address()
  223. vote := withValidator(voteProto, addr, 69)
  224. _, err = signAddVote(privValidators[69], withBlockHash(vote, tmrand.Bytes(32)), voteSet)
  225. require.NoError(t, err)
  226. blockID, ok = voteSet.TwoThirdsMajority()
  227. assert.False(t, ok || !blockID.IsZero(),
  228. "there should be no 2/3 majority: last vote added had different BlockHash")
  229. }
  230. // 71st validator voted for the right BlockHash & BlockPartSetHeader
  231. {
  232. pubKey, err := privValidators[70].GetPubKey()
  233. require.NoError(t, err)
  234. addr := pubKey.Address()
  235. vote := withValidator(voteProto, addr, 70)
  236. _, err = signAddVote(privValidators[70], vote, voteSet)
  237. require.NoError(t, err)
  238. blockID, ok = voteSet.TwoThirdsMajority()
  239. assert.True(t, ok && blockID.Equals(BlockID{blockHash, blockPartSetHeader}),
  240. "there should be 2/3 majority")
  241. }
  242. }
  243. func TestVoteSet_Conflicts(t *testing.T) {
  244. height, round := int64(1), int32(0)
  245. voteSet, _, privValidators := randVoteSet(height, round, tmproto.PrevoteType, 4, 1)
  246. blockHash1 := tmrand.Bytes(32)
  247. blockHash2 := tmrand.Bytes(32)
  248. voteProto := &Vote{
  249. ValidatorAddress: nil,
  250. ValidatorIndex: -1,
  251. Height: height,
  252. Round: round,
  253. Timestamp: tmtime.Now(),
  254. Type: tmproto.PrevoteType,
  255. BlockID: BlockID{nil, PartSetHeader{}},
  256. }
  257. val0, err := privValidators[0].GetPubKey()
  258. require.NoError(t, err)
  259. val0Addr := val0.Address()
  260. // val0 votes for nil.
  261. {
  262. vote := withValidator(voteProto, val0Addr, 0)
  263. added, err := signAddVote(privValidators[0], vote, voteSet)
  264. if !added || err != nil {
  265. t.Errorf("expected VoteSet.Add to succeed")
  266. }
  267. }
  268. // val0 votes again for blockHash1.
  269. {
  270. vote := withValidator(voteProto, val0Addr, 0)
  271. added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash1), voteSet)
  272. assert.False(t, added, "conflicting vote")
  273. assert.Error(t, err, "conflicting vote")
  274. }
  275. // start tracking blockHash1
  276. voteSet.SetPeerMaj23("peerA", BlockID{blockHash1, PartSetHeader{}})
  277. // val0 votes again for blockHash1.
  278. {
  279. vote := withValidator(voteProto, val0Addr, 0)
  280. added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash1), voteSet)
  281. assert.True(t, added, "called SetPeerMaj23()")
  282. assert.Error(t, err, "conflicting vote")
  283. }
  284. // attempt tracking blockHash2, should fail because already set for peerA.
  285. voteSet.SetPeerMaj23("peerA", BlockID{blockHash2, PartSetHeader{}})
  286. // val0 votes again for blockHash1.
  287. {
  288. vote := withValidator(voteProto, val0Addr, 0)
  289. added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash2), voteSet)
  290. assert.False(t, added, "duplicate SetPeerMaj23() from peerA")
  291. assert.Error(t, err, "conflicting vote")
  292. }
  293. // val1 votes for blockHash1.
  294. {
  295. pv, err := privValidators[1].GetPubKey()
  296. assert.NoError(t, err)
  297. addr := pv.Address()
  298. vote := withValidator(voteProto, addr, 1)
  299. added, err := signAddVote(privValidators[1], withBlockHash(vote, blockHash1), voteSet)
  300. if !added || err != nil {
  301. t.Errorf("expected VoteSet.Add to succeed")
  302. }
  303. }
  304. // check
  305. if voteSet.HasTwoThirdsMajority() {
  306. t.Errorf("we shouldn't have 2/3 majority yet")
  307. }
  308. if voteSet.HasTwoThirdsAny() {
  309. t.Errorf("we shouldn't have 2/3 if any votes yet")
  310. }
  311. // val2 votes for blockHash2.
  312. {
  313. pv, err := privValidators[2].GetPubKey()
  314. assert.NoError(t, err)
  315. addr := pv.Address()
  316. vote := withValidator(voteProto, addr, 2)
  317. added, err := signAddVote(privValidators[2], withBlockHash(vote, blockHash2), voteSet)
  318. if !added || err != nil {
  319. t.Errorf("expected VoteSet.Add to succeed")
  320. }
  321. }
  322. // check
  323. if voteSet.HasTwoThirdsMajority() {
  324. t.Errorf("we shouldn't have 2/3 majority yet")
  325. }
  326. if !voteSet.HasTwoThirdsAny() {
  327. t.Errorf("we should have 2/3 if any votes")
  328. }
  329. // now attempt tracking blockHash1
  330. voteSet.SetPeerMaj23("peerB", BlockID{blockHash1, PartSetHeader{}})
  331. // val2 votes for blockHash1.
  332. {
  333. pv, err := privValidators[2].GetPubKey()
  334. assert.NoError(t, err)
  335. addr := pv.Address()
  336. vote := withValidator(voteProto, addr, 2)
  337. added, err := signAddVote(privValidators[2], withBlockHash(vote, blockHash1), voteSet)
  338. assert.True(t, added)
  339. assert.Error(t, err, "conflicting vote")
  340. }
  341. // check
  342. if !voteSet.HasTwoThirdsMajority() {
  343. t.Errorf("we should have 2/3 majority for blockHash1")
  344. }
  345. blockIDMaj23, _ := voteSet.TwoThirdsMajority()
  346. if !bytes.Equal(blockIDMaj23.Hash, blockHash1) {
  347. t.Errorf("got the wrong 2/3 majority blockhash")
  348. }
  349. if !voteSet.HasTwoThirdsAny() {
  350. t.Errorf("we should have 2/3 if any votes")
  351. }
  352. }
  353. func TestVoteSet_MakeCommit(t *testing.T) {
  354. height, round := int64(1), int32(0)
  355. voteSet, _, privValidators := randVoteSet(height, round, tmproto.PrecommitType, 10, 1)
  356. blockHash, blockPartSetHeader := crypto.CRandBytes(32), PartSetHeader{123, crypto.CRandBytes(32)}
  357. voteProto := &Vote{
  358. ValidatorAddress: nil,
  359. ValidatorIndex: -1,
  360. Height: height,
  361. Round: round,
  362. Timestamp: tmtime.Now(),
  363. Type: tmproto.PrecommitType,
  364. BlockID: BlockID{blockHash, blockPartSetHeader},
  365. }
  366. // 6 out of 10 voted for some block.
  367. for i := int32(0); i < 6; i++ {
  368. pv, err := privValidators[i].GetPubKey()
  369. assert.NoError(t, err)
  370. addr := pv.Address()
  371. vote := withValidator(voteProto, addr, i)
  372. _, err = signAddVote(privValidators[i], vote, voteSet)
  373. if err != nil {
  374. t.Error(err)
  375. }
  376. }
  377. // MakeCommit should fail.
  378. assert.Panics(t, func() { voteSet.MakeCommit() }, "Doesn't have +2/3 majority")
  379. // 7th voted for some other block.
  380. {
  381. pv, err := privValidators[6].GetPubKey()
  382. assert.NoError(t, err)
  383. addr := pv.Address()
  384. vote := withValidator(voteProto, addr, 6)
  385. vote = withBlockHash(vote, tmrand.Bytes(32))
  386. vote = withBlockPartSetHeader(vote, PartSetHeader{123, tmrand.Bytes(32)})
  387. _, err = signAddVote(privValidators[6], vote, voteSet)
  388. require.NoError(t, err)
  389. }
  390. // The 8th voted like everyone else.
  391. {
  392. pv, err := privValidators[7].GetPubKey()
  393. assert.NoError(t, err)
  394. addr := pv.Address()
  395. vote := withValidator(voteProto, addr, 7)
  396. _, err = signAddVote(privValidators[7], vote, voteSet)
  397. require.NoError(t, err)
  398. }
  399. // The 9th voted for nil.
  400. {
  401. pv, err := privValidators[8].GetPubKey()
  402. assert.NoError(t, err)
  403. addr := pv.Address()
  404. vote := withValidator(voteProto, addr, 8)
  405. vote.BlockID = BlockID{}
  406. _, err = signAddVote(privValidators[8], vote, voteSet)
  407. require.NoError(t, err)
  408. }
  409. commit := voteSet.MakeCommit()
  410. // Commit should have 10 elements
  411. assert.Equal(t, 10, len(commit.Signatures))
  412. // Ensure that Commit is good.
  413. if err := commit.ValidateBasic(); err != nil {
  414. t.Errorf("error in Commit.ValidateBasic(): %v", err)
  415. }
  416. }
  417. func buildVoteSet(
  418. height int64, round int32, nonVotes, nonNilVotes, nilVotes int,
  419. voteType tmproto.SignedMsgType) (voteSet *VoteSet, valSet *ValidatorSet,
  420. privValidators []PrivValidator, blockID BlockID) {
  421. blockID = makeBlockIDRandom()
  422. voteSet, valSet, privValidators = buildVoteSetForBlock(height, round, nonVotes, nonNilVotes, nilVotes, voteType,
  423. blockID)
  424. return
  425. }
  426. func buildVoteSetForBlock(height int64,
  427. round int32, nonVotes, nonNilVotes, nilVotes int,
  428. voteType tmproto.SignedMsgType, blockID BlockID) (*VoteSet, *ValidatorSet, []PrivValidator) {
  429. valSize := nonVotes + nilVotes + nonNilVotes
  430. voteSet, valSet, privValidators := randVoteSet(height, round, voteType, valSize, 1)
  431. voteProto := &Vote{
  432. ValidatorAddress: nil,
  433. ValidatorIndex: -1,
  434. Height: height,
  435. Round: round,
  436. Type: voteType,
  437. Timestamp: tmtime.Now(),
  438. BlockID: blockID,
  439. }
  440. for i := 0; i < nonNilVotes; i++ {
  441. pubKey, _ := privValidators[i].GetPubKey()
  442. addr := pubKey.Address()
  443. vote := withValidator(voteProto, addr, int32(i))
  444. _, _ = signAddVote(privValidators[i], vote, voteSet)
  445. }
  446. for i := nonNilVotes; i < nonNilVotes+nilVotes; i++ {
  447. pubKey, _ := privValidators[i].GetPubKey()
  448. addr := pubKey.Address()
  449. vote := withValidator(voteProto, addr, int32(i))
  450. _, _ = signAddVote(privValidators[i], withBlockHash(vote, nil), voteSet)
  451. }
  452. return voteSet, valSet, privValidators
  453. }
  454. // NOTE: privValidators are in order
  455. func randVoteSet(
  456. height int64,
  457. round int32,
  458. signedMsgType tmproto.SignedMsgType,
  459. numValidators int,
  460. votingPower int64,
  461. ) (*VoteSet, *ValidatorSet, []PrivValidator) {
  462. valSet, privValidators := RandValidatorSet(numValidators, votingPower)
  463. return NewVoteSet("test_chain_id", height, round, signedMsgType, valSet), valSet, privValidators
  464. }
  465. // Convenience: Return new vote with different validator address/index
  466. func withValidator(vote *Vote, addr []byte, idx int32) *Vote {
  467. vote = vote.Copy()
  468. vote.ValidatorAddress = addr
  469. vote.ValidatorIndex = idx
  470. return vote
  471. }
  472. // Convenience: Return new vote with different height
  473. func withHeight(vote *Vote, height int64) *Vote {
  474. vote = vote.Copy()
  475. vote.Height = height
  476. return vote
  477. }
  478. // Convenience: Return new vote with different round
  479. func withRound(vote *Vote, round int32) *Vote {
  480. vote = vote.Copy()
  481. vote.Round = round
  482. return vote
  483. }
  484. // Convenience: Return new vote with different type
  485. func withType(vote *Vote, signedMsgType byte) *Vote {
  486. vote = vote.Copy()
  487. vote.Type = tmproto.SignedMsgType(signedMsgType)
  488. return vote
  489. }
  490. // Convenience: Return new vote with different blockHash
  491. func withBlockHash(vote *Vote, blockHash []byte) *Vote {
  492. vote = vote.Copy()
  493. vote.BlockID.Hash = blockHash
  494. return vote
  495. }
  496. // Convenience: Return new vote with different blockParts
  497. func withBlockPartSetHeader(vote *Vote, blockPartsHeader PartSetHeader) *Vote {
  498. vote = vote.Copy()
  499. vote.BlockID.PartSetHeader = blockPartsHeader
  500. return vote
  501. }