github.com/vipernet-xyz/tm@v0.34.24/types/vote_set.go (about)

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