@ -18,27 +18,72 @@ import (
)
)
/ *
/ *
HTTP is a Client implementation that communicates with a t endermint node over
json rpc and webs ockets.
HTTP is a Client implementation that communicates with a T endermint node over
JSON RPC and WebS ockets.
This is the main implementation you probably want to use in production code .
This is the main implementation you probably want to use in production code .
There are other implementations when calling the t endermint node in - process
There are other implementations when calling the T endermint node in - process
( Local ) , or when you want to mock out the server for test code ( mock ) .
( Local ) , or when you want to mock out the server for test code ( mock ) .
You can subscribe for any event published by Tendermint using Subscribe method .
You can subscribe for any event published by Tendermint using Subscribe method .
Note delivery is best - effort . If you don ' t read events fast enough or network
is slow , Tendermint might cancel the subscription . The client will attempt to
Note delivery is best - effort . If you don ' t read events fast enough or network is
slow , Tendermint might cancel the subscription . The client will attempt to
resubscribe ( you don ' t need to do anything ) . It will keep trying every second
resubscribe ( you don ' t need to do anything ) . It will keep trying every second
indefinitely until successful .
indefinitely until successful .
Request batching is available for JSON RPC requests over HTTP , which conforms to
the JSON RPC specification ( https : //www.jsonrpc.org/specification#batch). See
the example for more details .
* /
* /
type HTTP struct {
type HTTP struct {
remote string
remote string
rpc * rpcclient . JSONRPCClient
rpc * rpcclient . JSONRPCClient
* baseRPCClient
* WSEvents
* WSEvents
}
}
// NewHTTP takes a remote endpoint in the form tcp://<host>:<port>
// and the websocket path (which always seems to be "/websocket")
// BatchHTTP provides the same interface as `HTTP`, but allows for batching of
// requests (as per https://www.jsonrpc.org/specification#batch). Do not
// instantiate directly - rather use the HTTP.NewBatch() method to create an
// instance of this struct.
//
// Batching of HTTP requests is thread-safe in the sense that multiple
// goroutines can each create their own batches and send them using the same
// HTTP client. Multiple goroutines could also enqueue transactions in a single
// batch, but ordering of transactions in the batch cannot be guaranteed in such
// an example.
type BatchHTTP struct {
rpcBatch * rpcclient . JSONRPCRequestBatch
* baseRPCClient
}
// rpcClient is an internal interface to which our RPC clients (batch and
// non-batch) must conform. Acts as an additional code-level sanity check to
// make sure the implementations stay coherent.
type rpcClient interface {
ABCIClient
HistoryClient
NetworkClient
SignClient
StatusClient
}
// baseRPCClient implements the basic RPC method logic without the actual
// underlying RPC call functionality, which is provided by `caller`.
type baseRPCClient struct {
caller rpcclient . JSONRPCCaller
}
var _ rpcClient = ( * HTTP ) ( nil )
var _ rpcClient = ( * BatchHTTP ) ( nil )
var _ rpcClient = ( * baseRPCClient ) ( nil )
//-----------------------------------------------------------------------------
// HTTP
// NewHTTP takes a remote endpoint in the form <protocol>://<host>:<port> and
// the websocket path (which always seems to be "/websocket")
func NewHTTP ( remote , wsEndpoint string ) * HTTP {
func NewHTTP ( remote , wsEndpoint string ) * HTTP {
rc := rpcclient . NewJSONRPCClient ( remote )
rc := rpcclient . NewJSONRPCClient ( remote )
cdc := rc . Codec ( )
cdc := rc . Codec ( )
@ -46,39 +91,76 @@ func NewHTTP(remote, wsEndpoint string) *HTTP {
rc . SetCodec ( cdc )
rc . SetCodec ( cdc )
return & HTTP {
return & HTTP {
rpc : rc ,
remote : remote ,
WSEvents : newWSEvents ( cdc , remote , wsEndpoint ) ,
rpc : rc ,
remote : remote ,
baseRPCClient : & baseRPCClient { caller : rc } ,
WSEvents : newWSEvents ( cdc , remote , wsEndpoint ) ,
}
}
}
}
var _ Client = ( * HTTP ) ( nil )
var _ Client = ( * HTTP ) ( nil )
func ( c * HTTP ) Status ( ) ( * ctypes . ResultStatus , error ) {
// NewBatch creates a new batch client for this HTTP client.
func ( c * HTTP ) NewBatch ( ) * BatchHTTP {
rpcBatch := c . rpc . NewRequestBatch ( )
return & BatchHTTP {
rpcBatch : rpcBatch ,
baseRPCClient : & baseRPCClient {
caller : rpcBatch ,
} ,
}
}
//-----------------------------------------------------------------------------
// BatchHTTP
// Send is a convenience function for an HTTP batch that will trigger the
// compilation of the batched requests and send them off using the client as a
// single request. On success, this returns a list of the deserialized results
// from each request in the sent batch.
func ( b * BatchHTTP ) Send ( ) ( [ ] interface { } , error ) {
return b . rpcBatch . Send ( )
}
// Clear will empty out this batch of requests and return the number of requests
// that were cleared out.
func ( b * BatchHTTP ) Clear ( ) int {
return b . rpcBatch . Clear ( )
}
// Count returns the number of enqueued requests waiting to be sent.
func ( b * BatchHTTP ) Count ( ) int {
return b . rpcBatch . Count ( )
}
//-----------------------------------------------------------------------------
// baseRPCClient
func ( c * baseRPCClient ) Status ( ) ( * ctypes . ResultStatus , error ) {
result := new ( ctypes . ResultStatus )
result := new ( ctypes . ResultStatus )
_ , err := c . rpc . Call ( "status" , map [ string ] interface { } { } , result )
_ , err := c . calle r. Call ( "status" , map [ string ] interface { } { } , result )
if err != nil {
if err != nil {
return nil , errors . Wrap ( err , "Status" )
return nil , errors . Wrap ( err , "Status" )
}
}
return result , nil
return result , nil
}
}
func ( c * HTTP ) ABCIInfo ( ) ( * ctypes . ResultABCIInfo , error ) {
func ( c * baseRPCClient ) ABCIInfo ( ) ( * ctypes . ResultABCIInfo , error ) {
result := new ( ctypes . ResultABCIInfo )
result := new ( ctypes . ResultABCIInfo )
_ , err := c . rpc . Call ( "abci_info" , map [ string ] interface { } { } , result )
_ , err := c . calle r. Call ( "abci_info" , map [ string ] interface { } { } , result )
if err != nil {
if err != nil {
return nil , errors . Wrap ( err , "ABCIInfo" )
return nil , errors . Wrap ( err , "ABCIInfo" )
}
}
return result , nil
return result , nil
}
}
func ( c * HTTP ) ABCIQuery ( path string , data cmn . HexBytes ) ( * ctypes . ResultABCIQuery , error ) {
func ( c * baseRPCClient ) ABCIQuery ( path string , data cmn . HexBytes ) ( * ctypes . ResultABCIQuery , error ) {
return c . ABCIQueryWithOptions ( path , data , DefaultABCIQueryOptions )
return c . ABCIQueryWithOptions ( path , data , DefaultABCIQueryOptions )
}
}
func ( c * HTTP ) ABCIQueryWithOptions ( path string , data cmn . HexBytes , opts ABCIQueryOptions ) ( * ctypes . ResultABCIQuery , error ) {
func ( c * baseRPCClient ) ABCIQueryWithOptions ( path string , data cmn . HexBytes , opts ABCIQueryOptions ) ( * ctypes . ResultABCIQuery , error ) {
result := new ( ctypes . ResultABCIQuery )
result := new ( ctypes . ResultABCIQuery )
_ , err := c . rpc . Call ( "abci_query" ,
_ , err := c . calle r. Call ( "abci_query" ,
map [ string ] interface { } { "path" : path , "data" : data , "height" : opts . Height , "prove" : opts . Prove } ,
map [ string ] interface { } { "path" : path , "data" : data , "height" : opts . Height , "prove" : opts . Prove } ,
result )
result )
if err != nil {
if err != nil {
@ -87,89 +169,89 @@ func (c *HTTP) ABCIQueryWithOptions(path string, data cmn.HexBytes, opts ABCIQue
return result , nil
return result , nil
}
}
func ( c * HTTP ) BroadcastTxCommit ( tx types . Tx ) ( * ctypes . ResultBroadcastTxCommit , error ) {
func ( c * baseRPCClient ) BroadcastTxCommit ( tx types . Tx ) ( * ctypes . ResultBroadcastTxCommit , error ) {
result := new ( ctypes . ResultBroadcastTxCommit )
result := new ( ctypes . ResultBroadcastTxCommit )
_ , err := c . rpc . Call ( "broadcast_tx_commit" , map [ string ] interface { } { "tx" : tx } , result )
_ , err := c . calle r. Call ( "broadcast_tx_commit" , map [ string ] interface { } { "tx" : tx } , result )
if err != nil {
if err != nil {
return nil , errors . Wrap ( err , "broadcast_tx_commit" )
return nil , errors . Wrap ( err , "broadcast_tx_commit" )
}
}
return result , nil
return result , nil
}
}
func ( c * HTTP ) BroadcastTxAsync ( tx types . Tx ) ( * ctypes . ResultBroadcastTx , error ) {
func ( c * baseRPCClient ) BroadcastTxAsync ( tx types . Tx ) ( * ctypes . ResultBroadcastTx , error ) {
return c . broadcastTX ( "broadcast_tx_async" , tx )
return c . broadcastTX ( "broadcast_tx_async" , tx )
}
}
func ( c * HTTP ) BroadcastTxSync ( tx types . Tx ) ( * ctypes . ResultBroadcastTx , error ) {
func ( c * baseRPCClient ) BroadcastTxSync ( tx types . Tx ) ( * ctypes . ResultBroadcastTx , error ) {
return c . broadcastTX ( "broadcast_tx_sync" , tx )
return c . broadcastTX ( "broadcast_tx_sync" , tx )
}
}
func ( c * HTTP ) broadcastTX ( route string , tx types . Tx ) ( * ctypes . ResultBroadcastTx , error ) {
func ( c * baseRPCClient ) broadcastTX ( route string , tx types . Tx ) ( * ctypes . ResultBroadcastTx , error ) {
result := new ( ctypes . ResultBroadcastTx )
result := new ( ctypes . ResultBroadcastTx )
_ , err := c . rpc . Call ( route , map [ string ] interface { } { "tx" : tx } , result )
_ , err := c . calle r. Call ( route , map [ string ] interface { } { "tx" : tx } , result )
if err != nil {
if err != nil {
return nil , errors . Wrap ( err , route )
return nil , errors . Wrap ( err , route )
}
}
return result , nil
return result , nil
}
}
func ( c * HTTP ) UnconfirmedTxs ( limit int ) ( * ctypes . ResultUnconfirmedTxs , error ) {
func ( c * baseRPCClient ) UnconfirmedTxs ( limit int ) ( * ctypes . ResultUnconfirmedTxs , error ) {
result := new ( ctypes . ResultUnconfirmedTxs )
result := new ( ctypes . ResultUnconfirmedTxs )
_ , err := c . rpc . Call ( "unconfirmed_txs" , map [ string ] interface { } { "limit" : limit } , result )
_ , err := c . calle r. Call ( "unconfirmed_txs" , map [ string ] interface { } { "limit" : limit } , result )
if err != nil {
if err != nil {
return nil , errors . Wrap ( err , "unconfirmed_txs" )
return nil , errors . Wrap ( err , "unconfirmed_txs" )
}
}
return result , nil
return result , nil
}
}
func ( c * HTTP ) NumUnconfirmedTxs ( ) ( * ctypes . ResultUnconfirmedTxs , error ) {
func ( c * baseRPCClient ) NumUnconfirmedTxs ( ) ( * ctypes . ResultUnconfirmedTxs , error ) {
result := new ( ctypes . ResultUnconfirmedTxs )
result := new ( ctypes . ResultUnconfirmedTxs )
_ , err := c . rpc . Call ( "num_unconfirmed_txs" , map [ string ] interface { } { } , result )
_ , err := c . calle r. Call ( "num_unconfirmed_txs" , map [ string ] interface { } { } , result )
if err != nil {
if err != nil {
return nil , errors . Wrap ( err , "num_unconfirmed_txs" )
return nil , errors . Wrap ( err , "num_unconfirmed_txs" )
}
}
return result , nil
return result , nil
}
}
func ( c * HTTP ) NetInfo ( ) ( * ctypes . ResultNetInfo , error ) {
func ( c * baseRPCClient ) NetInfo ( ) ( * ctypes . ResultNetInfo , error ) {
result := new ( ctypes . ResultNetInfo )
result := new ( ctypes . ResultNetInfo )
_ , err := c . rpc . Call ( "net_info" , map [ string ] interface { } { } , result )
_ , err := c . calle r. Call ( "net_info" , map [ string ] interface { } { } , result )
if err != nil {
if err != nil {
return nil , errors . Wrap ( err , "NetInfo" )
return nil , errors . Wrap ( err , "NetInfo" )
}
}
return result , nil
return result , nil
}
}
func ( c * HTTP ) DumpConsensusState ( ) ( * ctypes . ResultDumpConsensusState , error ) {
func ( c * baseRPCClient ) DumpConsensusState ( ) ( * ctypes . ResultDumpConsensusState , error ) {
result := new ( ctypes . ResultDumpConsensusState )
result := new ( ctypes . ResultDumpConsensusState )
_ , err := c . rpc . Call ( "dump_consensus_state" , map [ string ] interface { } { } , result )
_ , err := c . calle r. Call ( "dump_consensus_state" , map [ string ] interface { } { } , result )
if err != nil {
if err != nil {
return nil , errors . Wrap ( err , "DumpConsensusState" )
return nil , errors . Wrap ( err , "DumpConsensusState" )
}
}
return result , nil
return result , nil
}
}
func ( c * HTTP ) ConsensusState ( ) ( * ctypes . ResultConsensusState , error ) {
func ( c * baseRPCClient ) ConsensusState ( ) ( * ctypes . ResultConsensusState , error ) {
result := new ( ctypes . ResultConsensusState )
result := new ( ctypes . ResultConsensusState )
_ , err := c . rpc . Call ( "consensus_state" , map [ string ] interface { } { } , result )
_ , err := c . calle r. Call ( "consensus_state" , map [ string ] interface { } { } , result )
if err != nil {
if err != nil {
return nil , errors . Wrap ( err , "ConsensusState" )
return nil , errors . Wrap ( err , "ConsensusState" )
}
}
return result , nil
return result , nil
}
}
func ( c * HTTP ) Health ( ) ( * ctypes . ResultHealth , error ) {
func ( c * baseRPCClient ) Health ( ) ( * ctypes . ResultHealth , error ) {
result := new ( ctypes . ResultHealth )
result := new ( ctypes . ResultHealth )
_ , err := c . rpc . Call ( "health" , map [ string ] interface { } { } , result )
_ , err := c . calle r. Call ( "health" , map [ string ] interface { } { } , result )
if err != nil {
if err != nil {
return nil , errors . Wrap ( err , "Health" )
return nil , errors . Wrap ( err , "Health" )
}
}
return result , nil
return result , nil
}
}
func ( c * HTTP ) BlockchainInfo ( minHeight , maxHeight int64 ) ( * ctypes . ResultBlockchainInfo , error ) {
func ( c * baseRPCClient ) BlockchainInfo ( minHeight , maxHeight int64 ) ( * ctypes . ResultBlockchainInfo , error ) {
result := new ( ctypes . ResultBlockchainInfo )
result := new ( ctypes . ResultBlockchainInfo )
_ , err := c . rpc . Call ( "blockchain" ,
_ , err := c . calle r. Call ( "blockchain" ,
map [ string ] interface { } { "minHeight" : minHeight , "maxHeight" : maxHeight } ,
map [ string ] interface { } { "minHeight" : minHeight , "maxHeight" : maxHeight } ,
result )
result )
if err != nil {
if err != nil {
@ -178,56 +260,56 @@ func (c *HTTP) BlockchainInfo(minHeight, maxHeight int64) (*ctypes.ResultBlockch
return result , nil
return result , nil
}
}
func ( c * HTTP ) Genesis ( ) ( * ctypes . ResultGenesis , error ) {
func ( c * baseRPCClient ) Genesis ( ) ( * ctypes . ResultGenesis , error ) {
result := new ( ctypes . ResultGenesis )
result := new ( ctypes . ResultGenesis )
_ , err := c . rpc . Call ( "genesis" , map [ string ] interface { } { } , result )
_ , err := c . calle r. Call ( "genesis" , map [ string ] interface { } { } , result )
if err != nil {
if err != nil {
return nil , errors . Wrap ( err , "Genesis" )
return nil , errors . Wrap ( err , "Genesis" )
}
}
return result , nil
return result , nil
}
}
func ( c * HTTP ) Block ( height * int64 ) ( * ctypes . ResultBlock , error ) {
func ( c * baseRPCClient ) Block ( height * int64 ) ( * ctypes . ResultBlock , error ) {
result := new ( ctypes . ResultBlock )
result := new ( ctypes . ResultBlock )
_ , err := c . rpc . Call ( "block" , map [ string ] interface { } { "height" : height } , result )
_ , err := c . calle r. Call ( "block" , map [ string ] interface { } { "height" : height } , result )
if err != nil {
if err != nil {
return nil , errors . Wrap ( err , "Block" )
return nil , errors . Wrap ( err , "Block" )
}
}
return result , nil
return result , nil
}
}
func ( c * HTTP ) BlockResults ( height * int64 ) ( * ctypes . ResultBlockResults , error ) {
func ( c * baseRPCClient ) BlockResults ( height * int64 ) ( * ctypes . ResultBlockResults , error ) {
result := new ( ctypes . ResultBlockResults )
result := new ( ctypes . ResultBlockResults )
_ , err := c . rpc . Call ( "block_results" , map [ string ] interface { } { "height" : height } , result )
_ , err := c . calle r. Call ( "block_results" , map [ string ] interface { } { "height" : height } , result )
if err != nil {
if err != nil {
return nil , errors . Wrap ( err , "Block Result" )
return nil , errors . Wrap ( err , "Block Result" )
}
}
return result , nil
return result , nil
}
}
func ( c * HTTP ) Commit ( height * int64 ) ( * ctypes . ResultCommit , error ) {
func ( c * baseRPCClient ) Commit ( height * int64 ) ( * ctypes . ResultCommit , error ) {
result := new ( ctypes . ResultCommit )
result := new ( ctypes . ResultCommit )
_ , err := c . rpc . Call ( "commit" , map [ string ] interface { } { "height" : height } , result )
_ , err := c . calle r. Call ( "commit" , map [ string ] interface { } { "height" : height } , result )
if err != nil {
if err != nil {
return nil , errors . Wrap ( err , "Commit" )
return nil , errors . Wrap ( err , "Commit" )
}
}
return result , nil
return result , nil
}
}
func ( c * HTTP ) Tx ( hash [ ] byte , prove bool ) ( * ctypes . ResultTx , error ) {
func ( c * baseRPCClient ) Tx ( hash [ ] byte , prove bool ) ( * ctypes . ResultTx , error ) {
result := new ( ctypes . ResultTx )
result := new ( ctypes . ResultTx )
params := map [ string ] interface { } {
params := map [ string ] interface { } {
"hash" : hash ,
"hash" : hash ,
"prove" : prove ,
"prove" : prove ,
}
}
_ , err := c . rpc . Call ( "tx" , params , result )
_ , err := c . calle r. Call ( "tx" , params , result )
if err != nil {
if err != nil {
return nil , errors . Wrap ( err , "Tx" )
return nil , errors . Wrap ( err , "Tx" )
}
}
return result , nil
return result , nil
}
}
func ( c * HTTP ) TxSearch ( query string , prove bool , page , perPage int ) ( * ctypes . ResultTxSearch , error ) {
func ( c * baseRPCClient ) TxSearch ( query string , prove bool , page , perPage int ) ( * ctypes . ResultTxSearch , error ) {
result := new ( ctypes . ResultTxSearch )
result := new ( ctypes . ResultTxSearch )
params := map [ string ] interface { } {
params := map [ string ] interface { } {
"query" : query ,
"query" : query ,
@ -235,23 +317,24 @@ func (c *HTTP) TxSearch(query string, prove bool, page, perPage int) (*ctypes.Re
"page" : page ,
"page" : page ,
"per_page" : perPage ,
"per_page" : perPage ,
}
}
_ , err := c . rpc . Call ( "tx_search" , params , result )
_ , err := c . calle r. Call ( "tx_search" , params , result )
if err != nil {
if err != nil {
return nil , errors . Wrap ( err , "TxSearch" )
return nil , errors . Wrap ( err , "TxSearch" )
}
}
return result , nil
return result , nil
}
}
func ( c * HTTP ) Validators ( height * int64 ) ( * ctypes . ResultValidators , error ) {
func ( c * baseRPCClient ) Validators ( height * int64 ) ( * ctypes . ResultValidators , error ) {
result := new ( ctypes . ResultValidators )
result := new ( ctypes . ResultValidators )
_ , err := c . rpc . Call ( "validators" , map [ string ] interface { } { "height" : height } , result )
_ , err := c . calle r. Call ( "validators" , map [ string ] interface { } { "height" : height } , result )
if err != nil {
if err != nil {
return nil , errors . Wrap ( err , "Validators" )
return nil , errors . Wrap ( err , "Validators" )
}
}
return result , nil
return result , nil
}
}
/** websocket event stuff here... **/
//-----------------------------------------------------------------------------
// WSEvents
type WSEvents struct {
type WSEvents struct {
cmn . BaseService
cmn . BaseService