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