github.com/vipernet-xyz/tm@v0.34.24/spec/light-client/verification/verification_003_draft.md (about)

     1  # Light Client Verificaiton
     2  
     3  #### **[LCV-FUNC-VERIFYCOMMITLIGHT.1]**
     4  
     5  VerifyCommitLight verifies that 2/3+ of the signatures for a validator set were for
     6  a given blockID. The function will finish early and thus may not check all signatures.
     7  
     8  ```go
     9  func VerifyCommitLight(chainID string, vals *ValidatorSet, blockID BlockID,
    10  height int64, commit *Commit) error {
    11    // run a basic validation of the arguments
    12    if err := verifyBasicValsAndCommit(vals, commit, height, blockID); err != nil {
    13      return err
    14    }
    15  
    16    // calculate voting power needed
    17    votingPowerNeeded := vals.TotalVotingPower() * 2 / 3
    18  
    19    var (
    20      val                *Validator
    21      valIdx             int32
    22      seenVals                 = make(map[int32]int, len(commit.Signatures))
    23      talliedVotingPower int64 = 0
    24      voteSignBytes      []byte
    25    )
    26    for idx, commitSig := range commit.Signatures {
    27      // ignore all commit signatures that are not for the block
    28      if !commitSig.ForBlock() {
    29        continue
    30      }
    31  
    32      // If the vals and commit have a 1-to-1 correspondance we can retrieve
    33      // them by index else we need to retrieve them by address
    34      if lookUpByIndex {
    35        val = vals.Validators[idx]
    36      } else {
    37        valIdx, val = vals.GetByAddress(commitSig.ValidatorAddress)  
    38  
    39        // if the signature doesn't belong to anyone in the validator set
    40        // then we just skip over it
    41        if val == nil {
    42          continue
    43        }
    44  
    45        // because we are getting validators by address we need to make sure
    46        // that the same validator doesn't commit twice
    47        if firstIndex, ok := seenVals[valIdx]; ok {
    48          secondIndex := idx
    49          return fmt.Errorf("double vote from %v (%d and %d)", val, firstIndex, secondIndex)
    50        }
    51        seenVals[valIdx] = idx
    52      }
    53  
    54      voteSignBytes = commit.VoteSignBytes(chainID, int32(idx))
    55  
    56      if !val.PubKey.VerifySignature(voteSignBytes, commitSig.Signature) {
    57        return fmt.Errorf("wrong signature (#%d): %X", idx, commitSig.Signature)
    58      }
    59  
    60      // Add the voting power of the validator
    61      // to the tally
    62      talliedVotingPower += val.VotingPower
    63  
    64      // check if we have enough signatures and can thus exit early
    65      if talliedVotingPower > votingPowerNeeded {
    66        return nil
    67      }
    68    }
    69  
    70    if got, needed := talliedVotingPower, votingPowerNeeded; got <= needed {
    71      return ErrNotEnoughVotingPowerSigned{Got: got, Needed: needed}
    72    }
    73  
    74    return nil
    75  }
    76  ```