func (voteSet *VoteSet) TwoThirdsMajority() (blockID pbtypes.BlockID, ok bool) {
	if voteSet == nil {
		return pbtypes.BlockID{}, false
	}
	voteSet.mtx.Lock()
	defer voteSet.mtx.Unlock()
	if voteSet.maj23 != nil {
		return *voteSet.maj23, true
	} else {
		return pbtypes.BlockID{}, false
	}
}
Returns either a blockhash (or nil) that received +2/3 majority.
If there exists no such majority, returns (nil, PartSetHeader{}, false).
package types
import (
	"bytes"
	"errors"
	"fmt"
	"strings"
	"sync"
	pbtypes "github.com/annchain/annchain/angine/protos/types"
	. "github.com/annchain/annchain/module/lib/go-common"
	"github.com/annchain/annchain/module/xlib/def"
)
var (
	ErrVoteUnexpectedStep          = errors.New("Unexpected step")
	ErrVoteInvalidValidatorIndex   = errors.New("Invalid round vote validator index")
	ErrVoteInvalidValidatorAddress = errors.New("Invalid round vote validator address")
	ErrVoteInvalidSignature        = errors.New("Invalid round vote signature")
	ErrVoteMultiSignature          = errors.New("Multi round vote signature")
	ErrVoteInvalidBlockHash        = errors.New("Invalid block hash")
	ErrVoteNilVoteSet              = errors.New("VoteSet is nil")
)
type VoteSet struct {
	chainID string
	height  def.INT
	round   def.INT
	type_   pbtypes.VoteType
	mtx           sync.Mutex
	valSet        *ValidatorSet
	votesBitArray *BitArray
	votes         []*pbtypes.Vote             
	sum           int64                       
	maj23         *pbtypes.BlockID            
	votesByBlock  map[string]*blockVotes      
	peerMaj23s    map[string]pbtypes.BlockID  
}
func NewVoteSet(chainID string, height def.INT, round def.INT, type_ pbtypes.VoteType, valSet *ValidatorSet) *VoteSet {
	if height == 0 {
		PanicSanity("Cannot make VoteSet for height == 0, doesn't make sense.")
	}
	vset := &VoteSet{
		chainID:       chainID,
		height:        height,
		round:         round,
		type_:         type_,
		valSet:        valSet,
		votesBitArray: NewBitArray(valSet.Size()),
		votes:         make([]*pbtypes.Vote, valSet.Size()),
		sum:           0,
		maj23:         nil,
		votesByBlock:  make(map[string]*blockVotes, valSet.Size()),
		peerMaj23s:    make(map[string]pbtypes.BlockID),
	}
	for i := range vset.votes {
		vset.votes[i] = &pbtypes.Vote{}
	}
	return vset
}
func (voteSet *VoteSet) ChainID() string {
	return voteSet.chainID
}
func (voteSet *VoteSet) Height() def.INT {
	if voteSet == nil {
		return 0
	}
	return voteSet.height
}
func (voteSet *VoteSet) Round() def.INT {
	if voteSet == nil {
		return -1
	}
	return voteSet.round
}
func (voteSet *VoteSet) Type() pbtypes.VoteType {
	if voteSet == nil {
		return 0x00
	}
	return voteSet.type_
}
func (voteSet *VoteSet) Size() int {
	if voteSet == nil {
		return 0
	}
	return voteSet.valSet.Size()
}
func (voteSet *VoteSet) AddVote(vote *pbtypes.Vote) (added bool, err error) {
	if voteSet == nil {
		return false, ErrVoteNilVoteSet
	}
	voteSet.mtx.Lock()
	defer voteSet.mtx.Unlock()
	return voteSet.addVote(vote)
}
func (voteSet *VoteSet) addVote(vote *pbtypes.Vote) (added bool, err error) {
	if !vote.Exist() {
		return false, nil
	}
	vdata := vote.GetData()
	valIndex := int(vdata.GetValidatorIndex())
	valAddr := vdata.GetValidatorAddress()
	blockKey := vdata.GetBlockID().Key()
	if valIndex < 0 || len(valAddr) == 0 {
		return false, ErrVoteInvalidValidatorIndex
	}
	if (vdata.Height != voteSet.height) ||
		(vdata.Round != voteSet.round) ||
		(vdata.Type != voteSet.type_) {
		return false, ErrVoteUnexpectedStep
	}
	lookupAddr, val := voteSet.valSet.GetByIndex(valIndex)
	if val == nil {
		return false, ErrVoteInvalidValidatorIndex
	}
	if !bytes.Equal(valAddr, lookupAddr) {
		return false, ErrVoteInvalidValidatorAddress
	}
	voteSig := NewDefaultSignature(vote.GetSignature())
	if existing, ok := voteSet.getVote(valIndex, blockKey); ok {
		exisSig := NewDefaultSignature(existing.GetSignature())
		if exisSig.Equals(voteSig) {
			return false, nil  
		} else {
			return false, ErrVoteInvalidSignature  
		}
	}
	if !val.PubKey.VerifyBytes(SignBytes(voteSet.chainID, vdata), voteSig) {
		return false, ErrVoteInvalidSignature
	}
	added, conflicting := voteSet.addVerifiedVote(vote, blockKey, val.VotingPower)
	if conflicting.Exist() {
		return added, &ErrVoteConflictingVotes{
			VoteA: conflicting,
			VoteB: vote,
		}
	} else {
		if !added {
			PanicSanity("Expected to add non-conflicting vote")
		}
		return added, nil
	}
}
func (voteSet *VoteSet) getVote(valIndex int, blockKey string) (vote *pbtypes.Vote, ok bool) {
	if existing := voteSet.votes[valIndex]; existing.Exist() && existing.GetData().GetBlockID().Key() == blockKey {
		return existing, true
	}
	if existing := voteSet.votesByBlock[blockKey].getByIndex(valIndex); existing.Exist() {
		return existing, true
	}
	return nil, false
}
func (voteSet *VoteSet) addVerifiedVote(vote *pbtypes.Vote, blockKey string, votingPower def.INT) (added bool, conflicting *pbtypes.Vote) {
	vdata := vote.GetData()
	valIndex := int(vdata.ValidatorIndex)
	if existing := voteSet.votes[valIndex]; existing.Exist() {
		if existing.GetData().GetBlockID().Equals(vdata.BlockID) {
			PanicSanity("addVerifiedVote does not expect duplicate votes")
		} else {
			conflicting = existing
		}
		if voteSet.maj23 != nil && voteSet.maj23.Key() == blockKey {
			voteSet.votes[valIndex] = vote
			voteSet.votesBitArray.SetIndex(valIndex, true)
		}
	} else {
		voteSet.votes[valIndex] = vote
		voteSet.votesBitArray.SetIndex(valIndex, true)
		voteSet.sum += votingPower
	}
	votesByBlock, ok := voteSet.votesByBlock[blockKey]
	if ok {
		if conflicting.Exist() && !votesByBlock.peerMaj23 {
			return false, conflicting
		}
	} else {
		if conflicting.Exist() {
			return false, conflicting
		} else {
			votesByBlock = newBlockVotes(false, voteSet.valSet.Size())
			voteSet.votesByBlock[blockKey] = votesByBlock
		}
	}
	origSum := votesByBlock.sum
	quorum := voteSet.valSet.TotalVotingPower()*2/3 + 1
	votesByBlock.addVerifiedVote(vote, votingPower)
	if origSum < quorum && quorum <= votesByBlock.sum {
		if voteSet.maj23 == nil {
			maj23BlockID := *vdata.BlockID
			voteSet.maj23 = &maj23BlockID
			for i, vote := range votesByBlock.votes {
				if vote.Exist() {
					voteSet.votes[i] = vote
				}
			}
		}
	}
	return true, conflicting
}
func (voteSet *VoteSet) SetPeerMaj23(peerID string, blockID *pbtypes.BlockID) {
	if voteSet == nil {
		PanicSanity("SetPeerMaj23() on nil VoteSet")
	}
	voteSet.mtx.Lock()
	defer voteSet.mtx.Unlock()
	blockKey := blockID.Key()
	if existing, ok := voteSet.peerMaj23s[peerID]; ok {
		if existing.Equals(blockID) {
			return  
		} else {
			return  
		}
	}
	voteSet.peerMaj23s[peerID] = *blockID
	votesByBlock, ok := voteSet.votesByBlock[blockKey]
	if ok {
		if votesByBlock.peerMaj23 {
			return  
		} else {
			votesByBlock.peerMaj23 = true
		}
	} else {
		votesByBlock = newBlockVotes(true, voteSet.valSet.Size())
		voteSet.votesByBlock[blockKey] = votesByBlock
	}
}
func (voteSet *VoteSet) BitArray() *BitArray {
	if voteSet == nil {
		return nil
	}
	voteSet.mtx.Lock()
	defer voteSet.mtx.Unlock()
	return voteSet.votesBitArray.Copy()
}
func (voteSet *VoteSet) BitArrayByBlockID(blockID *pbtypes.BlockID) *BitArray {
	if voteSet == nil || blockID == nil {
		return nil
	}
	voteSet.mtx.Lock()
	defer voteSet.mtx.Unlock()
	votesByBlock, ok := voteSet.votesByBlock[blockID.Key()]
	if ok {
		return votesByBlock.bitArray.Copy()
	}
	return nil
}
func (voteSet *VoteSet) GetByIndex(valIndex int) *pbtypes.Vote {
	if voteSet == nil {
		return nil
	}
	voteSet.mtx.Lock()
	defer voteSet.mtx.Unlock()
	return voteSet.votes[valIndex]
}
func (voteSet *VoteSet) GetByAddress(address []byte) *pbtypes.Vote {
	if voteSet == nil {
		return nil
	}
	voteSet.mtx.Lock()
	defer voteSet.mtx.Unlock()
	valIndex, val := voteSet.valSet.GetByAddress(address)
	if val == nil {
		PanicSanity("GetByAddress(address) returned nil")
	}
	return voteSet.votes[valIndex]
}
func (voteSet *VoteSet) HasTwoThirdsMajority() bool {
	if voteSet == nil {
		return false
	}
	voteSet.mtx.Lock()
	defer voteSet.mtx.Unlock()
	return voteSet.maj23 != nil
}
func (voteSet *VoteSet) IsCommit() bool {
	if voteSet == nil {
		return false
	}
	if voteSet.type_ != pbtypes.VoteType_Precommit {
		return false
	}
	voteSet.mtx.Lock()
	defer voteSet.mtx.Unlock()
	return voteSet.maj23 != nil
}
func (voteSet *VoteSet) HasTwoThirdsAny() bool {
	if voteSet == nil {
		return false
	}
	voteSet.mtx.Lock()
	defer voteSet.mtx.Unlock()
	return voteSet.sum > voteSet.valSet.TotalVotingPower()*2/3
}
func (voteSet *VoteSet) HasAll() bool {
	return voteSet.sum == voteSet.valSet.TotalVotingPower()
}