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