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