github.com/lazyledger/lazyledger-core@v0.35.0-dev.0.20210613111200-4c651f053571/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/lazyledger/lazyledger-core/libs/bytes" 11 tmjson "github.com/lazyledger/lazyledger-core/libs/json" 12 "github.com/lazyledger/lazyledger-core/libs/log" 13 tmpubsub "github.com/lazyledger/lazyledger-core/libs/pubsub" 14 "github.com/lazyledger/lazyledger-core/libs/service" 15 tmsync "github.com/lazyledger/lazyledger-core/libs/sync" 16 rpcclient "github.com/lazyledger/lazyledger-core/rpc/client" 17 ctypes "github.com/lazyledger/lazyledger-core/rpc/core/types" 18 jsonrpcclient "github.com/lazyledger/lazyledger-core/rpc/jsonrpc/client" 19 "github.com/lazyledger/lazyledger-core/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 // NewWithTimeout does the same thing as New, except you can set a Timeout for 120 // http.Client. A Timeout of zero means no timeout. 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 142 wsEvents, err := newWSEvents(remote, wsEndpoint) 143 if err != nil { 144 return nil, err 145 } 146 147 httpClient := &HTTP{ 148 rpc: rc, 149 remote: remote, 150 baseRPCClient: &baseRPCClient{caller: rc}, 151 WSEvents: wsEvents, 152 } 153 154 return httpClient, nil 155 } 156 157 var _ rpcclient.Client = (*HTTP)(nil) 158 159 // SetLogger sets a logger. 160 func (c *HTTP) SetLogger(l log.Logger) { 161 c.WSEvents.SetLogger(l) 162 } 163 164 // Remote returns the remote network address in a string form. 165 func (c *HTTP) Remote() string { 166 return c.remote 167 } 168 169 // NewBatch creates a new batch client for this HTTP client. 170 func (c *HTTP) NewBatch() *BatchHTTP { 171 rpcBatch := c.rpc.NewRequestBatch() 172 return &BatchHTTP{ 173 rpcBatch: rpcBatch, 174 baseRPCClient: &baseRPCClient{ 175 caller: rpcBatch, 176 }, 177 } 178 } 179 180 //----------------------------------------------------------------------------- 181 // BatchHTTP 182 183 // Send is a convenience function for an HTTP batch that will trigger the 184 // compilation of the batched requests and send them off using the client as a 185 // single request. On success, this returns a list of the deserialized results 186 // from each request in the sent batch. 187 func (b *BatchHTTP) Send(ctx context.Context) ([]interface{}, error) { 188 return b.rpcBatch.Send(ctx) 189 } 190 191 // Clear will empty out this batch of requests and return the number of requests 192 // that were cleared out. 193 func (b *BatchHTTP) Clear() int { 194 return b.rpcBatch.Clear() 195 } 196 197 // Count returns the number of enqueued requests waiting to be sent. 198 func (b *BatchHTTP) Count() int { 199 return b.rpcBatch.Count() 200 } 201 202 //----------------------------------------------------------------------------- 203 // baseRPCClient 204 205 func (c *baseRPCClient) Status(ctx context.Context) (*ctypes.ResultStatus, error) { 206 result := new(ctypes.ResultStatus) 207 _, err := c.caller.Call(ctx, "status", map[string]interface{}{}, result) 208 if err != nil { 209 return nil, err 210 } 211 212 return result, nil 213 } 214 215 func (c *baseRPCClient) ABCIInfo(ctx context.Context) (*ctypes.ResultABCIInfo, error) { 216 result := new(ctypes.ResultABCIInfo) 217 _, err := c.caller.Call(ctx, "abci_info", map[string]interface{}{}, result) 218 if err != nil { 219 return nil, err 220 } 221 222 return result, nil 223 } 224 225 func (c *baseRPCClient) ABCIQuery( 226 ctx context.Context, 227 path string, 228 data bytes.HexBytes, 229 ) (*ctypes.ResultABCIQuery, error) { 230 return c.ABCIQueryWithOptions(ctx, path, data, rpcclient.DefaultABCIQueryOptions) 231 } 232 233 func (c *baseRPCClient) ABCIQueryWithOptions( 234 ctx context.Context, 235 path string, 236 data bytes.HexBytes, 237 opts rpcclient.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) { 238 result := new(ctypes.ResultABCIQuery) 239 _, err := c.caller.Call(ctx, "abci_query", 240 map[string]interface{}{"path": path, "data": data, "height": opts.Height, "prove": opts.Prove}, 241 result) 242 if err != nil { 243 return nil, err 244 } 245 246 return result, nil 247 } 248 249 func (c *baseRPCClient) BroadcastTxCommit( 250 ctx context.Context, 251 tx types.Tx, 252 ) (*ctypes.ResultBroadcastTxCommit, error) { 253 result := new(ctypes.ResultBroadcastTxCommit) 254 _, err := c.caller.Call(ctx, "broadcast_tx_commit", map[string]interface{}{"tx": tx}, result) 255 if err != nil { 256 return nil, err 257 } 258 return result, nil 259 } 260 261 func (c *baseRPCClient) BroadcastTxAsync( 262 ctx context.Context, 263 tx types.Tx, 264 ) (*ctypes.ResultBroadcastTx, error) { 265 return c.broadcastTX(ctx, "broadcast_tx_async", tx) 266 } 267 268 func (c *baseRPCClient) BroadcastTxSync( 269 ctx context.Context, 270 tx types.Tx, 271 ) (*ctypes.ResultBroadcastTx, error) { 272 return c.broadcastTX(ctx, "broadcast_tx_sync", tx) 273 } 274 275 func (c *baseRPCClient) broadcastTX( 276 ctx context.Context, 277 route string, 278 tx types.Tx, 279 ) (*ctypes.ResultBroadcastTx, error) { 280 result := new(ctypes.ResultBroadcastTx) 281 _, err := c.caller.Call(ctx, route, map[string]interface{}{"tx": tx}, result) 282 if err != nil { 283 return nil, err 284 } 285 return result, nil 286 } 287 288 func (c *baseRPCClient) UnconfirmedTxs( 289 ctx context.Context, 290 limit *int, 291 ) (*ctypes.ResultUnconfirmedTxs, error) { 292 result := new(ctypes.ResultUnconfirmedTxs) 293 params := make(map[string]interface{}) 294 if limit != nil { 295 params["limit"] = limit 296 } 297 _, err := c.caller.Call(ctx, "unconfirmed_txs", params, result) 298 if err != nil { 299 return nil, err 300 } 301 return result, nil 302 } 303 304 func (c *baseRPCClient) NumUnconfirmedTxs(ctx context.Context) (*ctypes.ResultUnconfirmedTxs, error) { 305 result := new(ctypes.ResultUnconfirmedTxs) 306 _, err := c.caller.Call(ctx, "num_unconfirmed_txs", map[string]interface{}{}, result) 307 if err != nil { 308 return nil, err 309 } 310 return result, nil 311 } 312 313 func (c *baseRPCClient) CheckTx(ctx context.Context, tx types.Tx) (*ctypes.ResultCheckTx, error) { 314 result := new(ctypes.ResultCheckTx) 315 _, err := c.caller.Call(ctx, "check_tx", map[string]interface{}{"tx": tx}, result) 316 if err != nil { 317 return nil, err 318 } 319 return result, nil 320 } 321 322 func (c *baseRPCClient) NetInfo(ctx context.Context) (*ctypes.ResultNetInfo, error) { 323 result := new(ctypes.ResultNetInfo) 324 _, err := c.caller.Call(ctx, "net_info", map[string]interface{}{}, result) 325 if err != nil { 326 return nil, err 327 } 328 return result, nil 329 } 330 331 func (c *baseRPCClient) DumpConsensusState(ctx context.Context) (*ctypes.ResultDumpConsensusState, error) { 332 result := new(ctypes.ResultDumpConsensusState) 333 _, err := c.caller.Call(ctx, "dump_consensus_state", map[string]interface{}{}, result) 334 if err != nil { 335 return nil, err 336 } 337 return result, nil 338 } 339 340 func (c *baseRPCClient) ConsensusState(ctx context.Context) (*ctypes.ResultConsensusState, error) { 341 result := new(ctypes.ResultConsensusState) 342 _, err := c.caller.Call(ctx, "consensus_state", map[string]interface{}{}, result) 343 if err != nil { 344 return nil, err 345 } 346 return result, nil 347 } 348 349 func (c *baseRPCClient) ConsensusParams( 350 ctx context.Context, 351 height *int64, 352 ) (*ctypes.ResultConsensusParams, error) { 353 result := new(ctypes.ResultConsensusParams) 354 params := make(map[string]interface{}) 355 if height != nil { 356 params["height"] = height 357 } 358 _, err := c.caller.Call(ctx, "consensus_params", params, result) 359 if err != nil { 360 return nil, err 361 } 362 return result, nil 363 } 364 365 func (c *baseRPCClient) Health(ctx context.Context) (*ctypes.ResultHealth, error) { 366 result := new(ctypes.ResultHealth) 367 _, err := c.caller.Call(ctx, "health", map[string]interface{}{}, result) 368 if err != nil { 369 return nil, err 370 } 371 return result, nil 372 } 373 374 func (c *baseRPCClient) BlockchainInfo( 375 ctx context.Context, 376 minHeight, 377 maxHeight int64, 378 ) (*ctypes.ResultBlockchainInfo, error) { 379 result := new(ctypes.ResultBlockchainInfo) 380 _, err := c.caller.Call(ctx, "blockchain", 381 map[string]interface{}{"minHeight": minHeight, "maxHeight": maxHeight}, 382 result) 383 if err != nil { 384 return nil, err 385 } 386 return result, nil 387 } 388 389 func (c *baseRPCClient) Genesis(ctx context.Context) (*ctypes.ResultGenesis, error) { 390 result := new(ctypes.ResultGenesis) 391 _, err := c.caller.Call(ctx, "genesis", map[string]interface{}{}, result) 392 if err != nil { 393 return nil, err 394 } 395 return result, nil 396 } 397 398 func (c *baseRPCClient) Block(ctx context.Context, height *int64) (*ctypes.ResultBlock, error) { 399 result := new(ctypes.ResultBlock) 400 params := make(map[string]interface{}) 401 if height != nil { 402 params["height"] = height 403 } 404 _, err := c.caller.Call(ctx, "block", params, result) 405 if err != nil { 406 return nil, err 407 } 408 return result, nil 409 } 410 411 func (c *baseRPCClient) BlockByHash(ctx context.Context, hash []byte) (*ctypes.ResultBlock, error) { 412 result := new(ctypes.ResultBlock) 413 params := map[string]interface{}{ 414 "hash": hash, 415 } 416 _, err := c.caller.Call(ctx, "block_by_hash", params, result) 417 if err != nil { 418 return nil, err 419 } 420 return result, nil 421 } 422 423 func (c *baseRPCClient) BlockResults( 424 ctx context.Context, 425 height *int64, 426 ) (*ctypes.ResultBlockResults, error) { 427 result := new(ctypes.ResultBlockResults) 428 params := make(map[string]interface{}) 429 if height != nil { 430 params["height"] = height 431 } 432 _, err := c.caller.Call(ctx, "block_results", params, result) 433 if err != nil { 434 return nil, err 435 } 436 return result, nil 437 } 438 439 func (c *baseRPCClient) Commit(ctx context.Context, height *int64) (*ctypes.ResultCommit, error) { 440 result := new(ctypes.ResultCommit) 441 params := make(map[string]interface{}) 442 if height != nil { 443 params["height"] = height 444 } 445 _, err := c.caller.Call(ctx, "commit", params, result) 446 if err != nil { 447 return nil, err 448 } 449 return result, nil 450 } 451 452 func (c *baseRPCClient) DataAvailabilityHeader( 453 ctx context.Context, 454 height *int64, 455 ) (*ctypes.ResultDataAvailabilityHeader, error) { 456 result := new(ctypes.ResultDataAvailabilityHeader) 457 params := make(map[string]interface{}) 458 if height != nil { 459 params["height"] = height 460 } 461 _, err := c.caller.Call(ctx, "data_availability_header", params, result) 462 if err != nil { 463 return nil, err 464 } 465 return result, nil 466 } 467 468 func (c *baseRPCClient) Tx(ctx context.Context, hash []byte, prove bool) (*ctypes.ResultTx, error) { 469 result := new(ctypes.ResultTx) 470 params := map[string]interface{}{ 471 "hash": hash, 472 "prove": prove, 473 } 474 _, err := c.caller.Call(ctx, "tx", params, result) 475 if err != nil { 476 return nil, err 477 } 478 return result, nil 479 } 480 481 func (c *baseRPCClient) TxSearch( 482 ctx context.Context, 483 query string, 484 prove bool, 485 page, 486 perPage *int, 487 orderBy string, 488 ) ( 489 *ctypes.ResultTxSearch, error) { 490 result := new(ctypes.ResultTxSearch) 491 params := map[string]interface{}{ 492 "query": query, 493 "prove": prove, 494 "order_by": orderBy, 495 } 496 if page != nil { 497 params["page"] = page 498 } 499 if perPage != nil { 500 params["per_page"] = perPage 501 } 502 _, err := c.caller.Call(ctx, "tx_search", params, result) 503 if err != nil { 504 return nil, err 505 } 506 return result, nil 507 } 508 509 func (c *baseRPCClient) Validators( 510 ctx context.Context, 511 height *int64, 512 page, 513 perPage *int, 514 ) (*ctypes.ResultValidators, error) { 515 result := new(ctypes.ResultValidators) 516 params := make(map[string]interface{}) 517 if page != nil { 518 params["page"] = page 519 } 520 if perPage != nil { 521 params["per_page"] = perPage 522 } 523 if height != nil { 524 params["height"] = height 525 } 526 _, err := c.caller.Call(ctx, "validators", params, result) 527 if err != nil { 528 return nil, err 529 } 530 return result, nil 531 } 532 533 func (c *baseRPCClient) BroadcastEvidence( 534 ctx context.Context, 535 ev types.Evidence, 536 ) (*ctypes.ResultBroadcastEvidence, error) { 537 result := new(ctypes.ResultBroadcastEvidence) 538 _, err := c.caller.Call(ctx, "broadcast_evidence", map[string]interface{}{"evidence": ev}, result) 539 if err != nil { 540 return nil, err 541 } 542 return result, nil 543 } 544 545 //----------------------------------------------------------------------------- 546 // WSEvents 547 548 var errNotRunning = errors.New("client is not running. Use .Start() method to start") 549 550 // WSEvents is a wrapper around WSClient, which implements EventsClient. 551 type WSEvents struct { 552 service.BaseService 553 remote string 554 endpoint string 555 ws *jsonrpcclient.WSClient 556 557 mtx tmsync.RWMutex 558 subscriptions map[string]chan ctypes.ResultEvent // query -> chan 559 } 560 561 func newWSEvents(remote, endpoint string) (*WSEvents, error) { 562 w := &WSEvents{ 563 endpoint: endpoint, 564 remote: remote, 565 subscriptions: make(map[string]chan ctypes.ResultEvent), 566 } 567 w.BaseService = *service.NewBaseService(nil, "WSEvents", w) 568 569 var err error 570 w.ws, err = jsonrpcclient.NewWS(w.remote, w.endpoint, jsonrpcclient.OnReconnect(func() { 571 // resubscribe immediately 572 w.redoSubscriptionsAfter(0 * time.Second) 573 })) 574 if err != nil { 575 return nil, err 576 } 577 w.ws.SetLogger(w.Logger) 578 579 return w, nil 580 } 581 582 // OnStart implements service.Service by starting WSClient and event loop. 583 func (w *WSEvents) OnStart() error { 584 if err := w.ws.Start(); err != nil { 585 return err 586 } 587 588 go w.eventListener() 589 590 return nil 591 } 592 593 // OnStop implements service.Service by stopping WSClient. 594 func (w *WSEvents) OnStop() { 595 if err := w.ws.Stop(); err != nil { 596 w.Logger.Error("Can't stop ws client", "err", err) 597 } 598 } 599 600 // Subscribe implements EventsClient by using WSClient to subscribe given 601 // subscriber to query. By default, returns a channel with cap=1. Error is 602 // returned if it fails to subscribe. 603 // 604 // Channel is never closed to prevent clients from seeing an erroneous event. 605 // 606 // It returns an error if WSEvents is not running. 607 func (w *WSEvents) Subscribe(ctx context.Context, subscriber, query string, 608 outCapacity ...int) (out <-chan ctypes.ResultEvent, err error) { 609 610 if !w.IsRunning() { 611 return nil, errNotRunning 612 } 613 614 if err := w.ws.Subscribe(ctx, query); err != nil { 615 return nil, err 616 } 617 618 outCap := 1 619 if len(outCapacity) > 0 { 620 outCap = outCapacity[0] 621 } 622 623 outc := make(chan ctypes.ResultEvent, outCap) 624 w.mtx.Lock() 625 // subscriber param is ignored because Tendermint will override it with 626 // remote IP anyway. 627 w.subscriptions[query] = outc 628 w.mtx.Unlock() 629 630 return outc, nil 631 } 632 633 // Unsubscribe implements EventsClient by using WSClient to unsubscribe given 634 // subscriber from query. 635 // 636 // It returns an error if WSEvents is not running. 637 func (w *WSEvents) Unsubscribe(ctx context.Context, subscriber, query string) error { 638 if !w.IsRunning() { 639 return errNotRunning 640 } 641 642 if err := w.ws.Unsubscribe(ctx, query); err != nil { 643 return err 644 } 645 646 w.mtx.Lock() 647 _, ok := w.subscriptions[query] 648 if ok { 649 delete(w.subscriptions, query) 650 } 651 w.mtx.Unlock() 652 653 return nil 654 } 655 656 // UnsubscribeAll implements EventsClient by using WSClient to unsubscribe 657 // given subscriber from all the queries. 658 // 659 // It returns an error if WSEvents is not running. 660 func (w *WSEvents) UnsubscribeAll(ctx context.Context, subscriber string) error { 661 if !w.IsRunning() { 662 return errNotRunning 663 } 664 665 if err := w.ws.UnsubscribeAll(ctx); err != nil { 666 return err 667 } 668 669 w.mtx.Lock() 670 w.subscriptions = make(map[string]chan ctypes.ResultEvent) 671 w.mtx.Unlock() 672 673 return nil 674 } 675 676 // After being reconnected, it is necessary to redo subscription to server 677 // otherwise no data will be automatically received. 678 func (w *WSEvents) redoSubscriptionsAfter(d time.Duration) { 679 time.Sleep(d) 680 681 w.mtx.RLock() 682 defer w.mtx.RUnlock() 683 for q := range w.subscriptions { 684 err := w.ws.Subscribe(context.Background(), q) 685 if err != nil { 686 w.Logger.Error("Failed to resubscribe", "err", err) 687 } 688 } 689 } 690 691 func isErrAlreadySubscribed(err error) bool { 692 return strings.Contains(err.Error(), tmpubsub.ErrAlreadySubscribed.Error()) 693 } 694 695 func (w *WSEvents) eventListener() { 696 for { 697 select { 698 case resp, ok := <-w.ws.ResponsesCh: 699 if !ok { 700 return 701 } 702 703 if resp.Error != nil { 704 w.Logger.Error("WS error", "err", resp.Error.Error()) 705 // Error can be ErrAlreadySubscribed or max client (subscriptions per 706 // client) reached or Tendermint exited. 707 // We can ignore ErrAlreadySubscribed, but need to retry in other 708 // cases. 709 if !isErrAlreadySubscribed(resp.Error) { 710 // Resubscribe after 1 second to give Tendermint time to restart (if 711 // crashed). 712 w.redoSubscriptionsAfter(1 * time.Second) 713 } 714 continue 715 } 716 717 result := new(ctypes.ResultEvent) 718 err := tmjson.Unmarshal(resp.Result, result) 719 if err != nil { 720 w.Logger.Error("failed to unmarshal response", "err", err) 721 continue 722 } 723 724 w.mtx.RLock() 725 if out, ok := w.subscriptions[result.Query]; ok { 726 if cap(out) == 0 { 727 out <- *result 728 } else { 729 select { 730 case out <- *result: 731 default: 732 w.Logger.Error("wanted to publish ResultEvent, but out channel is full", "result", result, "query", result.Query) 733 } 734 } 735 } 736 w.mtx.RUnlock() 737 case <-w.Quit(): 738 return 739 } 740 } 741 }