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.

134 lines
3.9 KiB

  1. /*
  2. Package client defines a provider that uses a rpcclient
  3. to get information, which is used to get new headers
  4. and validators directly from a Tendermint client.
  5. */
  6. package client
  7. import (
  8. "fmt"
  9. log "github.com/tendermint/tendermint/libs/log"
  10. "github.com/tendermint/tendermint/lite"
  11. lerr "github.com/tendermint/tendermint/lite/errors"
  12. rpcclient "github.com/tendermint/tendermint/rpc/client"
  13. ctypes "github.com/tendermint/tendermint/rpc/core/types"
  14. "github.com/tendermint/tendermint/types"
  15. )
  16. // SignStatusClient combines a SignClient and StatusClient.
  17. type SignStatusClient interface {
  18. rpcclient.SignClient
  19. rpcclient.StatusClient
  20. }
  21. type provider struct {
  22. logger log.Logger
  23. chainID string
  24. client SignStatusClient
  25. }
  26. // NewProvider implements Provider (but not PersistentProvider).
  27. func NewProvider(chainID string, client SignStatusClient) lite.Provider {
  28. return &provider{
  29. logger: log.NewNopLogger(),
  30. chainID: chainID,
  31. client: client,
  32. }
  33. }
  34. // NewHTTPProvider can connect to a tendermint json-rpc endpoint
  35. // at the given url, and uses that as a read-only provider.
  36. func NewHTTPProvider(chainID, remote string) lite.Provider {
  37. return NewProvider(chainID, rpcclient.NewHTTP(remote, "/websocket"))
  38. }
  39. // Implements Provider.
  40. func (p *provider) SetLogger(logger log.Logger) {
  41. logger = logger.With("module", "lite/client")
  42. p.logger = logger
  43. }
  44. // StatusClient returns the internal client as a StatusClient
  45. func (p *provider) StatusClient() rpcclient.StatusClient {
  46. return p.client
  47. }
  48. // LatestFullCommit implements Provider.
  49. func (p *provider) LatestFullCommit(chainID string, minHeight, maxHeight int64) (fc lite.FullCommit, err error) {
  50. if chainID != p.chainID {
  51. err = fmt.Errorf("expected chainID %s, got %s", p.chainID, chainID)
  52. return
  53. }
  54. if maxHeight != 0 && maxHeight < minHeight {
  55. err = fmt.Errorf("need maxHeight == 0 or minHeight <= maxHeight, got min %v and max %v",
  56. minHeight, maxHeight)
  57. return
  58. }
  59. commit, err := p.fetchLatestCommit(minHeight, maxHeight)
  60. if err != nil {
  61. return
  62. }
  63. fc, err = p.fillFullCommit(commit.SignedHeader)
  64. return
  65. }
  66. // fetchLatestCommit fetches the latest commit from the client.
  67. func (p *provider) fetchLatestCommit(minHeight int64, maxHeight int64) (*ctypes.ResultCommit, error) {
  68. status, err := p.client.Status()
  69. if err != nil {
  70. return nil, err
  71. }
  72. if status.SyncInfo.LatestBlockHeight < minHeight {
  73. err = fmt.Errorf("provider is at %v but require minHeight=%v",
  74. status.SyncInfo.LatestBlockHeight, minHeight)
  75. return nil, err
  76. }
  77. if maxHeight == 0 {
  78. maxHeight = status.SyncInfo.LatestBlockHeight
  79. } else if status.SyncInfo.LatestBlockHeight < maxHeight {
  80. maxHeight = status.SyncInfo.LatestBlockHeight
  81. }
  82. return p.client.Commit(&maxHeight)
  83. }
  84. // Implements Provider.
  85. func (p *provider) ValidatorSet(chainID string, height int64) (valset *types.ValidatorSet, err error) {
  86. return p.getValidatorSet(chainID, height)
  87. }
  88. func (p *provider) getValidatorSet(chainID string, height int64) (valset *types.ValidatorSet, err error) {
  89. if chainID != p.chainID {
  90. err = fmt.Errorf("expected chainID %s, got %s", p.chainID, chainID)
  91. return
  92. }
  93. if height < 1 {
  94. err = fmt.Errorf("expected height >= 1, got height %v", height)
  95. return
  96. }
  97. res, err := p.client.Validators(&height)
  98. if err != nil {
  99. // TODO pass through other types of errors.
  100. return nil, lerr.ErrUnknownValidators(chainID, height)
  101. }
  102. valset = types.NewValidatorSet(res.Validators)
  103. return
  104. }
  105. // This does no validation.
  106. func (p *provider) fillFullCommit(signedHeader types.SignedHeader) (fc lite.FullCommit, err error) {
  107. // Get the validators.
  108. valset, err := p.getValidatorSet(signedHeader.ChainID, signedHeader.Height)
  109. if err != nil {
  110. return lite.FullCommit{}, err
  111. }
  112. // Get the next validators.
  113. nextValset, err := p.getValidatorSet(signedHeader.ChainID, signedHeader.Height+1)
  114. if err != nil {
  115. return lite.FullCommit{}, err
  116. }
  117. return lite.NewFullCommit(signedHeader, valset, nextValset), nil
  118. }