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.

531 lines
16 KiB

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