github.com/DFWallet/tendermint-cosmos@v0.0.2/abci/client/grpc_client.go (about) 1 package abcicli 2 3 import ( 4 "fmt" 5 "net" 6 "sync" 7 "time" 8 9 "golang.org/x/net/context" 10 "google.golang.org/grpc" 11 12 "github.com/DFWallet/tendermint-cosmos/abci/types" 13 tmnet "github.com/DFWallet/tendermint-cosmos/libs/net" 14 "github.com/DFWallet/tendermint-cosmos/libs/service" 15 tmsync "github.com/DFWallet/tendermint-cosmos/libs/sync" 16 ) 17 18 var _ Client = (*grpcClient)(nil) 19 20 // A stripped copy of the remoteClient that makes 21 // synchronous calls using grpc 22 type grpcClient struct { 23 service.BaseService 24 mustConnect bool 25 26 client types.ABCIApplicationClient 27 conn *grpc.ClientConn 28 chReqRes chan *ReqRes // dispatches "async" responses to callbacks *in order*, needed by mempool 29 30 mtx tmsync.Mutex 31 addr string 32 err error 33 resCb func(*types.Request, *types.Response) // listens to all callbacks 34 } 35 36 func NewGRPCClient(addr string, mustConnect bool) Client { 37 cli := &grpcClient{ 38 addr: addr, 39 mustConnect: mustConnect, 40 // Buffering the channel is needed to make calls appear asynchronous, 41 // which is required when the caller makes multiple async calls before 42 // processing callbacks (e.g. due to holding locks). 64 means that a 43 // caller can make up to 64 async calls before a callback must be 44 // processed (otherwise it deadlocks). It also means that we can make 64 45 // gRPC calls while processing a slow callback at the channel head. 46 chReqRes: make(chan *ReqRes, 64), 47 } 48 cli.BaseService = *service.NewBaseService(nil, "grpcClient", cli) 49 return cli 50 } 51 52 func dialerFunc(ctx context.Context, addr string) (net.Conn, error) { 53 return tmnet.Connect(addr) 54 } 55 56 func (cli *grpcClient) OnStart() error { 57 if err := cli.BaseService.OnStart(); err != nil { 58 return err 59 } 60 61 // This processes asynchronous request/response messages and dispatches 62 // them to callbacks. 63 go func() { 64 // Use a separate function to use defer for mutex unlocks (this handles panics) 65 callCb := func(reqres *ReqRes) { 66 cli.mtx.Lock() 67 defer cli.mtx.Unlock() 68 69 reqres.SetDone() 70 reqres.Done() 71 72 // Notify client listener if set 73 if cli.resCb != nil { 74 cli.resCb(reqres.Request, reqres.Response) 75 } 76 77 // Notify reqRes listener if set 78 if cb := reqres.GetCallback(); cb != nil { 79 cb(reqres.Response) 80 } 81 } 82 for reqres := range cli.chReqRes { 83 if reqres != nil { 84 callCb(reqres) 85 } else { 86 cli.Logger.Error("Received nil reqres") 87 } 88 } 89 }() 90 91 RETRY_LOOP: 92 for { 93 conn, err := grpc.Dial(cli.addr, grpc.WithInsecure(), grpc.WithContextDialer(dialerFunc)) 94 if err != nil { 95 if cli.mustConnect { 96 return err 97 } 98 cli.Logger.Error(fmt.Sprintf("abci.grpcClient failed to connect to %v. Retrying...\n", cli.addr), "err", err) 99 time.Sleep(time.Second * dialRetryIntervalSeconds) 100 continue RETRY_LOOP 101 } 102 103 cli.Logger.Info("Dialed server. Waiting for echo.", "addr", cli.addr) 104 client := types.NewABCIApplicationClient(conn) 105 cli.conn = conn 106 107 ENSURE_CONNECTED: 108 for { 109 _, err := client.Echo(context.Background(), &types.RequestEcho{Message: "hello"}, grpc.WaitForReady(true)) 110 if err == nil { 111 break ENSURE_CONNECTED 112 } 113 cli.Logger.Error("Echo failed", "err", err) 114 time.Sleep(time.Second * echoRetryIntervalSeconds) 115 } 116 117 cli.client = client 118 return nil 119 } 120 } 121 122 func (cli *grpcClient) OnStop() { 123 cli.BaseService.OnStop() 124 125 if cli.conn != nil { 126 cli.conn.Close() 127 } 128 close(cli.chReqRes) 129 } 130 131 func (cli *grpcClient) StopForError(err error) { 132 if !cli.IsRunning() { 133 return 134 } 135 136 cli.mtx.Lock() 137 if cli.err == nil { 138 cli.err = err 139 } 140 cli.mtx.Unlock() 141 142 cli.Logger.Error(fmt.Sprintf("Stopping abci.grpcClient for error: %v", err.Error())) 143 if err := cli.Stop(); err != nil { 144 cli.Logger.Error("Error stopping abci.grpcClient", "err", err) 145 } 146 } 147 148 func (cli *grpcClient) Error() error { 149 cli.mtx.Lock() 150 defer cli.mtx.Unlock() 151 return cli.err 152 } 153 154 // Set listener for all responses 155 // NOTE: callback may get internally generated flush responses. 156 func (cli *grpcClient) SetResponseCallback(resCb Callback) { 157 cli.mtx.Lock() 158 cli.resCb = resCb 159 cli.mtx.Unlock() 160 } 161 162 //---------------------------------------- 163 // GRPC calls are synchronous, but some callbacks expect to be called asynchronously 164 // (eg. the mempool expects to be able to lock to remove bad txs from cache). 165 // To accommodate, we finish each call in its own go-routine, 166 // which is expensive, but easy - if you want something better, use the socket protocol! 167 // maybe one day, if people really want it, we use grpc streams, 168 // but hopefully not :D 169 170 func (cli *grpcClient) EchoAsync(msg string) *ReqRes { 171 req := types.ToRequestEcho(msg) 172 res, err := cli.client.Echo(context.Background(), req.GetEcho(), grpc.WaitForReady(true)) 173 if err != nil { 174 cli.StopForError(err) 175 } 176 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_Echo{Echo: res}}) 177 } 178 179 func (cli *grpcClient) FlushAsync() *ReqRes { 180 req := types.ToRequestFlush() 181 res, err := cli.client.Flush(context.Background(), req.GetFlush(), grpc.WaitForReady(true)) 182 if err != nil { 183 cli.StopForError(err) 184 } 185 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_Flush{Flush: res}}) 186 } 187 188 func (cli *grpcClient) InfoAsync(params types.RequestInfo) *ReqRes { 189 req := types.ToRequestInfo(params) 190 res, err := cli.client.Info(context.Background(), req.GetInfo(), grpc.WaitForReady(true)) 191 if err != nil { 192 cli.StopForError(err) 193 } 194 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_Info{Info: res}}) 195 } 196 197 func (cli *grpcClient) SetOptionAsync(params types.RequestSetOption) *ReqRes { 198 req := types.ToRequestSetOption(params) 199 res, err := cli.client.SetOption(context.Background(), req.GetSetOption(), grpc.WaitForReady(true)) 200 if err != nil { 201 cli.StopForError(err) 202 } 203 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_SetOption{SetOption: res}}) 204 } 205 206 func (cli *grpcClient) DeliverTxAsync(params types.RequestDeliverTx) *ReqRes { 207 req := types.ToRequestDeliverTx(params) 208 res, err := cli.client.DeliverTx(context.Background(), req.GetDeliverTx(), grpc.WaitForReady(true)) 209 if err != nil { 210 cli.StopForError(err) 211 } 212 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_DeliverTx{DeliverTx: res}}) 213 } 214 215 func (cli *grpcClient) CheckTxAsync(params types.RequestCheckTx) *ReqRes { 216 req := types.ToRequestCheckTx(params) 217 res, err := cli.client.CheckTx(context.Background(), req.GetCheckTx(), grpc.WaitForReady(true)) 218 if err != nil { 219 cli.StopForError(err) 220 } 221 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_CheckTx{CheckTx: res}}) 222 } 223 224 func (cli *grpcClient) QueryAsync(params types.RequestQuery) *ReqRes { 225 req := types.ToRequestQuery(params) 226 res, err := cli.client.Query(context.Background(), req.GetQuery(), grpc.WaitForReady(true)) 227 if err != nil { 228 cli.StopForError(err) 229 } 230 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_Query{Query: res}}) 231 } 232 233 func (cli *grpcClient) CommitAsync() *ReqRes { 234 req := types.ToRequestCommit() 235 res, err := cli.client.Commit(context.Background(), req.GetCommit(), grpc.WaitForReady(true)) 236 if err != nil { 237 cli.StopForError(err) 238 } 239 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_Commit{Commit: res}}) 240 } 241 242 func (cli *grpcClient) InitChainAsync(params types.RequestInitChain) *ReqRes { 243 req := types.ToRequestInitChain(params) 244 res, err := cli.client.InitChain(context.Background(), req.GetInitChain(), grpc.WaitForReady(true)) 245 if err != nil { 246 cli.StopForError(err) 247 } 248 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_InitChain{InitChain: res}}) 249 } 250 251 func (cli *grpcClient) BeginBlockAsync(params types.RequestBeginBlock) *ReqRes { 252 req := types.ToRequestBeginBlock(params) 253 res, err := cli.client.BeginBlock(context.Background(), req.GetBeginBlock(), grpc.WaitForReady(true)) 254 if err != nil { 255 cli.StopForError(err) 256 } 257 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_BeginBlock{BeginBlock: res}}) 258 } 259 260 func (cli *grpcClient) EndBlockAsync(params types.RequestEndBlock) *ReqRes { 261 req := types.ToRequestEndBlock(params) 262 res, err := cli.client.EndBlock(context.Background(), req.GetEndBlock(), grpc.WaitForReady(true)) 263 if err != nil { 264 cli.StopForError(err) 265 } 266 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_EndBlock{EndBlock: res}}) 267 } 268 269 func (cli *grpcClient) ListSnapshotsAsync(params types.RequestListSnapshots) *ReqRes { 270 req := types.ToRequestListSnapshots(params) 271 res, err := cli.client.ListSnapshots(context.Background(), req.GetListSnapshots(), grpc.WaitForReady(true)) 272 if err != nil { 273 cli.StopForError(err) 274 } 275 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_ListSnapshots{ListSnapshots: res}}) 276 } 277 278 func (cli *grpcClient) OfferSnapshotAsync(params types.RequestOfferSnapshot) *ReqRes { 279 req := types.ToRequestOfferSnapshot(params) 280 res, err := cli.client.OfferSnapshot(context.Background(), req.GetOfferSnapshot(), grpc.WaitForReady(true)) 281 if err != nil { 282 cli.StopForError(err) 283 } 284 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_OfferSnapshot{OfferSnapshot: res}}) 285 } 286 287 func (cli *grpcClient) LoadSnapshotChunkAsync(params types.RequestLoadSnapshotChunk) *ReqRes { 288 req := types.ToRequestLoadSnapshotChunk(params) 289 res, err := cli.client.LoadSnapshotChunk(context.Background(), req.GetLoadSnapshotChunk(), grpc.WaitForReady(true)) 290 if err != nil { 291 cli.StopForError(err) 292 } 293 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_LoadSnapshotChunk{LoadSnapshotChunk: res}}) 294 } 295 296 func (cli *grpcClient) ApplySnapshotChunkAsync(params types.RequestApplySnapshotChunk) *ReqRes { 297 req := types.ToRequestApplySnapshotChunk(params) 298 res, err := cli.client.ApplySnapshotChunk(context.Background(), req.GetApplySnapshotChunk(), grpc.WaitForReady(true)) 299 if err != nil { 300 cli.StopForError(err) 301 } 302 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_ApplySnapshotChunk{ApplySnapshotChunk: res}}) 303 } 304 305 // finishAsyncCall creates a ReqRes for an async call, and immediately populates it 306 // with the response. We don't complete it until it's been ordered via the channel. 307 func (cli *grpcClient) finishAsyncCall(req *types.Request, res *types.Response) *ReqRes { 308 reqres := NewReqRes(req) 309 reqres.Response = res 310 cli.chReqRes <- reqres // use channel for async responses, since they must be ordered 311 return reqres 312 } 313 314 // finishSyncCall waits for an async call to complete. It is necessary to call all 315 // sync calls asynchronously as well, to maintain call and response ordering via 316 // the channel, and this method will wait until the async call completes. 317 func (cli *grpcClient) finishSyncCall(reqres *ReqRes) *types.Response { 318 // It's possible that the callback is called twice, since the callback can 319 // be called immediately on SetCallback() in addition to after it has been 320 // set. This is because completing the ReqRes happens in a separate critical 321 // section from the one where the callback is called: there is a race where 322 // SetCallback() is called between completing the ReqRes and dispatching the 323 // callback. 324 // 325 // We also buffer the channel with 1 response, since SetCallback() will be 326 // called synchronously if the reqres is already completed, in which case 327 // it will block on sending to the channel since it hasn't gotten around to 328 // receiving from it yet. 329 // 330 // ReqRes should really handle callback dispatch internally, to guarantee 331 // that it's only called once and avoid the above race conditions. 332 var once sync.Once 333 ch := make(chan *types.Response, 1) 334 reqres.SetCallback(func(res *types.Response) { 335 once.Do(func() { 336 ch <- res 337 }) 338 }) 339 return <-ch 340 } 341 342 //---------------------------------------- 343 344 func (cli *grpcClient) FlushSync() error { 345 return nil 346 } 347 348 func (cli *grpcClient) EchoSync(msg string) (*types.ResponseEcho, error) { 349 reqres := cli.EchoAsync(msg) 350 // StopForError should already have been called if error is set 351 return cli.finishSyncCall(reqres).GetEcho(), cli.Error() 352 } 353 354 func (cli *grpcClient) InfoSync(req types.RequestInfo) (*types.ResponseInfo, error) { 355 reqres := cli.InfoAsync(req) 356 return cli.finishSyncCall(reqres).GetInfo(), cli.Error() 357 } 358 359 func (cli *grpcClient) SetOptionSync(req types.RequestSetOption) (*types.ResponseSetOption, error) { 360 reqres := cli.SetOptionAsync(req) 361 return reqres.Response.GetSetOption(), cli.Error() 362 } 363 364 func (cli *grpcClient) DeliverTxSync(params types.RequestDeliverTx) (*types.ResponseDeliverTx, error) { 365 reqres := cli.DeliverTxAsync(params) 366 return cli.finishSyncCall(reqres).GetDeliverTx(), cli.Error() 367 } 368 369 func (cli *grpcClient) CheckTxSync(params types.RequestCheckTx) (*types.ResponseCheckTx, error) { 370 reqres := cli.CheckTxAsync(params) 371 return cli.finishSyncCall(reqres).GetCheckTx(), cli.Error() 372 } 373 374 func (cli *grpcClient) QuerySync(req types.RequestQuery) (*types.ResponseQuery, error) { 375 reqres := cli.QueryAsync(req) 376 return cli.finishSyncCall(reqres).GetQuery(), cli.Error() 377 } 378 379 func (cli *grpcClient) CommitSync() (*types.ResponseCommit, error) { 380 reqres := cli.CommitAsync() 381 return cli.finishSyncCall(reqres).GetCommit(), cli.Error() 382 } 383 384 func (cli *grpcClient) InitChainSync(params types.RequestInitChain) (*types.ResponseInitChain, error) { 385 reqres := cli.InitChainAsync(params) 386 return cli.finishSyncCall(reqres).GetInitChain(), cli.Error() 387 } 388 389 func (cli *grpcClient) BeginBlockSync(params types.RequestBeginBlock) (*types.ResponseBeginBlock, error) { 390 reqres := cli.BeginBlockAsync(params) 391 return cli.finishSyncCall(reqres).GetBeginBlock(), cli.Error() 392 } 393 394 func (cli *grpcClient) EndBlockSync(params types.RequestEndBlock) (*types.ResponseEndBlock, error) { 395 reqres := cli.EndBlockAsync(params) 396 return cli.finishSyncCall(reqres).GetEndBlock(), cli.Error() 397 } 398 399 func (cli *grpcClient) ListSnapshotsSync(params types.RequestListSnapshots) (*types.ResponseListSnapshots, error) { 400 reqres := cli.ListSnapshotsAsync(params) 401 return cli.finishSyncCall(reqres).GetListSnapshots(), cli.Error() 402 } 403 404 func (cli *grpcClient) OfferSnapshotSync(params types.RequestOfferSnapshot) (*types.ResponseOfferSnapshot, error) { 405 reqres := cli.OfferSnapshotAsync(params) 406 return cli.finishSyncCall(reqres).GetOfferSnapshot(), cli.Error() 407 } 408 409 func (cli *grpcClient) LoadSnapshotChunkSync( 410 params types.RequestLoadSnapshotChunk) (*types.ResponseLoadSnapshotChunk, error) { 411 reqres := cli.LoadSnapshotChunkAsync(params) 412 return cli.finishSyncCall(reqres).GetLoadSnapshotChunk(), cli.Error() 413 } 414 415 func (cli *grpcClient) ApplySnapshotChunkSync( 416 params types.RequestApplySnapshotChunk) (*types.ResponseApplySnapshotChunk, error) { 417 reqres := cli.ApplySnapshotChunkAsync(params) 418 return cli.finishSyncCall(reqres).GetApplySnapshotChunk(), cli.Error() 419 }