mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 06:42:16 +00:00
* Vulnerability in light client proxy When calling GetCertifiedCommit the light client proxy would call Certify and even on error return the Commit as if it had been correctly certified. Now it returns the error correctly and returns an empty Commit on error. * Improve names for clarity The lite package now contains StaticCertifier, DynamicCertifier and InqueringCertifier. This also changes the method receivers from one letter to two letter names, which will make future refactoring easier and follows the coding standards. * Fix test failures * Rename files * remove dead code
97 lines
2.7 KiB
Go
97 lines
2.7 KiB
Go
package lite
|
|
|
|
import (
|
|
"github.com/tendermint/tendermint/types"
|
|
|
|
liteErr "github.com/tendermint/tendermint/lite/errors"
|
|
)
|
|
|
|
var _ Certifier = (*DynamicCertifier)(nil)
|
|
|
|
// DynamicCertifier uses a StaticCertifier for Certify, but adds an
|
|
// Update method to allow for a change of validators.
|
|
//
|
|
// You can pass in a FullCommit with another validator set,
|
|
// and if this is a provably secure transition (< 1/3 change,
|
|
// sufficient signatures), then it will update the
|
|
// validator set for the next Certify call.
|
|
// For security, it will only follow validator set changes
|
|
// going forward.
|
|
type DynamicCertifier struct {
|
|
cert *StaticCertifier
|
|
lastHeight int64
|
|
}
|
|
|
|
// NewDynamic returns a new dynamic certifier.
|
|
func NewDynamicCertifier(chainID string, vals *types.ValidatorSet, height int64) *DynamicCertifier {
|
|
return &DynamicCertifier{
|
|
cert: NewStaticCertifier(chainID, vals),
|
|
lastHeight: height,
|
|
}
|
|
}
|
|
|
|
// ChainID returns the chain id of this certifier.
|
|
// Implements Certifier.
|
|
func (dc *DynamicCertifier) ChainID() string {
|
|
return dc.cert.ChainID()
|
|
}
|
|
|
|
// Validators returns the validators of this certifier.
|
|
func (dc *DynamicCertifier) Validators() *types.ValidatorSet {
|
|
return dc.cert.vSet
|
|
}
|
|
|
|
// Hash returns the hash of this certifier.
|
|
func (dc *DynamicCertifier) Hash() []byte {
|
|
return dc.cert.Hash()
|
|
}
|
|
|
|
// LastHeight returns the last height of this certifier.
|
|
func (dc *DynamicCertifier) LastHeight() int64 {
|
|
return dc.lastHeight
|
|
}
|
|
|
|
// Certify will verify whether the commit is valid and will update the height if it is or return an
|
|
// error if it is not.
|
|
// Implements Certifier.
|
|
func (dc *DynamicCertifier) Certify(check Commit) error {
|
|
err := dc.cert.Certify(check)
|
|
if err == nil {
|
|
// update last seen height if input is valid
|
|
dc.lastHeight = check.Height()
|
|
}
|
|
return err
|
|
}
|
|
|
|
// Update will verify if this is a valid change and update
|
|
// the certifying validator set if safe to do so.
|
|
//
|
|
// Returns an error if update is impossible (invalid proof or IsTooMuchChangeErr)
|
|
func (dc *DynamicCertifier) Update(fc FullCommit) error {
|
|
// ignore all checkpoints in the past -> only to the future
|
|
h := fc.Height()
|
|
if h <= dc.lastHeight {
|
|
return liteErr.ErrPastTime()
|
|
}
|
|
|
|
// first, verify if the input is self-consistent....
|
|
err := fc.ValidateBasic(dc.ChainID())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// now, make sure not too much change... meaning this commit
|
|
// would be approved by the currently known validator set
|
|
// as well as the new set
|
|
commit := fc.Commit.Commit
|
|
err = dc.Validators().VerifyCommitAny(fc.Validators, dc.ChainID(), commit.BlockID, h, commit)
|
|
if err != nil {
|
|
return liteErr.ErrTooMuchChange()
|
|
}
|
|
|
|
// looks good, we can update
|
|
dc.cert = NewStaticCertifier(dc.ChainID(), fc.Validators)
|
|
dc.lastHeight = h
|
|
return nil
|
|
}
|