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  }