github.com/okex/exchain@v1.8.0/libs/tendermint/lite2/rpc/client.go (about)

     1  package rpc
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"crypto/sha256"
     7  	"errors"
     8  	"fmt"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/okex/exchain/libs/tendermint/mempool"
    13  
    14  	"github.com/okex/exchain/libs/tendermint/crypto/merkle"
    15  	tmbytes "github.com/okex/exchain/libs/tendermint/libs/bytes"
    16  	service "github.com/okex/exchain/libs/tendermint/libs/service"
    17  	lite "github.com/okex/exchain/libs/tendermint/lite2"
    18  	rpcclient "github.com/okex/exchain/libs/tendermint/rpc/client"
    19  	ctypes "github.com/okex/exchain/libs/tendermint/rpc/core/types"
    20  	rpctypes "github.com/okex/exchain/libs/tendermint/rpc/jsonrpc/types"
    21  	"github.com/okex/exchain/libs/tendermint/types"
    22  )
    23  
    24  var errNegOrZeroHeight = errors.New("negative or zero height")
    25  
    26  // Client is an RPC client, which uses lite#Client to verify data (if it can be
    27  // proved!).
    28  type Client struct {
    29  	service.BaseService
    30  
    31  	next rpcclient.Client
    32  	lc   *lite.Client
    33  	prt  *merkle.ProofRuntime
    34  }
    35  
    36  func (c *Client) GetUnconfirmedTxByHash(hash [sha256.Size]byte) (types.Tx, error) {
    37  	return nil, mempool.ErrNoSuchTx
    38  }
    39  
    40  var _ rpcclient.Client = (*Client)(nil)
    41  
    42  // NewClient returns a new client.
    43  func NewClient(next rpcclient.Client, lc *lite.Client) *Client {
    44  	c := &Client{
    45  		next: next,
    46  		lc:   lc,
    47  		prt:  defaultProofRuntime(),
    48  	}
    49  	c.BaseService = *service.NewBaseService(nil, "Client", c)
    50  	return c
    51  }
    52  
    53  func (c *Client) OnStart() error {
    54  	if !c.next.IsRunning() {
    55  		return c.next.Start()
    56  	}
    57  	return nil
    58  }
    59  
    60  func (c *Client) OnStop() {
    61  	if c.next.IsRunning() {
    62  		c.next.Stop()
    63  	}
    64  }
    65  
    66  func (c *Client) Status() (*ctypes.ResultStatus, error) {
    67  	return c.next.Status()
    68  }
    69  
    70  func (c *Client) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
    71  	return c.next.ABCIInfo()
    72  }
    73  
    74  func (c *Client) ABCIQuery(path string, data tmbytes.HexBytes) (*ctypes.ResultABCIQuery, error) {
    75  	return c.ABCIQueryWithOptions(path, data, rpcclient.DefaultABCIQueryOptions)
    76  }
    77  
    78  // GetWithProofOptions is useful if you want full access to the ABCIQueryOptions.
    79  // XXX Usage of path?  It's not used, and sometimes it's /, sometimes /key, sometimes /store.
    80  func (c *Client) ABCIQueryWithOptions(path string, data tmbytes.HexBytes,
    81  	opts rpcclient.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
    82  
    83  	res, err := c.next.ABCIQueryWithOptions(path, data, opts)
    84  	if err != nil {
    85  		return nil, err
    86  	}
    87  	resp := res.Response
    88  
    89  	// Validate the response.
    90  	if resp.IsErr() {
    91  		return nil, fmt.Errorf("err response code: %v", resp.Code)
    92  	}
    93  	if len(resp.Key) == 0 || resp.Proof == nil {
    94  		return nil, errors.New("empty tree")
    95  	}
    96  	if resp.Height <= 0 {
    97  		return nil, errNegOrZeroHeight
    98  	}
    99  
   100  	// Update the light client if we're behind.
   101  	// NOTE: AppHash for height H is in header H+1.
   102  	h, err := c.updateLiteClientIfNeededTo(resp.Height + 1)
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  
   107  	// Validate the value proof against the trusted header.
   108  	if resp.Value != nil {
   109  		// Value exists
   110  		// XXX How do we encode the key into a string...
   111  		storeName, err := parseQueryStorePath(path)
   112  		if err != nil {
   113  			return nil, err
   114  		}
   115  		kp := merkle.KeyPath{}
   116  		kp = kp.AppendKey([]byte(storeName), merkle.KeyEncodingURL)
   117  		kp = kp.AppendKey(resp.Key, merkle.KeyEncodingURL)
   118  		err = c.prt.VerifyValue(resp.Proof, h.AppHash, kp.String(), resp.Value)
   119  		if err != nil {
   120  			return nil, fmt.Errorf("verify value proof: %w", err)
   121  		}
   122  		return &ctypes.ResultABCIQuery{Response: resp}, nil
   123  	}
   124  
   125  	// OR validate the ansence proof against the trusted header.
   126  	// XXX How do we encode the key into a string...
   127  	err = c.prt.VerifyAbsence(resp.Proof, h.AppHash, string(resp.Key))
   128  	if err != nil {
   129  		return nil, fmt.Errorf("verify absence proof: %w", err)
   130  	}
   131  	return &ctypes.ResultABCIQuery{Response: resp}, nil
   132  }
   133  
   134  func (c *Client) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
   135  	return c.next.BroadcastTxCommit(tx)
   136  }
   137  
   138  func (c *Client) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
   139  	return c.next.BroadcastTxAsync(tx)
   140  }
   141  
   142  func (c *Client) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
   143  	return c.next.BroadcastTxSync(tx)
   144  }
   145  
   146  func (c *Client) UnconfirmedTxs(limit int) (*ctypes.ResultUnconfirmedTxs, error) {
   147  	return c.next.UnconfirmedTxs(limit)
   148  }
   149  
   150  func (c *Client) NumUnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error) {
   151  	return c.next.NumUnconfirmedTxs()
   152  }
   153  
   154  func (c *Client) UserUnconfirmedTxs(address string, limit int) (*ctypes.ResultUserUnconfirmedTxs, error) {
   155  	return c.next.UserUnconfirmedTxs(address, limit)
   156  }
   157  
   158  func (c *Client) UserNumUnconfirmedTxs(address string) (*ctypes.ResultUserUnconfirmedTxs, error) {
   159  	return c.next.UserNumUnconfirmedTxs(address)
   160  }
   161  
   162  func (c *Client) GetAddressList() (*ctypes.ResultUnconfirmedAddresses, error) {
   163  	return c.next.GetAddressList()
   164  }
   165  
   166  func (c *Client) GetPendingNonce(address string) (*ctypes.ResultPendingNonce, bool) {
   167  	return c.next.GetPendingNonce(address)
   168  }
   169  
   170  func (c *Client) NetInfo() (*ctypes.ResultNetInfo, error) {
   171  	return c.next.NetInfo()
   172  }
   173  
   174  func (c *Client) DumpConsensusState() (*ctypes.ResultDumpConsensusState, error) {
   175  	return c.next.DumpConsensusState()
   176  }
   177  
   178  func (c *Client) ConsensusState() (*ctypes.ResultConsensusState, error) {
   179  	return c.next.ConsensusState()
   180  }
   181  
   182  func (c *Client) ConsensusParams(height *int64) (*ctypes.ResultConsensusParams, error) {
   183  	res, err := c.next.ConsensusParams(height)
   184  	if err != nil {
   185  		return nil, err
   186  	}
   187  
   188  	// Validate res.
   189  	if err := res.ConsensusParams.Validate(); err != nil {
   190  		return nil, err
   191  	}
   192  	if res.BlockHeight <= 0 {
   193  		return nil, errNegOrZeroHeight
   194  	}
   195  
   196  	// Update the light client if we're behind.
   197  	h, err := c.updateLiteClientIfNeededTo(res.BlockHeight)
   198  	if err != nil {
   199  		return nil, err
   200  	}
   201  
   202  	// Verify hash.
   203  	if cH, tH := res.ConsensusParams.Hash(), h.ConsensusHash; !bytes.Equal(cH, tH) {
   204  		return nil, fmt.Errorf("params hash %X does not match trusted hash %X",
   205  			cH, tH)
   206  	}
   207  
   208  	return res, nil
   209  }
   210  
   211  func (c *Client) Health() (*ctypes.ResultHealth, error) {
   212  	return c.next.Health()
   213  }
   214  
   215  func (c *Client) LatestBlockNumber() (int64, error) {
   216  	info, err := c.BlockchainInfo(0, 0)
   217  	if err != nil {
   218  		return 0, err
   219  	}
   220  	return info.LastHeight, nil
   221  }
   222  
   223  // BlockchainInfo calls rpcclient#BlockchainInfo and then verifies every header
   224  // returned.
   225  func (c *Client) BlockchainInfo(minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) {
   226  	res, err := c.next.BlockchainInfo(minHeight, maxHeight)
   227  	if err != nil {
   228  		return nil, err
   229  	}
   230  
   231  	// Validate res.
   232  	for i, meta := range res.BlockMetas {
   233  		if meta == nil {
   234  			return nil, fmt.Errorf("nil block meta %d", i)
   235  		}
   236  		if err := meta.ValidateBasic(); err != nil {
   237  			return nil, fmt.Errorf("invalid block meta %d: %w", i, err)
   238  		}
   239  	}
   240  
   241  	// Update the light client if we're behind.
   242  	if len(res.BlockMetas) > 0 {
   243  		lastHeight := res.BlockMetas[len(res.BlockMetas)-1].Header.Height
   244  		if _, err := c.updateLiteClientIfNeededTo(lastHeight); err != nil {
   245  			return nil, err
   246  		}
   247  	}
   248  
   249  	// Verify each of the BlockMetas.
   250  	for _, meta := range res.BlockMetas {
   251  		h, err := c.lc.TrustedHeader(meta.Header.Height)
   252  		if err != nil {
   253  			return nil, fmt.Errorf("trusted header %d: %w", meta.Header.Height, err)
   254  		}
   255  		if bmH, tH := meta.Header.Hash(), h.Hash(); !bytes.Equal(bmH, tH) {
   256  			return nil, fmt.Errorf("block meta header %X does not match with trusted header %X",
   257  				bmH, tH)
   258  		}
   259  	}
   260  
   261  	return res, nil
   262  }
   263  
   264  func (c *Client) Genesis() (*ctypes.ResultGenesis, error) {
   265  	return c.next.Genesis()
   266  }
   267  
   268  // Block calls rpcclient#Block and then verifies the result.
   269  func (c *Client) Block(height *int64) (*ctypes.ResultBlock, error) {
   270  	res, err := c.next.Block(height)
   271  	if err != nil {
   272  		return nil, err
   273  	}
   274  
   275  	// Validate res.
   276  	if err := res.BlockID.ValidateBasic(); err != nil {
   277  		return nil, err
   278  	}
   279  	if err := res.Block.ValidateBasic(); err != nil {
   280  		return nil, err
   281  	}
   282  	if bmH, bH := res.BlockID.Hash, res.Block.Hash(); !bytes.Equal(bmH, bH) {
   283  		return nil, fmt.Errorf("blockID %X does not match with block %X",
   284  			bmH, bH)
   285  	}
   286  
   287  	// Update the light client if we're behind.
   288  	h, err := c.updateLiteClientIfNeededTo(res.Block.Height)
   289  	if err != nil {
   290  		return nil, err
   291  	}
   292  
   293  	// Verify block.
   294  	if bH, tH := res.Block.Hash(), h.Hash(); !bytes.Equal(bH, tH) {
   295  		return nil, fmt.Errorf("block header %X does not match with trusted header %X",
   296  			bH, tH)
   297  	}
   298  
   299  	return res, nil
   300  }
   301  
   302  // Block calls rpcclient#Block and then verifies the result.
   303  func (c *Client) BlockInfo(height *int64) (*types.BlockMeta, error) {
   304  	res, err := c.next.BlockInfo(height)
   305  	if err != nil {
   306  		return nil, err
   307  	}
   308  
   309  	// Validate res.
   310  	if err := res.Header.ValidateBasic(); err != nil {
   311  		return nil, err
   312  	}
   313  
   314  	return res, nil
   315  }
   316  
   317  func (c *Client) BlockResults(height *int64) (*ctypes.ResultBlockResults, error) {
   318  	res, err := c.next.BlockResults(height)
   319  	if err != nil {
   320  		return nil, err
   321  	}
   322  
   323  	// Validate res.
   324  	if res.Height <= 0 {
   325  		return nil, errNegOrZeroHeight
   326  	}
   327  
   328  	// Update the light client if we're behind.
   329  	h, err := c.updateLiteClientIfNeededTo(res.Height + 1)
   330  	if err != nil {
   331  		return nil, err
   332  	}
   333  
   334  	// Verify block results.
   335  	results := types.NewResults(res.TxsResults)
   336  	if rH, tH := results.Hash(), h.LastResultsHash; !bytes.Equal(rH, tH) {
   337  		return nil, fmt.Errorf("last results %X does not match with trusted last results %X",
   338  			rH, tH)
   339  	}
   340  
   341  	return res, nil
   342  }
   343  
   344  func (c *Client) Commit(height *int64) (*ctypes.ResultCommit, error) {
   345  	res, err := c.next.Commit(height)
   346  	if err != nil {
   347  		return nil, err
   348  	}
   349  
   350  	// Validate res.
   351  	if err := res.SignedHeader.ValidateBasic(c.lc.ChainID()); err != nil {
   352  		return nil, err
   353  	}
   354  	if res.Height <= 0 {
   355  		return nil, errNegOrZeroHeight
   356  	}
   357  
   358  	// Update the light client if we're behind.
   359  	h, err := c.updateLiteClientIfNeededTo(res.Height)
   360  	if err != nil {
   361  		return nil, err
   362  	}
   363  
   364  	// Verify commit.
   365  	if rH, tH := res.Hash(), h.Hash(); !bytes.Equal(rH, tH) {
   366  		return nil, fmt.Errorf("header %X does not match with trusted header %X",
   367  			rH, tH)
   368  	}
   369  
   370  	return res, nil
   371  }
   372  
   373  // Tx calls rpcclient#Tx method and then verifies the proof if such was
   374  // requested.
   375  func (c *Client) Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) {
   376  	res, err := c.next.Tx(hash, prove)
   377  	if err != nil || !prove {
   378  		return res, err
   379  	}
   380  
   381  	// Validate res.
   382  	if res.Height <= 0 {
   383  		return nil, errNegOrZeroHeight
   384  	}
   385  
   386  	// Update the light client if we're behind.
   387  	h, err := c.updateLiteClientIfNeededTo(res.Height)
   388  	if err != nil {
   389  		return nil, err
   390  	}
   391  
   392  	// Validate the proof.
   393  	return res, res.Proof.Validate(h.DataHash, res.Height)
   394  }
   395  
   396  func (c *Client) TxSearch(query string, prove bool, page, perPage int, orderBy string) (
   397  	*ctypes.ResultTxSearch, error) {
   398  	return c.next.TxSearch(query, prove, page, perPage, orderBy)
   399  }
   400  
   401  // Validators fetches and verifies validators.
   402  //
   403  // WARNING: only full validator sets are verified (when length of validators is
   404  // less than +perPage+. +perPage+ default is 30, max is 100).
   405  func (c *Client) Validators(height *int64, page, perPage int) (*ctypes.ResultValidators, error) {
   406  	res, err := c.next.Validators(height, page, perPage)
   407  	if err != nil {
   408  		return nil, err
   409  	}
   410  
   411  	// Validate res.
   412  	if res.BlockHeight <= 0 {
   413  		return nil, errNegOrZeroHeight
   414  	}
   415  
   416  	// Update the light client if we're behind.
   417  	h, err := c.updateLiteClientIfNeededTo(res.BlockHeight)
   418  	if err != nil {
   419  		return nil, err
   420  	}
   421  
   422  	// Verify validators.
   423  	if res.Count <= res.Total {
   424  		if rH, tH := types.NewValidatorSet(res.Validators).Hash(*height), h.ValidatorsHash; !bytes.Equal(rH, tH) {
   425  			return nil, fmt.Errorf("validators %X does not match with trusted validators %X",
   426  				rH, tH)
   427  		}
   428  	}
   429  
   430  	return res, nil
   431  }
   432  
   433  func (c *Client) BroadcastEvidence(ev types.Evidence) (*ctypes.ResultBroadcastEvidence, error) {
   434  	return c.next.BroadcastEvidence(ev)
   435  }
   436  
   437  func (c *Client) Subscribe(ctx context.Context, subscriber, query string,
   438  	outCapacity ...int) (out <-chan ctypes.ResultEvent, err error) {
   439  	return c.next.Subscribe(ctx, subscriber, query, outCapacity...)
   440  }
   441  
   442  func (c *Client) Unsubscribe(ctx context.Context, subscriber, query string) error {
   443  	return c.next.Unsubscribe(ctx, subscriber, query)
   444  }
   445  
   446  func (c *Client) UnsubscribeAll(ctx context.Context, subscriber string) error {
   447  	return c.next.UnsubscribeAll(ctx, subscriber)
   448  }
   449  
   450  func (c *Client) updateLiteClientIfNeededTo(height int64) (*types.SignedHeader, error) {
   451  	h, err := c.lc.VerifyHeaderAtHeight(height, time.Now())
   452  	if err != nil {
   453  		return nil, fmt.Errorf("failed to update light client to %d: %w", height, err)
   454  	}
   455  	return h, nil
   456  }
   457  
   458  func (c *Client) RegisterOpDecoder(typ string, dec merkle.OpDecoder) {
   459  	c.prt.RegisterOpDecoder(typ, dec)
   460  }
   461  
   462  // SubscribeWS subscribes for events using the given query and remote address as
   463  // a subscriber, but does not verify responses (UNSAFE)!
   464  // TODO: verify data
   465  func (c *Client) SubscribeWS(ctx *rpctypes.Context, query string) (*ctypes.ResultSubscribe, error) {
   466  	out, err := c.next.Subscribe(context.Background(), ctx.RemoteAddr(), query)
   467  	if err != nil {
   468  		return nil, err
   469  	}
   470  
   471  	go func() {
   472  		for {
   473  			select {
   474  			case resultEvent := <-out:
   475  				// We should have a switch here that performs a validation
   476  				// depending on the event's type.
   477  				ctx.WSConn.TryWriteRPCResponse(
   478  					rpctypes.NewRPCSuccessResponse(
   479  						ctx.WSConn.Codec(),
   480  						rpctypes.JSONRPCStringID(fmt.Sprintf("%v#event", ctx.JSONReq.ID)),
   481  						resultEvent,
   482  					))
   483  			case <-c.Quit():
   484  				return
   485  			}
   486  		}
   487  	}()
   488  
   489  	return &ctypes.ResultSubscribe{}, nil
   490  }
   491  
   492  // UnsubscribeWS calls original client's Unsubscribe using remote address as a
   493  // subscriber.
   494  func (c *Client) UnsubscribeWS(ctx *rpctypes.Context, query string) (*ctypes.ResultUnsubscribe, error) {
   495  	err := c.next.Unsubscribe(context.Background(), ctx.RemoteAddr(), query)
   496  	if err != nil {
   497  		return nil, err
   498  	}
   499  	return &ctypes.ResultUnsubscribe{}, nil
   500  }
   501  
   502  // UnsubscribeAllWS calls original client's UnsubscribeAll using remote address
   503  // as a subscriber.
   504  func (c *Client) UnsubscribeAllWS(ctx *rpctypes.Context) (*ctypes.ResultUnsubscribe, error) {
   505  	err := c.next.UnsubscribeAll(context.Background(), ctx.RemoteAddr())
   506  	if err != nil {
   507  		return nil, err
   508  	}
   509  	return &ctypes.ResultUnsubscribe{}, nil
   510  }
   511  
   512  func parseQueryStorePath(path string) (storeName string, err error) {
   513  	if !strings.HasPrefix(path, "/") {
   514  		return "", errors.New("expected path to start with /")
   515  	}
   516  
   517  	paths := strings.SplitN(path[1:], "/", 3)
   518  	switch {
   519  	case len(paths) != 3:
   520  		return "", errors.New("expected format like /store/<storeName>/key")
   521  	case paths[0] != "store":
   522  		return "", errors.New("expected format like /store/<storeName>/key")
   523  	case paths[2] != "key":
   524  		return "", errors.New("expected format like /store/<storeName>/key")
   525  	}
   526  
   527  	return paths[1], nil
   528  }