gitlab.com/gpdionisio/tendermint@v0.34.19-dev2/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 err = voteSet.SetPeerMaj23("peerA", BlockID{blockHash1, PartSetHeader{}}) 311 require.NoError(t, err) 312 313 // val0 votes again for blockHash1. 314 { 315 vote := withValidator(voteProto, val0Addr, 0) 316 added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash1), voteSet) 317 assert.True(t, added, "called SetPeerMaj23()") 318 assert.Error(t, err, "conflicting vote") 319 } 320 321 // attempt tracking blockHash2, should fail because already set for peerA. 322 err = voteSet.SetPeerMaj23("peerA", BlockID{blockHash2, PartSetHeader{}}) 323 require.Error(t, err) 324 325 // val0 votes again for blockHash1. 326 { 327 vote := withValidator(voteProto, val0Addr, 0) 328 added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash2), voteSet) 329 assert.False(t, added, "duplicate SetPeerMaj23() from peerA") 330 assert.Error(t, err, "conflicting vote") 331 } 332 333 // val1 votes for blockHash1. 334 { 335 pv, err := privValidators[1].GetPubKey() 336 assert.NoError(t, err) 337 addr := pv.Address() 338 vote := withValidator(voteProto, addr, 1) 339 added, err := signAddVote(privValidators[1], withBlockHash(vote, blockHash1), voteSet) 340 if !added || err != nil { 341 t.Errorf("expected VoteSet.Add to succeed") 342 } 343 } 344 345 // check 346 if voteSet.HasTwoThirdsMajority() { 347 t.Errorf("we shouldn't have 2/3 majority yet") 348 } 349 if voteSet.HasTwoThirdsAny() { 350 t.Errorf("we shouldn't have 2/3 if any votes yet") 351 } 352 353 // val2 votes for blockHash2. 354 { 355 pv, err := privValidators[2].GetPubKey() 356 assert.NoError(t, err) 357 addr := pv.Address() 358 vote := withValidator(voteProto, addr, 2) 359 added, err := signAddVote(privValidators[2], withBlockHash(vote, blockHash2), voteSet) 360 if !added || err != nil { 361 t.Errorf("expected VoteSet.Add to succeed") 362 } 363 } 364 365 // check 366 if voteSet.HasTwoThirdsMajority() { 367 t.Errorf("we shouldn't have 2/3 majority yet") 368 } 369 if !voteSet.HasTwoThirdsAny() { 370 t.Errorf("we should have 2/3 if any votes") 371 } 372 373 // now attempt tracking blockHash1 374 err = voteSet.SetPeerMaj23("peerB", BlockID{blockHash1, PartSetHeader{}}) 375 require.NoError(t, err) 376 377 // val2 votes for blockHash1. 378 { 379 pv, err := privValidators[2].GetPubKey() 380 assert.NoError(t, err) 381 addr := pv.Address() 382 vote := withValidator(voteProto, addr, 2) 383 added, err := signAddVote(privValidators[2], withBlockHash(vote, blockHash1), voteSet) 384 assert.True(t, added) 385 assert.Error(t, err, "conflicting vote") 386 } 387 388 // check 389 if !voteSet.HasTwoThirdsMajority() { 390 t.Errorf("we should have 2/3 majority for blockHash1") 391 } 392 blockIDMaj23, _ := voteSet.TwoThirdsMajority() 393 if !bytes.Equal(blockIDMaj23.Hash, blockHash1) { 394 t.Errorf("got the wrong 2/3 majority blockhash") 395 } 396 if !voteSet.HasTwoThirdsAny() { 397 t.Errorf("we should have 2/3 if any votes") 398 } 399 } 400 401 func TestVoteSet_MakeCommit(t *testing.T) { 402 height, round := int64(1), int32(0) 403 voteSet, _, privValidators := randVoteSet(height, round, tmproto.PrecommitType, 10, 1) 404 blockHash, blockPartSetHeader := crypto.CRandBytes(32), PartSetHeader{123, crypto.CRandBytes(32)} 405 406 voteProto := &Vote{ 407 ValidatorAddress: nil, 408 ValidatorIndex: -1, 409 Height: height, 410 Round: round, 411 Timestamp: tmtime.Now(), 412 Type: tmproto.PrecommitType, 413 BlockID: BlockID{blockHash, blockPartSetHeader}, 414 } 415 416 // 6 out of 10 voted for some block. 417 for i := int32(0); i < 6; i++ { 418 pv, err := privValidators[i].GetPubKey() 419 assert.NoError(t, err) 420 addr := pv.Address() 421 vote := withValidator(voteProto, addr, i) 422 _, err = signAddVote(privValidators[i], vote, voteSet) 423 if err != nil { 424 t.Error(err) 425 } 426 } 427 428 // MakeCommit should fail. 429 assert.Panics(t, func() { voteSet.MakeCommit() }, "Doesn't have +2/3 majority") 430 431 // 7th voted for some other block. 432 { 433 pv, err := privValidators[6].GetPubKey() 434 assert.NoError(t, err) 435 addr := pv.Address() 436 vote := withValidator(voteProto, addr, 6) 437 vote = withBlockHash(vote, tmrand.Bytes(32)) 438 vote = withBlockPartSetHeader(vote, PartSetHeader{123, tmrand.Bytes(32)}) 439 440 _, err = signAddVote(privValidators[6], vote, voteSet) 441 require.NoError(t, err) 442 } 443 444 // The 8th voted like everyone else. 445 { 446 pv, err := privValidators[7].GetPubKey() 447 assert.NoError(t, err) 448 addr := pv.Address() 449 vote := withValidator(voteProto, addr, 7) 450 _, err = signAddVote(privValidators[7], vote, voteSet) 451 require.NoError(t, err) 452 } 453 454 // The 9th voted for nil. 455 { 456 pv, err := privValidators[8].GetPubKey() 457 assert.NoError(t, err) 458 addr := pv.Address() 459 vote := withValidator(voteProto, addr, 8) 460 vote.BlockID = BlockID{} 461 462 _, err = signAddVote(privValidators[8], vote, voteSet) 463 require.NoError(t, err) 464 } 465 466 commit := voteSet.MakeCommit() 467 468 // Commit should have 10 elements 469 assert.Equal(t, 10, len(commit.Signatures)) 470 471 // Ensure that Commit is good. 472 if err := commit.ValidateBasic(); err != nil { 473 t.Errorf("error in Commit.ValidateBasic(): %v", err) 474 } 475 } 476 477 // NOTE: privValidators are in order 478 func randVoteSet( 479 height int64, 480 round int32, 481 signedMsgType tmproto.SignedMsgType, 482 numValidators int, 483 votingPower int64, 484 ) (*VoteSet, *ValidatorSet, []PrivValidator) { 485 valSet, privValidators := RandValidatorSet(numValidators, votingPower) 486 return NewVoteSet("test_chain_id", height, round, signedMsgType, valSet), valSet, privValidators 487 } 488 489 // Convenience: Return new vote with different validator address/index 490 func withValidator(vote *Vote, addr []byte, idx int32) *Vote { 491 vote = vote.Copy() 492 vote.ValidatorAddress = addr 493 vote.ValidatorIndex = idx 494 return vote 495 } 496 497 // Convenience: Return new vote with different height 498 func withHeight(vote *Vote, height int64) *Vote { 499 vote = vote.Copy() 500 vote.Height = height 501 return vote 502 } 503 504 // Convenience: Return new vote with different round 505 func withRound(vote *Vote, round int32) *Vote { 506 vote = vote.Copy() 507 vote.Round = round 508 return vote 509 } 510 511 // Convenience: Return new vote with different type 512 func withType(vote *Vote, signedMsgType byte) *Vote { 513 vote = vote.Copy() 514 vote.Type = tmproto.SignedMsgType(signedMsgType) 515 return vote 516 } 517 518 // Convenience: Return new vote with different blockHash 519 func withBlockHash(vote *Vote, blockHash []byte) *Vote { 520 vote = vote.Copy() 521 vote.BlockID.Hash = blockHash 522 return vote 523 } 524 525 // Convenience: Return new vote with different blockParts 526 func withBlockPartSetHeader(vote *Vote, blockPartsHeader PartSetHeader) *Vote { 527 vote = vote.Copy() 528 vote.BlockID.PartSetHeader = blockPartsHeader 529 return vote 530 }