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.

589 lines
18 KiB

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