- package light
-
- import (
- "github.com/tendermint/tendermint/types"
-
- lightErr "github.com/tendermint/tendermint/light/errors"
- )
-
- var _ Certifier = &Dynamic{}
-
- // Dynamic uses a Static 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 Dynamic struct {
- cert *Static
- lastHeight int
- }
-
- // NewDynamic returns a new dynamic certifier.
- func NewDynamic(chainID string, vals *types.ValidatorSet, height int) *Dynamic {
- return &Dynamic{
- cert: NewStatic(chainID, vals),
- lastHeight: height,
- }
- }
-
- // ChainID returns the chain id of this certifier.
- func (c *Dynamic) ChainID() string {
- return c.cert.ChainID()
- }
-
- // Validators returns the validators of this certifier.
- func (c *Dynamic) Validators() *types.ValidatorSet {
- return c.cert.vSet
- }
-
- // Hash returns the hash of this certifier.
- func (c *Dynamic) Hash() []byte {
- return c.cert.Hash()
- }
-
- // LastHeight returns the last height of this certifier.
- func (c *Dynamic) LastHeight() int {
- return c.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.
- func (c *Dynamic) Certify(check Commit) error {
- err := c.cert.Certify(check)
- if err == nil {
- // update last seen height if input is valid
- c.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 (c *Dynamic) Update(fc FullCommit) error {
- // ignore all checkpoints in the past -> only to the future
- h := fc.Height()
- if h <= c.lastHeight {
- return lightErr.ErrPastTime()
- }
-
- // first, verify if the input is self-consistent....
- err := fc.ValidateBasic(c.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 = c.Validators().VerifyCommitAny(fc.Validators, c.ChainID(),
- commit.BlockID, h, commit)
- if err != nil {
- return lightErr.ErrTooMuchChange()
- }
-
- // looks good, we can update
- c.cert = NewStatic(c.ChainID(), fc.Validators)
- c.lastHeight = h
- return nil
- }
|