gitlab.com/gpdionisio/tendermint@v0.34.19-dev2/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/tendermint/tendermint/abci/types" 13 tmnet "github.com/tendermint/tendermint/libs/net" 14 "github.com/tendermint/tendermint/libs/service" 15 tmsync "github.com/tendermint/tendermint/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 //nolint:staticcheck // SA1019 Existing use of deprecated but supported dial option. 94 conn, err := grpc.Dial(cli.addr, grpc.WithInsecure(), grpc.WithContextDialer(dialerFunc)) 95 if err != nil { 96 if cli.mustConnect { 97 return err 98 } 99 cli.Logger.Error(fmt.Sprintf("abci.grpcClient failed to connect to %v. Retrying...\n", cli.addr), "err", err) 100 time.Sleep(time.Second * dialRetryIntervalSeconds) 101 continue RETRY_LOOP 102 } 103 104 cli.Logger.Info("Dialed server. Waiting for echo.", "addr", cli.addr) 105 client := types.NewABCIApplicationClient(conn) 106 cli.conn = conn 107 108 ENSURE_CONNECTED: 109 for { 110 _, err := client.Echo(context.Background(), &types.RequestEcho{Message: "hello"}, grpc.WaitForReady(true)) 111 if err == nil { 112 break ENSURE_CONNECTED 113 } 114 cli.Logger.Error("Echo failed", "err", err) 115 time.Sleep(time.Second * echoRetryIntervalSeconds) 116 } 117 118 cli.client = client 119 return nil 120 } 121 } 122 123 func (cli *grpcClient) OnStop() { 124 cli.BaseService.OnStop() 125 126 if cli.conn != nil { 127 cli.conn.Close() 128 } 129 close(cli.chReqRes) 130 } 131 132 func (cli *grpcClient) StopForError(err error) { 133 if !cli.IsRunning() { 134 return 135 } 136 137 cli.mtx.Lock() 138 if cli.err == nil { 139 cli.err = err 140 } 141 cli.mtx.Unlock() 142 143 cli.Logger.Error(fmt.Sprintf("Stopping abci.grpcClient for error: %v", err.Error())) 144 if err := cli.Stop(); err != nil { 145 cli.Logger.Error("Error stopping abci.grpcClient", "err", err) 146 } 147 } 148 149 func (cli *grpcClient) Error() error { 150 cli.mtx.Lock() 151 defer cli.mtx.Unlock() 152 return cli.err 153 } 154 155 // Set listener for all responses 156 // NOTE: callback may get internally generated flush responses. 157 func (cli *grpcClient) SetResponseCallback(resCb Callback) { 158 cli.mtx.Lock() 159 cli.resCb = resCb 160 cli.mtx.Unlock() 161 } 162 163 //---------------------------------------- 164 // GRPC calls are synchronous, but some callbacks expect to be called asynchronously 165 // (eg. the mempool expects to be able to lock to remove bad txs from cache). 166 // To accommodate, we finish each call in its own go-routine, 167 // which is expensive, but easy - if you want something better, use the socket protocol! 168 // maybe one day, if people really want it, we use grpc streams, 169 // but hopefully not :D 170 171 func (cli *grpcClient) EchoAsync(msg string) *ReqRes { 172 req := types.ToRequestEcho(msg) 173 res, err := cli.client.Echo(context.Background(), req.GetEcho(), grpc.WaitForReady(true)) 174 if err != nil { 175 cli.StopForError(err) 176 } 177 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_Echo{Echo: res}}) 178 } 179 180 func (cli *grpcClient) FlushAsync() *ReqRes { 181 req := types.ToRequestFlush() 182 res, err := cli.client.Flush(context.Background(), req.GetFlush(), grpc.WaitForReady(true)) 183 if err != nil { 184 cli.StopForError(err) 185 } 186 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_Flush{Flush: res}}) 187 } 188 189 func (cli *grpcClient) InfoAsync(params types.RequestInfo) *ReqRes { 190 req := types.ToRequestInfo(params) 191 res, err := cli.client.Info(context.Background(), req.GetInfo(), grpc.WaitForReady(true)) 192 if err != nil { 193 cli.StopForError(err) 194 } 195 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_Info{Info: res}}) 196 } 197 198 func (cli *grpcClient) SetOptionAsync(params types.RequestSetOption) *ReqRes { 199 req := types.ToRequestSetOption(params) 200 res, err := cli.client.SetOption(context.Background(), req.GetSetOption(), grpc.WaitForReady(true)) 201 if err != nil { 202 cli.StopForError(err) 203 } 204 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_SetOption{SetOption: res}}) 205 } 206 207 func (cli *grpcClient) DeliverTxAsync(params types.RequestDeliverTx) *ReqRes { 208 req := types.ToRequestDeliverTx(params) 209 res, err := cli.client.DeliverTx(context.Background(), req.GetDeliverTx(), grpc.WaitForReady(true)) 210 if err != nil { 211 cli.StopForError(err) 212 } 213 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_DeliverTx{DeliverTx: res}}) 214 } 215 216 func (cli *grpcClient) CheckTxAsync(params types.RequestCheckTx) *ReqRes { 217 req := types.ToRequestCheckTx(params) 218 res, err := cli.client.CheckTx(context.Background(), req.GetCheckTx(), grpc.WaitForReady(true)) 219 if err != nil { 220 cli.StopForError(err) 221 } 222 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_CheckTx{CheckTx: res}}) 223 } 224 225 func (cli *grpcClient) QueryAsync(params types.RequestQuery) *ReqRes { 226 req := types.ToRequestQuery(params) 227 res, err := cli.client.Query(context.Background(), req.GetQuery(), grpc.WaitForReady(true)) 228 if err != nil { 229 cli.StopForError(err) 230 } 231 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_Query{Query: res}}) 232 } 233 234 func (cli *grpcClient) CommitAsync() *ReqRes { 235 req := types.ToRequestCommit() 236 res, err := cli.client.Commit(context.Background(), req.GetCommit(), grpc.WaitForReady(true)) 237 if err != nil { 238 cli.StopForError(err) 239 } 240 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_Commit{Commit: res}}) 241 } 242 243 func (cli *grpcClient) InitChainAsync(params types.RequestInitChain) *ReqRes { 244 req := types.ToRequestInitChain(params) 245 res, err := cli.client.InitChain(context.Background(), req.GetInitChain(), grpc.WaitForReady(true)) 246 if err != nil { 247 cli.StopForError(err) 248 } 249 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_InitChain{InitChain: res}}) 250 } 251 252 func (cli *grpcClient) BeginBlockAsync(params types.RequestBeginBlock) *ReqRes { 253 req := types.ToRequestBeginBlock(params) 254 res, err := cli.client.BeginBlock(context.Background(), req.GetBeginBlock(), grpc.WaitForReady(true)) 255 if err != nil { 256 cli.StopForError(err) 257 } 258 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_BeginBlock{BeginBlock: res}}) 259 } 260 261 func (cli *grpcClient) EndBlockAsync(params types.RequestEndBlock) *ReqRes { 262 req := types.ToRequestEndBlock(params) 263 res, err := cli.client.EndBlock(context.Background(), req.GetEndBlock(), grpc.WaitForReady(true)) 264 if err != nil { 265 cli.StopForError(err) 266 } 267 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_EndBlock{EndBlock: res}}) 268 } 269 270 func (cli *grpcClient) ListSnapshotsAsync(params types.RequestListSnapshots) *ReqRes { 271 req := types.ToRequestListSnapshots(params) 272 res, err := cli.client.ListSnapshots(context.Background(), req.GetListSnapshots(), grpc.WaitForReady(true)) 273 if err != nil { 274 cli.StopForError(err) 275 } 276 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_ListSnapshots{ListSnapshots: res}}) 277 } 278 279 func (cli *grpcClient) OfferSnapshotAsync(params types.RequestOfferSnapshot) *ReqRes { 280 req := types.ToRequestOfferSnapshot(params) 281 res, err := cli.client.OfferSnapshot(context.Background(), req.GetOfferSnapshot(), grpc.WaitForReady(true)) 282 if err != nil { 283 cli.StopForError(err) 284 } 285 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_OfferSnapshot{OfferSnapshot: res}}) 286 } 287 288 func (cli *grpcClient) LoadSnapshotChunkAsync(params types.RequestLoadSnapshotChunk) *ReqRes { 289 req := types.ToRequestLoadSnapshotChunk(params) 290 res, err := cli.client.LoadSnapshotChunk(context.Background(), req.GetLoadSnapshotChunk(), grpc.WaitForReady(true)) 291 if err != nil { 292 cli.StopForError(err) 293 } 294 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_LoadSnapshotChunk{LoadSnapshotChunk: res}}) 295 } 296 297 func (cli *grpcClient) ApplySnapshotChunkAsync(params types.RequestApplySnapshotChunk) *ReqRes { 298 req := types.ToRequestApplySnapshotChunk(params) 299 res, err := cli.client.ApplySnapshotChunk(context.Background(), req.GetApplySnapshotChunk(), grpc.WaitForReady(true)) 300 if err != nil { 301 cli.StopForError(err) 302 } 303 return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_ApplySnapshotChunk{ApplySnapshotChunk: res}}) 304 } 305 306 // finishAsyncCall creates a ReqRes for an async call, and immediately populates it 307 // with the response. We don't complete it until it's been ordered via the channel. 308 func (cli *grpcClient) finishAsyncCall(req *types.Request, res *types.Response) *ReqRes { 309 reqres := NewReqRes(req) 310 reqres.Response = res 311 cli.chReqRes <- reqres // use channel for async responses, since they must be ordered 312 return reqres 313 } 314 315 // finishSyncCall waits for an async call to complete. It is necessary to call all 316 // sync calls asynchronously as well, to maintain call and response ordering via 317 // the channel, and this method will wait until the async call completes. 318 func (cli *grpcClient) finishSyncCall(reqres *ReqRes) *types.Response { 319 // It's possible that the callback is called twice, since the callback can 320 // be called immediately on SetCallback() in addition to after it has been 321 // set. This is because completing the ReqRes happens in a separate critical 322 // section from the one where the callback is called: there is a race where 323 // SetCallback() is called between completing the ReqRes and dispatching the 324 // callback. 325 // 326 // We also buffer the channel with 1 response, since SetCallback() will be 327 // called synchronously if the reqres is already completed, in which case 328 // it will block on sending to the channel since it hasn't gotten around to 329 // receiving from it yet. 330 // 331 // ReqRes should really handle callback dispatch internally, to guarantee 332 // that it's only called once and avoid the above race conditions. 333 var once sync.Once 334 ch := make(chan *types.Response, 1) 335 reqres.SetCallback(func(res *types.Response) { 336 once.Do(func() { 337 ch <- res 338 }) 339 }) 340 return <-ch 341 } 342 343 //---------------------------------------- 344 345 func (cli *grpcClient) FlushSync() error { 346 return nil 347 } 348 349 func (cli *grpcClient) EchoSync(msg string) (*types.ResponseEcho, error) { 350 reqres := cli.EchoAsync(msg) 351 // StopForError should already have been called if error is set 352 return cli.finishSyncCall(reqres).GetEcho(), cli.Error() 353 } 354 355 func (cli *grpcClient) InfoSync(req types.RequestInfo) (*types.ResponseInfo, error) { 356 reqres := cli.InfoAsync(req) 357 return cli.finishSyncCall(reqres).GetInfo(), cli.Error() 358 } 359 360 func (cli *grpcClient) SetOptionSync(req types.RequestSetOption) (*types.ResponseSetOption, error) { 361 reqres := cli.SetOptionAsync(req) 362 return reqres.Response.GetSetOption(), cli.Error() 363 } 364 365 func (cli *grpcClient) DeliverTxSync(params types.RequestDeliverTx) (*types.ResponseDeliverTx, error) { 366 reqres := cli.DeliverTxAsync(params) 367 return cli.finishSyncCall(reqres).GetDeliverTx(), cli.Error() 368 } 369 370 func (cli *grpcClient) CheckTxSync(params types.RequestCheckTx) (*types.ResponseCheckTx, error) { 371 reqres := cli.CheckTxAsync(params) 372 return cli.finishSyncCall(reqres).GetCheckTx(), cli.Error() 373 } 374 375 func (cli *grpcClient) QuerySync(req types.RequestQuery) (*types.ResponseQuery, error) { 376 reqres := cli.QueryAsync(req) 377 return cli.finishSyncCall(reqres).GetQuery(), cli.Error() 378 } 379 380 func (cli *grpcClient) CommitSync() (*types.ResponseCommit, error) { 381 reqres := cli.CommitAsync() 382 return cli.finishSyncCall(reqres).GetCommit(), cli.Error() 383 } 384 385 func (cli *grpcClient) InitChainSync(params types.RequestInitChain) (*types.ResponseInitChain, error) { 386 reqres := cli.InitChainAsync(params) 387 return cli.finishSyncCall(reqres).GetInitChain(), cli.Error() 388 } 389 390 func (cli *grpcClient) BeginBlockSync(params types.RequestBeginBlock) (*types.ResponseBeginBlock, error) { 391 reqres := cli.BeginBlockAsync(params) 392 return cli.finishSyncCall(reqres).GetBeginBlock(), cli.Error() 393 } 394 395 func (cli *grpcClient) EndBlockSync(params types.RequestEndBlock) (*types.ResponseEndBlock, error) { 396 reqres := cli.EndBlockAsync(params) 397 return cli.finishSyncCall(reqres).GetEndBlock(), cli.Error() 398 } 399 400 func (cli *grpcClient) ListSnapshotsSync(params types.RequestListSnapshots) (*types.ResponseListSnapshots, error) { 401 reqres := cli.ListSnapshotsAsync(params) 402 return cli.finishSyncCall(reqres).GetListSnapshots(), cli.Error() 403 } 404 405 func (cli *grpcClient) OfferSnapshotSync(params types.RequestOfferSnapshot) (*types.ResponseOfferSnapshot, error) { 406 reqres := cli.OfferSnapshotAsync(params) 407 return cli.finishSyncCall(reqres).GetOfferSnapshot(), cli.Error() 408 } 409 410 func (cli *grpcClient) LoadSnapshotChunkSync( 411 params types.RequestLoadSnapshotChunk) (*types.ResponseLoadSnapshotChunk, error) { 412 reqres := cli.LoadSnapshotChunkAsync(params) 413 return cli.finishSyncCall(reqres).GetLoadSnapshotChunk(), cli.Error() 414 } 415 416 func (cli *grpcClient) ApplySnapshotChunkSync( 417 params types.RequestApplySnapshotChunk) (*types.ResponseApplySnapshotChunk, error) { 418 reqres := cli.ApplySnapshotChunkAsync(params) 419 return cli.finishSyncCall(reqres).GetApplySnapshotChunk(), cli.Error() 420 }