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