|
@ -714,82 +714,6 @@ func (vals *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, |
|
|
return ErrNotEnoughVotingPowerSigned{Got: talliedVotingPower, Needed: votingPowerNeeded} |
|
|
return ErrNotEnoughVotingPowerSigned{Got: talliedVotingPower, Needed: votingPowerNeeded} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// VerifyFutureCommit will check to see if the set would be valid with a different
|
|
|
|
|
|
// validator set.
|
|
|
|
|
|
//
|
|
|
|
|
|
// vals is the old validator set that we know. Over 2/3 of the power in old
|
|
|
|
|
|
// signed this block.
|
|
|
|
|
|
//
|
|
|
|
|
|
// In Tendermint, 1/3 of the voting power can halt or fork the chain, but 1/3
|
|
|
|
|
|
// can't make arbitrary state transitions. You still need > 2/3 Byzantine to
|
|
|
|
|
|
// make arbitrary state transitions.
|
|
|
|
|
|
//
|
|
|
|
|
|
// To preserve this property in the light client, we also require > 2/3 of the
|
|
|
|
|
|
// old vals to sign the future commit at H, that way we preserve the property
|
|
|
|
|
|
// that if they weren't being truthful about the validator set at H (block hash
|
|
|
|
|
|
// -> vals hash) or about the app state (block hash -> app hash) we can slash
|
|
|
|
|
|
// > 2/3. Otherwise, the light client isn't providing the same security
|
|
|
|
|
|
// guarantees.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Even if we added a slashing condition that if you sign a block header with
|
|
|
|
|
|
// the wrong validator set, then we would only need > 1/3 of signatures from
|
|
|
|
|
|
// the old vals on the new commit, it wouldn't be sufficient because the new
|
|
|
|
|
|
// vals can be arbitrary and commit some arbitrary app hash.
|
|
|
|
|
|
//
|
|
|
|
|
|
// newSet is the validator set that signed this block. Only votes from new are
|
|
|
|
|
|
// sufficient for 2/3 majority in the new set as well, for it to be a valid
|
|
|
|
|
|
// commit.
|
|
|
|
|
|
//
|
|
|
|
|
|
// NOTE: This doesn't check whether the commit is a future commit, because the
|
|
|
|
|
|
// current height isn't part of the ValidatorSet. Caller must check that the
|
|
|
|
|
|
// commit height is greater than the height for this validator set.
|
|
|
|
|
|
func (vals *ValidatorSet) VerifyFutureCommit(newSet *ValidatorSet, chainID string, |
|
|
|
|
|
blockID BlockID, height int64, commit *Commit) error { |
|
|
|
|
|
oldVals := vals |
|
|
|
|
|
|
|
|
|
|
|
// Commit must be a valid commit for newSet.
|
|
|
|
|
|
err := newSet.VerifyCommit(chainID, blockID, height, commit) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
return err |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Check old voting power.
|
|
|
|
|
|
oldVotingPower := int64(0) |
|
|
|
|
|
seen := map[int32]bool{} |
|
|
|
|
|
|
|
|
|
|
|
for idx, commitSig := range commit.Signatures { |
|
|
|
|
|
if commitSig.Absent() { |
|
|
|
|
|
continue // OK, some signatures can be absent.
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// See if this validator is in oldVals.
|
|
|
|
|
|
oldIdx, val := oldVals.GetByAddress(commitSig.ValidatorAddress) |
|
|
|
|
|
if val == nil || seen[oldIdx] { |
|
|
|
|
|
continue // missing or double vote...
|
|
|
|
|
|
} |
|
|
|
|
|
seen[oldIdx] = true |
|
|
|
|
|
|
|
|
|
|
|
// Validate signature.
|
|
|
|
|
|
voteSignBytes := commit.VoteSignBytes(chainID, int32(idx)) |
|
|
|
|
|
if !val.PubKey.VerifyBytes(voteSignBytes, commitSig.Signature) { |
|
|
|
|
|
return fmt.Errorf("wrong signature (#%d): %X", idx, commitSig.Signature) |
|
|
|
|
|
} |
|
|
|
|
|
// Good!
|
|
|
|
|
|
if blockID.Equals(commitSig.BlockID(commit.BlockID)) { |
|
|
|
|
|
oldVotingPower += val.VotingPower |
|
|
|
|
|
} |
|
|
|
|
|
// else {
|
|
|
|
|
|
// It's OK that the BlockID doesn't match. We include stray
|
|
|
|
|
|
// signatures (~votes for nil) to measure validator availability.
|
|
|
|
|
|
// }
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if got, needed := oldVotingPower, oldVals.TotalVotingPower()*2/3; got <= needed { |
|
|
|
|
|
return ErrNotEnoughVotingPowerSigned{Got: got, Needed: needed} |
|
|
|
|
|
} |
|
|
|
|
|
return nil |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// VerifyCommitTrusting verifies that trustLevel of the validator set signed
|
|
|
// VerifyCommitTrusting verifies that trustLevel of the validator set signed
|
|
|
// this commit.
|
|
|
// this commit.
|
|
|
//
|
|
|
//
|
|
|