2015-08-10 20:38:45 -07:00
|
|
|
package types
|
2014-10-14 13:11:54 -07:00
|
|
|
|
|
|
|
import (
|
2014-10-31 18:35:38 -07:00
|
|
|
"bytes"
|
|
|
|
|
2015-10-22 17:39:06 -07:00
|
|
|
. "github.com/tendermint/go-common"
|
|
|
|
. "github.com/tendermint/go-common/test"
|
2016-01-12 15:58:48 -08:00
|
|
|
"github.com/tendermint/go-crypto"
|
2014-10-14 13:11:54 -07:00
|
|
|
|
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
2015-12-31 15:02:38 -08:00
|
|
|
// Move it out?
|
2015-08-10 20:38:45 -07:00
|
|
|
func randVoteSet(height int, round int, type_ byte, numValidators int, votingPower int64) (*VoteSet, *ValidatorSet, []*PrivValidator) {
|
2015-12-31 15:02:38 -08:00
|
|
|
valSet, privValidators := RandValidatorSet(numValidators, votingPower)
|
2016-05-08 15:00:58 -07:00
|
|
|
return NewVoteSet("test_chain_id", height, round, type_, valSet), valSet, privValidators
|
2015-08-10 20:38:45 -07:00
|
|
|
}
|
2014-10-15 20:15:38 -07:00
|
|
|
|
2014-12-23 23:20:49 -08:00
|
|
|
// Convenience: Return new vote with different height
|
2015-08-10 20:38:45 -07:00
|
|
|
func withHeight(vote *Vote, height int) *Vote {
|
2014-12-23 23:20:49 -08:00
|
|
|
vote = vote.Copy()
|
|
|
|
vote.Height = height
|
|
|
|
return vote
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convenience: Return new vote with different round
|
2015-08-10 20:38:45 -07:00
|
|
|
func withRound(vote *Vote, round int) *Vote {
|
2014-12-23 23:20:49 -08:00
|
|
|
vote = vote.Copy()
|
|
|
|
vote.Round = round
|
|
|
|
return vote
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convenience: Return new vote with different type
|
2015-08-10 20:38:45 -07:00
|
|
|
func withType(vote *Vote, type_ byte) *Vote {
|
2014-12-23 23:20:49 -08:00
|
|
|
vote = vote.Copy()
|
|
|
|
vote.Type = type_
|
|
|
|
return vote
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convenience: Return new vote with different blockHash
|
2015-08-10 20:38:45 -07:00
|
|
|
func withBlockHash(vote *Vote, blockHash []byte) *Vote {
|
2014-12-23 23:20:49 -08:00
|
|
|
vote = vote.Copy()
|
|
|
|
vote.BlockHash = blockHash
|
|
|
|
return vote
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convenience: Return new vote with different blockParts
|
2015-08-12 22:36:43 -07:00
|
|
|
func withBlockPartsHeader(vote *Vote, blockPartsHeader PartSetHeader) *Vote {
|
2014-12-23 23:20:49 -08:00
|
|
|
vote = vote.Copy()
|
2015-08-12 22:36:43 -07:00
|
|
|
vote.BlockPartsHeader = blockPartsHeader
|
2014-12-23 23:20:49 -08:00
|
|
|
return vote
|
|
|
|
}
|
|
|
|
|
2015-08-10 20:38:45 -07:00
|
|
|
func signAddVote(privVal *PrivValidator, vote *Vote, voteSet *VoteSet) (bool, error) {
|
2016-05-08 15:00:58 -07:00
|
|
|
vote.Signature = privVal.Sign(SignBytes(voteSet.ChainID(), vote)).(crypto.SignatureEd25519)
|
2015-06-04 13:36:47 -07:00
|
|
|
added, _, err := voteSet.AddByAddress(privVal.Address, vote)
|
2014-12-23 23:20:49 -08:00
|
|
|
return added, err
|
|
|
|
}
|
|
|
|
|
2014-10-14 13:11:54 -07:00
|
|
|
func TestAddVote(t *testing.T) {
|
2015-06-25 20:28:34 -07:00
|
|
|
height, round := 1, 0
|
2015-08-10 20:38:45 -07:00
|
|
|
voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrevote, 10, 1)
|
2014-12-17 01:37:13 -08:00
|
|
|
val0 := privValidators[0]
|
2014-10-15 20:15:38 -07:00
|
|
|
|
2014-10-15 23:55:52 -07:00
|
|
|
// t.Logf(">> %v", voteSet)
|
2014-10-15 20:15:38 -07:00
|
|
|
|
2014-12-17 01:37:13 -08:00
|
|
|
if voteSet.GetByAddress(val0.Address) != nil {
|
|
|
|
t.Errorf("Expected GetByAddress(val0.Address) to be nil")
|
2014-10-15 23:55:52 -07:00
|
|
|
}
|
|
|
|
if voteSet.BitArray().GetIndex(0) {
|
|
|
|
t.Errorf("Expected BitArray.GetIndex(0) to be false")
|
|
|
|
}
|
2014-10-30 03:32:09 -07:00
|
|
|
hash, header, ok := voteSet.TwoThirdsMajority()
|
|
|
|
if hash != nil || !header.IsZero() || ok {
|
2014-10-15 23:55:52 -07:00
|
|
|
t.Errorf("There should be no 2/3 majority")
|
|
|
|
}
|
|
|
|
|
2015-08-10 20:38:45 -07:00
|
|
|
vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: nil}
|
2014-12-23 23:20:49 -08:00
|
|
|
signAddVote(val0, vote, voteSet)
|
2014-10-15 20:15:38 -07:00
|
|
|
|
2014-12-17 01:37:13 -08:00
|
|
|
if voteSet.GetByAddress(val0.Address) == nil {
|
|
|
|
t.Errorf("Expected GetByAddress(val0.Address) to be present")
|
2014-10-15 23:55:52 -07:00
|
|
|
}
|
|
|
|
if !voteSet.BitArray().GetIndex(0) {
|
|
|
|
t.Errorf("Expected BitArray.GetIndex(0) to be true")
|
|
|
|
}
|
2014-10-30 03:32:09 -07:00
|
|
|
hash, header, ok = voteSet.TwoThirdsMajority()
|
|
|
|
if hash != nil || !header.IsZero() || ok {
|
2014-10-15 23:55:52 -07:00
|
|
|
t.Errorf("There should be no 2/3 majority")
|
|
|
|
}
|
2014-10-14 13:11:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func Test2_3Majority(t *testing.T) {
|
2015-06-25 20:28:34 -07:00
|
|
|
height, round := 1, 0
|
2015-08-10 20:38:45 -07:00
|
|
|
voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrevote, 10, 1)
|
2014-10-15 23:55:52 -07:00
|
|
|
|
2015-08-10 20:38:45 -07:00
|
|
|
vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: nil}
|
2014-12-23 23:20:49 -08:00
|
|
|
|
2014-10-15 23:55:52 -07:00
|
|
|
// 6 out of 10 voted for nil.
|
|
|
|
for i := 0; i < 6; i++ {
|
2014-12-23 23:20:49 -08:00
|
|
|
signAddVote(privValidators[i], vote, voteSet)
|
2014-10-15 23:55:52 -07:00
|
|
|
}
|
2014-10-30 03:32:09 -07:00
|
|
|
hash, header, ok := voteSet.TwoThirdsMajority()
|
|
|
|
if hash != nil || !header.IsZero() || ok {
|
2014-10-15 23:55:52 -07:00
|
|
|
t.Errorf("There should be no 2/3 majority")
|
|
|
|
}
|
|
|
|
|
|
|
|
// 7th validator voted for some blockhash
|
2014-10-31 18:35:38 -07:00
|
|
|
{
|
2014-12-23 23:20:49 -08:00
|
|
|
signAddVote(privValidators[6], withBlockHash(vote, RandBytes(32)), voteSet)
|
2014-10-31 18:35:38 -07:00
|
|
|
hash, header, ok = voteSet.TwoThirdsMajority()
|
|
|
|
if hash != nil || !header.IsZero() || ok {
|
|
|
|
t.Errorf("There should be no 2/3 majority")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 8th validator voted for nil.
|
|
|
|
{
|
2014-12-23 23:20:49 -08:00
|
|
|
signAddVote(privValidators[7], vote, voteSet)
|
2014-10-31 18:35:38 -07:00
|
|
|
hash, header, ok = voteSet.TwoThirdsMajority()
|
|
|
|
if hash != nil || !header.IsZero() || !ok {
|
|
|
|
t.Errorf("There should be 2/3 majority for nil")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test2_3MajorityRedux(t *testing.T) {
|
2015-06-25 20:28:34 -07:00
|
|
|
height, round := 1, 0
|
2015-08-10 20:38:45 -07:00
|
|
|
voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrevote, 100, 1)
|
2014-10-31 18:35:38 -07:00
|
|
|
|
2016-03-13 10:01:32 -07:00
|
|
|
blockHash := crypto.CRandBytes(32)
|
2015-06-25 20:28:34 -07:00
|
|
|
blockPartsTotal := 123
|
2016-03-13 10:01:32 -07:00
|
|
|
blockPartsHeader := PartSetHeader{blockPartsTotal, crypto.CRandBytes(32)}
|
2014-10-31 18:35:38 -07:00
|
|
|
|
2015-08-12 22:36:43 -07:00
|
|
|
vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: blockHash, BlockPartsHeader: blockPartsHeader}
|
2014-12-23 23:20:49 -08:00
|
|
|
|
2014-10-31 18:35:38 -07:00
|
|
|
// 66 out of 100 voted for nil.
|
|
|
|
for i := 0; i < 66; i++ {
|
2014-12-23 23:20:49 -08:00
|
|
|
signAddVote(privValidators[i], vote, voteSet)
|
2014-10-31 18:35:38 -07:00
|
|
|
}
|
|
|
|
hash, header, ok := voteSet.TwoThirdsMajority()
|
2014-10-30 03:32:09 -07:00
|
|
|
if hash != nil || !header.IsZero() || ok {
|
2014-10-15 23:55:52 -07:00
|
|
|
t.Errorf("There should be no 2/3 majority")
|
|
|
|
}
|
|
|
|
|
2014-10-31 18:35:38 -07:00
|
|
|
// 67th validator voted for nil
|
|
|
|
{
|
2014-12-23 23:20:49 -08:00
|
|
|
signAddVote(privValidators[66], withBlockHash(vote, nil), voteSet)
|
2014-10-31 18:35:38 -07:00
|
|
|
hash, header, ok = voteSet.TwoThirdsMajority()
|
|
|
|
if hash != nil || !header.IsZero() || ok {
|
|
|
|
t.Errorf("There should be no 2/3 majority: last vote added was nil")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 68th validator voted for a different BlockParts PartSetHeader
|
|
|
|
{
|
2016-03-13 10:01:32 -07:00
|
|
|
blockPartsHeader := PartSetHeader{blockPartsTotal, crypto.CRandBytes(32)}
|
2015-08-12 22:36:43 -07:00
|
|
|
signAddVote(privValidators[67], withBlockPartsHeader(vote, blockPartsHeader), voteSet)
|
2014-10-31 18:35:38 -07:00
|
|
|
hash, header, ok = voteSet.TwoThirdsMajority()
|
|
|
|
if hash != nil || !header.IsZero() || ok {
|
|
|
|
t.Errorf("There should be no 2/3 majority: last vote added had different PartSetHeader Hash")
|
|
|
|
}
|
2014-10-15 23:55:52 -07:00
|
|
|
}
|
|
|
|
|
2014-10-31 18:35:38 -07:00
|
|
|
// 69th validator voted for different BlockParts Total
|
|
|
|
{
|
2015-08-12 22:36:43 -07:00
|
|
|
blockPartsHeader := PartSetHeader{blockPartsTotal + 1, blockPartsHeader.Hash}
|
|
|
|
signAddVote(privValidators[68], withBlockPartsHeader(vote, blockPartsHeader), voteSet)
|
2014-10-31 18:35:38 -07:00
|
|
|
hash, header, ok = voteSet.TwoThirdsMajority()
|
|
|
|
if hash != nil || !header.IsZero() || ok {
|
|
|
|
t.Errorf("There should be no 2/3 majority: last vote added had different PartSetHeader Total")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 70th validator voted for different BlockHash
|
|
|
|
{
|
2014-12-23 23:20:49 -08:00
|
|
|
signAddVote(privValidators[69], withBlockHash(vote, RandBytes(32)), voteSet)
|
2014-10-31 18:35:38 -07:00
|
|
|
hash, header, ok = voteSet.TwoThirdsMajority()
|
|
|
|
if hash != nil || !header.IsZero() || ok {
|
|
|
|
t.Errorf("There should be no 2/3 majority: last vote added had different BlockHash")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-12 22:36:43 -07:00
|
|
|
// 71st validator voted for the right BlockHash & BlockPartsHeader
|
2014-10-31 18:35:38 -07:00
|
|
|
{
|
2014-12-23 23:20:49 -08:00
|
|
|
signAddVote(privValidators[70], vote, voteSet)
|
2014-10-31 18:35:38 -07:00
|
|
|
hash, header, ok = voteSet.TwoThirdsMajority()
|
2015-08-12 22:36:43 -07:00
|
|
|
if !bytes.Equal(hash, blockHash) || !header.Equals(blockPartsHeader) || !ok {
|
2014-10-31 18:35:38 -07:00
|
|
|
t.Errorf("There should be 2/3 majority")
|
|
|
|
}
|
|
|
|
}
|
2014-10-15 23:55:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestBadVotes(t *testing.T) {
|
2015-06-25 20:28:34 -07:00
|
|
|
height, round := 1, 0
|
2015-08-10 20:38:45 -07:00
|
|
|
voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrevote, 10, 1)
|
2014-10-15 23:55:52 -07:00
|
|
|
|
|
|
|
// val0 votes for nil.
|
2015-08-10 20:38:45 -07:00
|
|
|
vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: nil}
|
2014-12-23 23:20:49 -08:00
|
|
|
added, err := signAddVote(privValidators[0], vote, voteSet)
|
2014-10-15 23:55:52 -07:00
|
|
|
if !added || err != nil {
|
2015-06-04 13:36:47 -07:00
|
|
|
t.Errorf("Expected VoteSet.Add to succeed")
|
2014-10-15 23:55:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// val0 votes again for some block.
|
2014-12-23 23:20:49 -08:00
|
|
|
added, err = signAddVote(privValidators[0], withBlockHash(vote, RandBytes(32)), voteSet)
|
2014-10-15 23:55:52 -07:00
|
|
|
if added || err == nil {
|
2015-06-04 13:36:47 -07:00
|
|
|
t.Errorf("Expected VoteSet.Add to fail, dupeout.")
|
2014-10-15 23:55:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// val1 votes on another height
|
2014-12-23 23:20:49 -08:00
|
|
|
added, err = signAddVote(privValidators[1], withHeight(vote, height+1), voteSet)
|
2014-10-15 23:55:52 -07:00
|
|
|
if added {
|
2015-06-04 13:36:47 -07:00
|
|
|
t.Errorf("Expected VoteSet.Add to fail, wrong height")
|
2014-10-15 23:55:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// val2 votes on another round
|
2014-12-23 23:20:49 -08:00
|
|
|
added, err = signAddVote(privValidators[2], withRound(vote, round+1), voteSet)
|
2014-10-15 23:55:52 -07:00
|
|
|
if added {
|
2015-06-04 13:36:47 -07:00
|
|
|
t.Errorf("Expected VoteSet.Add to fail, wrong round")
|
2014-10-15 23:55:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// val3 votes of another type.
|
2015-08-10 20:38:45 -07:00
|
|
|
added, err = signAddVote(privValidators[3], withType(vote, VoteTypePrecommit), voteSet)
|
2014-10-15 23:55:52 -07:00
|
|
|
if added {
|
2015-06-04 13:36:47 -07:00
|
|
|
t.Errorf("Expected VoteSet.Add to fail, wrong type")
|
2014-10-15 23:55:52 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-02 09:10:16 -07:00
|
|
|
func TestMakeCommit(t *testing.T) {
|
2015-06-25 20:28:34 -07:00
|
|
|
height, round := 1, 0
|
2015-08-10 20:38:45 -07:00
|
|
|
voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrecommit, 10, 1)
|
2016-03-13 10:01:32 -07:00
|
|
|
blockHash, blockPartsHeader := crypto.CRandBytes(32), PartSetHeader{123, crypto.CRandBytes(32)}
|
2014-10-31 18:35:38 -07:00
|
|
|
|
2015-08-10 20:38:45 -07:00
|
|
|
vote := &Vote{Height: height, Round: round, Type: VoteTypePrecommit,
|
2015-08-12 22:36:43 -07:00
|
|
|
BlockHash: blockHash, BlockPartsHeader: blockPartsHeader}
|
2014-12-23 23:20:49 -08:00
|
|
|
|
|
|
|
// 6 out of 10 voted for some block.
|
2014-10-31 18:35:38 -07:00
|
|
|
for i := 0; i < 6; i++ {
|
2014-12-23 23:20:49 -08:00
|
|
|
signAddVote(privValidators[i], vote, voteSet)
|
2014-10-31 18:35:38 -07:00
|
|
|
}
|
|
|
|
|
2016-04-02 09:10:16 -07:00
|
|
|
// MakeCommit should fail.
|
|
|
|
AssertPanics(t, "Doesn't have +2/3 majority", func() { voteSet.MakeCommit() })
|
2014-10-31 18:35:38 -07:00
|
|
|
|
|
|
|
// 7th voted for some other block.
|
|
|
|
{
|
2014-12-23 23:20:49 -08:00
|
|
|
vote := withBlockHash(vote, RandBytes(32))
|
2015-08-12 22:36:43 -07:00
|
|
|
vote = withBlockPartsHeader(vote, PartSetHeader{123, RandBytes(32)})
|
2014-12-23 23:20:49 -08:00
|
|
|
signAddVote(privValidators[6], vote, voteSet)
|
2014-10-31 18:35:38 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// The 8th voted like everyone else.
|
|
|
|
{
|
2014-12-23 23:20:49 -08:00
|
|
|
signAddVote(privValidators[7], vote, voteSet)
|
2014-10-31 18:35:38 -07:00
|
|
|
}
|
|
|
|
|
2016-04-02 09:10:16 -07:00
|
|
|
commit := voteSet.MakeCommit()
|
2014-10-31 18:35:38 -07:00
|
|
|
|
2016-04-02 09:10:16 -07:00
|
|
|
// Commit should have 10 elements
|
|
|
|
if len(commit.Precommits) != 10 {
|
|
|
|
t.Errorf("Commit Precommits should have the same number of precommits as validators")
|
2014-10-31 18:35:38 -07:00
|
|
|
}
|
|
|
|
|
2016-04-02 09:10:16 -07:00
|
|
|
// Ensure that Commit precommits are ordered.
|
|
|
|
if err := commit.ValidateBasic(); err != nil {
|
|
|
|
t.Errorf("Error in Commit.ValidateBasic(): %v", err)
|
2014-10-31 18:35:38 -07:00
|
|
|
}
|
2014-12-17 01:37:13 -08:00
|
|
|
|
2014-10-31 18:35:38 -07:00
|
|
|
}
|