- 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
- }
|