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