|
@ -1,8 +1,6 @@ |
|
|
package certifiers |
|
|
package certifiers |
|
|
|
|
|
|
|
|
import ( |
|
|
import ( |
|
|
"github.com/pkg/errors" |
|
|
|
|
|
|
|
|
|
|
|
"github.com/tendermint/tendermint/types" |
|
|
"github.com/tendermint/tendermint/types" |
|
|
|
|
|
|
|
|
certerr "github.com/tendermint/tendermint/certifiers/errors" |
|
|
certerr "github.com/tendermint/tendermint/certifiers/errors" |
|
@ -78,7 +76,7 @@ func (c *Dynamic) Update(fc FullCommit) error { |
|
|
// would be approved by the currently known validator set
|
|
|
// would be approved by the currently known validator set
|
|
|
// as well as the new set
|
|
|
// as well as the new set
|
|
|
commit := fc.Commit.Commit |
|
|
commit := fc.Commit.Commit |
|
|
err = VerifyCommitAny(c.Validators(), fc.Validators, c.ChainID(), |
|
|
|
|
|
|
|
|
err = c.Validators().VerifyCommitAny(fc.Validators, c.ChainID(), |
|
|
commit.BlockID, h, commit) |
|
|
commit.BlockID, h, commit) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
return certerr.ErrTooMuchChange() |
|
|
return certerr.ErrTooMuchChange() |
|
@ -89,85 +87,3 @@ func (c *Dynamic) Update(fc FullCommit) error { |
|
|
c.lastHeight = h |
|
|
c.lastHeight = h |
|
|
return nil |
|
|
return nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// VerifyCommitAny will check to see if the set would
|
|
|
|
|
|
// be valid with a different validator set.
|
|
|
|
|
|
//
|
|
|
|
|
|
// old is the validator set that we know
|
|
|
|
|
|
// * over 2/3 of the power in old signed this block
|
|
|
|
|
|
//
|
|
|
|
|
|
// cur is the validator set that signed this block
|
|
|
|
|
|
// * only votes from old are sufficient for 2/3 majority
|
|
|
|
|
|
// in the new set as well
|
|
|
|
|
|
//
|
|
|
|
|
|
// That means that:
|
|
|
|
|
|
// * 10% of the valset can't just declare themselves kings
|
|
|
|
|
|
// * If the validator set is 3x old size, we need more proof to trust
|
|
|
|
|
|
//
|
|
|
|
|
|
// *** TODO: move this.
|
|
|
|
|
|
// It belongs in tendermint/types/validator_set.go: VerifyCommitAny
|
|
|
|
|
|
func VerifyCommitAny(old, cur *types.ValidatorSet, chainID string, |
|
|
|
|
|
blockID types.BlockID, height int, commit *types.Commit) error { |
|
|
|
|
|
|
|
|
|
|
|
if cur.Size() != len(commit.Precommits) { |
|
|
|
|
|
return errors.Errorf("Invalid commit -- wrong set size: %v vs %v", cur.Size(), len(commit.Precommits)) |
|
|
|
|
|
} |
|
|
|
|
|
if height != commit.Height() { |
|
|
|
|
|
return errors.Errorf("Invalid commit -- wrong height: %v vs %v", height, commit.Height()) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
oldVotingPower := int64(0) |
|
|
|
|
|
curVotingPower := int64(0) |
|
|
|
|
|
seen := map[int]bool{} |
|
|
|
|
|
round := commit.Round() |
|
|
|
|
|
|
|
|
|
|
|
for idx, precommit := range commit.Precommits { |
|
|
|
|
|
// first check as in VerifyCommit
|
|
|
|
|
|
if precommit == nil { |
|
|
|
|
|
continue |
|
|
|
|
|
} |
|
|
|
|
|
if precommit.Height != height { |
|
|
|
|
|
return certerr.ErrHeightMismatch(height, precommit.Height) |
|
|
|
|
|
} |
|
|
|
|
|
if precommit.Round != round { |
|
|
|
|
|
return errors.Errorf("Invalid commit -- wrong round: %v vs %v", round, precommit.Round) |
|
|
|
|
|
} |
|
|
|
|
|
if precommit.Type != types.VoteTypePrecommit { |
|
|
|
|
|
return errors.Errorf("Invalid commit -- not precommit @ index %v", idx) |
|
|
|
|
|
} |
|
|
|
|
|
if !blockID.Equals(precommit.BlockID) { |
|
|
|
|
|
continue // Not an error, but doesn't count
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// we only grab by address, ignoring unknown validators
|
|
|
|
|
|
vi, ov := old.GetByAddress(precommit.ValidatorAddress) |
|
|
|
|
|
if ov == nil || seen[vi] { |
|
|
|
|
|
continue // missing or double vote...
|
|
|
|
|
|
} |
|
|
|
|
|
seen[vi] = true |
|
|
|
|
|
|
|
|
|
|
|
// Validate signature old school
|
|
|
|
|
|
precommitSignBytes := types.SignBytes(chainID, precommit) |
|
|
|
|
|
if !ov.PubKey.VerifyBytes(precommitSignBytes, precommit.Signature) { |
|
|
|
|
|
return errors.Errorf("Invalid commit -- invalid signature: %v", precommit) |
|
|
|
|
|
} |
|
|
|
|
|
// Good precommit!
|
|
|
|
|
|
oldVotingPower += ov.VotingPower |
|
|
|
|
|
|
|
|
|
|
|
// check new school
|
|
|
|
|
|
_, cv := cur.GetByIndex(idx) |
|
|
|
|
|
if cv.PubKey.Equals(ov.PubKey) { |
|
|
|
|
|
// make sure this is properly set in the current block as well
|
|
|
|
|
|
curVotingPower += cv.VotingPower |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if oldVotingPower <= old.TotalVotingPower()*2/3 { |
|
|
|
|
|
return errors.Errorf("Invalid commit -- insufficient old voting power: got %v, needed %v", |
|
|
|
|
|
oldVotingPower, (old.TotalVotingPower()*2/3 + 1)) |
|
|
|
|
|
} else if curVotingPower <= cur.TotalVotingPower()*2/3 { |
|
|
|
|
|
return errors.Errorf("Invalid commit -- insufficient cur voting power: got %v, needed %v", |
|
|
|
|
|
curVotingPower, (cur.TotalVotingPower()*2/3 + 1)) |
|
|
|
|
|
} |
|
|
|
|
|
return nil |
|
|
|
|
|
} |
|
|
|