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.

530 lines
16 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. err = voteSet.SetPeerMaj23("peerA", BlockID{blockHash1, PartSetHeader{}})
  277. require.NoError(t, err)
  278. // val0 votes again for blockHash1.
  279. {
  280. vote := withValidator(voteProto, val0Addr, 0)
  281. added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash1), voteSet)
  282. assert.True(t, added, "called SetPeerMaj23()")
  283. assert.Error(t, err, "conflicting vote")
  284. }
  285. // attempt tracking blockHash2, should fail because already set for peerA.
  286. err = voteSet.SetPeerMaj23("peerA", BlockID{blockHash2, PartSetHeader{}})
  287. require.Error(t, err)
  288. // val0 votes again for blockHash1.
  289. {
  290. vote := withValidator(voteProto, val0Addr, 0)
  291. added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash2), voteSet)
  292. assert.False(t, added, "duplicate SetPeerMaj23() from peerA")
  293. assert.Error(t, err, "conflicting vote")
  294. }
  295. // val1 votes for blockHash1.
  296. {
  297. pv, err := privValidators[1].GetPubKey()
  298. assert.NoError(t, err)
  299. addr := pv.Address()
  300. vote := withValidator(voteProto, addr, 1)
  301. added, err := signAddVote(privValidators[1], withBlockHash(vote, blockHash1), voteSet)
  302. if !added || err != nil {
  303. t.Errorf("expected VoteSet.Add to succeed")
  304. }
  305. }
  306. // check
  307. if voteSet.HasTwoThirdsMajority() {
  308. t.Errorf("we shouldn't have 2/3 majority yet")
  309. }
  310. if voteSet.HasTwoThirdsAny() {
  311. t.Errorf("we shouldn't have 2/3 if any votes yet")
  312. }
  313. // val2 votes for blockHash2.
  314. {
  315. pv, err := privValidators[2].GetPubKey()
  316. assert.NoError(t, err)
  317. addr := pv.Address()
  318. vote := withValidator(voteProto, addr, 2)
  319. added, err := signAddVote(privValidators[2], withBlockHash(vote, blockHash2), voteSet)
  320. if !added || err != nil {
  321. t.Errorf("expected VoteSet.Add to succeed")
  322. }
  323. }
  324. // check
  325. if voteSet.HasTwoThirdsMajority() {
  326. t.Errorf("we shouldn't have 2/3 majority yet")
  327. }
  328. if !voteSet.HasTwoThirdsAny() {
  329. t.Errorf("we should have 2/3 if any votes")
  330. }
  331. // now attempt tracking blockHash1
  332. err = voteSet.SetPeerMaj23("peerB", BlockID{blockHash1, PartSetHeader{}})
  333. require.NoError(t, err)
  334. // val2 votes for blockHash1.
  335. {
  336. pv, err := privValidators[2].GetPubKey()
  337. assert.NoError(t, err)
  338. addr := pv.Address()
  339. vote := withValidator(voteProto, addr, 2)
  340. added, err := signAddVote(privValidators[2], withBlockHash(vote, blockHash1), voteSet)
  341. assert.True(t, added)
  342. assert.Error(t, err, "conflicting vote")
  343. }
  344. // check
  345. if !voteSet.HasTwoThirdsMajority() {
  346. t.Errorf("we should have 2/3 majority for blockHash1")
  347. }
  348. blockIDMaj23, _ := voteSet.TwoThirdsMajority()
  349. if !bytes.Equal(blockIDMaj23.Hash, blockHash1) {
  350. t.Errorf("got the wrong 2/3 majority blockhash")
  351. }
  352. if !voteSet.HasTwoThirdsAny() {
  353. t.Errorf("we should have 2/3 if any votes")
  354. }
  355. }
  356. func TestVoteSet_MakeCommit(t *testing.T) {
  357. height, round := int64(1), int32(0)
  358. voteSet, _, privValidators := randVoteSet(height, round, tmproto.PrecommitType, 10, 1)
  359. blockHash, blockPartSetHeader := crypto.CRandBytes(32), PartSetHeader{123, crypto.CRandBytes(32)}
  360. voteProto := &Vote{
  361. ValidatorAddress: nil,
  362. ValidatorIndex: -1,
  363. Height: height,
  364. Round: round,
  365. Timestamp: tmtime.Now(),
  366. Type: tmproto.PrecommitType,
  367. BlockID: BlockID{blockHash, blockPartSetHeader},
  368. }
  369. // 6 out of 10 voted for some block.
  370. for i := int32(0); i < 6; i++ {
  371. pv, err := privValidators[i].GetPubKey()
  372. assert.NoError(t, err)
  373. addr := pv.Address()
  374. vote := withValidator(voteProto, addr, i)
  375. _, err = signAddVote(privValidators[i], vote, voteSet)
  376. if err != nil {
  377. t.Error(err)
  378. }
  379. }
  380. // MakeCommit should fail.
  381. assert.Panics(t, func() { voteSet.MakeCommit() }, "Doesn't have +2/3 majority")
  382. // 7th voted for some other block.
  383. {
  384. pv, err := privValidators[6].GetPubKey()
  385. assert.NoError(t, err)
  386. addr := pv.Address()
  387. vote := withValidator(voteProto, addr, 6)
  388. vote = withBlockHash(vote, tmrand.Bytes(32))
  389. vote = withBlockPartSetHeader(vote, PartSetHeader{123, tmrand.Bytes(32)})
  390. _, err = signAddVote(privValidators[6], vote, voteSet)
  391. require.NoError(t, err)
  392. }
  393. // The 8th voted like everyone else.
  394. {
  395. pv, err := privValidators[7].GetPubKey()
  396. assert.NoError(t, err)
  397. addr := pv.Address()
  398. vote := withValidator(voteProto, addr, 7)
  399. _, err = signAddVote(privValidators[7], vote, voteSet)
  400. require.NoError(t, err)
  401. }
  402. // The 9th voted for nil.
  403. {
  404. pv, err := privValidators[8].GetPubKey()
  405. assert.NoError(t, err)
  406. addr := pv.Address()
  407. vote := withValidator(voteProto, addr, 8)
  408. vote.BlockID = BlockID{}
  409. _, err = signAddVote(privValidators[8], vote, voteSet)
  410. require.NoError(t, err)
  411. }
  412. commit := voteSet.MakeCommit()
  413. // Commit should have 10 elements
  414. assert.Equal(t, 10, len(commit.Signatures))
  415. // Ensure that Commit is good.
  416. if err := commit.ValidateBasic(); err != nil {
  417. t.Errorf("error in Commit.ValidateBasic(): %v", err)
  418. }
  419. }
  420. // NOTE: privValidators are in order
  421. func randVoteSet(
  422. height int64,
  423. round int32,
  424. signedMsgType tmproto.SignedMsgType,
  425. numValidators int,
  426. votingPower int64,
  427. ) (*VoteSet, *ValidatorSet, []PrivValidator) {
  428. valSet, privValidators := RandValidatorSet(numValidators, votingPower)
  429. return NewVoteSet("test_chain_id", height, round, signedMsgType, valSet), valSet, privValidators
  430. }
  431. // Convenience: Return new vote with different validator address/index
  432. func withValidator(vote *Vote, addr []byte, idx int32) *Vote {
  433. vote = vote.Copy()
  434. vote.ValidatorAddress = addr
  435. vote.ValidatorIndex = idx
  436. return vote
  437. }
  438. // Convenience: Return new vote with different height
  439. func withHeight(vote *Vote, height int64) *Vote {
  440. vote = vote.Copy()
  441. vote.Height = height
  442. return vote
  443. }
  444. // Convenience: Return new vote with different round
  445. func withRound(vote *Vote, round int32) *Vote {
  446. vote = vote.Copy()
  447. vote.Round = round
  448. return vote
  449. }
  450. // Convenience: Return new vote with different type
  451. func withType(vote *Vote, signedMsgType byte) *Vote {
  452. vote = vote.Copy()
  453. vote.Type = tmproto.SignedMsgType(signedMsgType)
  454. return vote
  455. }
  456. // Convenience: Return new vote with different blockHash
  457. func withBlockHash(vote *Vote, blockHash []byte) *Vote {
  458. vote = vote.Copy()
  459. vote.BlockID.Hash = blockHash
  460. return vote
  461. }
  462. // Convenience: Return new vote with different blockParts
  463. func withBlockPartSetHeader(vote *Vote, blockPartsHeader PartSetHeader) *Vote {
  464. vote = vote.Copy()
  465. vote.BlockID.PartSetHeader = blockPartsHeader
  466. return vote
  467. }