github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/tendermint/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/fibonacci-chain/fbc/libs/tendermint/libs/log" 12 "github.com/fibonacci-chain/fbc/libs/tendermint/lite" 13 lerr "github.com/fibonacci-chain/fbc/libs/tendermint/lite/errors" 14 rpcclient "github.com/fibonacci-chain/fbc/libs/tendermint/rpc/client" 15 rpchttp "github.com/fibonacci-chain/fbc/libs/tendermint/rpc/client/http" 16 ctypes "github.com/fibonacci-chain/fbc/libs/tendermint/rpc/core/types" 17 "github.com/fibonacci-chain/fbc/libs/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 maxHeight != 0 && maxHeight < minHeight { 65 err = fmt.Errorf("need maxHeight == 0 or minHeight <= maxHeight, got min %v and max %v", 66 minHeight, maxHeight) 67 return 68 } 69 commit, err := p.fetchLatestCommit(minHeight, maxHeight) 70 if err != nil { 71 return 72 } 73 if !verifyEqualChainId(commit.ChainID, p.chainID, commit.Height) { 74 err = fmt.Errorf("expected chainID %s, got %s", p.chainID, commit.ChainID) 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 !verifyEqualChainId(chainID, p.chainID, height) { 107 err = fmt.Errorf("expected chainID %s, got %s", p.chainID, chainID) 108 return 109 } 110 if height < types.GetStartBlockHeight()+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 // Get the validators. 126 valset, err := p.getValidatorSet(signedHeader.ChainID, signedHeader.Height) 127 if err != nil { 128 return lite.FullCommit{}, err 129 } 130 131 // Get the next validators. 132 nextValset, err := p.getValidatorSet(signedHeader.ChainID, signedHeader.Height+1) 133 if err != nil { 134 return lite.FullCommit{}, err 135 } 136 137 return lite.NewFullCommit(signedHeader, valset, nextValset), nil 138 } 139 140 func verifyEqualChainId(chain1 string, flagChainId string, h int64) bool { 141 if flagChainId == types.TestNet { 142 if h < types.TestNetChangeChainId && chain1 == types.TestNetChainName1 { 143 return true 144 } 145 } 146 return chain1 == flagChainId 147 }