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