github.com/vipernet-xyz/tendermint-core@v0.32.0/lite2/rpc/client.go (about)

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