github.com/okex/exchain@v1.8.0/libs/tendermint/types/vote_set.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"github.com/okex/exchain/libs/tendermint/libs/automation"
     7  	"strings"
     8  	"sync"
     9  
    10  	"github.com/pkg/errors"
    11  
    12  	"github.com/okex/exchain/libs/tendermint/libs/bits"
    13  )
    14  
    15  const (
    16  	// MaxVotesCount is the maximum number of votes in a set. Used in ValidateBasic funcs for
    17  	// protection against DOS attacks. Note this implies a corresponding equal limit to
    18  	// the number of validators.
    19  	MaxVotesCount = 10000
    20  )
    21  
    22  // UNSTABLE
    23  // XXX: duplicate of p2p.ID to avoid dependence between packages.
    24  // Perhaps we can have a minimal types package containing this (and other things?)
    25  // that both `types` and `p2p` import ?
    26  type P2PID string
    27  
    28  /*
    29  	VoteSet helps collect signatures from validators at each height+round for a
    30  	predefined vote type.
    31  
    32  	We need VoteSet to be able to keep track of conflicting votes when validators
    33  	double-sign.  Yet, we can't keep track of *all* the votes seen, as that could
    34  	be a DoS attack vector.
    35  
    36  	There are two storage areas for votes.
    37  	1. voteSet.votes
    38  	2. voteSet.votesByBlock
    39  
    40  	`.votes` is the "canonical" list of votes.  It always has at least one vote,
    41  	if a vote from a validator had been seen at all.  Usually it keeps track of
    42  	the first vote seen, but when a 2/3 majority is found, votes for that get
    43  	priority and are copied over from `.votesByBlock`.
    44  
    45  	`.votesByBlock` keeps track of a list of votes for a particular block.  There
    46  	are two ways a &blockVotes{} gets created in `.votesByBlock`.
    47  	1. the first vote seen by a validator was for the particular block.
    48  	2. a peer claims to have seen 2/3 majority for the particular block.
    49  
    50  	Since the first vote from a validator will always get added in `.votesByBlock`
    51  	, all votes in `.votes` will have a corresponding entry in `.votesByBlock`.
    52  
    53  	When a &blockVotes{} in `.votesByBlock` reaches a 2/3 majority quorum, its
    54  	votes are copied into `.votes`.
    55  
    56  	All this is memory bounded because conflicting votes only get added if a peer
    57  	told us to track that block, each peer only gets to tell us 1 such block, and,
    58  	there's only a limited number of peers.
    59  
    60  	NOTE: Assumes that the sum total of voting power does not exceed MaxUInt64.
    61  */
    62  type VoteSet struct {
    63  	chainID       string
    64  	height        int64
    65  	round         int
    66  	signedMsgType SignedMsgType
    67  	valSet        *ValidatorSet
    68  
    69  	mtx           sync.Mutex
    70  	votesBitArray *bits.BitArray
    71  	votes         []*Vote                // Primary votes to share
    72  	sum           int64                  // Sum of voting power for seen votes, discounting conflicts
    73  	maj23         *BlockID               // First 2/3 majority seen
    74  	votesByBlock  map[string]*blockVotes // string(blockHash|blockParts) -> blockVotes
    75  	peerMaj23s    map[P2PID]BlockID      // Maj23 for each peer
    76  }
    77  
    78  // Constructs a new VoteSet struct used to accumulate votes for given height/round.
    79  func NewVoteSet(chainID string, height int64, round int, signedMsgType SignedMsgType, valSet *ValidatorSet) *VoteSet {
    80  	if height == 0 {
    81  		panic("Cannot make VoteSet for height == 0, doesn't make sense.")
    82  	}
    83  	return &VoteSet{
    84  		chainID:       chainID,
    85  		height:        height,
    86  		round:         round,
    87  		signedMsgType: signedMsgType,
    88  		valSet:        valSet,
    89  		votesBitArray: bits.NewBitArray(valSet.Size()),
    90  		votes:         make([]*Vote, valSet.Size()),
    91  		sum:           0,
    92  		maj23:         nil,
    93  		votesByBlock:  make(map[string]*blockVotes, valSet.Size()),
    94  		peerMaj23s:    make(map[P2PID]BlockID),
    95  	}
    96  }
    97  
    98  func (voteSet *VoteSet) ChainID() string {
    99  	return voteSet.chainID
   100  }
   101  
   102  // Implements VoteSetReader.
   103  func (voteSet *VoteSet) GetHeight() int64 {
   104  	if voteSet == nil {
   105  		return 0
   106  	}
   107  	return voteSet.height
   108  }
   109  
   110  // Implements VoteSetReader.
   111  func (voteSet *VoteSet) GetRound() int {
   112  	if voteSet == nil {
   113  		return -1
   114  	}
   115  	return voteSet.round
   116  }
   117  
   118  // Implements VoteSetReader.
   119  func (voteSet *VoteSet) Type() byte {
   120  	if voteSet == nil {
   121  		return 0x00
   122  	}
   123  	return byte(voteSet.signedMsgType)
   124  }
   125  
   126  // Implements VoteSetReader.
   127  func (voteSet *VoteSet) Size() int {
   128  	if voteSet == nil {
   129  		return 0
   130  	}
   131  	return voteSet.valSet.Size()
   132  }
   133  
   134  // Returns added=true if vote is valid and new.
   135  // Otherwise returns err=ErrVote[
   136  //		UnexpectedStep | InvalidIndex | InvalidAddress |
   137  //		InvalidSignature | InvalidBlockHash | ConflictingVotes ]
   138  // Duplicate votes return added=false, err=nil.
   139  // Conflicting votes return added=*, err=ErrVoteConflictingVotes.
   140  // NOTE: vote should not be mutated after adding.
   141  // NOTE: VoteSet must not be nil
   142  // NOTE: Vote must not be nil
   143  func (voteSet *VoteSet) AddVote(vote *Vote) (added bool, err error) {
   144  	if voteSet == nil {
   145  		panic("AddVote() on nil VoteSet")
   146  	}
   147  	voteSet.mtx.Lock()
   148  	defer voteSet.mtx.Unlock()
   149  
   150  	return voteSet.addVote(vote)
   151  }
   152  
   153  // NOTE: Validates as much as possible before attempting to verify the signature.
   154  func (voteSet *VoteSet) addVote(vote *Vote) (added bool, err error) {
   155  	if vote == nil {
   156  		return false, ErrVoteNil
   157  	}
   158  	valIndex := vote.ValidatorIndex
   159  	valAddr := vote.ValidatorAddress
   160  	blockKey := vote.BlockID.Key()
   161  
   162  	// Ensure that validator index was set
   163  	if valIndex < 0 {
   164  		return false, errors.Wrap(ErrVoteInvalidValidatorIndex, "Index < 0")
   165  	} else if len(valAddr) == 0 {
   166  		return false, errors.Wrap(ErrVoteInvalidValidatorAddress, "Empty address")
   167  	}
   168  
   169  	// Make sure the step matches.
   170  	if (vote.Height != voteSet.height) ||
   171  		(vote.Round != voteSet.round) ||
   172  		(vote.Type != voteSet.signedMsgType) {
   173  		return false, errors.Wrapf(ErrVoteUnexpectedStep, "Expected %d/%d/%d, but got %d/%d/%d",
   174  			voteSet.height, voteSet.round, voteSet.signedMsgType,
   175  			vote.Height, vote.Round, vote.Type)
   176  	}
   177  
   178  	// Ensure that signer is a validator.
   179  	lookupAddr, val := voteSet.valSet.GetByIndex(valIndex)
   180  	if val == nil {
   181  		return false, errors.Wrapf(ErrVoteInvalidValidatorIndex,
   182  			"Cannot find validator %d in valSet of size %d", valIndex, voteSet.valSet.Size())
   183  	}
   184  
   185  	// Ensure that the signer has the right address.
   186  	if !bytes.Equal(valAddr, lookupAddr) {
   187  		return false, errors.Wrapf(ErrVoteInvalidValidatorAddress,
   188  			"vote.ValidatorAddress (%X) does not match address (%X) for vote.ValidatorIndex (%d)\n"+
   189  				"Ensure the genesis file is correct across all validators.",
   190  			valAddr, lookupAddr, valIndex)
   191  	}
   192  
   193  	// If we already know of this vote, return false.
   194  	if existing, ok := voteSet.getVote(valIndex, blockKey); ok {
   195  		if bytes.Equal(existing.Signature, vote.Signature) {
   196  			return false, nil // duplicate
   197  		}
   198  		return false, errors.Wrapf(ErrVoteNonDeterministicSignature, "Existing vote: %v; New vote: %v", existing, vote)
   199  	}
   200  
   201  	// Check signature.
   202  	if err := vote.Verify(voteSet.chainID, val.PubKey); err != nil {
   203  		return false, errors.Wrapf(err, "Failed to verify vote with ChainID %s and PubKey %s", voteSet.chainID, val.PubKey)
   204  	}
   205  
   206  	// Add vote and get conflicting vote if any.
   207  	added, conflicting := voteSet.addVerifiedVote(vote, blockKey, val.VotingPower)
   208  	if conflicting != nil {
   209  		return added, NewConflictingVoteError(val, conflicting, vote)
   210  	}
   211  	if !added {
   212  		panic("Expected to add non-conflicting vote")
   213  	}
   214  	return added, nil
   215  }
   216  
   217  // Returns (vote, true) if vote exists for valIndex and blockKey.
   218  func (voteSet *VoteSet) getVote(valIndex int, blockKey string) (vote *Vote, ok bool) {
   219  	if existing := voteSet.votes[valIndex]; existing != nil && existing.BlockID.Key() == blockKey {
   220  		return existing, true
   221  	}
   222  	if existing := voteSet.votesByBlock[blockKey].getByIndex(valIndex); existing != nil {
   223  		return existing, true
   224  	}
   225  	return nil, false
   226  }
   227  
   228  // Assumes signature is valid.
   229  // If conflicting vote exists, returns it.
   230  func (voteSet *VoteSet) addVerifiedVote(
   231  	vote *Vote,
   232  	blockKey string,
   233  	votingPower int64,
   234  ) (added bool, conflicting *Vote) {
   235  	valIndex := vote.ValidatorIndex
   236  
   237  	// Already exists in voteSet.votes?
   238  	if existing := voteSet.votes[valIndex]; existing != nil {
   239  		if existing.BlockID.Equals(vote.BlockID) {
   240  			panic("addVerifiedVote does not expect duplicate votes")
   241  		} else {
   242  			conflicting = existing
   243  		}
   244  		// Replace vote if blockKey matches voteSet.maj23.
   245  		if voteSet.maj23 != nil && voteSet.maj23.Key() == blockKey {
   246  			voteSet.votes[valIndex] = vote
   247  			voteSet.votesBitArray.SetIndex(valIndex, true)
   248  		}
   249  		// Otherwise don't add it to voteSet.votes
   250  	} else {
   251  		// Add to voteSet.votes and incr .sum
   252  		voteSet.votes[valIndex] = vote
   253  		voteSet.votesBitArray.SetIndex(valIndex, true)
   254  		voteSet.sum += votingPower
   255  	}
   256  
   257  	votesByBlock, ok := voteSet.votesByBlock[blockKey]
   258  	if ok {
   259  		if conflicting != nil && !votesByBlock.peerMaj23 {
   260  			// There's a conflict and no peer claims that this block is special.
   261  			return false, conflicting
   262  		}
   263  		// We'll add the vote in a bit.
   264  	} else {
   265  		// .votesByBlock doesn't exist...
   266  		if conflicting != nil {
   267  			// ... and there's a conflicting vote.
   268  			// We're not even tracking this blockKey, so just forget it.
   269  			return false, conflicting
   270  		}
   271  		// ... and there's no conflicting vote.
   272  		// Start tracking this blockKey
   273  		votesByBlock = newBlockVotes(false, voteSet.valSet.Size())
   274  		voteSet.votesByBlock[blockKey] = votesByBlock
   275  		// We'll add the vote in a bit.
   276  	}
   277  
   278  	// Before adding to votesByBlock, see if we'll exceed quorum
   279  	origSum := votesByBlock.sum
   280  	quorum := voteSet.valSet.TotalVotingPower()*2/3 + 1
   281  
   282  	// Add vote to votesByBlock
   283  	votesByBlock.addVerifiedVote(vote, votingPower)
   284  
   285  	// If we just crossed the quorum threshold and have 2/3 majority...
   286  	if origSum < quorum && quorum <= votesByBlock.sum {
   287  		// Only consider the first quorum reached
   288  		if voteSet.maj23 == nil {
   289  			maj23BlockID := vote.BlockID
   290  			voteSet.maj23 = &maj23BlockID
   291  			// And also copy votes over to voteSet.votes
   292  			for i, vote := range votesByBlock.votes {
   293  				if vote != nil {
   294  					voteSet.votes[i] = vote
   295  				}
   296  			}
   297  		}
   298  	}
   299  
   300  	return true, conflicting
   301  }
   302  
   303  // If a peer claims that it has 2/3 majority for given blockKey, call this.
   304  // NOTE: if there are too many peers, or too much peer churn,
   305  // this can cause memory issues.
   306  // TODO: implement ability to remove peers too
   307  // NOTE: VoteSet must not be nil
   308  func (voteSet *VoteSet) SetPeerMaj23(peerID P2PID, blockID BlockID) error {
   309  	if voteSet == nil {
   310  		panic("SetPeerMaj23() on nil VoteSet")
   311  	}
   312  	voteSet.mtx.Lock()
   313  	defer voteSet.mtx.Unlock()
   314  
   315  	blockKey := blockID.Key()
   316  
   317  	// Make sure peer hasn't already told us something.
   318  	if existing, ok := voteSet.peerMaj23s[peerID]; ok {
   319  		if existing.Equals(blockID) {
   320  			return nil // Nothing to do
   321  		}
   322  		return fmt.Errorf("setPeerMaj23: Received conflicting blockID from peer %v. Got %v, expected %v",
   323  			peerID, blockID, existing)
   324  	}
   325  	voteSet.peerMaj23s[peerID] = blockID
   326  
   327  	// Create .votesByBlock entry if needed.
   328  	votesByBlock, ok := voteSet.votesByBlock[blockKey]
   329  	if ok {
   330  		if votesByBlock.peerMaj23 {
   331  			return nil // Nothing to do
   332  		}
   333  		votesByBlock.peerMaj23 = true
   334  		// No need to copy votes, already there.
   335  	} else {
   336  		votesByBlock = newBlockVotes(true, voteSet.valSet.Size())
   337  		voteSet.votesByBlock[blockKey] = votesByBlock
   338  		// No need to copy votes, no votes to copy over.
   339  	}
   340  	return nil
   341  }
   342  
   343  // Implements VoteSetReader.
   344  func (voteSet *VoteSet) BitArray() *bits.BitArray {
   345  	if voteSet == nil {
   346  		return nil
   347  	}
   348  	voteSet.mtx.Lock()
   349  	defer voteSet.mtx.Unlock()
   350  	return voteSet.votesBitArray.Copy()
   351  }
   352  
   353  func (voteSet *VoteSet) BitArrayByBlockID(blockID BlockID) *bits.BitArray {
   354  	if voteSet == nil {
   355  		return nil
   356  	}
   357  	voteSet.mtx.Lock()
   358  	defer voteSet.mtx.Unlock()
   359  	votesByBlock, ok := voteSet.votesByBlock[blockID.Key()]
   360  	if ok {
   361  		return votesByBlock.bitArray.Copy()
   362  	}
   363  	return nil
   364  }
   365  
   366  // NOTE: if validator has conflicting votes, returns "canonical" vote
   367  // Implements VoteSetReader.
   368  func (voteSet *VoteSet) GetByIndex(valIndex int) *Vote {
   369  	if voteSet == nil {
   370  		return nil
   371  	}
   372  	voteSet.mtx.Lock()
   373  	defer voteSet.mtx.Unlock()
   374  	return voteSet.votes[valIndex]
   375  }
   376  
   377  func (voteSet *VoteSet) GetByAddress(address []byte) *Vote {
   378  	if voteSet == nil {
   379  		return nil
   380  	}
   381  	voteSet.mtx.Lock()
   382  	defer voteSet.mtx.Unlock()
   383  	valIndex, val := voteSet.valSet.GetByAddress(address)
   384  	if val == nil {
   385  		panic("GetByAddress(address) returned nil")
   386  	}
   387  	return voteSet.votes[valIndex]
   388  }
   389  
   390  func (voteSet *VoteSet) HasTwoThirdsMajority() bool {
   391  	if voteSet == nil {
   392  		return false
   393  	}
   394  	voteSet.mtx.Lock()
   395  	defer voteSet.mtx.Unlock()
   396  	return voteSet.maj23 != nil
   397  }
   398  
   399  // Implements VoteSetReader.
   400  func (voteSet *VoteSet) IsCommit() bool {
   401  	if voteSet == nil {
   402  		return false
   403  	}
   404  	if voteSet.signedMsgType != PrecommitType {
   405  		return false
   406  	}
   407  	voteSet.mtx.Lock()
   408  	defer voteSet.mtx.Unlock()
   409  	return voteSet.maj23 != nil
   410  }
   411  
   412  func (voteSet *VoteSet) HasTwoThirdsAny() bool {
   413  	if voteSet == nil {
   414  		return false
   415  	}
   416  	voteSet.mtx.Lock()
   417  	defer voteSet.mtx.Unlock()
   418  	return voteSet.sum > voteSet.valSet.TotalVotingPower()*2/3
   419  }
   420  
   421  func (voteSet *VoteSet) HasAll() bool {
   422  	voteSet.mtx.Lock()
   423  	defer voteSet.mtx.Unlock()
   424  	return voteSet.sum == voteSet.valSet.TotalVotingPower()
   425  }
   426  
   427  // If there was a +2/3 majority for blockID, return blockID and true.
   428  // Else, return the empty BlockID{} and false.
   429  func (voteSet *VoteSet) TwoThirdsMajority() (blockID BlockID, ok bool) {
   430  	if voteSet == nil {
   431  		return BlockID{}, false
   432  	}
   433  
   434  	switch voteSet.signedMsgType {
   435  	case PrevoteType:
   436  		if automation.PrevotesNotMaj23(voteSet.height, voteSet.round) {
   437  			return BlockID{}, false
   438  		}
   439  	case PrecommitType:
   440  		if automation.PrecommitsNotMaj23(voteSet.height, voteSet.round) {
   441  			return BlockID{}, false
   442  		}
   443  	}
   444  
   445  	voteSet.mtx.Lock()
   446  	defer voteSet.mtx.Unlock()
   447  	if voteSet.maj23 != nil {
   448  		return *voteSet.maj23, true
   449  	}
   450  	return BlockID{}, false
   451  }
   452  
   453  //--------------------------------------------------------------------------------
   454  // Strings and JSON
   455  
   456  func (voteSet *VoteSet) String() string {
   457  	if voteSet == nil {
   458  		return "nil-VoteSet"
   459  	}
   460  	return voteSet.StringIndented("")
   461  }
   462  
   463  func (voteSet *VoteSet) StringIndented(indent string) string {
   464  	voteSet.mtx.Lock()
   465  	defer voteSet.mtx.Unlock()
   466  	voteStrings := make([]string, len(voteSet.votes))
   467  	for i, vote := range voteSet.votes {
   468  		if vote == nil {
   469  			voteStrings[i] = nilVoteStr
   470  		} else {
   471  			voteStrings[i] = vote.String()
   472  		}
   473  	}
   474  	return fmt.Sprintf(`VoteSet{
   475  %s  H:%v R:%v T:%v
   476  %s  %v
   477  %s  %v
   478  %s  %v
   479  %s}`,
   480  		indent, voteSet.height, voteSet.round, voteSet.signedMsgType,
   481  		indent, strings.Join(voteStrings, "\n"+indent+"  "),
   482  		indent, voteSet.votesBitArray,
   483  		indent, voteSet.peerMaj23s,
   484  		indent)
   485  }
   486  
   487  // Marshal the VoteSet to JSON. Same as String(), just in JSON,
   488  // and without the height/round/signedMsgType (since its already included in the votes).
   489  func (voteSet *VoteSet) MarshalJSON() ([]byte, error) {
   490  	voteSet.mtx.Lock()
   491  	defer voteSet.mtx.Unlock()
   492  	return cdc.MarshalJSON(VoteSetJSON{
   493  		voteSet.voteStrings(),
   494  		voteSet.bitArrayString(),
   495  		voteSet.peerMaj23s,
   496  	})
   497  }
   498  
   499  // More human readable JSON of the vote set
   500  // NOTE: insufficient for unmarshalling from (compressed votes)
   501  // TODO: make the peerMaj23s nicer to read (eg just the block hash)
   502  type VoteSetJSON struct {
   503  	Votes         []string          `json:"votes"`
   504  	VotesBitArray string            `json:"votes_bit_array"`
   505  	PeerMaj23s    map[P2PID]BlockID `json:"peer_maj_23s"`
   506  }
   507  
   508  // Return the bit-array of votes including
   509  // the fraction of power that has voted like:
   510  // "BA{29:xx__x__x_x___x__x_______xxx__} 856/1304 = 0.66"
   511  func (voteSet *VoteSet) BitArrayString() string {
   512  	voteSet.mtx.Lock()
   513  	defer voteSet.mtx.Unlock()
   514  	return voteSet.bitArrayString()
   515  }
   516  
   517  func (voteSet *VoteSet) bitArrayString() string {
   518  	bAString := voteSet.votesBitArray.String()
   519  	voted, total, fracVoted := voteSet.sumTotalFrac()
   520  	return fmt.Sprintf("%s %d/%d = %.2f", bAString, voted, total, fracVoted)
   521  }
   522  
   523  // Returns a list of votes compressed to more readable strings.
   524  func (voteSet *VoteSet) VoteStrings() []string {
   525  	voteSet.mtx.Lock()
   526  	defer voteSet.mtx.Unlock()
   527  	return voteSet.voteStrings()
   528  }
   529  
   530  func (voteSet *VoteSet) voteStrings() []string {
   531  	voteStrings := make([]string, len(voteSet.votes))
   532  	for i, vote := range voteSet.votes {
   533  		if vote == nil {
   534  			voteStrings[i] = nilVoteStr
   535  		} else {
   536  			voteStrings[i] = vote.String()
   537  		}
   538  	}
   539  	return voteStrings
   540  }
   541  
   542  func (voteSet *VoteSet) StringShort() string {
   543  	if voteSet == nil {
   544  		return "nil-VoteSet"
   545  	}
   546  	voteSet.mtx.Lock()
   547  	defer voteSet.mtx.Unlock()
   548  	_, _, frac := voteSet.sumTotalFrac()
   549  	return fmt.Sprintf(`VoteSet{H:%v R:%v T:%v +2/3:%v(%v) %v %v}`,
   550  		voteSet.height, voteSet.round, voteSet.signedMsgType, voteSet.maj23, frac, voteSet.votesBitArray, voteSet.peerMaj23s)
   551  }
   552  
   553  // return the power voted, the total, and the fraction
   554  func (voteSet *VoteSet) sumTotalFrac() (int64, int64, float64) {
   555  	voted, total := voteSet.sum, voteSet.valSet.TotalVotingPower()
   556  	fracVoted := float64(voted) / float64(total)
   557  	return voted, total, fracVoted
   558  }
   559  
   560  //--------------------------------------------------------------------------------
   561  // Commit
   562  
   563  // MakeCommit constructs a Commit from the VoteSet. It only includes precommits
   564  // for the block, which has 2/3+ majority, and nil.
   565  //
   566  // Panics if the vote type is not PrecommitType or if there's no +2/3 votes for
   567  // a single block.
   568  func (voteSet *VoteSet) MakeCommit() *Commit {
   569  	if voteSet.signedMsgType != PrecommitType {
   570  		panic("Cannot MakeCommit() unless VoteSet.Type is PrecommitType")
   571  	}
   572  	voteSet.mtx.Lock()
   573  	defer voteSet.mtx.Unlock()
   574  
   575  	// Make sure we have a 2/3 majority
   576  	if voteSet.maj23 == nil {
   577  		panic("Cannot MakeCommit() unless a blockhash has +2/3")
   578  	}
   579  
   580  	// For every validator, get the precommit
   581  	commitSigs := make([]CommitSig, len(voteSet.votes))
   582  	for i, v := range voteSet.votes {
   583  		commitSig := v.CommitSig()
   584  		// if block ID exists but doesn't match, exclude sig
   585  		if commitSig.ForBlock() && !v.BlockID.Equals(*voteSet.maj23) {
   586  			commitSig = NewCommitSigAbsent()
   587  		}
   588  		commitSigs[i] = commitSig
   589  	}
   590  
   591  	return NewCommit(voteSet.GetHeight(), voteSet.GetRound(), *voteSet.maj23, commitSigs)
   592  }
   593  
   594  //--------------------------------------------------------------------------------
   595  
   596  /*
   597  	Votes for a particular block
   598  	There are two ways a *blockVotes gets created for a blockKey.
   599  	1. first (non-conflicting) vote of a validator w/ blockKey (peerMaj23=false)
   600  	2. A peer claims to have a 2/3 majority w/ blockKey (peerMaj23=true)
   601  */
   602  type blockVotes struct {
   603  	peerMaj23 bool           // peer claims to have maj23
   604  	bitArray  *bits.BitArray // valIndex -> hasVote?
   605  	votes     []*Vote        // valIndex -> *Vote
   606  	sum       int64          // vote sum
   607  }
   608  
   609  func newBlockVotes(peerMaj23 bool, numValidators int) *blockVotes {
   610  	return &blockVotes{
   611  		peerMaj23: peerMaj23,
   612  		bitArray:  bits.NewBitArray(numValidators),
   613  		votes:     make([]*Vote, numValidators),
   614  		sum:       0,
   615  	}
   616  }
   617  
   618  func (vs *blockVotes) addVerifiedVote(vote *Vote, votingPower int64) {
   619  	valIndex := vote.ValidatorIndex
   620  	if existing := vs.votes[valIndex]; existing == nil {
   621  		vs.bitArray.SetIndex(valIndex, true)
   622  		vs.votes[valIndex] = vote
   623  		vs.sum += votingPower
   624  	}
   625  }
   626  
   627  func (vs *blockVotes) getByIndex(index int) *Vote {
   628  	if vs == nil {
   629  		return nil
   630  	}
   631  	return vs.votes[index]
   632  }
   633  
   634  //--------------------------------------------------------------------------------
   635  
   636  // Common interface between *consensus.VoteSet and types.Commit
   637  type VoteSetReader interface {
   638  	GetHeight() int64
   639  	GetRound() int
   640  	Type() byte
   641  	Size() int
   642  	BitArray() *bits.BitArray
   643  	GetByIndex(int) *Vote
   644  	IsCommit() bool
   645  }