|
@ -13,82 +13,19 @@ import ( |
|
|
tmtime "github.com/tendermint/tendermint/types/time" |
|
|
tmtime "github.com/tendermint/tendermint/types/time" |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
// NOTE: privValidators are in order
|
|
|
|
|
|
func randVoteSet( |
|
|
|
|
|
height int64, |
|
|
|
|
|
round int32, |
|
|
|
|
|
signedMsgType tmproto.SignedMsgType, |
|
|
|
|
|
numValidators int, |
|
|
|
|
|
votingPower int64, |
|
|
|
|
|
) (*VoteSet, *ValidatorSet, []PrivValidator) { |
|
|
|
|
|
valSet, privValidators := RandValidatorSet(numValidators, votingPower) |
|
|
|
|
|
return NewVoteSet("test_chain_id", height, round, signedMsgType, valSet), valSet, privValidators |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Convenience: Return new vote with different validator address/index
|
|
|
|
|
|
func withValidator(vote *Vote, addr []byte, idx int32) *Vote { |
|
|
|
|
|
vote = vote.Copy() |
|
|
|
|
|
vote.ValidatorAddress = addr |
|
|
|
|
|
vote.ValidatorIndex = idx |
|
|
|
|
|
return vote |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Convenience: Return new vote with different height
|
|
|
|
|
|
func withHeight(vote *Vote, height int64) *Vote { |
|
|
|
|
|
vote = vote.Copy() |
|
|
|
|
|
vote.Height = height |
|
|
|
|
|
return vote |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Convenience: Return new vote with different round
|
|
|
|
|
|
func withRound(vote *Vote, round int32) *Vote { |
|
|
|
|
|
vote = vote.Copy() |
|
|
|
|
|
vote.Round = round |
|
|
|
|
|
return vote |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Convenience: Return new vote with different type
|
|
|
|
|
|
func withType(vote *Vote, signedMsgType byte) *Vote { |
|
|
|
|
|
vote = vote.Copy() |
|
|
|
|
|
vote.Type = tmproto.SignedMsgType(signedMsgType) |
|
|
|
|
|
return vote |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Convenience: Return new vote with different blockHash
|
|
|
|
|
|
func withBlockHash(vote *Vote, blockHash []byte) *Vote { |
|
|
|
|
|
vote = vote.Copy() |
|
|
|
|
|
vote.BlockID.Hash = blockHash |
|
|
|
|
|
return vote |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Convenience: Return new vote with different blockParts
|
|
|
|
|
|
func withBlockPartsHeader(vote *Vote, blockPartsHeader PartSetHeader) *Vote { |
|
|
|
|
|
vote = vote.Copy() |
|
|
|
|
|
vote.BlockID.PartsHeader = blockPartsHeader |
|
|
|
|
|
return vote |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func TestAddVote(t *testing.T) { |
|
|
|
|
|
|
|
|
func TestVoteSet_AddVote_Good(t *testing.T) { |
|
|
height, round := int64(1), int32(0) |
|
|
height, round := int64(1), int32(0) |
|
|
voteSet, _, privValidators := randVoteSet(height, round, tmproto.PrevoteType, 10, 1) |
|
|
voteSet, _, privValidators := randVoteSet(height, round, tmproto.PrevoteType, 10, 1) |
|
|
val0 := privValidators[0] |
|
|
val0 := privValidators[0] |
|
|
|
|
|
|
|
|
// t.Logf(">> %v", voteSet)
|
|
|
|
|
|
|
|
|
|
|
|
val0p, err := val0.GetPubKey() |
|
|
val0p, err := val0.GetPubKey() |
|
|
require.NoError(t, err) |
|
|
require.NoError(t, err) |
|
|
val0Addr := val0p.Address() |
|
|
val0Addr := val0p.Address() |
|
|
|
|
|
|
|
|
if voteSet.GetByAddress(val0Addr) != nil { |
|
|
|
|
|
t.Errorf("expected GetByAddress(val0.Address) to be nil") |
|
|
|
|
|
} |
|
|
|
|
|
if voteSet.BitArray().GetIndex(0) { |
|
|
|
|
|
t.Errorf("expected BitArray.GetIndex(0) to be false") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
assert.Nil(t, voteSet.GetByAddress(val0Addr)) |
|
|
|
|
|
assert.False(t, voteSet.BitArray().GetIndex(0)) |
|
|
blockID, ok := voteSet.TwoThirdsMajority() |
|
|
blockID, ok := voteSet.TwoThirdsMajority() |
|
|
if ok || !blockID.IsZero() { |
|
|
|
|
|
t.Errorf("there should be no 2/3 majority") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
assert.False(t, ok || !blockID.IsZero(), "there should be no 2/3 majority") |
|
|
|
|
|
|
|
|
vote := &Vote{ |
|
|
vote := &Vote{ |
|
|
ValidatorAddress: val0Addr, |
|
|
ValidatorAddress: val0Addr, |
|
@ -100,23 +37,90 @@ func TestAddVote(t *testing.T) { |
|
|
BlockID: BlockID{nil, PartSetHeader{}}, |
|
|
BlockID: BlockID{nil, PartSetHeader{}}, |
|
|
} |
|
|
} |
|
|
_, err = signAddVote(val0, vote, voteSet) |
|
|
_, err = signAddVote(val0, vote, voteSet) |
|
|
if err != nil { |
|
|
|
|
|
t.Error(err) |
|
|
|
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
|
|
|
|
assert.NotNil(t, voteSet.GetByAddress(val0Addr)) |
|
|
|
|
|
assert.True(t, voteSet.BitArray().GetIndex(0)) |
|
|
|
|
|
blockID, ok = voteSet.TwoThirdsMajority() |
|
|
|
|
|
assert.False(t, ok || !blockID.IsZero(), "there should be no 2/3 majority") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func TestVoteSet_AddVote_Bad(t *testing.T) { |
|
|
|
|
|
height, round := int64(1), int32(0) |
|
|
|
|
|
voteSet, _, privValidators := randVoteSet(height, round, tmproto.PrevoteType, 10, 1) |
|
|
|
|
|
|
|
|
|
|
|
voteProto := &Vote{ |
|
|
|
|
|
ValidatorAddress: nil, |
|
|
|
|
|
ValidatorIndex: -1, |
|
|
|
|
|
Height: height, |
|
|
|
|
|
Round: round, |
|
|
|
|
|
Timestamp: tmtime.Now(), |
|
|
|
|
|
Type: tmproto.PrevoteType, |
|
|
|
|
|
BlockID: BlockID{nil, PartSetHeader{}}, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if voteSet.GetByAddress(val0Addr) == nil { |
|
|
|
|
|
t.Errorf("expected GetByAddress(val0.Address) to be present") |
|
|
|
|
|
|
|
|
// val0 votes for nil.
|
|
|
|
|
|
{ |
|
|
|
|
|
pubKey, err := privValidators[0].GetPubKey() |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
addr := pubKey.Address() |
|
|
|
|
|
vote := withValidator(voteProto, addr, 0) |
|
|
|
|
|
added, err := signAddVote(privValidators[0], vote, voteSet) |
|
|
|
|
|
if !added || err != nil { |
|
|
|
|
|
t.Errorf("expected VoteSet.Add to succeed") |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
if !voteSet.BitArray().GetIndex(0) { |
|
|
|
|
|
t.Errorf("expected BitArray.GetIndex(0) to be true") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// val0 votes again for some block.
|
|
|
|
|
|
{ |
|
|
|
|
|
pubKey, err := privValidators[0].GetPubKey() |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
addr := pubKey.Address() |
|
|
|
|
|
vote := withValidator(voteProto, addr, 0) |
|
|
|
|
|
added, err := signAddVote(privValidators[0], withBlockHash(vote, tmrand.Bytes(32)), voteSet) |
|
|
|
|
|
if added || err == nil { |
|
|
|
|
|
t.Errorf("expected VoteSet.Add to fail, conflicting vote.") |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
blockID, ok = voteSet.TwoThirdsMajority() |
|
|
|
|
|
if ok || !blockID.IsZero() { |
|
|
|
|
|
t.Errorf("there should be no 2/3 majority") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// val1 votes on another height
|
|
|
|
|
|
{ |
|
|
|
|
|
pubKey, err := privValidators[1].GetPubKey() |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
addr := pubKey.Address() |
|
|
|
|
|
vote := withValidator(voteProto, addr, 1) |
|
|
|
|
|
added, err := signAddVote(privValidators[1], withHeight(vote, height+1), voteSet) |
|
|
|
|
|
if added || err == nil { |
|
|
|
|
|
t.Errorf("expected VoteSet.Add to fail, wrong height") |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// val2 votes on another round
|
|
|
|
|
|
{ |
|
|
|
|
|
pubKey, err := privValidators[2].GetPubKey() |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
addr := pubKey.Address() |
|
|
|
|
|
vote := withValidator(voteProto, addr, 2) |
|
|
|
|
|
added, err := signAddVote(privValidators[2], withRound(vote, round+1), voteSet) |
|
|
|
|
|
if added || err == nil { |
|
|
|
|
|
t.Errorf("expected VoteSet.Add to fail, wrong round") |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// val3 votes of another type.
|
|
|
|
|
|
{ |
|
|
|
|
|
pubKey, err := privValidators[3].GetPubKey() |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
addr := pubKey.Address() |
|
|
|
|
|
vote := withValidator(voteProto, addr, 3) |
|
|
|
|
|
added, err := signAddVote(privValidators[3], withType(vote, byte(tmproto.PrecommitType)), voteSet) |
|
|
|
|
|
if added || err == nil { |
|
|
|
|
|
t.Errorf("expected VoteSet.Add to fail, wrong type") |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func Test2_3Majority(t *testing.T) { |
|
|
|
|
|
|
|
|
func TestVoteSet_2_3Majority(t *testing.T) { |
|
|
height, round := int64(1), int32(0) |
|
|
height, round := int64(1), int32(0) |
|
|
voteSet, _, privValidators := randVoteSet(height, round, tmproto.PrevoteType, 10, 1) |
|
|
voteSet, _, privValidators := randVoteSet(height, round, tmproto.PrevoteType, 10, 1) |
|
|
|
|
|
|
|
@ -136,14 +140,10 @@ func Test2_3Majority(t *testing.T) { |
|
|
addr := pubKey.Address() |
|
|
addr := pubKey.Address() |
|
|
vote := withValidator(voteProto, addr, i) |
|
|
vote := withValidator(voteProto, addr, i) |
|
|
_, err = signAddVote(privValidators[i], vote, voteSet) |
|
|
_, err = signAddVote(privValidators[i], vote, voteSet) |
|
|
if err != nil { |
|
|
|
|
|
t.Error(err) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
require.NoError(t, err) |
|
|
} |
|
|
} |
|
|
blockID, ok := voteSet.TwoThirdsMajority() |
|
|
blockID, ok := voteSet.TwoThirdsMajority() |
|
|
if ok || !blockID.IsZero() { |
|
|
|
|
|
t.Errorf("there should be no 2/3 majority") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
assert.False(t, ok || !blockID.IsZero(), "there should be no 2/3 majority") |
|
|
|
|
|
|
|
|
// 7th validator voted for some blockhash
|
|
|
// 7th validator voted for some blockhash
|
|
|
{ |
|
|
{ |
|
@ -152,13 +152,9 @@ func Test2_3Majority(t *testing.T) { |
|
|
addr := pubKey.Address() |
|
|
addr := pubKey.Address() |
|
|
vote := withValidator(voteProto, addr, 6) |
|
|
vote := withValidator(voteProto, addr, 6) |
|
|
_, err = signAddVote(privValidators[6], withBlockHash(vote, tmrand.Bytes(32)), voteSet) |
|
|
_, err = signAddVote(privValidators[6], withBlockHash(vote, tmrand.Bytes(32)), voteSet) |
|
|
if err != nil { |
|
|
|
|
|
t.Error(err) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
require.NoError(t, err) |
|
|
blockID, ok = voteSet.TwoThirdsMajority() |
|
|
blockID, ok = voteSet.TwoThirdsMajority() |
|
|
if ok || !blockID.IsZero() { |
|
|
|
|
|
t.Errorf("there should be no 2/3 majority") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
assert.False(t, ok || !blockID.IsZero(), "there should be no 2/3 majority") |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 8th validator voted for nil.
|
|
|
// 8th validator voted for nil.
|
|
@ -168,17 +164,13 @@ func Test2_3Majority(t *testing.T) { |
|
|
addr := pubKey.Address() |
|
|
addr := pubKey.Address() |
|
|
vote := withValidator(voteProto, addr, 7) |
|
|
vote := withValidator(voteProto, addr, 7) |
|
|
_, err = signAddVote(privValidators[7], vote, voteSet) |
|
|
_, err = signAddVote(privValidators[7], vote, voteSet) |
|
|
if err != nil { |
|
|
|
|
|
t.Error(err) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
require.NoError(t, err) |
|
|
blockID, ok = voteSet.TwoThirdsMajority() |
|
|
blockID, ok = voteSet.TwoThirdsMajority() |
|
|
if !ok || !blockID.IsZero() { |
|
|
|
|
|
t.Errorf("there should be 2/3 majority for nil") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
assert.True(t, ok || blockID.IsZero(), "there should be 2/3 majority for nil") |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func Test2_3MajorityRedux(t *testing.T) { |
|
|
|
|
|
|
|
|
func TestVoteSet_2_3MajorityRedux(t *testing.T) { |
|
|
height, round := int64(1), int32(0) |
|
|
height, round := int64(1), int32(0) |
|
|
voteSet, _, privValidators := randVoteSet(height, round, tmproto.PrevoteType, 100, 1) |
|
|
voteSet, _, privValidators := randVoteSet(height, round, tmproto.PrevoteType, 100, 1) |
|
|
|
|
|
|
|
@ -203,14 +195,11 @@ func Test2_3MajorityRedux(t *testing.T) { |
|
|
addr := pubKey.Address() |
|
|
addr := pubKey.Address() |
|
|
vote := withValidator(voteProto, addr, i) |
|
|
vote := withValidator(voteProto, addr, i) |
|
|
_, err = signAddVote(privValidators[i], vote, voteSet) |
|
|
_, err = signAddVote(privValidators[i], vote, voteSet) |
|
|
if err != nil { |
|
|
|
|
|
t.Error(err) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
require.NoError(t, err) |
|
|
} |
|
|
} |
|
|
blockID, ok := voteSet.TwoThirdsMajority() |
|
|
blockID, ok := voteSet.TwoThirdsMajority() |
|
|
if ok || !blockID.IsZero() { |
|
|
|
|
|
t.Errorf("there should be no 2/3 majority") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
assert.False(t, ok || !blockID.IsZero(), |
|
|
|
|
|
"there should be no 2/3 majority") |
|
|
|
|
|
|
|
|
// 67th validator voted for nil
|
|
|
// 67th validator voted for nil
|
|
|
{ |
|
|
{ |
|
@ -219,13 +208,10 @@ func Test2_3MajorityRedux(t *testing.T) { |
|
|
adrr := pubKey.Address() |
|
|
adrr := pubKey.Address() |
|
|
vote := withValidator(voteProto, adrr, 66) |
|
|
vote := withValidator(voteProto, adrr, 66) |
|
|
_, err = signAddVote(privValidators[66], withBlockHash(vote, nil), voteSet) |
|
|
_, err = signAddVote(privValidators[66], withBlockHash(vote, nil), voteSet) |
|
|
if err != nil { |
|
|
|
|
|
t.Error(err) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
require.NoError(t, err) |
|
|
blockID, ok = voteSet.TwoThirdsMajority() |
|
|
blockID, ok = voteSet.TwoThirdsMajority() |
|
|
if ok || !blockID.IsZero() { |
|
|
|
|
|
t.Errorf("there should be no 2/3 majority: last vote added was nil") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
assert.False(t, ok || !blockID.IsZero(), |
|
|
|
|
|
"there should be no 2/3 majority: last vote added was nil") |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 68th validator voted for a different BlockParts PartSetHeader
|
|
|
// 68th validator voted for a different BlockParts PartSetHeader
|
|
@ -236,13 +222,10 @@ func Test2_3MajorityRedux(t *testing.T) { |
|
|
vote := withValidator(voteProto, addr, 67) |
|
|
vote := withValidator(voteProto, addr, 67) |
|
|
blockPartsHeader := PartSetHeader{blockPartsTotal, crypto.CRandBytes(32)} |
|
|
blockPartsHeader := PartSetHeader{blockPartsTotal, crypto.CRandBytes(32)} |
|
|
_, err = signAddVote(privValidators[67], withBlockPartsHeader(vote, blockPartsHeader), voteSet) |
|
|
_, err = signAddVote(privValidators[67], withBlockPartsHeader(vote, blockPartsHeader), voteSet) |
|
|
if err != nil { |
|
|
|
|
|
t.Error(err) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
require.NoError(t, err) |
|
|
blockID, ok = voteSet.TwoThirdsMajority() |
|
|
blockID, ok = voteSet.TwoThirdsMajority() |
|
|
if ok || !blockID.IsZero() { |
|
|
|
|
|
t.Errorf("there should be no 2/3 majority: last vote added had different PartSetHeader Hash") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
assert.False(t, ok || !blockID.IsZero(), |
|
|
|
|
|
"there should be no 2/3 majority: last vote added had different PartSetHeader Hash") |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 69th validator voted for different BlockParts Total
|
|
|
// 69th validator voted for different BlockParts Total
|
|
@ -253,13 +236,10 @@ func Test2_3MajorityRedux(t *testing.T) { |
|
|
vote := withValidator(voteProto, addr, 68) |
|
|
vote := withValidator(voteProto, addr, 68) |
|
|
blockPartsHeader := PartSetHeader{blockPartsTotal + 1, blockPartsHeader.Hash} |
|
|
blockPartsHeader := PartSetHeader{blockPartsTotal + 1, blockPartsHeader.Hash} |
|
|
_, err = signAddVote(privValidators[68], withBlockPartsHeader(vote, blockPartsHeader), voteSet) |
|
|
_, err = signAddVote(privValidators[68], withBlockPartsHeader(vote, blockPartsHeader), voteSet) |
|
|
if err != nil { |
|
|
|
|
|
t.Error(err) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
require.NoError(t, err) |
|
|
blockID, ok = voteSet.TwoThirdsMajority() |
|
|
blockID, ok = voteSet.TwoThirdsMajority() |
|
|
if ok || !blockID.IsZero() { |
|
|
|
|
|
t.Errorf("there should be no 2/3 majority: last vote added had different PartSetHeader Total") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
assert.False(t, ok || !blockID.IsZero(), |
|
|
|
|
|
"there should be no 2/3 majority: last vote added had different PartSetHeader Total") |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 70th validator voted for different BlockHash
|
|
|
// 70th validator voted for different BlockHash
|
|
@ -269,13 +249,10 @@ func Test2_3MajorityRedux(t *testing.T) { |
|
|
addr := pubKey.Address() |
|
|
addr := pubKey.Address() |
|
|
vote := withValidator(voteProto, addr, 69) |
|
|
vote := withValidator(voteProto, addr, 69) |
|
|
_, err = signAddVote(privValidators[69], withBlockHash(vote, tmrand.Bytes(32)), voteSet) |
|
|
_, err = signAddVote(privValidators[69], withBlockHash(vote, tmrand.Bytes(32)), voteSet) |
|
|
if err != nil { |
|
|
|
|
|
t.Error(err) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
require.NoError(t, err) |
|
|
blockID, ok = voteSet.TwoThirdsMajority() |
|
|
blockID, ok = voteSet.TwoThirdsMajority() |
|
|
if ok || !blockID.IsZero() { |
|
|
|
|
|
t.Errorf("there should be no 2/3 majority: last vote added had different BlockHash") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
assert.False(t, ok || !blockID.IsZero(), |
|
|
|
|
|
"there should be no 2/3 majority: last vote added had different BlockHash") |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 71st validator voted for the right BlockHash & BlockPartsHeader
|
|
|
// 71st validator voted for the right BlockHash & BlockPartsHeader
|
|
@ -285,92 +262,14 @@ func Test2_3MajorityRedux(t *testing.T) { |
|
|
addr := pubKey.Address() |
|
|
addr := pubKey.Address() |
|
|
vote := withValidator(voteProto, addr, 70) |
|
|
vote := withValidator(voteProto, addr, 70) |
|
|
_, err = signAddVote(privValidators[70], vote, voteSet) |
|
|
_, err = signAddVote(privValidators[70], vote, voteSet) |
|
|
if err != nil { |
|
|
|
|
|
t.Error(err) |
|
|
|
|
|
} |
|
|
|
|
|
blockID, ok = voteSet.TwoThirdsMajority() |
|
|
|
|
|
if !ok || !blockID.Equals(BlockID{blockHash, blockPartsHeader}) { |
|
|
|
|
|
t.Errorf("there should be 2/3 majority") |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func TestBadVotes(t *testing.T) { |
|
|
|
|
|
height, round := int64(1), int32(0) |
|
|
|
|
|
voteSet, _, privValidators := randVoteSet(height, round, tmproto.PrevoteType, 10, 1) |
|
|
|
|
|
|
|
|
|
|
|
voteProto := &Vote{ |
|
|
|
|
|
ValidatorAddress: nil, |
|
|
|
|
|
ValidatorIndex: -1, |
|
|
|
|
|
Height: height, |
|
|
|
|
|
Round: round, |
|
|
|
|
|
Timestamp: tmtime.Now(), |
|
|
|
|
|
Type: tmproto.PrevoteType, |
|
|
|
|
|
BlockID: BlockID{nil, PartSetHeader{}}, |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// val0 votes for nil.
|
|
|
|
|
|
{ |
|
|
|
|
|
pubKey, err := privValidators[0].GetPubKey() |
|
|
|
|
|
require.NoError(t, err) |
|
|
require.NoError(t, err) |
|
|
addr := pubKey.Address() |
|
|
|
|
|
vote := withValidator(voteProto, addr, 0) |
|
|
|
|
|
added, err := signAddVote(privValidators[0], vote, voteSet) |
|
|
|
|
|
if !added || err != nil { |
|
|
|
|
|
t.Errorf("expected VoteSet.Add to succeed") |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// val0 votes again for some block.
|
|
|
|
|
|
{ |
|
|
|
|
|
pubKey, err := privValidators[0].GetPubKey() |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
addr := pubKey.Address() |
|
|
|
|
|
vote := withValidator(voteProto, addr, 0) |
|
|
|
|
|
added, err := signAddVote(privValidators[0], withBlockHash(vote, tmrand.Bytes(32)), voteSet) |
|
|
|
|
|
if added || err == nil { |
|
|
|
|
|
t.Errorf("expected VoteSet.Add to fail, conflicting vote.") |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// val1 votes on another height
|
|
|
|
|
|
{ |
|
|
|
|
|
pubKey, err := privValidators[1].GetPubKey() |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
addr := pubKey.Address() |
|
|
|
|
|
vote := withValidator(voteProto, addr, 1) |
|
|
|
|
|
added, err := signAddVote(privValidators[1], withHeight(vote, height+1), voteSet) |
|
|
|
|
|
if added || err == nil { |
|
|
|
|
|
t.Errorf("expected VoteSet.Add to fail, wrong height") |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// val2 votes on another round
|
|
|
|
|
|
{ |
|
|
|
|
|
pubKey, err := privValidators[2].GetPubKey() |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
addr := pubKey.Address() |
|
|
|
|
|
vote := withValidator(voteProto, addr, 2) |
|
|
|
|
|
added, err := signAddVote(privValidators[2], withRound(vote, round+1), voteSet) |
|
|
|
|
|
if added || err == nil { |
|
|
|
|
|
t.Errorf("expected VoteSet.Add to fail, wrong round") |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// val3 votes of another type.
|
|
|
|
|
|
{ |
|
|
|
|
|
pubKey, err := privValidators[3].GetPubKey() |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
addr := pubKey.Address() |
|
|
|
|
|
vote := withValidator(voteProto, addr, 3) |
|
|
|
|
|
added, err := signAddVote(privValidators[3], withType(vote, byte(tmproto.PrecommitType)), voteSet) |
|
|
|
|
|
if added || err == nil { |
|
|
|
|
|
t.Errorf("expected VoteSet.Add to fail, wrong type") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
blockID, ok = voteSet.TwoThirdsMajority() |
|
|
|
|
|
assert.True(t, ok && blockID.Equals(BlockID{blockHash, blockPartsHeader}), |
|
|
|
|
|
"there should be 2/3 majority") |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func TestConflicts(t *testing.T) { |
|
|
|
|
|
|
|
|
func TestVoteSet_Conflicts(t *testing.T) { |
|
|
height, round := int64(1), int32(0) |
|
|
height, round := int64(1), int32(0) |
|
|
voteSet, _, privValidators := randVoteSet(height, round, tmproto.PrevoteType, 4, 1) |
|
|
voteSet, _, privValidators := randVoteSet(height, round, tmproto.PrevoteType, 4, 1) |
|
|
blockHash1 := tmrand.Bytes(32) |
|
|
blockHash1 := tmrand.Bytes(32) |
|
@ -403,12 +302,8 @@ func TestConflicts(t *testing.T) { |
|
|
{ |
|
|
{ |
|
|
vote := withValidator(voteProto, val0Addr, 0) |
|
|
vote := withValidator(voteProto, val0Addr, 0) |
|
|
added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash1), voteSet) |
|
|
added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash1), voteSet) |
|
|
if added { |
|
|
|
|
|
t.Errorf("expected VoteSet.Add to fail, conflicting vote.") |
|
|
|
|
|
} |
|
|
|
|
|
if err == nil { |
|
|
|
|
|
t.Errorf("expected VoteSet.Add to return error, conflicting vote.") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
assert.False(t, added, "conflicting vote") |
|
|
|
|
|
assert.Error(t, err, "conflicting vote") |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// start tracking blockHash1
|
|
|
// start tracking blockHash1
|
|
@ -418,12 +313,8 @@ func TestConflicts(t *testing.T) { |
|
|
{ |
|
|
{ |
|
|
vote := withValidator(voteProto, val0Addr, 0) |
|
|
vote := withValidator(voteProto, val0Addr, 0) |
|
|
added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash1), voteSet) |
|
|
added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash1), voteSet) |
|
|
if !added { |
|
|
|
|
|
t.Errorf("expected VoteSet.Add to succeed, called SetPeerMaj23().") |
|
|
|
|
|
} |
|
|
|
|
|
if err == nil { |
|
|
|
|
|
t.Errorf("expected VoteSet.Add to return error, conflicting vote.") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
assert.True(t, added, "called SetPeerMaj23()") |
|
|
|
|
|
assert.Error(t, err, "conflicting vote") |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// attempt tracking blockHash2, should fail because already set for peerA.
|
|
|
// attempt tracking blockHash2, should fail because already set for peerA.
|
|
@ -433,12 +324,8 @@ func TestConflicts(t *testing.T) { |
|
|
{ |
|
|
{ |
|
|
vote := withValidator(voteProto, val0Addr, 0) |
|
|
vote := withValidator(voteProto, val0Addr, 0) |
|
|
added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash2), voteSet) |
|
|
added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash2), voteSet) |
|
|
if added { |
|
|
|
|
|
t.Errorf("expected VoteSet.Add to fail, duplicate SetPeerMaj23() from peerA") |
|
|
|
|
|
} |
|
|
|
|
|
if err == nil { |
|
|
|
|
|
t.Errorf("expected VoteSet.Add to return error, conflicting vote.") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
assert.False(t, added, "duplicate SetPeerMaj23() from peerA") |
|
|
|
|
|
assert.Error(t, err, "conflicting vote") |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// val1 votes for blockHash1.
|
|
|
// val1 votes for blockHash1.
|
|
@ -491,12 +378,8 @@ func TestConflicts(t *testing.T) { |
|
|
addr := pv.Address() |
|
|
addr := pv.Address() |
|
|
vote := withValidator(voteProto, addr, 2) |
|
|
vote := withValidator(voteProto, addr, 2) |
|
|
added, err := signAddVote(privValidators[2], withBlockHash(vote, blockHash1), voteSet) |
|
|
added, err := signAddVote(privValidators[2], withBlockHash(vote, blockHash1), voteSet) |
|
|
if !added { |
|
|
|
|
|
t.Errorf("expected VoteSet.Add to succeed") |
|
|
|
|
|
} |
|
|
|
|
|
if err == nil { |
|
|
|
|
|
t.Errorf("expected VoteSet.Add to return error, conflicting vote") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
assert.True(t, added) |
|
|
|
|
|
assert.Error(t, err, "conflicting vote") |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// check
|
|
|
// check
|
|
@ -510,10 +393,9 @@ func TestConflicts(t *testing.T) { |
|
|
if !voteSet.HasTwoThirdsAny() { |
|
|
if !voteSet.HasTwoThirdsAny() { |
|
|
t.Errorf("we should have 2/3 if any votes") |
|
|
t.Errorf("we should have 2/3 if any votes") |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func TestMakeCommit(t *testing.T) { |
|
|
|
|
|
|
|
|
func TestVoteSet_MakeCommit(t *testing.T) { |
|
|
height, round := int64(1), int32(0) |
|
|
height, round := int64(1), int32(0) |
|
|
voteSet, _, privValidators := randVoteSet(height, round, tmproto.PrecommitType, 10, 1) |
|
|
voteSet, _, privValidators := randVoteSet(height, round, tmproto.PrecommitType, 10, 1) |
|
|
blockHash, blockPartsHeader := crypto.CRandBytes(32), PartSetHeader{123, crypto.CRandBytes(32)} |
|
|
blockHash, blockPartsHeader := crypto.CRandBytes(32), PartSetHeader{123, crypto.CRandBytes(32)} |
|
@ -553,9 +435,7 @@ func TestMakeCommit(t *testing.T) { |
|
|
vote = withBlockPartsHeader(vote, PartSetHeader{123, tmrand.Bytes(32)}) |
|
|
vote = withBlockPartsHeader(vote, PartSetHeader{123, tmrand.Bytes(32)}) |
|
|
|
|
|
|
|
|
_, err = signAddVote(privValidators[6], vote, voteSet) |
|
|
_, err = signAddVote(privValidators[6], vote, voteSet) |
|
|
if err != nil { |
|
|
|
|
|
t.Error(err) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
require.NoError(t, err) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// The 8th voted like everyone else.
|
|
|
// The 8th voted like everyone else.
|
|
@ -565,9 +445,7 @@ func TestMakeCommit(t *testing.T) { |
|
|
addr := pv.Address() |
|
|
addr := pv.Address() |
|
|
vote := withValidator(voteProto, addr, 7) |
|
|
vote := withValidator(voteProto, addr, 7) |
|
|
_, err = signAddVote(privValidators[7], vote, voteSet) |
|
|
_, err = signAddVote(privValidators[7], vote, voteSet) |
|
|
if err != nil { |
|
|
|
|
|
t.Error(err) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
require.NoError(t, err) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// The 9th voted for nil.
|
|
|
// The 9th voted for nil.
|
|
@ -579,17 +457,13 @@ func TestMakeCommit(t *testing.T) { |
|
|
vote.BlockID = BlockID{} |
|
|
vote.BlockID = BlockID{} |
|
|
|
|
|
|
|
|
_, err = signAddVote(privValidators[8], vote, voteSet) |
|
|
_, err = signAddVote(privValidators[8], vote, voteSet) |
|
|
if err != nil { |
|
|
|
|
|
t.Error(err) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
require.NoError(t, err) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
commit := voteSet.MakeCommit() |
|
|
commit := voteSet.MakeCommit() |
|
|
|
|
|
|
|
|
// Commit should have 10 elements
|
|
|
// Commit should have 10 elements
|
|
|
if len(commit.Signatures) != 10 { |
|
|
|
|
|
t.Errorf("expected commit to include %d elems, got %d", 10, len(commit.Signatures)) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
assert.Equal(t, 10, len(commit.Signatures)) |
|
|
|
|
|
|
|
|
// Ensure that Commit is good.
|
|
|
// Ensure that Commit is good.
|
|
|
if err := commit.ValidateBasic(); err != nil { |
|
|
if err := commit.ValidateBasic(); err != nil { |
|
@ -636,3 +510,58 @@ func buildVoteSetForBlock(height int64, |
|
|
} |
|
|
} |
|
|
return voteSet, valSet, privValidators |
|
|
return voteSet, valSet, privValidators |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// NOTE: privValidators are in order
|
|
|
|
|
|
func randVoteSet( |
|
|
|
|
|
height int64, |
|
|
|
|
|
round int32, |
|
|
|
|
|
signedMsgType tmproto.SignedMsgType, |
|
|
|
|
|
numValidators int, |
|
|
|
|
|
votingPower int64, |
|
|
|
|
|
) (*VoteSet, *ValidatorSet, []PrivValidator) { |
|
|
|
|
|
valSet, privValidators := RandValidatorSet(numValidators, votingPower) |
|
|
|
|
|
return NewVoteSet("test_chain_id", height, round, signedMsgType, valSet), valSet, privValidators |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Convenience: Return new vote with different validator address/index
|
|
|
|
|
|
func withValidator(vote *Vote, addr []byte, idx int32) *Vote { |
|
|
|
|
|
vote = vote.Copy() |
|
|
|
|
|
vote.ValidatorAddress = addr |
|
|
|
|
|
vote.ValidatorIndex = idx |
|
|
|
|
|
return vote |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Convenience: Return new vote with different height
|
|
|
|
|
|
func withHeight(vote *Vote, height int64) *Vote { |
|
|
|
|
|
vote = vote.Copy() |
|
|
|
|
|
vote.Height = height |
|
|
|
|
|
return vote |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Convenience: Return new vote with different round
|
|
|
|
|
|
func withRound(vote *Vote, round int32) *Vote { |
|
|
|
|
|
vote = vote.Copy() |
|
|
|
|
|
vote.Round = round |
|
|
|
|
|
return vote |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Convenience: Return new vote with different type
|
|
|
|
|
|
func withType(vote *Vote, signedMsgType byte) *Vote { |
|
|
|
|
|
vote = vote.Copy() |
|
|
|
|
|
vote.Type = tmproto.SignedMsgType(signedMsgType) |
|
|
|
|
|
return vote |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Convenience: Return new vote with different blockHash
|
|
|
|
|
|
func withBlockHash(vote *Vote, blockHash []byte) *Vote { |
|
|
|
|
|
vote = vote.Copy() |
|
|
|
|
|
vote.BlockID.Hash = blockHash |
|
|
|
|
|
return vote |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Convenience: Return new vote with different blockParts
|
|
|
|
|
|
func withBlockPartsHeader(vote *Vote, blockPartsHeader PartSetHeader) *Vote { |
|
|
|
|
|
vote = vote.Copy() |
|
|
|
|
|
vote.BlockID.PartsHeader = blockPartsHeader |
|
|
|
|
|
return vote |
|
|
|
|
|
} |