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 }