// Returns whether +2/3 have prevoted/committed for BlockHash. func (pol *POL) Verify(valSet *sm.ValidatorSet) error { if uint(len(pol.Votes)) != valSet.Size() { return fmt.Errorf("Invalid POL votes count: Expected %v, got %v", valSet.Size(), len(pol.Votes)) } talliedVotingPower := uint64(0) prevoteDoc := account.SignBytes(&types.Vote{ Height: pol.Height, Round: pol.Round, Type: types.VoteTypePrevote, BlockHash: pol.BlockHash, BlockParts: pol.BlockParts, }) seenValidators := map[string]struct{}{} for idx, vote := range pol.Votes { // vote may be zero, in which case skip. if vote.Signature.IsZero() { continue } voteDoc := prevoteDoc _, val := valSet.GetByIndex(uint(idx)) // Commit vote? if vote.Round < pol.Round { voteDoc = account.SignBytes(&types.Vote{ Height: pol.Height, Round: vote.Round, Type: types.VoteTypeCommit, BlockHash: pol.BlockHash, BlockParts: pol.BlockParts, }) } else if vote.Round > pol.Round { return fmt.Errorf("Invalid commit round %v for POL %v", vote.Round, pol) } // Validate if _, seen := seenValidators[string(val.Address)]; seen { return fmt.Errorf("Duplicate validator for vote %v for POL %v", vote, pol) } if !val.PubKey.VerifyBytes(voteDoc, vote.Signature) { return fmt.Errorf("Invalid signature for vote %v for POL %v", vote, pol) } // Tally seenValidators[string(val.Address)] = struct{}{} talliedVotingPower += val.VotingPower } if talliedVotingPower > valSet.TotalVotingPower()*2/3 { return nil } else { return fmt.Errorf("Invalid POL, insufficient voting power %v, needed %v", talliedVotingPower, (valSet.TotalVotingPower()*2/3 + 1)) } }
// Constructs a new VoteSet struct used to accumulate votes for given height/round. func NewVoteSet(height uint, round uint, type_ byte, valSet *sm.ValidatorSet) *VoteSet { if height == 0 { panic("Cannot make VoteSet for height == 0, doesn't make sense.") } if type_ == types.VoteTypeCommit && round != 0 { panic("Expected round 0 for commit vote set") } return &VoteSet{ height: height, round: round, type_: type_, valSet: valSet, votes: make([]*types.Vote, valSet.Size()), votesBitArray: NewBitArray(valSet.Size()), votesByBlock: make(map[string]uint64), totalVotes: 0, } }