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