tendermint/abci/client/socket_client.go

407 lines
10 KiB
Go
Raw Normal View History

2017-01-12 15:47:55 -05:00
package abcicli
2016-03-24 10:19:48 -07:00
import (
"bufio"
"container/list"
"errors"
2016-03-24 10:19:48 -07:00
"fmt"
"net"
2016-05-14 02:22:32 -04:00
"reflect"
2016-03-24 10:19:48 -07:00
"sync"
"time"
2018-06-22 06:59:02 +02:00
"github.com/tendermint/tendermint/abci/types"
2018-07-01 22:36:49 -04:00
cmn "github.com/tendermint/tendermint/libs/common"
2016-03-24 10:19:48 -07:00
)
2017-09-21 15:26:43 -04:00
const reqQueueSize = 256 // TODO make configurable
// const maxResponseSize = 1048576 // 1MB TODO make configurable
const flushThrottleMS = 20 // Don't wait longer than...
2016-03-24 10:19:48 -07:00
var _ Client = (*socketClient)(nil)
2016-03-24 10:19:48 -07:00
// This is goroutine-safe, but users should beware that
// the application in general is not meant to be interfaced
// with concurrent callers.
type socketClient struct {
2017-01-23 20:26:17 -08:00
cmn.BaseService
2016-03-24 10:19:48 -07:00
reqQueue chan *ReqRes
2017-01-23 20:26:17 -08:00
flushTimer *cmn.ThrottleTimer
2016-03-24 10:19:48 -07:00
mustConnect bool
mtx sync.Mutex
addr string
conn net.Conn
err error
reqSent *list.List
resCb func(*types.Request, *types.Response) // listens to all callbacks
2016-03-24 10:19:48 -07:00
}
func NewSocketClient(addr string, mustConnect bool) *socketClient {
cli := &socketClient{
2016-03-24 10:19:48 -07:00
reqQueue: make(chan *ReqRes, reqQueueSize),
2017-01-23 20:26:17 -08:00
flushTimer: cmn.NewThrottleTimer("socketClient", flushThrottleMS),
2016-03-24 10:19:48 -07:00
mustConnect: mustConnect,
addr: addr,
reqSent: list.New(),
resCb: nil,
}
2017-01-23 20:26:17 -08:00
cli.BaseService = *cmn.NewBaseService(nil, "socketClient", cli)
return cli
2016-03-24 10:19:48 -07:00
}
func (cli *socketClient) OnStart() error {
2017-09-21 15:32:06 -04:00
if err := cli.BaseService.OnStart(); err != nil {
return err
}
var err error
var conn net.Conn
2016-05-24 21:51:28 -04:00
RETRY_LOOP:
for {
2017-01-23 20:26:17 -08:00
conn, err = cmn.Connect(cli.addr)
2016-05-24 21:51:28 -04:00
if err != nil {
if cli.mustConnect {
return err
2016-03-24 10:19:48 -07:00
}
2018-11-16 23:36:42 +01:00
cli.Logger.Error(fmt.Sprintf("abci.socketClient failed to connect to %v. Retrying...", cli.addr), "err", err)
2017-11-28 07:47:51 +00:00
time.Sleep(time.Second * dialRetryIntervalSeconds)
2017-01-17 00:26:32 -08:00
continue RETRY_LOOP
2016-03-24 10:19:48 -07:00
}
cli.conn = conn
2016-05-24 21:51:28 -04:00
go cli.sendRequestsRoutine(conn)
go cli.recvResponseRoutine(conn)
return nil
2016-05-24 21:51:28 -04:00
}
2016-03-24 10:19:48 -07:00
}
func (cli *socketClient) OnStop() {
2016-10-28 12:06:40 -07:00
cli.BaseService.OnStop()
cli.mtx.Lock()
defer cli.mtx.Unlock()
2016-03-24 10:19:48 -07:00
if cli.conn != nil {
cli.conn.Close()
}
2016-08-10 17:58:11 -04:00
cli.flushQueue()
2016-03-24 10:19:48 -07:00
}
// Stop the client and set the error
func (cli *socketClient) StopForError(err error) {
2016-08-10 17:58:11 -04:00
if !cli.IsRunning() {
return
}
cli.mtx.Lock()
2016-03-24 10:19:48 -07:00
if cli.err == nil {
cli.err = err
}
cli.mtx.Unlock()
2017-04-28 00:37:18 +04:00
cli.Logger.Error(fmt.Sprintf("Stopping abci.socketClient for error: %v", err.Error()))
2016-03-24 10:19:48 -07:00
cli.Stop()
}
func (cli *socketClient) Error() error {
2016-03-24 10:19:48 -07:00
cli.mtx.Lock()
defer cli.mtx.Unlock()
return cli.err
2016-03-24 10:19:48 -07:00
}
// Set listener for all responses
// NOTE: callback may get internally generated flush responses.
func (cli *socketClient) SetResponseCallback(resCb Callback) {
cli.mtx.Lock()
cli.resCb = resCb
abci: localClient improvements & bugfixes & pubsub Unsubscribe issues (#2748) * use READ lock/unlock in ConsensusState#GetLastHeight Refs #2721 * do not use defers when there's no need * fix peer formatting (output its address instead of the pointer) ``` [54310]: E[11-02|11:59:39.851] Connection failed @ sendRoutine module=p2p peer=0xb78f00 conn=MConn{74.207.236.148:26656} err="pong timeout" ``` https://github.com/tendermint/tendermint/issues/2721#issuecomment-435326581 * panic if peer has no state https://github.com/tendermint/tendermint/issues/2721#issuecomment-435347165 It's confusing that sometimes we check if peer has a state, but most of the times we expect it to be there 1. https://github.com/tendermint/tendermint/blob/add79700b5fe84417538202b6c927c8cc5383672/mempool/reactor.go#L138 2. https://github.com/tendermint/tendermint/blob/add79700b5fe84417538202b6c927c8cc5383672/rpc/core/consensus.go#L196 (edited) I will change everything to always assume peer has a state and panic otherwise that should help identify issues earlier * abci/localclient: extend lock on app callback App callback should be protected by lock as well (note this was already done for InitChainAsync, why not for others???). Otherwise, when we execute the block, tx might come in and call the callback in the same time we're updating it in execBlockOnProxyApp => DATA RACE Fixes #2721 Consensus state is locked ``` goroutine 113333 [semacquire, 309 minutes]: sync.runtime_SemacquireMutex(0xc00180009c, 0xc0000c7e00) /usr/local/go/src/runtime/sema.go:71 +0x3d sync.(*RWMutex).RLock(0xc001800090) /usr/local/go/src/sync/rwmutex.go:50 +0x4e github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).GetRoundState(0xc001800000, 0x0) /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus/state.go:218 +0x46 github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusReactor).queryMaj23Routine(0xc0017def80, 0x11104a0, 0xc0072488f0, 0xc007248 9c0) /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus/reactor.go:735 +0x16d created by github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusReactor).AddPeer /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus/reactor.go:172 +0x236 ``` because localClient is locked ``` goroutine 1899 [semacquire, 309 minutes]: sync.runtime_SemacquireMutex(0xc00003363c, 0xc0000cb500) /usr/local/go/src/runtime/sema.go:71 +0x3d sync.(*Mutex).Lock(0xc000033638) /usr/local/go/src/sync/mutex.go:134 +0xff github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/abci/client.(*localClient).SetResponseCallback(0xc0001fb560, 0xc007868540) /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/abci/client/local_client.go:32 +0x33 github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/proxy.(*appConnConsensus).SetResponseCallback(0xc00002f750, 0xc007868540) /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/proxy/app_conn.go:57 +0x40 github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/state.execBlockOnProxyApp(0x1104e20, 0xc002ca0ba0, 0x11092a0, 0xc00002f750, 0xc0001fe960, 0xc000bfc660, 0x110cfe0, 0xc000090330, 0xc9d12, 0xc000d9d5a0, ...) /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/state/execution.go:230 +0x1fd github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/state.(*BlockExecutor).ApplyBlock(0xc002c2a230, 0x7, 0x0, 0xc000eae880, 0x6, 0xc002e52c60, 0x16, 0x1f927, 0xc9d12, 0xc000d9d5a0, ...) /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/state/execution.go:96 +0x142 github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).finalizeCommit(0xc001800000, 0x1f928) /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus/state.go:1339 +0xa3e github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).tryFinalizeCommit(0xc001800000, 0x1f928) /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus/state.go:1270 +0x451 github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).enterCommit.func1(0xc001800000, 0x0, 0x1f928) /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus/state.go:1218 +0x90 github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).enterCommit(0xc001800000, 0x1f928, 0x0) /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus/state.go:1247 +0x6b8 github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).addVote(0xc001800000, 0xc003d8dea0, 0xc000cf4cc0, 0x28, 0xf1, 0xc003bc7ad0, 0xc003bc7b10) /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus/state.go:1659 +0xbad github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).tryAddVote(0xc001800000, 0xc003d8dea0, 0xc000cf4cc0, 0x28, 0xf1, 0xf1, 0xf1) /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus/state.go:1517 +0x59 github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).handleMsg(0xc001800000, 0xd98200, 0xc0070dbed0, 0xc000cf4cc0, 0x28) /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus/state.go:660 +0x64b github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).receiveRoutine(0xc001800000, 0x0) /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus/state.go:617 +0x670 created by github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).OnStart /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/consensus/state.go:311 +0x132 ``` tx comes in and CheckTx is executed right when we execute the block ``` goroutine 111044 [semacquire, 309 minutes]: sync.runtime_SemacquireMutex(0xc00003363c, 0x0) /usr/local/go/src/runtime/sema.go:71 +0x3d sync.(*Mutex).Lock(0xc000033638) /usr/local/go/src/sync/mutex.go:134 +0xff github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/abci/client.(*localClient).CheckTxAsync(0xc0001fb0e0, 0xc002d94500, 0x13f, 0x280, 0x0) /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/abci/client/local_client.go:85 +0x47 github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/proxy.(*appConnMempool).CheckTxAsync(0xc00002f720, 0xc002d94500, 0x13f, 0x280, 0x1) /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/proxy/app_conn.go:114 +0x51 github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/mempool.(*Mempool).CheckTx(0xc002d3a320, 0xc002d94500, 0x13f, 0x280, 0xc0072355f0, 0x0, 0x0) /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/mempool/mempool.go:316 +0x17b github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/rpc/core.BroadcastTxSync(0xc002d94500, 0x13f, 0x280, 0x0, 0x0, 0x0) /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/rpc/core/mempool.go:93 +0xb8 reflect.Value.call(0xd85560, 0x10326c0, 0x13, 0xec7b8b, 0x4, 0xc00663f180, 0x1, 0x1, 0xc00663f180, 0xc00663f188, ...) /usr/local/go/src/reflect/value.go:447 +0x449 reflect.Value.Call(0xd85560, 0x10326c0, 0x13, 0xc00663f180, 0x1, 0x1, 0x0, 0x0, 0xc005cc9344) /usr/local/go/src/reflect/value.go:308 +0xa4 github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/rpc/lib/server.makeHTTPHandler.func2(0x1102060, 0xc00663f100, 0xc0082d7900) /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/rpc/lib/server/handlers.go:269 +0x188 net/http.HandlerFunc.ServeHTTP(0xc002c81f20, 0x1102060, 0xc00663f100, 0xc0082d7900) /usr/local/go/src/net/http/server.go:1964 +0x44 net/http.(*ServeMux).ServeHTTP(0xc002c81b60, 0x1102060, 0xc00663f100, 0xc0082d7900) /usr/local/go/src/net/http/server.go:2361 +0x127 github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/rpc/lib/server.maxBytesHandler.ServeHTTP(0x10f8a40, 0xc002c81b60, 0xf4240, 0x1102060, 0xc00663f100, 0xc0082d7900) /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/rpc/lib/server/http_server.go:219 +0xcf github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/rpc/lib/server.RecoverAndLogHandler.func1(0x1103220, 0xc00121e620, 0xc0082d7900) /root/go/src/github.com/MinterTeam/minter-go-node/vendor/github.com/tendermint/tendermint/rpc/lib/server/http_server.go:192 +0x394 net/http.HandlerFunc.ServeHTTP(0xc002c06ea0, 0x1103220, 0xc00121e620, 0xc0082d7900) /usr/local/go/src/net/http/server.go:1964 +0x44 net/http.serverHandler.ServeHTTP(0xc001a1aa90, 0x1103220, 0xc00121e620, 0xc0082d7900) /usr/local/go/src/net/http/server.go:2741 +0xab net/http.(*conn).serve(0xc00785a3c0, 0x11041a0, 0xc000f844c0) /usr/local/go/src/net/http/server.go:1847 +0x646 created by net/http.(*Server).Serve /usr/local/go/src/net/http/server.go:2851 +0x2f5 ``` * consensus: use read lock in Receive#VoteMessage * use defer to unlock mutex because application might panic * use defer in every method of the localClient * add a changelog entry * drain channels before Unsubscribe(All) Read https://github.com/tendermint/tendermint/blob/55362ed76630f3e1ebec159a598f6a9fb5892cb1/libs/pubsub/pubsub.go#L13 for the detailed explanation of the issue. We'll need to fix it someday. Make sure to keep an eye on https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-033-pubsub.md * retry instead of panic when peer has no state in reactors other than consensus in /dump_consensus_state RPC endpoint, skip a peer with no state * rpc/core/mempool: simplify error messages * rpc/core/mempool: use time.After instead of timer also, do not log DeliverTx result (to be consistent with other memthods) * unlock before calling the callback in reqRes#SetCallback
2018-11-13 20:32:51 +04:00
cli.mtx.Unlock()
}
2016-03-24 10:19:48 -07:00
//----------------------------------------
func (cli *socketClient) sendRequestsRoutine(conn net.Conn) {
2016-03-24 10:19:48 -07:00
w := bufio.NewWriter(conn)
for {
select {
case <-cli.flushTimer.Ch:
select {
case cli.reqQueue <- NewReqRes(types.ToRequestFlush()):
2016-03-24 10:19:48 -07:00
default:
// Probably will fill the buffer, or retry later.
}
case <-cli.Quit():
2016-03-24 10:19:48 -07:00
return
case reqres := <-cli.reqQueue:
cli.willSendReq(reqres)
err := types.WriteMessage(reqres.Request, w)
if err != nil {
cli.StopForError(fmt.Errorf("Error writing msg: %v", err))
2016-03-24 10:19:48 -07:00
return
}
2017-04-28 00:37:18 +04:00
// cli.Logger.Debug("Sent request", "requestType", reflect.TypeOf(reqres.Request), "request", reqres.Request)
2016-05-17 20:06:24 -04:00
if _, ok := reqres.Request.Value.(*types.Request_Flush); ok {
2016-03-24 10:19:48 -07:00
err = w.Flush()
if err != nil {
cli.StopForError(fmt.Errorf("Error flushing writer: %v", err))
2016-03-24 10:19:48 -07:00
return
}
}
}
}
}
func (cli *socketClient) recvResponseRoutine(conn net.Conn) {
2016-03-24 10:19:48 -07:00
r := bufio.NewReader(conn) // Buffer reads
for {
var res = &types.Response{}
err := types.ReadMessage(r, res)
if err != nil {
cli.StopForError(err)
return
}
2016-05-17 20:06:24 -04:00
switch r := res.Value.(type) {
2016-05-14 02:22:32 -04:00
case *types.Response_Exception:
2016-03-24 10:19:48 -07:00
// XXX After setting cli.err, release waiters (e.g. reqres.Done())
2016-05-14 02:22:32 -04:00
cli.StopForError(errors.New(r.Exception.Error))
return
2016-03-24 10:19:48 -07:00
default:
2017-04-28 00:37:18 +04:00
// cli.Logger.Debug("Received response", "responseType", reflect.TypeOf(res), "response", res)
2016-03-24 10:19:48 -07:00
err := cli.didRecvResponse(res)
if err != nil {
cli.StopForError(err)
return
2016-03-24 10:19:48 -07:00
}
}
}
}
func (cli *socketClient) willSendReq(reqres *ReqRes) {
2016-03-24 10:19:48 -07:00
cli.mtx.Lock()
defer cli.mtx.Unlock()
cli.reqSent.PushBack(reqres)
}
func (cli *socketClient) didRecvResponse(res *types.Response) error {
2016-03-24 10:19:48 -07:00
cli.mtx.Lock()
defer cli.mtx.Unlock()
// Get the first ReqRes
next := cli.reqSent.Front()
if next == nil {
2016-05-17 20:06:24 -04:00
return fmt.Errorf("Unexpected result type %v when nothing expected", reflect.TypeOf(res.Value))
2016-03-24 10:19:48 -07:00
}
reqres := next.Value.(*ReqRes)
if !resMatchesReq(reqres.Request, res) {
return fmt.Errorf("Unexpected result type %v when response to %v expected",
2016-05-17 20:06:24 -04:00
reflect.TypeOf(res.Value), reflect.TypeOf(reqres.Request.Value))
2016-03-24 10:19:48 -07:00
}
reqres.Response = res // Set response
reqres.Done() // Release waiters
cli.reqSent.Remove(next) // Pop first item from linked list
// Notify reqRes listener if set
if cb := reqres.GetCallback(); cb != nil {
cb(res)
}
// Notify client listener if set
if cli.resCb != nil {
cli.resCb(reqres.Request, res)
}
return nil
}
//----------------------------------------
func (cli *socketClient) EchoAsync(msg string) *ReqRes {
2016-05-14 02:22:32 -04:00
return cli.queueRequest(types.ToRequestEcho(msg))
2016-03-24 10:19:48 -07:00
}
func (cli *socketClient) FlushAsync() *ReqRes {
2016-05-14 02:22:32 -04:00
return cli.queueRequest(types.ToRequestFlush())
2016-03-24 10:19:48 -07:00
}
2017-09-22 11:10:39 -04:00
func (cli *socketClient) InfoAsync(req types.RequestInfo) *ReqRes {
return cli.queueRequest(types.ToRequestInfo(req))
2016-03-24 10:19:48 -07:00
}
func (cli *socketClient) SetOptionAsync(req types.RequestSetOption) *ReqRes {
return cli.queueRequest(types.ToRequestSetOption(req))
2016-03-24 10:19:48 -07:00
}
2017-01-12 15:27:08 -05:00
func (cli *socketClient) DeliverTxAsync(tx []byte) *ReqRes {
return cli.queueRequest(types.ToRequestDeliverTx(tx))
2016-03-24 10:19:48 -07:00
}
func (cli *socketClient) CheckTxAsync(tx []byte) *ReqRes {
2016-05-14 02:22:32 -04:00
return cli.queueRequest(types.ToRequestCheckTx(tx))
2016-03-24 10:19:48 -07:00
}
2017-11-27 20:27:18 +00:00
func (cli *socketClient) QueryAsync(req types.RequestQuery) *ReqRes {
return cli.queueRequest(types.ToRequestQuery(req))
2016-03-24 10:19:48 -07:00
}
func (cli *socketClient) CommitAsync() *ReqRes {
2016-05-14 02:22:32 -04:00
return cli.queueRequest(types.ToRequestCommit())
2016-03-24 10:19:48 -07:00
}
func (cli *socketClient) InitChainAsync(req types.RequestInitChain) *ReqRes {
return cli.queueRequest(types.ToRequestInitChain(req))
2016-03-24 10:19:48 -07:00
}
func (cli *socketClient) BeginBlockAsync(req types.RequestBeginBlock) *ReqRes {
return cli.queueRequest(types.ToRequestBeginBlock(req))
2016-03-26 22:35:23 -07:00
}
func (cli *socketClient) EndBlockAsync(req types.RequestEndBlock) *ReqRes {
return cli.queueRequest(types.ToRequestEndBlock(req))
2016-03-24 10:19:48 -07:00
}
//----------------------------------------
func (cli *socketClient) FlushSync() error {
2016-08-10 17:58:11 -04:00
reqRes := cli.queueRequest(types.ToRequestFlush())
2016-09-08 21:41:35 -04:00
if err := cli.Error(); err != nil {
return err
2016-08-10 17:58:11 -04:00
}
reqRes.Wait() // NOTE: if we don't flush the queue, its possible to get stuck here
2016-09-08 21:41:35 -04:00
return cli.Error()
2016-03-24 10:19:48 -07:00
}
func (cli *socketClient) EchoSync(msg string) (*types.ResponseEcho, error) {
reqres := cli.queueRequest(types.ToRequestEcho(msg))
cli.FlushSync()
return reqres.Response.GetEcho(), cli.Error()
}
func (cli *socketClient) InfoSync(req types.RequestInfo) (*types.ResponseInfo, error) {
2017-09-22 11:10:39 -04:00
reqres := cli.queueRequest(types.ToRequestInfo(req))
2016-03-24 10:19:48 -07:00
cli.FlushSync()
return reqres.Response.GetInfo(), cli.Error()
2016-03-24 10:19:48 -07:00
}
func (cli *socketClient) SetOptionSync(req types.RequestSetOption) (*types.ResponseSetOption, error) {
reqres := cli.queueRequest(types.ToRequestSetOption(req))
2016-03-24 10:19:48 -07:00
cli.FlushSync()
return reqres.Response.GetSetOption(), cli.Error()
2016-03-24 10:19:48 -07:00
}
func (cli *socketClient) DeliverTxSync(tx []byte) (*types.ResponseDeliverTx, error) {
2017-01-12 15:27:08 -05:00
reqres := cli.queueRequest(types.ToRequestDeliverTx(tx))
2016-03-24 10:19:48 -07:00
cli.FlushSync()
2017-11-22 19:37:51 -06:00
return reqres.Response.GetDeliverTx(), cli.Error()
2016-03-24 10:19:48 -07:00
}
func (cli *socketClient) CheckTxSync(tx []byte) (*types.ResponseCheckTx, error) {
2016-05-14 02:22:32 -04:00
reqres := cli.queueRequest(types.ToRequestCheckTx(tx))
2016-03-24 10:19:48 -07:00
cli.FlushSync()
2017-11-22 19:37:51 -06:00
return reqres.Response.GetCheckTx(), cli.Error()
2016-03-24 10:19:48 -07:00
}
func (cli *socketClient) QuerySync(req types.RequestQuery) (*types.ResponseQuery, error) {
reqres := cli.queueRequest(types.ToRequestQuery(req))
2016-03-24 10:19:48 -07:00
cli.FlushSync()
return reqres.Response.GetQuery(), cli.Error()
2016-03-24 10:19:48 -07:00
}
func (cli *socketClient) CommitSync() (*types.ResponseCommit, error) {
2016-05-14 02:22:32 -04:00
reqres := cli.queueRequest(types.ToRequestCommit())
2016-03-24 10:19:48 -07:00
cli.FlushSync()
2017-11-22 19:37:51 -06:00
return reqres.Response.GetCommit(), cli.Error()
2016-03-24 10:19:48 -07:00
}
func (cli *socketClient) InitChainSync(req types.RequestInitChain) (*types.ResponseInitChain, error) {
reqres := cli.queueRequest(types.ToRequestInitChain(req))
2016-03-24 10:19:48 -07:00
cli.FlushSync()
return reqres.Response.GetInitChain(), cli.Error()
2016-03-24 10:19:48 -07:00
}
func (cli *socketClient) BeginBlockSync(req types.RequestBeginBlock) (*types.ResponseBeginBlock, error) {
reqres := cli.queueRequest(types.ToRequestBeginBlock(req))
2016-03-26 22:35:23 -07:00
cli.FlushSync()
return reqres.Response.GetBeginBlock(), cli.Error()
2016-03-26 22:35:23 -07:00
}
func (cli *socketClient) EndBlockSync(req types.RequestEndBlock) (*types.ResponseEndBlock, error) {
reqres := cli.queueRequest(types.ToRequestEndBlock(req))
2016-03-24 10:19:48 -07:00
cli.FlushSync()
return reqres.Response.GetEndBlock(), cli.Error()
2016-03-24 10:19:48 -07:00
}
//----------------------------------------
func (cli *socketClient) queueRequest(req *types.Request) *ReqRes {
2016-03-24 10:19:48 -07:00
reqres := NewReqRes(req)
2016-05-18 18:30:38 -04:00
2016-03-24 10:19:48 -07:00
// TODO: set cli.err if reqQueue times out
cli.reqQueue <- reqres
// Maybe auto-flush, or unset auto-flush
2016-05-17 20:06:24 -04:00
switch req.Value.(type) {
2016-05-14 02:22:32 -04:00
case *types.Request_Flush:
2016-03-24 10:19:48 -07:00
cli.flushTimer.Unset()
default:
cli.flushTimer.Set()
}
return reqres
}
func (cli *socketClient) flushQueue() {
// mark all in-flight messages as resolved (they will get cli.Error())
for req := cli.reqSent.Front(); req != nil; req = req.Next() {
reqres := req.Value.(*ReqRes)
reqres.Done()
}
// mark all queued messages as resolved
LOOP:
for {
select {
case reqres := <-cli.reqQueue:
reqres.Done()
default:
break LOOP
}
}
}
2016-03-24 10:19:48 -07:00
//----------------------------------------
func resMatchesReq(req *types.Request, res *types.Response) (ok bool) {
2016-05-17 20:06:24 -04:00
switch req.Value.(type) {
2016-05-14 02:22:32 -04:00
case *types.Request_Echo:
2016-05-17 20:06:24 -04:00
_, ok = res.Value.(*types.Response_Echo)
2016-05-14 02:22:32 -04:00
case *types.Request_Flush:
2016-05-17 20:06:24 -04:00
_, ok = res.Value.(*types.Response_Flush)
2016-05-14 02:22:32 -04:00
case *types.Request_Info:
2016-05-17 20:06:24 -04:00
_, ok = res.Value.(*types.Response_Info)
2016-05-14 02:22:32 -04:00
case *types.Request_SetOption:
2016-05-17 20:06:24 -04:00
_, ok = res.Value.(*types.Response_SetOption)
2017-01-12 15:27:08 -05:00
case *types.Request_DeliverTx:
_, ok = res.Value.(*types.Response_DeliverTx)
2016-05-14 02:22:32 -04:00
case *types.Request_CheckTx:
2016-05-17 20:06:24 -04:00
_, ok = res.Value.(*types.Response_CheckTx)
2016-05-14 02:22:32 -04:00
case *types.Request_Commit:
2016-05-17 20:06:24 -04:00
_, ok = res.Value.(*types.Response_Commit)
2016-05-14 02:22:32 -04:00
case *types.Request_Query:
2016-05-17 20:06:24 -04:00
_, ok = res.Value.(*types.Response_Query)
2016-05-14 02:22:32 -04:00
case *types.Request_InitChain:
2016-05-17 20:06:24 -04:00
_, ok = res.Value.(*types.Response_InitChain)
2016-11-03 19:50:57 -04:00
case *types.Request_BeginBlock:
_, ok = res.Value.(*types.Response_BeginBlock)
2016-05-14 02:22:32 -04:00
case *types.Request_EndBlock:
2016-05-17 20:06:24 -04:00
_, ok = res.Value.(*types.Response_EndBlock)
2016-05-14 02:22:32 -04:00
}
return ok
2016-03-24 10:19:48 -07:00
}