github.com/franono/tendermint@v0.32.2-0.20200527150959-749313264ce9/rpc/client/http/http.go (about)

     1  package http
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"net/http"
     7  	"strings"
     8  	"sync"
     9  	"time"
    10  
    11  	amino "github.com/tendermint/go-amino"
    12  
    13  	"github.com/franono/tendermint/libs/bytes"
    14  	"github.com/franono/tendermint/libs/log"
    15  	tmpubsub "github.com/franono/tendermint/libs/pubsub"
    16  	"github.com/franono/tendermint/libs/service"
    17  	rpcclient "github.com/franono/tendermint/rpc/client"
    18  	ctypes "github.com/franono/tendermint/rpc/core/types"
    19  	jsonrpcclient "github.com/franono/tendermint/rpc/jsonrpc/client"
    20  	"github.com/franono/tendermint/types"
    21  )
    22  
    23  /*
    24  HTTP is a Client implementation that communicates with a Tendermint node over
    25  JSON RPC and WebSockets.
    26  
    27  This is the main implementation you probably want to use in production code.
    28  There are other implementations when calling the Tendermint node in-process
    29  (Local), or when you want to mock out the server for test code (mock).
    30  
    31  You can subscribe for any event published by Tendermint using Subscribe method.
    32  Note delivery is best-effort. If you don't read events fast enough or network is
    33  slow, Tendermint might cancel the subscription. The client will attempt to
    34  resubscribe (you don't need to do anything). It will keep trying every second
    35  indefinitely until successful.
    36  
    37  Request batching is available for JSON RPC requests over HTTP, which conforms to
    38  the JSON RPC specification (https://www.jsonrpc.org/specification#batch). See
    39  the example for more details.
    40  
    41  Example:
    42  
    43  		c, err := New("http://192.168.1.10:26657", "/websocket")
    44  		if err != nil {
    45  			// handle error
    46  		}
    47  
    48  		// call Start/Stop if you're subscribing to events
    49  		err = c.Start()
    50  		if err != nil {
    51  			// handle error
    52  		}
    53  		defer c.Stop()
    54  
    55  		res, err := c.Status()
    56  		if err != nil {
    57  			// handle error
    58  		}
    59  
    60  		// handle result
    61  */
    62  type HTTP struct {
    63  	remote string
    64  	rpc    *jsonrpcclient.Client
    65  
    66  	*baseRPCClient
    67  	*WSEvents
    68  }
    69  
    70  // BatchHTTP provides the same interface as `HTTP`, but allows for batching of
    71  // requests (as per https://www.jsonrpc.org/specification#batch). Do not
    72  // instantiate directly - rather use the HTTP.NewBatch() method to create an
    73  // instance of this struct.
    74  //
    75  // Batching of HTTP requests is thread-safe in the sense that multiple
    76  // goroutines can each create their own batches and send them using the same
    77  // HTTP client. Multiple goroutines could also enqueue transactions in a single
    78  // batch, but ordering of transactions in the batch cannot be guaranteed in such
    79  // an example.
    80  type BatchHTTP struct {
    81  	rpcBatch *jsonrpcclient.RequestBatch
    82  	*baseRPCClient
    83  }
    84  
    85  // rpcClient is an internal interface to which our RPC clients (batch and
    86  // non-batch) must conform. Acts as an additional code-level sanity check to
    87  // make sure the implementations stay coherent.
    88  type rpcClient interface {
    89  	rpcclient.ABCIClient
    90  	rpcclient.HistoryClient
    91  	rpcclient.NetworkClient
    92  	rpcclient.SignClient
    93  	rpcclient.StatusClient
    94  }
    95  
    96  // baseRPCClient implements the basic RPC method logic without the actual
    97  // underlying RPC call functionality, which is provided by `caller`.
    98  type baseRPCClient struct {
    99  	caller jsonrpcclient.Caller
   100  }
   101  
   102  var _ rpcClient = (*HTTP)(nil)
   103  var _ rpcClient = (*BatchHTTP)(nil)
   104  var _ rpcClient = (*baseRPCClient)(nil)
   105  
   106  //-----------------------------------------------------------------------------
   107  // HTTP
   108  
   109  // New takes a remote endpoint in the form <protocol>://<host>:<port> and
   110  // the websocket path (which always seems to be "/websocket")
   111  // An error is returned on invalid remote. The function panics when remote is nil.
   112  func New(remote, wsEndpoint string) (*HTTP, error) {
   113  	httpClient, err := jsonrpcclient.DefaultHTTPClient(remote)
   114  	if err != nil {
   115  		return nil, err
   116  	}
   117  	return NewWithClient(remote, wsEndpoint, httpClient)
   118  }
   119  
   120  // Create timeout enabled http client
   121  func NewWithTimeout(remote, wsEndpoint string, timeout uint) (*HTTP, error) {
   122  	httpClient, err := jsonrpcclient.DefaultHTTPClient(remote)
   123  	if err != nil {
   124  		return nil, err
   125  	}
   126  	httpClient.Timeout = time.Duration(timeout) * time.Second
   127  	return NewWithClient(remote, wsEndpoint, httpClient)
   128  }
   129  
   130  // NewWithClient allows for setting a custom http client (See New).
   131  // An error is returned on invalid remote. The function panics when remote is nil.
   132  func NewWithClient(remote, wsEndpoint string, client *http.Client) (*HTTP, error) {
   133  	if client == nil {
   134  		panic("nil http.Client provided")
   135  	}
   136  
   137  	rc, err := jsonrpcclient.NewWithHTTPClient(remote, client)
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  	cdc := rc.Codec()
   142  	ctypes.RegisterAmino(cdc)
   143  	rc.SetCodec(cdc)
   144  
   145  	wsEvents, err := newWSEvents(cdc, remote, wsEndpoint)
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  
   150  	httpClient := &HTTP{
   151  		rpc:           rc,
   152  		remote:        remote,
   153  		baseRPCClient: &baseRPCClient{caller: rc},
   154  		WSEvents:      wsEvents,
   155  	}
   156  
   157  	return httpClient, nil
   158  }
   159  
   160  var _ rpcclient.Client = (*HTTP)(nil)
   161  
   162  // SetLogger sets a logger.
   163  func (c *HTTP) SetLogger(l log.Logger) {
   164  	c.WSEvents.SetLogger(l)
   165  }
   166  
   167  // Remote returns the remote network address in a string form.
   168  func (c *HTTP) Remote() string {
   169  	return c.remote
   170  }
   171  
   172  // NewBatch creates a new batch client for this HTTP client.
   173  func (c *HTTP) NewBatch() *BatchHTTP {
   174  	rpcBatch := c.rpc.NewRequestBatch()
   175  	return &BatchHTTP{
   176  		rpcBatch: rpcBatch,
   177  		baseRPCClient: &baseRPCClient{
   178  			caller: rpcBatch,
   179  		},
   180  	}
   181  }
   182  
   183  //-----------------------------------------------------------------------------
   184  // BatchHTTP
   185  
   186  // Send is a convenience function for an HTTP batch that will trigger the
   187  // compilation of the batched requests and send them off using the client as a
   188  // single request. On success, this returns a list of the deserialized results
   189  // from each request in the sent batch.
   190  func (b *BatchHTTP) Send() ([]interface{}, error) {
   191  	return b.rpcBatch.Send()
   192  }
   193  
   194  // Clear will empty out this batch of requests and return the number of requests
   195  // that were cleared out.
   196  func (b *BatchHTTP) Clear() int {
   197  	return b.rpcBatch.Clear()
   198  }
   199  
   200  // Count returns the number of enqueued requests waiting to be sent.
   201  func (b *BatchHTTP) Count() int {
   202  	return b.rpcBatch.Count()
   203  }
   204  
   205  //-----------------------------------------------------------------------------
   206  // baseRPCClient
   207  
   208  func (c *baseRPCClient) Status() (*ctypes.ResultStatus, error) {
   209  	result := new(ctypes.ResultStatus)
   210  	_, err := c.caller.Call("status", map[string]interface{}{}, result)
   211  	if err != nil {
   212  		return nil, err
   213  	}
   214  	return result, nil
   215  }
   216  
   217  func (c *baseRPCClient) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
   218  	result := new(ctypes.ResultABCIInfo)
   219  	_, err := c.caller.Call("abci_info", map[string]interface{}{}, result)
   220  	if err != nil {
   221  		return nil, err
   222  	}
   223  	return result, nil
   224  }
   225  
   226  func (c *baseRPCClient) ABCIQuery(path string, data bytes.HexBytes) (*ctypes.ResultABCIQuery, error) {
   227  	return c.ABCIQueryWithOptions(path, data, rpcclient.DefaultABCIQueryOptions)
   228  }
   229  
   230  func (c *baseRPCClient) ABCIQueryWithOptions(
   231  	path string,
   232  	data bytes.HexBytes,
   233  	opts rpcclient.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
   234  	result := new(ctypes.ResultABCIQuery)
   235  	_, err := c.caller.Call("abci_query",
   236  		map[string]interface{}{"path": path, "data": data, "height": opts.Height, "prove": opts.Prove},
   237  		result)
   238  	if err != nil {
   239  		return nil, err
   240  	}
   241  	return result, nil
   242  }
   243  
   244  func (c *baseRPCClient) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
   245  	result := new(ctypes.ResultBroadcastTxCommit)
   246  	_, err := c.caller.Call("broadcast_tx_commit", map[string]interface{}{"tx": tx}, result)
   247  	if err != nil {
   248  		return nil, err
   249  	}
   250  	return result, nil
   251  }
   252  
   253  func (c *baseRPCClient) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
   254  	return c.broadcastTX("broadcast_tx_async", tx)
   255  }
   256  
   257  func (c *baseRPCClient) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
   258  	return c.broadcastTX("broadcast_tx_sync", tx)
   259  }
   260  
   261  func (c *baseRPCClient) broadcastTX(route string, tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
   262  	result := new(ctypes.ResultBroadcastTx)
   263  	_, err := c.caller.Call(route, map[string]interface{}{"tx": tx}, result)
   264  	if err != nil {
   265  		return nil, err
   266  	}
   267  	return result, nil
   268  }
   269  
   270  func (c *baseRPCClient) UnconfirmedTxs(limit int) (*ctypes.ResultUnconfirmedTxs, error) {
   271  	result := new(ctypes.ResultUnconfirmedTxs)
   272  	_, err := c.caller.Call("unconfirmed_txs", map[string]interface{}{"limit": limit}, result)
   273  	if err != nil {
   274  		return nil, err
   275  	}
   276  	return result, nil
   277  }
   278  
   279  func (c *baseRPCClient) NumUnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error) {
   280  	result := new(ctypes.ResultUnconfirmedTxs)
   281  	_, err := c.caller.Call("num_unconfirmed_txs", map[string]interface{}{}, result)
   282  	if err != nil {
   283  		return nil, err
   284  	}
   285  	return result, nil
   286  }
   287  
   288  func (c *baseRPCClient) NetInfo() (*ctypes.ResultNetInfo, error) {
   289  	result := new(ctypes.ResultNetInfo)
   290  	_, err := c.caller.Call("net_info", map[string]interface{}{}, result)
   291  	if err != nil {
   292  		return nil, err
   293  	}
   294  	return result, nil
   295  }
   296  
   297  func (c *baseRPCClient) DumpConsensusState() (*ctypes.ResultDumpConsensusState, error) {
   298  	result := new(ctypes.ResultDumpConsensusState)
   299  	_, err := c.caller.Call("dump_consensus_state", map[string]interface{}{}, result)
   300  	if err != nil {
   301  		return nil, err
   302  	}
   303  	return result, nil
   304  }
   305  
   306  func (c *baseRPCClient) ConsensusState() (*ctypes.ResultConsensusState, error) {
   307  	result := new(ctypes.ResultConsensusState)
   308  	_, err := c.caller.Call("consensus_state", map[string]interface{}{}, result)
   309  	if err != nil {
   310  		return nil, err
   311  	}
   312  	return result, nil
   313  }
   314  
   315  func (c *baseRPCClient) ConsensusParams(height *int64) (*ctypes.ResultConsensusParams, error) {
   316  	result := new(ctypes.ResultConsensusParams)
   317  	params := make(map[string]interface{})
   318  	if height != nil {
   319  		params["height"] = height
   320  	}
   321  	_, err := c.caller.Call("consensus_params", params, result)
   322  	if err != nil {
   323  		return nil, err
   324  	}
   325  	return result, nil
   326  }
   327  
   328  func (c *baseRPCClient) Health() (*ctypes.ResultHealth, error) {
   329  	result := new(ctypes.ResultHealth)
   330  	_, err := c.caller.Call("health", map[string]interface{}{}, result)
   331  	if err != nil {
   332  		return nil, err
   333  	}
   334  	return result, nil
   335  }
   336  
   337  func (c *baseRPCClient) BlockchainInfo(minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) {
   338  	result := new(ctypes.ResultBlockchainInfo)
   339  	_, err := c.caller.Call("blockchain",
   340  		map[string]interface{}{"minHeight": minHeight, "maxHeight": maxHeight},
   341  		result)
   342  	if err != nil {
   343  		return nil, err
   344  	}
   345  	return result, nil
   346  }
   347  
   348  func (c *baseRPCClient) Genesis() (*ctypes.ResultGenesis, error) {
   349  	result := new(ctypes.ResultGenesis)
   350  	_, err := c.caller.Call("genesis", map[string]interface{}{}, result)
   351  	if err != nil {
   352  		return nil, err
   353  	}
   354  	return result, nil
   355  }
   356  
   357  func (c *baseRPCClient) Block(height *int64) (*ctypes.ResultBlock, error) {
   358  	result := new(ctypes.ResultBlock)
   359  	params := make(map[string]interface{})
   360  	if height != nil {
   361  		params["height"] = height
   362  	}
   363  	_, err := c.caller.Call("block", params, result)
   364  	if err != nil {
   365  		return nil, err
   366  	}
   367  	return result, nil
   368  }
   369  
   370  func (c *baseRPCClient) BlockResults(height *int64) (*ctypes.ResultBlockResults, error) {
   371  	result := new(ctypes.ResultBlockResults)
   372  	params := make(map[string]interface{})
   373  	if height != nil {
   374  		params["height"] = height
   375  	}
   376  	_, err := c.caller.Call("block_results", params, result)
   377  	if err != nil {
   378  		return nil, err
   379  	}
   380  	return result, nil
   381  }
   382  
   383  func (c *baseRPCClient) Commit(height *int64) (*ctypes.ResultCommit, error) {
   384  	result := new(ctypes.ResultCommit)
   385  	params := make(map[string]interface{})
   386  	if height != nil {
   387  		params["height"] = height
   388  	}
   389  	_, err := c.caller.Call("commit", params, result)
   390  	if err != nil {
   391  		return nil, err
   392  	}
   393  	return result, nil
   394  }
   395  
   396  func (c *baseRPCClient) Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) {
   397  	result := new(ctypes.ResultTx)
   398  	params := map[string]interface{}{
   399  		"hash":  hash,
   400  		"prove": prove,
   401  	}
   402  	_, err := c.caller.Call("tx", params, result)
   403  	if err != nil {
   404  		return nil, err
   405  	}
   406  	return result, nil
   407  }
   408  
   409  func (c *baseRPCClient) TxSearch(query string, prove bool, page, perPage int, orderBy string) (
   410  	*ctypes.ResultTxSearch, error) {
   411  	result := new(ctypes.ResultTxSearch)
   412  	params := map[string]interface{}{
   413  		"query":    query,
   414  		"prove":    prove,
   415  		"page":     page,
   416  		"per_page": perPage,
   417  		"order_by": orderBy,
   418  	}
   419  	_, err := c.caller.Call("tx_search", params, result)
   420  	if err != nil {
   421  		return nil, err
   422  	}
   423  	return result, nil
   424  }
   425  
   426  func (c *baseRPCClient) Validators(height *int64, page, perPage int) (*ctypes.ResultValidators, error) {
   427  	result := new(ctypes.ResultValidators)
   428  	params := map[string]interface{}{
   429  		"page":     page,
   430  		"per_page": perPage,
   431  	}
   432  	if height != nil {
   433  		params["height"] = height
   434  	}
   435  	_, err := c.caller.Call("validators", params, result)
   436  	if err != nil {
   437  		return nil, err
   438  	}
   439  	return result, nil
   440  }
   441  
   442  func (c *baseRPCClient) BroadcastEvidence(ev types.Evidence) (*ctypes.ResultBroadcastEvidence, error) {
   443  	result := new(ctypes.ResultBroadcastEvidence)
   444  	_, err := c.caller.Call("broadcast_evidence", map[string]interface{}{"evidence": ev}, result)
   445  	if err != nil {
   446  		return nil, err
   447  	}
   448  	return result, nil
   449  }
   450  
   451  //-----------------------------------------------------------------------------
   452  // WSEvents
   453  
   454  var errNotRunning = errors.New("client is not running. Use .Start() method to start")
   455  
   456  // WSEvents is a wrapper around WSClient, which implements EventsClient.
   457  type WSEvents struct {
   458  	service.BaseService
   459  	cdc      *amino.Codec
   460  	remote   string
   461  	endpoint string
   462  	ws       *jsonrpcclient.WSClient
   463  
   464  	mtx           sync.RWMutex
   465  	subscriptions map[string]chan ctypes.ResultEvent // query -> chan
   466  }
   467  
   468  func newWSEvents(cdc *amino.Codec, remote, endpoint string) (*WSEvents, error) {
   469  	w := &WSEvents{
   470  		cdc:           cdc,
   471  		endpoint:      endpoint,
   472  		remote:        remote,
   473  		subscriptions: make(map[string]chan ctypes.ResultEvent),
   474  	}
   475  	w.BaseService = *service.NewBaseService(nil, "WSEvents", w)
   476  
   477  	var err error
   478  	w.ws, err = jsonrpcclient.NewWS(w.remote, w.endpoint, jsonrpcclient.OnReconnect(func() {
   479  		// resubscribe immediately
   480  		w.redoSubscriptionsAfter(0 * time.Second)
   481  	}))
   482  	if err != nil {
   483  		return nil, err
   484  	}
   485  	w.ws.SetCodec(w.cdc)
   486  	w.ws.SetLogger(w.Logger)
   487  
   488  	return w, nil
   489  }
   490  
   491  // OnStart implements service.Service by starting WSClient and event loop.
   492  func (w *WSEvents) OnStart() error {
   493  	if err := w.ws.Start(); err != nil {
   494  		return err
   495  	}
   496  
   497  	go w.eventListener()
   498  
   499  	return nil
   500  }
   501  
   502  // OnStop implements service.Service by stopping WSClient.
   503  func (w *WSEvents) OnStop() {
   504  	_ = w.ws.Stop()
   505  }
   506  
   507  // Subscribe implements EventsClient by using WSClient to subscribe given
   508  // subscriber to query. By default, returns a channel with cap=1. Error is
   509  // returned if it fails to subscribe.
   510  //
   511  // Channel is never closed to prevent clients from seeing an erroneous event.
   512  //
   513  // It returns an error if WSEvents is not running.
   514  func (w *WSEvents) Subscribe(ctx context.Context, subscriber, query string,
   515  	outCapacity ...int) (out <-chan ctypes.ResultEvent, err error) {
   516  
   517  	if !w.IsRunning() {
   518  		return nil, errNotRunning
   519  	}
   520  
   521  	if err := w.ws.Subscribe(ctx, query); err != nil {
   522  		return nil, err
   523  	}
   524  
   525  	outCap := 1
   526  	if len(outCapacity) > 0 {
   527  		outCap = outCapacity[0]
   528  	}
   529  
   530  	outc := make(chan ctypes.ResultEvent, outCap)
   531  	w.mtx.Lock()
   532  	// subscriber param is ignored because Tendermint will override it with
   533  	// remote IP anyway.
   534  	w.subscriptions[query] = outc
   535  	w.mtx.Unlock()
   536  
   537  	return outc, nil
   538  }
   539  
   540  // Unsubscribe implements EventsClient by using WSClient to unsubscribe given
   541  // subscriber from query.
   542  //
   543  // It returns an error if WSEvents is not running.
   544  func (w *WSEvents) Unsubscribe(ctx context.Context, subscriber, query string) error {
   545  	if !w.IsRunning() {
   546  		return errNotRunning
   547  	}
   548  
   549  	if err := w.ws.Unsubscribe(ctx, query); err != nil {
   550  		return err
   551  	}
   552  
   553  	w.mtx.Lock()
   554  	_, ok := w.subscriptions[query]
   555  	if ok {
   556  		delete(w.subscriptions, query)
   557  	}
   558  	w.mtx.Unlock()
   559  
   560  	return nil
   561  }
   562  
   563  // UnsubscribeAll implements EventsClient by using WSClient to unsubscribe
   564  // given subscriber from all the queries.
   565  //
   566  // It returns an error if WSEvents is not running.
   567  func (w *WSEvents) UnsubscribeAll(ctx context.Context, subscriber string) error {
   568  	if !w.IsRunning() {
   569  		return errNotRunning
   570  	}
   571  
   572  	if err := w.ws.UnsubscribeAll(ctx); err != nil {
   573  		return err
   574  	}
   575  
   576  	w.mtx.Lock()
   577  	w.subscriptions = make(map[string]chan ctypes.ResultEvent)
   578  	w.mtx.Unlock()
   579  
   580  	return nil
   581  }
   582  
   583  // After being reconnected, it is necessary to redo subscription to server
   584  // otherwise no data will be automatically received.
   585  func (w *WSEvents) redoSubscriptionsAfter(d time.Duration) {
   586  	time.Sleep(d)
   587  
   588  	w.mtx.RLock()
   589  	defer w.mtx.RUnlock()
   590  	for q := range w.subscriptions {
   591  		err := w.ws.Subscribe(context.Background(), q)
   592  		if err != nil {
   593  			w.Logger.Error("Failed to resubscribe", "err", err)
   594  		}
   595  	}
   596  }
   597  
   598  func isErrAlreadySubscribed(err error) bool {
   599  	return strings.Contains(err.Error(), tmpubsub.ErrAlreadySubscribed.Error())
   600  }
   601  
   602  func (w *WSEvents) eventListener() {
   603  	for {
   604  		select {
   605  		case resp, ok := <-w.ws.ResponsesCh:
   606  			if !ok {
   607  				return
   608  			}
   609  
   610  			if resp.Error != nil {
   611  				w.Logger.Error("WS error", "err", resp.Error.Error())
   612  				// Error can be ErrAlreadySubscribed or max client (subscriptions per
   613  				// client) reached or Tendermint exited.
   614  				// We can ignore ErrAlreadySubscribed, but need to retry in other
   615  				// cases.
   616  				if !isErrAlreadySubscribed(resp.Error) {
   617  					// Resubscribe after 1 second to give Tendermint time to restart (if
   618  					// crashed).
   619  					w.redoSubscriptionsAfter(1 * time.Second)
   620  				}
   621  				continue
   622  			}
   623  
   624  			result := new(ctypes.ResultEvent)
   625  			err := w.cdc.UnmarshalJSON(resp.Result, result)
   626  			if err != nil {
   627  				w.Logger.Error("failed to unmarshal response", "err", err)
   628  				continue
   629  			}
   630  
   631  			w.mtx.RLock()
   632  			if out, ok := w.subscriptions[result.Query]; ok {
   633  				if cap(out) == 0 {
   634  					out <- *result
   635  				} else {
   636  					select {
   637  					case out <- *result:
   638  					default:
   639  						w.Logger.Error("wanted to publish ResultEvent, but out channel is full", "result", result, "query", result.Query)
   640  					}
   641  				}
   642  			}
   643  			w.mtx.RUnlock()
   644  		case <-w.Quit():
   645  			return
   646  		}
   647  	}
   648  }