tendermint/lite/client/provider.go

132 lines
3.7 KiB
Go
Raw Normal View History

2017-10-24 12:34:36 +02:00
/*
2019-07-08 13:23:58 +04:00
Package client defines a provider that uses an RPC client to get information
like new headers and validators directly from a Tendermint node.
Use either NewProvider or NewHTTPProvider to construct one.
2017-10-24 12:34:36 +02:00
*/
package client
import (
"fmt"
2017-10-24 12:34:36 +02:00
log "github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/lite"
lerr "github.com/tendermint/tendermint/lite/errors"
2017-10-24 12:34:36 +02:00
rpcclient "github.com/tendermint/tendermint/rpc/client"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/tendermint/tendermint/types"
)
// SignStatusClient combines a SignClient and StatusClient.
2017-10-24 12:34:36 +02:00
type SignStatusClient interface {
rpcclient.SignClient
rpcclient.StatusClient
}
type provider struct {
logger log.Logger
chainID string
client SignStatusClient
2017-10-24 12:34:36 +02:00
}
2019-07-08 13:23:58 +04:00
// NewProvider creates a lite.Provider using the given chain ID and
// SignStatusClient.
func NewProvider(chainID string, client SignStatusClient) lite.Provider {
return &provider{
logger: log.NewNopLogger(),
chainID: chainID,
client: client,
}
2017-10-24 12:34:36 +02:00
}
2019-07-08 13:23:58 +04:00
// NewHTTPProvider creates a lite.Provider, which is using the rpcclient.HTTP
// client under the hood.
func NewHTTPProvider(chainID, remote string) lite.Provider {
return NewProvider(chainID, rpcclient.NewHTTP(remote, "/websocket"))
}
2019-07-08 13:23:58 +04:00
// SetLogger implements lite.Provider.
func (p *provider) SetLogger(logger log.Logger) {
logger = logger.With("module", "lite/client")
p.logger = logger
2017-10-24 12:34:36 +02:00
}
2019-07-08 13:23:58 +04:00
// LatestFullCommit implements lite.Provider.
func (p *provider) LatestFullCommit(chainID string, minHeight, maxHeight int64) (fc lite.FullCommit, err error) {
if chainID != p.chainID {
2019-07-08 13:23:58 +04:00
return fc, fmt.Errorf("expected chainID %s, got %s", p.chainID, chainID)
2017-10-24 12:34:36 +02:00
}
2019-04-25 15:11:30 -04:00
if maxHeight != 0 && maxHeight < minHeight {
2019-07-08 13:23:58 +04:00
return fc, fmt.Errorf("need maxHeight == 0 or minHeight <= maxHeight, got min %v and max %v",
minHeight, maxHeight)
2017-10-24 12:34:36 +02:00
}
2019-04-25 15:11:30 -04:00
commit, err := p.fetchLatestCommit(minHeight, maxHeight)
2017-10-24 12:34:36 +02:00
if err != nil {
2019-07-08 13:23:58 +04:00
return fc, err
2017-10-24 12:34:36 +02:00
}
2019-04-25 15:11:30 -04:00
2019-07-08 13:23:58 +04:00
return p.fillFullCommit(commit.SignedHeader)
2017-10-24 12:34:36 +02:00
}
func (p *provider) fetchLatestCommit(minHeight int64, maxHeight int64) (*ctypes.ResultCommit, error) {
status, err := p.client.Status()
2017-10-24 12:34:36 +02:00
if err != nil {
return nil, err
2017-10-24 12:34:36 +02:00
}
2019-07-08 13:23:58 +04:00
if status.SyncInfo.LatestBlockHeight < minHeight {
2019-07-08 13:23:58 +04:00
return nil, fmt.Errorf("provider is at %d but require minHeight=%d",
status.SyncInfo.LatestBlockHeight, minHeight)
2017-10-24 12:34:36 +02:00
}
2019-07-08 13:23:58 +04:00
if maxHeight == 0 {
maxHeight = status.SyncInfo.LatestBlockHeight
} else if status.SyncInfo.LatestBlockHeight < maxHeight {
maxHeight = status.SyncInfo.LatestBlockHeight
}
2019-07-08 13:23:58 +04:00
return p.client.Commit(&maxHeight)
2017-10-24 12:34:36 +02:00
}
// This does no validation.
func (p *provider) fillFullCommit(signedHeader types.SignedHeader) (fc lite.FullCommit, err error) {
// Get the validators.
valset, err := p.getValidatorSet(signedHeader.ChainID, signedHeader.Height)
2017-10-24 12:34:36 +02:00
if err != nil {
return lite.FullCommit{}, err
2017-10-24 12:34:36 +02:00
}
// Get the next validators.
2018-06-19 23:55:15 -07:00
nextValset, err := p.getValidatorSet(signedHeader.ChainID, signedHeader.Height+1)
if err != nil {
return lite.FullCommit{}, err
2017-10-24 12:34:36 +02:00
}
2018-06-25 16:31:59 -07:00
return lite.NewFullCommit(signedHeader, valset, nextValset), nil
2017-10-24 12:34:36 +02:00
}
2019-07-08 13:23:58 +04:00
// ValidatorSet implements lite.Provider.
func (p *provider) ValidatorSet(chainID string, height int64) (valset *types.ValidatorSet, err error) {
return p.getValidatorSet(chainID, height)
}
func (p *provider) getValidatorSet(chainID string, height int64) (valset *types.ValidatorSet, err error) {
if chainID != p.chainID {
return nil, fmt.Errorf("expected chainID %s, got %s", p.chainID, chainID)
}
if height < 1 {
return nil, fmt.Errorf("expected height >= 1, got height %d", height)
}
res, err := p.client.Validators(&height)
if err != nil {
// TODO pass through other types of errors.
return nil, lerr.ErrUnknownValidators(chainID, height)
}
return types.NewValidatorSet(res.Validators), nil
}