github.com/adoriasoft/tendermint@v0.34.0-dev1.0.20200722151356-96d84601a75a/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  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
    13  	tmtime "github.com/tendermint/tendermint/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  	voteSet.SetPeerMaj23("peerA", BlockID{blockHash1, PartSetHeader{}})
   311  
   312  	// val0 votes again for blockHash1.
   313  	{
   314  		vote := withValidator(voteProto, val0Addr, 0)
   315  		added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash1), voteSet)
   316  		assert.True(t, added, "called SetPeerMaj23()")
   317  		assert.Error(t, err, "conflicting vote")
   318  	}
   319  
   320  	// attempt tracking blockHash2, should fail because already set for peerA.
   321  	voteSet.SetPeerMaj23("peerA", BlockID{blockHash2, PartSetHeader{}})
   322  
   323  	// val0 votes again for blockHash1.
   324  	{
   325  		vote := withValidator(voteProto, val0Addr, 0)
   326  		added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash2), voteSet)
   327  		assert.False(t, added, "duplicate SetPeerMaj23() from peerA")
   328  		assert.Error(t, err, "conflicting vote")
   329  	}
   330  
   331  	// val1 votes for blockHash1.
   332  	{
   333  		pv, err := privValidators[1].GetPubKey()
   334  		assert.NoError(t, err)
   335  		addr := pv.Address()
   336  		vote := withValidator(voteProto, addr, 1)
   337  		added, err := signAddVote(privValidators[1], withBlockHash(vote, blockHash1), voteSet)
   338  		if !added || err != nil {
   339  			t.Errorf("expected VoteSet.Add to succeed")
   340  		}
   341  	}
   342  
   343  	// check
   344  	if voteSet.HasTwoThirdsMajority() {
   345  		t.Errorf("we shouldn't have 2/3 majority yet")
   346  	}
   347  	if voteSet.HasTwoThirdsAny() {
   348  		t.Errorf("we shouldn't have 2/3 if any votes yet")
   349  	}
   350  
   351  	// val2 votes for blockHash2.
   352  	{
   353  		pv, err := privValidators[2].GetPubKey()
   354  		assert.NoError(t, err)
   355  		addr := pv.Address()
   356  		vote := withValidator(voteProto, addr, 2)
   357  		added, err := signAddVote(privValidators[2], withBlockHash(vote, blockHash2), voteSet)
   358  		if !added || err != nil {
   359  			t.Errorf("expected VoteSet.Add to succeed")
   360  		}
   361  	}
   362  
   363  	// check
   364  	if voteSet.HasTwoThirdsMajority() {
   365  		t.Errorf("we shouldn't have 2/3 majority yet")
   366  	}
   367  	if !voteSet.HasTwoThirdsAny() {
   368  		t.Errorf("we should have 2/3 if any votes")
   369  	}
   370  
   371  	// now attempt tracking blockHash1
   372  	voteSet.SetPeerMaj23("peerB", BlockID{blockHash1, PartSetHeader{}})
   373  
   374  	// val2 votes for blockHash1.
   375  	{
   376  		pv, err := privValidators[2].GetPubKey()
   377  		assert.NoError(t, err)
   378  		addr := pv.Address()
   379  		vote := withValidator(voteProto, addr, 2)
   380  		added, err := signAddVote(privValidators[2], withBlockHash(vote, blockHash1), voteSet)
   381  		assert.True(t, added)
   382  		assert.Error(t, err, "conflicting vote")
   383  	}
   384  
   385  	// check
   386  	if !voteSet.HasTwoThirdsMajority() {
   387  		t.Errorf("we should have 2/3 majority for blockHash1")
   388  	}
   389  	blockIDMaj23, _ := voteSet.TwoThirdsMajority()
   390  	if !bytes.Equal(blockIDMaj23.Hash, blockHash1) {
   391  		t.Errorf("got the wrong 2/3 majority blockhash")
   392  	}
   393  	if !voteSet.HasTwoThirdsAny() {
   394  		t.Errorf("we should have 2/3 if any votes")
   395  	}
   396  }
   397  
   398  func TestVoteSet_MakeCommit(t *testing.T) {
   399  	height, round := int64(1), int32(0)
   400  	voteSet, _, privValidators := randVoteSet(height, round, tmproto.PrecommitType, 10, 1)
   401  	blockHash, blockPartSetHeader := crypto.CRandBytes(32), PartSetHeader{123, crypto.CRandBytes(32)}
   402  
   403  	voteProto := &Vote{
   404  		ValidatorAddress: nil,
   405  		ValidatorIndex:   -1,
   406  		Height:           height,
   407  		Round:            round,
   408  		Timestamp:        tmtime.Now(),
   409  		Type:             tmproto.PrecommitType,
   410  		BlockID:          BlockID{blockHash, blockPartSetHeader},
   411  	}
   412  
   413  	// 6 out of 10 voted for some block.
   414  	for i := int32(0); i < 6; i++ {
   415  		pv, err := privValidators[i].GetPubKey()
   416  		assert.NoError(t, err)
   417  		addr := pv.Address()
   418  		vote := withValidator(voteProto, addr, i)
   419  		_, err = signAddVote(privValidators[i], vote, voteSet)
   420  		if err != nil {
   421  			t.Error(err)
   422  		}
   423  	}
   424  
   425  	// MakeCommit should fail.
   426  	assert.Panics(t, func() { voteSet.MakeCommit() }, "Doesn't have +2/3 majority")
   427  
   428  	// 7th voted for some other block.
   429  	{
   430  		pv, err := privValidators[6].GetPubKey()
   431  		assert.NoError(t, err)
   432  		addr := pv.Address()
   433  		vote := withValidator(voteProto, addr, 6)
   434  		vote = withBlockHash(vote, tmrand.Bytes(32))
   435  		vote = withBlockPartSetHeader(vote, PartSetHeader{123, tmrand.Bytes(32)})
   436  
   437  		_, err = signAddVote(privValidators[6], vote, voteSet)
   438  		require.NoError(t, err)
   439  	}
   440  
   441  	// The 8th voted like everyone else.
   442  	{
   443  		pv, err := privValidators[7].GetPubKey()
   444  		assert.NoError(t, err)
   445  		addr := pv.Address()
   446  		vote := withValidator(voteProto, addr, 7)
   447  		_, err = signAddVote(privValidators[7], vote, voteSet)
   448  		require.NoError(t, err)
   449  	}
   450  
   451  	// The 9th voted for nil.
   452  	{
   453  		pv, err := privValidators[8].GetPubKey()
   454  		assert.NoError(t, err)
   455  		addr := pv.Address()
   456  		vote := withValidator(voteProto, addr, 8)
   457  		vote.BlockID = BlockID{}
   458  
   459  		_, err = signAddVote(privValidators[8], vote, voteSet)
   460  		require.NoError(t, err)
   461  	}
   462  
   463  	commit := voteSet.MakeCommit()
   464  
   465  	// Commit should have 10 elements
   466  	assert.Equal(t, 10, len(commit.Signatures))
   467  
   468  	// Ensure that Commit is good.
   469  	if err := commit.ValidateBasic(); err != nil {
   470  		t.Errorf("error in Commit.ValidateBasic(): %v", err)
   471  	}
   472  }
   473  
   474  func buildVoteSet(
   475  	height int64, round int32, nonVotes, nonNilVotes, nilVotes int,
   476  	voteType tmproto.SignedMsgType) (voteSet *VoteSet, valSet *ValidatorSet,
   477  	privValidators []PrivValidator, blockID BlockID) {
   478  
   479  	blockID = makeBlockIDRandom()
   480  	voteSet, valSet, privValidators = buildVoteSetForBlock(height, round, nonVotes, nonNilVotes, nilVotes, voteType,
   481  		blockID)
   482  	return
   483  }
   484  
   485  func buildVoteSetForBlock(height int64,
   486  	round int32, nonVotes, nonNilVotes, nilVotes int,
   487  	voteType tmproto.SignedMsgType, blockID BlockID) (*VoteSet, *ValidatorSet, []PrivValidator) {
   488  	valSize := nonVotes + nilVotes + nonNilVotes
   489  	voteSet, valSet, privValidators := randVoteSet(height, round, voteType, valSize, 1)
   490  	voteProto := &Vote{
   491  		ValidatorAddress: nil,
   492  		ValidatorIndex:   -1,
   493  		Height:           height,
   494  		Round:            round,
   495  		Type:             voteType,
   496  		Timestamp:        tmtime.Now(),
   497  		BlockID:          blockID,
   498  	}
   499  	for i := 0; i < nonNilVotes; i++ {
   500  		pubKey, _ := privValidators[i].GetPubKey()
   501  		addr := pubKey.Address()
   502  		vote := withValidator(voteProto, addr, int32(i))
   503  		_, _ = signAddVote(privValidators[i], vote, voteSet)
   504  	}
   505  	for i := nonNilVotes; i < nonNilVotes+nilVotes; i++ {
   506  		pubKey, _ := privValidators[i].GetPubKey()
   507  		addr := pubKey.Address()
   508  		vote := withValidator(voteProto, addr, int32(i))
   509  		_, _ = signAddVote(privValidators[i], withBlockHash(vote, nil), voteSet)
   510  	}
   511  	return voteSet, valSet, privValidators
   512  }
   513  
   514  // NOTE: privValidators are in order
   515  func randVoteSet(
   516  	height int64,
   517  	round int32,
   518  	signedMsgType tmproto.SignedMsgType,
   519  	numValidators int,
   520  	votingPower int64,
   521  ) (*VoteSet, *ValidatorSet, []PrivValidator) {
   522  	valSet, privValidators := RandValidatorSet(numValidators, votingPower)
   523  	return NewVoteSet("test_chain_id", height, round, signedMsgType, valSet), valSet, privValidators
   524  }
   525  
   526  // Convenience: Return new vote with different validator address/index
   527  func withValidator(vote *Vote, addr []byte, idx int32) *Vote {
   528  	vote = vote.Copy()
   529  	vote.ValidatorAddress = addr
   530  	vote.ValidatorIndex = idx
   531  	return vote
   532  }
   533  
   534  // Convenience: Return new vote with different height
   535  func withHeight(vote *Vote, height int64) *Vote {
   536  	vote = vote.Copy()
   537  	vote.Height = height
   538  	return vote
   539  }
   540  
   541  // Convenience: Return new vote with different round
   542  func withRound(vote *Vote, round int32) *Vote {
   543  	vote = vote.Copy()
   544  	vote.Round = round
   545  	return vote
   546  }
   547  
   548  // Convenience: Return new vote with different type
   549  func withType(vote *Vote, signedMsgType byte) *Vote {
   550  	vote = vote.Copy()
   551  	vote.Type = tmproto.SignedMsgType(signedMsgType)
   552  	return vote
   553  }
   554  
   555  // Convenience: Return new vote with different blockHash
   556  func withBlockHash(vote *Vote, blockHash []byte) *Vote {
   557  	vote = vote.Copy()
   558  	vote.BlockID.Hash = blockHash
   559  	return vote
   560  }
   561  
   562  // Convenience: Return new vote with different blockParts
   563  func withBlockPartSetHeader(vote *Vote, blockPartsHeader PartSetHeader) *Vote {
   564  	vote = vote.Copy()
   565  	vote.BlockID.PartSetHeader = blockPartsHeader
   566  	return vote
   567  }