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