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