You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

95 lines
2.5 KiB

  1. package light
  2. import (
  3. "github.com/tendermint/tendermint/types"
  4. lightErr "github.com/tendermint/tendermint/light/errors"
  5. )
  6. var _ Certifier = &Dynamic{}
  7. // Dynamic uses a Static for Certify, but adds an
  8. // Update method to allow for a change of validators.
  9. //
  10. // You can pass in a FullCommit with another validator set,
  11. // and if this is a provably secure transition (< 1/3 change,
  12. // sufficient signatures), then it will update the
  13. // validator set for the next Certify call.
  14. // For security, it will only follow validator set changes
  15. // going forward.
  16. type Dynamic struct {
  17. cert *Static
  18. lastHeight int
  19. }
  20. // NewDynamic returns a new dynamic certifier.
  21. func NewDynamic(chainID string, vals *types.ValidatorSet, height int) *Dynamic {
  22. return &Dynamic{
  23. cert: NewStatic(chainID, vals),
  24. lastHeight: height,
  25. }
  26. }
  27. // ChainID returns the chain id of this certifier.
  28. func (c *Dynamic) ChainID() string {
  29. return c.cert.ChainID()
  30. }
  31. // Validators returns the validators of this certifier.
  32. func (c *Dynamic) Validators() *types.ValidatorSet {
  33. return c.cert.vSet
  34. }
  35. // Hash returns the hash of this certifier.
  36. func (c *Dynamic) Hash() []byte {
  37. return c.cert.Hash()
  38. }
  39. // LastHeight returns the last height of this certifier.
  40. func (c *Dynamic) LastHeight() int {
  41. return c.lastHeight
  42. }
  43. // Certify will verify whether the commit is valid and will update the height if it is or return an
  44. // error if it is not.
  45. func (c *Dynamic) Certify(check Commit) error {
  46. err := c.cert.Certify(check)
  47. if err == nil {
  48. // update last seen height if input is valid
  49. c.lastHeight = check.Height()
  50. }
  51. return err
  52. }
  53. // Update will verify if this is a valid change and update
  54. // the certifying validator set if safe to do so.
  55. //
  56. // Returns an error if update is impossible (invalid proof or IsTooMuchChangeErr)
  57. func (c *Dynamic) Update(fc FullCommit) error {
  58. // ignore all checkpoints in the past -> only to the future
  59. h := fc.Height()
  60. if h <= c.lastHeight {
  61. return lightErr.ErrPastTime()
  62. }
  63. // first, verify if the input is self-consistent....
  64. err := fc.ValidateBasic(c.ChainID())
  65. if err != nil {
  66. return err
  67. }
  68. // now, make sure not too much change... meaning this commit
  69. // would be approved by the currently known validator set
  70. // as well as the new set
  71. commit := fc.Commit.Commit
  72. err = c.Validators().VerifyCommitAny(fc.Validators, c.ChainID(),
  73. commit.BlockID, h, commit)
  74. if err != nil {
  75. return lightErr.ErrTooMuchChange()
  76. }
  77. // looks good, we can update
  78. c.cert = NewStatic(c.ChainID(), fc.Validators)
  79. c.lastHeight = h
  80. return nil
  81. }