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.

89 lines
2.2 KiB

  1. package certifiers
  2. import (
  3. "github.com/tendermint/tendermint/types"
  4. certerr "github.com/tendermint/tendermint/certifiers/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. func NewDynamic(chainID string, vals *types.ValidatorSet, height int) *Dynamic {
  21. return &Dynamic{
  22. cert: NewStatic(chainID, vals),
  23. lastHeight: height,
  24. }
  25. }
  26. func (c *Dynamic) ChainID() string {
  27. return c.cert.ChainID()
  28. }
  29. func (c *Dynamic) Validators() *types.ValidatorSet {
  30. return c.cert.vSet
  31. }
  32. func (c *Dynamic) Hash() []byte {
  33. return c.cert.Hash()
  34. }
  35. func (c *Dynamic) LastHeight() int {
  36. return c.lastHeight
  37. }
  38. // Certify handles this with
  39. func (c *Dynamic) Certify(check Commit) error {
  40. err := c.cert.Certify(check)
  41. if err == nil {
  42. // update last seen height if input is valid
  43. c.lastHeight = check.Height()
  44. }
  45. return err
  46. }
  47. // Update will verify if this is a valid change and update
  48. // the certifying validator set if safe to do so.
  49. //
  50. // Returns an error if update is impossible (invalid proof or IsTooMuchChangeErr)
  51. func (c *Dynamic) Update(fc FullCommit) error {
  52. // ignore all checkpoints in the past -> only to the future
  53. h := fc.Height()
  54. if h <= c.lastHeight {
  55. return certerr.ErrPastTime()
  56. }
  57. // first, verify if the input is self-consistent....
  58. err := fc.ValidateBasic(c.ChainID())
  59. if err != nil {
  60. return err
  61. }
  62. // now, make sure not too much change... meaning this commit
  63. // would be approved by the currently known validator set
  64. // as well as the new set
  65. commit := fc.Commit.Commit
  66. err = c.Validators().VerifyCommitAny(fc.Validators, c.ChainID(),
  67. commit.BlockID, h, commit)
  68. if err != nil {
  69. return certerr.ErrTooMuchChange()
  70. }
  71. // looks good, we can update
  72. c.cert = NewStatic(c.ChainID(), fc.Validators)
  73. c.lastHeight = h
  74. return nil
  75. }