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