github.com/DFWallet/tendermint-cosmos@v0.0.2/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/DFWallet/tendermint-cosmos/crypto"
    11  	tmrand "github.com/DFWallet/tendermint-cosmos/libs/rand"
    12  	tmproto "github.com/DFWallet/tendermint-cosmos/proto/tendermint/types"
    13  	tmtime "github.com/DFWallet/tendermint-cosmos/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  }