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