Fix HeightVoteSet bug where first catchup vote doesn't get added

This commit is contained in:
Jae Kwon 2015-12-31 15:02:38 -08:00
parent 0e7b069cd8
commit 9247b0fbd2
6 changed files with 89 additions and 32 deletions

View File

@ -95,14 +95,15 @@ func (hvs *HeightVoteSet) AddByIndex(valIndex int, vote *types.Vote, peerKey str
if voteSet == nil { if voteSet == nil {
if _, ok := hvs.peerCatchupRounds[peerKey]; !ok { if _, ok := hvs.peerCatchupRounds[peerKey]; !ok {
hvs.addRound(vote.Round) hvs.addRound(vote.Round)
voteSet = hvs.getVoteSet(vote.Round, vote.Type)
hvs.peerCatchupRounds[peerKey] = vote.Round hvs.peerCatchupRounds[peerKey] = vote.Round
} else { } else {
// Peer has sent a vote that does not match our round, // Peer has sent a vote that does not match our round,
// for more than one round. Bad peer! // for more than one round. Bad peer!
// TODO punish peer. // TODO punish peer.
log.Warn("Deal with peer giving votes from unwanted rounds") log.Warn("Deal with peer giving votes from unwanted rounds")
return
} }
return
} }
added, address, err = voteSet.AddByIndex(valIndex, vote) added, address, err = voteSet.AddByIndex(valIndex, vote)
return return

View File

@ -0,0 +1,48 @@
package consensus
import (
_ "github.com/tendermint/tendermint/config/tendermint_test"
"github.com/tendermint/tendermint/types"
"testing"
)
func TestPeerCatchupRounds(t *testing.T) {
valSet, privVals := types.RandValidatorSet(10, 1)
hvs := NewHeightVoteSet(1, valSet)
vote999_0 := makeVoteHR(t, 1, 999, privVals[0])
added, _, err := hvs.AddByIndex(0, vote999_0, "peer1")
if !added || err != nil {
t.Error("Expected to successfully add vote from peer", added, err)
}
vote1000_0 := makeVoteHR(t, 1, 1000, privVals[0])
added, _, err = hvs.AddByIndex(0, vote1000_0, "peer1")
if added {
t.Error("Expected to *not* add vote from peer, too many catchup rounds.")
}
added, _, err = hvs.AddByIndex(0, vote1000_0, "peer2")
if !added || err != nil {
t.Error("Expected to successfully add vote from another peer")
}
}
func makeVoteHR(t *testing.T, height, round int, privVal *types.PrivValidator) *types.Vote {
vote := &types.Vote{
Height: height,
Round: round,
Type: types.VoteTypePrecommit,
BlockHash: []byte("fakehash"),
}
chainID := config.GetString("chain_id")
err := privVal.SignVote(chainID, vote)
if err != nil {
t.Fatalf("Error signing vote: %v", err)
return nil
}
return vote
}

View File

@ -83,3 +83,24 @@ func (vc validatorCodec) Compare(o1 interface{}, o2 interface{}) int {
PanicSanity("ValidatorCodec.Compare not implemented") PanicSanity("ValidatorCodec.Compare not implemented")
return 0 return 0
} }
//--------------------------------------------------------------------------------
// For testing...
func RandValidator(randPower bool, minPower int64) (*Validator, *PrivValidator) {
privVal := GenPrivValidator()
_, tempFilePath := Tempfile("priv_validator_")
privVal.SetFile(tempFilePath)
votePower := minPower
if randPower {
votePower += int64(RandUint32())
}
val := &Validator{
Address: privVal.Address,
PubKey: privVal.PubKey,
LastCommitHeight: 0,
VotingPower: votePower,
Accum: 0,
}
return val, privVal
}

View File

@ -309,3 +309,19 @@ type accumComparable int64
func (ac accumComparable) Less(o interface{}) bool { func (ac accumComparable) Less(o interface{}) bool {
return int64(ac) > int64(o.(accumComparable)) return int64(ac) > int64(o.(accumComparable))
} }
//----------------------------------------
// For testing
func RandValidatorSet(numValidators int, votingPower int64) (*ValidatorSet, []*PrivValidator) {
vals := make([]*Validator, numValidators)
privValidators := make([]*PrivValidator, numValidators)
for i := 0; i < numValidators; i++ {
val, privValidator := RandValidator(false, votingPower)
vals[i] = val
privValidators[i] = privValidator
}
valSet := NewValidatorSet(vals)
sort.Sort(PrivValidatorsByAddress(privValidators))
return valSet, privValidators
}

View File

@ -300,24 +300,3 @@ func (voteSet *VoteSet) MakeValidation() *Validation {
Precommits: precommits, Precommits: precommits,
} }
} }
//--------------------------------------------------------------------------------
// For testing...
func RandValidator(randPower bool, minPower int64) (*Validator, *PrivValidator) {
privVal := GenPrivValidator()
_, tempFilePath := Tempfile("priv_validator_")
privVal.SetFile(tempFilePath)
votePower := minPower
if randPower {
votePower += int64(RandUint32())
}
val := &Validator{
Address: privVal.Address,
PubKey: privVal.PubKey,
LastCommitHeight: 0,
VotingPower: votePower,
Accum: 0,
}
return val, privVal
}

View File

@ -2,7 +2,6 @@ package types
import ( import (
"bytes" "bytes"
"sort"
. "github.com/tendermint/go-common" . "github.com/tendermint/go-common"
. "github.com/tendermint/go-common/test" . "github.com/tendermint/go-common/test"
@ -11,16 +10,9 @@ import (
"testing" "testing"
) )
// Move it out?
func randVoteSet(height int, round int, type_ byte, numValidators int, votingPower int64) (*VoteSet, *ValidatorSet, []*PrivValidator) { func randVoteSet(height int, round int, type_ byte, numValidators int, votingPower int64) (*VoteSet, *ValidatorSet, []*PrivValidator) {
vals := make([]*Validator, numValidators) valSet, privValidators := RandValidatorSet(numValidators, votingPower)
privValidators := make([]*PrivValidator, numValidators)
for i := 0; i < numValidators; i++ {
val, privValidator := RandValidator(false, votingPower)
vals[i] = val
privValidators[i] = privValidator
}
valSet := NewValidatorSet(vals)
sort.Sort(PrivValidatorsByAddress(privValidators))
return NewVoteSet(height, round, type_, valSet), valSet, privValidators return NewVoteSet(height, round, type_, valSet), valSet, privValidators
} }