github.com/line/ostracon@v1.0.10-0.20230328032236-7f20145f065d/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  
    14  	ocabci "github.com/line/ostracon/abci/types"
    15  	tmnet "github.com/line/ostracon/libs/net"
    16  	"github.com/line/ostracon/libs/service"
    17  	tmsync "github.com/line/ostracon/libs/sync"
    18  )
    19  
    20  var _ Client = (*grpcClient)(nil)
    21  
    22  // A stripped copy of the remoteClient that makes
    23  // synchronous calls using grpc
    24  type grpcClient struct {
    25  	service.BaseService
    26  	mustConnect bool
    27  
    28  	client ocabci.ABCIApplicationClient
    29  	conn   *grpc.ClientConn
    30  
    31  	mtx  tmsync.Mutex
    32  	addr string
    33  	err  error
    34  
    35  	globalCbMtx sync.Mutex
    36  	globalCb    func(*ocabci.Request, *ocabci.Response) // listens to all callbacks
    37  }
    38  
    39  func NewGRPCClient(addr string, mustConnect bool) Client {
    40  	cli := &grpcClient{
    41  		addr:        addr,
    42  		mustConnect: mustConnect,
    43  	}
    44  	cli.BaseService = *service.NewBaseService(nil, "grpcClient", cli)
    45  	return cli
    46  }
    47  
    48  func dialerFunc(ctx context.Context, addr string) (net.Conn, error) {
    49  	return tmnet.Connect(addr)
    50  }
    51  
    52  func (cli *grpcClient) OnStart() error {
    53  	if err := cli.BaseService.OnStart(); err != nil {
    54  		return err
    55  	}
    56  
    57  RETRY_LOOP:
    58  	for {
    59  		//nolint:staticcheck // SA1019 Existing use of deprecated but supported dial option.
    60  		conn, err := grpc.Dial(cli.addr, grpc.WithInsecure(), grpc.WithContextDialer(dialerFunc))
    61  		if err != nil {
    62  			if cli.mustConnect {
    63  				return err
    64  			}
    65  			cli.Logger.Error(fmt.Sprintf("abci.grpcClient failed to connect to %v.  Retrying...\n", cli.addr), "err", err)
    66  			time.Sleep(time.Second * dialRetryIntervalSeconds)
    67  			continue RETRY_LOOP
    68  		}
    69  
    70  		cli.Logger.Info("Dialed server. Waiting for echo.", "addr", cli.addr)
    71  		client := ocabci.NewABCIApplicationClient(conn)
    72  		cli.conn = conn
    73  
    74  	ENSURE_CONNECTED:
    75  		for {
    76  			_, err := client.Echo(context.Background(), &types.RequestEcho{Message: "hello"}, grpc.WaitForReady(true))
    77  			if err == nil {
    78  				break ENSURE_CONNECTED
    79  			}
    80  			cli.Logger.Error("Echo failed", "err", err)
    81  			time.Sleep(time.Second * echoRetryIntervalSeconds)
    82  		}
    83  
    84  		cli.client = client
    85  		return nil
    86  	}
    87  }
    88  
    89  func (cli *grpcClient) OnStop() {
    90  	cli.BaseService.OnStop()
    91  
    92  	if cli.conn != nil {
    93  		cli.conn.Close()
    94  	}
    95  }
    96  
    97  func (cli *grpcClient) StopForError(err error) {
    98  	if !cli.IsRunning() {
    99  		return
   100  	}
   101  
   102  	cli.mtx.Lock()
   103  	if cli.err == nil {
   104  		cli.err = err
   105  	}
   106  	cli.mtx.Unlock()
   107  
   108  	cli.Logger.Error(fmt.Sprintf("Stopping abci.grpcClient for error: %v", err.Error()))
   109  	if err := cli.Stop(); err != nil {
   110  		cli.Logger.Error("Error stopping abci.grpcClient", "err", err)
   111  	}
   112  }
   113  
   114  func (cli *grpcClient) Error() error {
   115  	cli.mtx.Lock()
   116  	defer cli.mtx.Unlock()
   117  	return cli.err
   118  }
   119  
   120  func (cli *grpcClient) SetGlobalCallback(globalCb GlobalCallback) {
   121  	cli.globalCbMtx.Lock()
   122  	defer cli.globalCbMtx.Unlock()
   123  	cli.globalCb = globalCb
   124  }
   125  
   126  func (cli *grpcClient) GetGlobalCallback() (cb GlobalCallback) {
   127  	cli.globalCbMtx.Lock()
   128  	defer cli.globalCbMtx.Unlock()
   129  	cb = cli.globalCb
   130  	return cb
   131  }
   132  
   133  //----------------------------------------
   134  // GRPC calls are synchronous, but some callbacks expect to be called asynchronously
   135  // (eg. the mempool expects to be able to lock to remove bad txs from cache).
   136  // To accommodate, we finish each call in its own go-routine,
   137  // which is expensive, but easy - if you want something better, use the socket protocol!
   138  // maybe one day, if people really want it, we use grpc streams,
   139  // but hopefully not :D
   140  
   141  func (cli *grpcClient) EchoAsync(msg string, cb ResponseCallback) *ReqRes {
   142  	req := ocabci.ToRequestEcho(msg)
   143  	res, err := cli.client.Echo(context.Background(), req.GetEcho(), grpc.WaitForReady(true))
   144  	if err != nil {
   145  		cli.StopForError(err)
   146  	}
   147  	return cli.finishAsyncCall(req, &ocabci.Response{Value: &ocabci.Response_Echo{Echo: res}}, cb)
   148  }
   149  
   150  func (cli *grpcClient) FlushAsync(cb ResponseCallback) *ReqRes {
   151  	req := ocabci.ToRequestFlush()
   152  	res, err := cli.client.Flush(context.Background(), req.GetFlush(), grpc.WaitForReady(true))
   153  	if err != nil {
   154  		cli.StopForError(err)
   155  	}
   156  	return cli.finishAsyncCall(req, &ocabci.Response{Value: &ocabci.Response_Flush{Flush: res}}, cb)
   157  }
   158  
   159  func (cli *grpcClient) InfoAsync(params types.RequestInfo, cb ResponseCallback) *ReqRes {
   160  	req := ocabci.ToRequestInfo(params)
   161  	res, err := cli.client.Info(context.Background(), req.GetInfo(), grpc.WaitForReady(true))
   162  	if err != nil {
   163  		cli.StopForError(err)
   164  	}
   165  	return cli.finishAsyncCall(req, &ocabci.Response{Value: &ocabci.Response_Info{Info: res}}, cb)
   166  }
   167  
   168  func (cli *grpcClient) SetOptionAsync(params types.RequestSetOption, cb ResponseCallback) *ReqRes {
   169  	req := ocabci.ToRequestSetOption(params)
   170  	res, err := cli.client.SetOption(context.Background(), req.GetSetOption(), grpc.WaitForReady(true))
   171  	if err != nil {
   172  		cli.StopForError(err)
   173  	}
   174  	return cli.finishAsyncCall(req, &ocabci.Response{Value: &ocabci.Response_SetOption{SetOption: res}}, cb)
   175  }
   176  
   177  func (cli *grpcClient) DeliverTxAsync(params types.RequestDeliverTx, cb ResponseCallback) *ReqRes {
   178  	req := ocabci.ToRequestDeliverTx(params)
   179  	res, err := cli.client.DeliverTx(context.Background(), req.GetDeliverTx(), grpc.WaitForReady(true))
   180  	if err != nil {
   181  		cli.StopForError(err)
   182  	}
   183  	return cli.finishAsyncCall(req, &ocabci.Response{Value: &ocabci.Response_DeliverTx{DeliverTx: res}}, cb)
   184  }
   185  
   186  func (cli *grpcClient) CheckTxAsync(params types.RequestCheckTx, cb ResponseCallback) *ReqRes {
   187  	req := ocabci.ToRequestCheckTx(params)
   188  	res, err := cli.client.CheckTx(context.Background(), req.GetCheckTx(), grpc.WaitForReady(true))
   189  	if err != nil {
   190  		cli.StopForError(err)
   191  	}
   192  	return cli.finishAsyncCall(req, &ocabci.Response{Value: &ocabci.Response_CheckTx{CheckTx: res}}, cb)
   193  }
   194  
   195  func (cli *grpcClient) QueryAsync(params types.RequestQuery, cb ResponseCallback) *ReqRes {
   196  	req := ocabci.ToRequestQuery(params)
   197  	res, err := cli.client.Query(context.Background(), req.GetQuery(), grpc.WaitForReady(true))
   198  	if err != nil {
   199  		cli.StopForError(err)
   200  	}
   201  	return cli.finishAsyncCall(req, &ocabci.Response{Value: &ocabci.Response_Query{Query: res}}, cb)
   202  }
   203  
   204  func (cli *grpcClient) CommitAsync(cb ResponseCallback) *ReqRes {
   205  	req := ocabci.ToRequestCommit()
   206  	res, err := cli.client.Commit(context.Background(), req.GetCommit(), grpc.WaitForReady(true))
   207  	if err != nil {
   208  		cli.StopForError(err)
   209  	}
   210  	return cli.finishAsyncCall(req, &ocabci.Response{Value: &ocabci.Response_Commit{Commit: res}}, cb)
   211  }
   212  
   213  func (cli *grpcClient) InitChainAsync(params types.RequestInitChain, cb ResponseCallback) *ReqRes {
   214  	req := ocabci.ToRequestInitChain(params)
   215  	res, err := cli.client.InitChain(context.Background(), req.GetInitChain(), grpc.WaitForReady(true))
   216  	if err != nil {
   217  		cli.StopForError(err)
   218  	}
   219  	return cli.finishAsyncCall(req, &ocabci.Response{Value: &ocabci.Response_InitChain{InitChain: res}}, cb)
   220  }
   221  
   222  func (cli *grpcClient) BeginBlockAsync(params ocabci.RequestBeginBlock, cb ResponseCallback) *ReqRes {
   223  	req := ocabci.ToRequestBeginBlock(params)
   224  	res, err := cli.client.BeginBlock(context.Background(), req.GetBeginBlock(), grpc.WaitForReady(true))
   225  	if err != nil {
   226  		cli.StopForError(err)
   227  	}
   228  	return cli.finishAsyncCall(req, &ocabci.Response{Value: &ocabci.Response_BeginBlock{BeginBlock: res}}, cb)
   229  }
   230  
   231  func (cli *grpcClient) EndBlockAsync(params types.RequestEndBlock, cb ResponseCallback) *ReqRes {
   232  	req := ocabci.ToRequestEndBlock(params)
   233  	res, err := cli.client.EndBlock(context.Background(), req.GetEndBlock(), grpc.WaitForReady(true))
   234  	if err != nil {
   235  		cli.StopForError(err)
   236  	}
   237  	return cli.finishAsyncCall(req, &ocabci.Response{Value: &ocabci.Response_EndBlock{EndBlock: res}}, cb)
   238  }
   239  
   240  func (cli *grpcClient) BeginRecheckTxAsync(params ocabci.RequestBeginRecheckTx, cb ResponseCallback) *ReqRes {
   241  	req := ocabci.ToRequestBeginRecheckTx(params)
   242  	res, err := cli.client.BeginRecheckTx(context.Background(), req.GetBeginRecheckTx(), grpc.WaitForReady(true))
   243  	if err != nil {
   244  		cli.StopForError(err)
   245  	}
   246  	return cli.finishAsyncCall(req, &ocabci.Response{Value: &ocabci.Response_BeginRecheckTx{BeginRecheckTx: res}}, cb)
   247  }
   248  
   249  func (cli *grpcClient) EndRecheckTxAsync(params ocabci.RequestEndRecheckTx, cb ResponseCallback) *ReqRes {
   250  	req := ocabci.ToRequestEndRecheckTx(params)
   251  	res, err := cli.client.EndRecheckTx(context.Background(), req.GetEndRecheckTx(), grpc.WaitForReady(true))
   252  	if err != nil {
   253  		cli.StopForError(err)
   254  	}
   255  	return cli.finishAsyncCall(req, &ocabci.Response{Value: &ocabci.Response_EndRecheckTx{EndRecheckTx: res}}, cb)
   256  }
   257  
   258  func (cli *grpcClient) ListSnapshotsAsync(params types.RequestListSnapshots, cb ResponseCallback) *ReqRes {
   259  	req := ocabci.ToRequestListSnapshots(params)
   260  	res, err := cli.client.ListSnapshots(context.Background(), req.GetListSnapshots(), grpc.WaitForReady(true))
   261  	if err != nil {
   262  		cli.StopForError(err)
   263  	}
   264  	return cli.finishAsyncCall(req, &ocabci.Response{Value: &ocabci.Response_ListSnapshots{ListSnapshots: res}}, cb)
   265  }
   266  
   267  func (cli *grpcClient) OfferSnapshotAsync(params types.RequestOfferSnapshot, cb ResponseCallback) *ReqRes {
   268  	req := ocabci.ToRequestOfferSnapshot(params)
   269  	res, err := cli.client.OfferSnapshot(context.Background(), req.GetOfferSnapshot(), grpc.WaitForReady(true))
   270  	if err != nil {
   271  		cli.StopForError(err)
   272  	}
   273  	return cli.finishAsyncCall(req, &ocabci.Response{Value: &ocabci.Response_OfferSnapshot{OfferSnapshot: res}}, cb)
   274  }
   275  
   276  func (cli *grpcClient) LoadSnapshotChunkAsync(params types.RequestLoadSnapshotChunk, cb ResponseCallback) *ReqRes {
   277  	req := ocabci.ToRequestLoadSnapshotChunk(params)
   278  	res, err := cli.client.LoadSnapshotChunk(context.Background(), req.GetLoadSnapshotChunk(), grpc.WaitForReady(true))
   279  	if err != nil {
   280  		cli.StopForError(err)
   281  	}
   282  	return cli.finishAsyncCall(req, &ocabci.Response{Value: &ocabci.Response_LoadSnapshotChunk{LoadSnapshotChunk: res}}, cb)
   283  }
   284  
   285  func (cli *grpcClient) ApplySnapshotChunkAsync(params types.RequestApplySnapshotChunk, cb ResponseCallback) *ReqRes {
   286  	req := ocabci.ToRequestApplySnapshotChunk(params)
   287  	res, err := cli.client.ApplySnapshotChunk(context.Background(), req.GetApplySnapshotChunk(), grpc.WaitForReady(true))
   288  	if err != nil {
   289  		cli.StopForError(err)
   290  	}
   291  	return cli.finishAsyncCall(req,
   292  		&ocabci.Response{Value: &ocabci.Response_ApplySnapshotChunk{ApplySnapshotChunk: res}}, cb)
   293  }
   294  
   295  func (cli *grpcClient) finishAsyncCall(req *ocabci.Request, res *ocabci.Response, cb ResponseCallback) *ReqRes {
   296  	reqRes := NewReqRes(req, cb)
   297  
   298  	// goroutine for callbacks
   299  	go func() {
   300  		set := reqRes.SetDone(res)
   301  		if set {
   302  			// Notify client listener if set
   303  			if globalCb := cli.GetGlobalCallback(); globalCb != nil {
   304  				globalCb(req, res)
   305  			}
   306  		}
   307  	}()
   308  
   309  	return reqRes
   310  }
   311  
   312  // ----------------------------------------
   313  func (cli *grpcClient) FlushSync() (*types.ResponseFlush, error) {
   314  	reqres := cli.FlushAsync(nil)
   315  	reqres.Wait()
   316  	return reqres.Response.GetFlush(), cli.Error()
   317  }
   318  
   319  func (cli *grpcClient) EchoSync(msg string) (*types.ResponseEcho, error) {
   320  	reqres := cli.EchoAsync(msg, nil)
   321  	reqres.Wait()
   322  	// StopForError should already have been called if error is set
   323  	return reqres.Response.GetEcho(), cli.Error()
   324  }
   325  
   326  func (cli *grpcClient) InfoSync(req types.RequestInfo) (*types.ResponseInfo, error) {
   327  	reqres := cli.InfoAsync(req, nil)
   328  	reqres.Wait()
   329  	return reqres.Response.GetInfo(), cli.Error()
   330  }
   331  
   332  func (cli *grpcClient) SetOptionSync(req types.RequestSetOption) (*types.ResponseSetOption, error) {
   333  	reqres := cli.SetOptionAsync(req, nil)
   334  	reqres.Wait()
   335  	return reqres.Response.GetSetOption(), cli.Error()
   336  }
   337  
   338  func (cli *grpcClient) DeliverTxSync(params types.RequestDeliverTx) (*types.ResponseDeliverTx, error) {
   339  	reqres := cli.DeliverTxAsync(params, nil)
   340  	reqres.Wait()
   341  	return reqres.Response.GetDeliverTx(), cli.Error()
   342  }
   343  
   344  func (cli *grpcClient) CheckTxSync(params types.RequestCheckTx) (*ocabci.ResponseCheckTx, error) {
   345  	reqres := cli.CheckTxAsync(params, nil)
   346  	reqres.Wait()
   347  	return reqres.Response.GetCheckTx(), cli.Error()
   348  }
   349  
   350  func (cli *grpcClient) QuerySync(req types.RequestQuery) (*types.ResponseQuery, error) {
   351  	reqres := cli.QueryAsync(req, nil)
   352  	reqres.Wait()
   353  	return reqres.Response.GetQuery(), cli.Error()
   354  }
   355  
   356  func (cli *grpcClient) CommitSync() (*types.ResponseCommit, error) {
   357  	reqres := cli.CommitAsync(nil)
   358  	reqres.Wait()
   359  	return reqres.Response.GetCommit(), cli.Error()
   360  }
   361  
   362  func (cli *grpcClient) InitChainSync(params types.RequestInitChain) (*types.ResponseInitChain, error) {
   363  	reqres := cli.InitChainAsync(params, nil)
   364  	reqres.Wait()
   365  	return reqres.Response.GetInitChain(), cli.Error()
   366  }
   367  
   368  func (cli *grpcClient) BeginBlockSync(params ocabci.RequestBeginBlock) (*types.ResponseBeginBlock, error) {
   369  	reqres := cli.BeginBlockAsync(params, nil)
   370  	reqres.Wait()
   371  	return reqres.Response.GetBeginBlock(), cli.Error()
   372  }
   373  
   374  func (cli *grpcClient) EndBlockSync(params types.RequestEndBlock) (*types.ResponseEndBlock, error) {
   375  	reqres := cli.EndBlockAsync(params, nil)
   376  	reqres.Wait()
   377  	return reqres.Response.GetEndBlock(), cli.Error()
   378  }
   379  
   380  func (cli *grpcClient) BeginRecheckTxSync(params ocabci.RequestBeginRecheckTx) (*ocabci.ResponseBeginRecheckTx, error) {
   381  	reqres := cli.BeginRecheckTxAsync(params, nil)
   382  	reqres.Wait()
   383  	return reqres.Response.GetBeginRecheckTx(), cli.Error()
   384  }
   385  
   386  func (cli *grpcClient) EndRecheckTxSync(params ocabci.RequestEndRecheckTx) (*ocabci.ResponseEndRecheckTx, error) {
   387  	reqres := cli.EndRecheckTxAsync(params, nil)
   388  	reqres.Wait()
   389  	return reqres.Response.GetEndRecheckTx(), cli.Error()
   390  }
   391  
   392  func (cli *grpcClient) ListSnapshotsSync(params types.RequestListSnapshots) (*types.ResponseListSnapshots, error) {
   393  	reqres := cli.ListSnapshotsAsync(params, nil)
   394  	reqres.Wait()
   395  	return reqres.Response.GetListSnapshots(), cli.Error()
   396  }
   397  
   398  func (cli *grpcClient) OfferSnapshotSync(params types.RequestOfferSnapshot) (*types.ResponseOfferSnapshot, error) {
   399  	reqres := cli.OfferSnapshotAsync(params, nil)
   400  	reqres.Wait()
   401  	return reqres.Response.GetOfferSnapshot(), cli.Error()
   402  }
   403  
   404  func (cli *grpcClient) LoadSnapshotChunkSync(
   405  	params types.RequestLoadSnapshotChunk) (*types.ResponseLoadSnapshotChunk, error) {
   406  	reqres := cli.LoadSnapshotChunkAsync(params, nil)
   407  	reqres.Wait()
   408  	return reqres.Response.GetLoadSnapshotChunk(), cli.Error()
   409  }
   410  
   411  func (cli *grpcClient) ApplySnapshotChunkSync(
   412  	params types.RequestApplySnapshotChunk) (*types.ResponseApplySnapshotChunk, error) {
   413  	reqres := cli.ApplySnapshotChunkAsync(params, nil)
   414  	reqres.Wait()
   415  	return reqres.Response.GetApplySnapshotChunk(), cli.Error()
   416  }