github.com/fiagdao/tendermint@v0.32.11-0.20220824195748-2087fcc480c1/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  )
    16  
    17  var _ Client = (*grpcClient)(nil)
    18  
    19  // A stripped copy of the remoteClient that makes
    20  // synchronous calls using grpc
    21  type grpcClient struct {
    22  	service.BaseService
    23  	mustConnect bool
    24  
    25  	client types.ABCIApplicationClient
    26  	conn   *grpc.ClientConn
    27  
    28  	mtx   sync.Mutex
    29  	addr  string
    30  	err   error
    31  	resCb func(*types.Request, *types.Response) // listens to all callbacks
    32  }
    33  
    34  func NewGRPCClient(addr string, mustConnect bool) Client {
    35  	cli := &grpcClient{
    36  		addr:        addr,
    37  		mustConnect: mustConnect,
    38  	}
    39  	cli.BaseService = *service.NewBaseService(nil, "grpcClient", cli)
    40  	return cli
    41  }
    42  
    43  func dialerFunc(ctx context.Context, addr string) (net.Conn, error) {
    44  	return tmnet.Connect(addr)
    45  }
    46  
    47  func (cli *grpcClient) OnStart() error {
    48  	if err := cli.BaseService.OnStart(); err != nil {
    49  		return err
    50  	}
    51  RETRY_LOOP:
    52  	for {
    53  		conn, err := grpc.Dial(cli.addr, grpc.WithInsecure(), grpc.WithContextDialer(dialerFunc))
    54  		if err != nil {
    55  			if cli.mustConnect {
    56  				return err
    57  			}
    58  			cli.Logger.Error(fmt.Sprintf("abci.grpcClient failed to connect to %v.  Retrying...\n", cli.addr), "err", err)
    59  			time.Sleep(time.Second * dialRetryIntervalSeconds)
    60  			continue RETRY_LOOP
    61  		}
    62  
    63  		cli.Logger.Info("Dialed server. Waiting for echo.", "addr", cli.addr)
    64  		client := types.NewABCIApplicationClient(conn)
    65  		cli.conn = conn
    66  
    67  	ENSURE_CONNECTED:
    68  		for {
    69  			_, err := client.Echo(context.Background(), &types.RequestEcho{Message: "hello"}, grpc.WaitForReady(true))
    70  			if err == nil {
    71  				break ENSURE_CONNECTED
    72  			}
    73  			cli.Logger.Error("Echo failed", "err", err)
    74  			time.Sleep(time.Second * echoRetryIntervalSeconds)
    75  		}
    76  
    77  		cli.client = client
    78  		return nil
    79  	}
    80  }
    81  
    82  func (cli *grpcClient) OnStop() {
    83  	cli.BaseService.OnStop()
    84  
    85  	if cli.conn != nil {
    86  		cli.conn.Close()
    87  	}
    88  }
    89  
    90  func (cli *grpcClient) StopForError(err error) {
    91  	cli.mtx.Lock()
    92  	if !cli.IsRunning() {
    93  		return
    94  	}
    95  
    96  	if cli.err == nil {
    97  		cli.err = err
    98  	}
    99  	cli.mtx.Unlock()
   100  
   101  	cli.Logger.Error(fmt.Sprintf("Stopping abci.grpcClient for error: %v", err.Error()))
   102  	cli.Stop()
   103  }
   104  
   105  func (cli *grpcClient) Error() error {
   106  	cli.mtx.Lock()
   107  	defer cli.mtx.Unlock()
   108  	return cli.err
   109  }
   110  
   111  // Set listener for all responses
   112  // NOTE: callback may get internally generated flush responses.
   113  func (cli *grpcClient) SetResponseCallback(resCb Callback) {
   114  	cli.mtx.Lock()
   115  	cli.resCb = resCb
   116  	cli.mtx.Unlock()
   117  }
   118  
   119  //----------------------------------------
   120  // GRPC calls are synchronous, but some callbacks expect to be called asynchronously
   121  // (eg. the mempool expects to be able to lock to remove bad txs from cache).
   122  // To accommodate, we finish each call in its own go-routine,
   123  // which is expensive, but easy - if you want something better, use the socket protocol!
   124  // maybe one day, if people really want it, we use grpc streams,
   125  // but hopefully not :D
   126  
   127  func (cli *grpcClient) EchoAsync(msg string) *ReqRes {
   128  	req := types.ToRequestEcho(msg)
   129  	res, err := cli.client.Echo(context.Background(), req.GetEcho(), grpc.WaitForReady(true))
   130  	if err != nil {
   131  		cli.StopForError(err)
   132  	}
   133  	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_Echo{Echo: res}})
   134  }
   135  
   136  func (cli *grpcClient) FlushAsync() *ReqRes {
   137  	req := types.ToRequestFlush()
   138  	res, err := cli.client.Flush(context.Background(), req.GetFlush(), grpc.WaitForReady(true))
   139  	if err != nil {
   140  		cli.StopForError(err)
   141  	}
   142  	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_Flush{Flush: res}})
   143  }
   144  
   145  func (cli *grpcClient) InfoAsync(params types.RequestInfo) *ReqRes {
   146  	req := types.ToRequestInfo(params)
   147  	res, err := cli.client.Info(context.Background(), req.GetInfo(), grpc.WaitForReady(true))
   148  	if err != nil {
   149  		cli.StopForError(err)
   150  	}
   151  	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_Info{Info: res}})
   152  }
   153  
   154  func (cli *grpcClient) SetOptionAsync(params types.RequestSetOption) *ReqRes {
   155  	req := types.ToRequestSetOption(params)
   156  	res, err := cli.client.SetOption(context.Background(), req.GetSetOption(), grpc.WaitForReady(true))
   157  	if err != nil {
   158  		cli.StopForError(err)
   159  	}
   160  	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_SetOption{SetOption: res}})
   161  }
   162  
   163  func (cli *grpcClient) DeliverTxAsync(params types.RequestDeliverTx) *ReqRes {
   164  	req := types.ToRequestDeliverTx(params)
   165  	res, err := cli.client.DeliverTx(context.Background(), req.GetDeliverTx(), grpc.WaitForReady(true))
   166  	if err != nil {
   167  		cli.StopForError(err)
   168  	}
   169  	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_DeliverTx{DeliverTx: res}})
   170  }
   171  
   172  func (cli *grpcClient) CheckTxAsync(params types.RequestCheckTx) *ReqRes {
   173  	req := types.ToRequestCheckTx(params)
   174  	res, err := cli.client.CheckTx(context.Background(), req.GetCheckTx(), grpc.WaitForReady(true))
   175  	if err != nil {
   176  		cli.StopForError(err)
   177  	}
   178  	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_CheckTx{CheckTx: res}})
   179  }
   180  
   181  func (cli *grpcClient) QueryAsync(params types.RequestQuery) *ReqRes {
   182  	req := types.ToRequestQuery(params)
   183  	res, err := cli.client.Query(context.Background(), req.GetQuery(), grpc.WaitForReady(true))
   184  	if err != nil {
   185  		cli.StopForError(err)
   186  	}
   187  	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_Query{Query: res}})
   188  }
   189  
   190  func (cli *grpcClient) CommitAsync() *ReqRes {
   191  	req := types.ToRequestCommit()
   192  	res, err := cli.client.Commit(context.Background(), req.GetCommit(), grpc.WaitForReady(true))
   193  	if err != nil {
   194  		cli.StopForError(err)
   195  	}
   196  	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_Commit{Commit: res}})
   197  }
   198  
   199  func (cli *grpcClient) InitChainAsync(params types.RequestInitChain) *ReqRes {
   200  	req := types.ToRequestInitChain(params)
   201  	res, err := cli.client.InitChain(context.Background(), req.GetInitChain(), grpc.WaitForReady(true))
   202  	if err != nil {
   203  		cli.StopForError(err)
   204  	}
   205  	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_InitChain{InitChain: res}})
   206  }
   207  
   208  func (cli *grpcClient) BeginBlockAsync(params types.RequestBeginBlock) *ReqRes {
   209  	req := types.ToRequestBeginBlock(params)
   210  	res, err := cli.client.BeginBlock(context.Background(), req.GetBeginBlock(), grpc.WaitForReady(true))
   211  	if err != nil {
   212  		cli.StopForError(err)
   213  	}
   214  	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_BeginBlock{BeginBlock: res}})
   215  }
   216  
   217  func (cli *grpcClient) EndBlockAsync(params types.RequestEndBlock) *ReqRes {
   218  	req := types.ToRequestEndBlock(params)
   219  	res, err := cli.client.EndBlock(context.Background(), req.GetEndBlock(), grpc.WaitForReady(true))
   220  	if err != nil {
   221  		cli.StopForError(err)
   222  	}
   223  	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_EndBlock{EndBlock: res}})
   224  }
   225  
   226  func (cli *grpcClient) finishAsyncCall(req *types.Request, res *types.Response) *ReqRes {
   227  	reqres := NewReqRes(req)
   228  	reqres.Response = res // Set response
   229  	reqres.Done()         // Release waiters
   230  	reqres.SetDone()      // so reqRes.SetCallback will run the callback
   231  
   232  	// goroutine for callbacks
   233  	go func() {
   234  		cli.mtx.Lock()
   235  		defer cli.mtx.Unlock()
   236  
   237  		// Notify client listener if set
   238  		if cli.resCb != nil {
   239  			cli.resCb(reqres.Request, res)
   240  		}
   241  
   242  		// Notify reqRes listener if set
   243  		if cb := reqres.GetCallback(); cb != nil {
   244  			cb(res)
   245  		}
   246  	}()
   247  
   248  	return reqres
   249  }
   250  
   251  //----------------------------------------
   252  
   253  func (cli *grpcClient) FlushSync() error {
   254  	return nil
   255  }
   256  
   257  func (cli *grpcClient) EchoSync(msg string) (*types.ResponseEcho, error) {
   258  	reqres := cli.EchoAsync(msg)
   259  	// StopForError should already have been called if error is set
   260  	return reqres.Response.GetEcho(), cli.Error()
   261  }
   262  
   263  func (cli *grpcClient) InfoSync(req types.RequestInfo) (*types.ResponseInfo, error) {
   264  	reqres := cli.InfoAsync(req)
   265  	return reqres.Response.GetInfo(), cli.Error()
   266  }
   267  
   268  func (cli *grpcClient) SetOptionSync(req types.RequestSetOption) (*types.ResponseSetOption, error) {
   269  	reqres := cli.SetOptionAsync(req)
   270  	return reqres.Response.GetSetOption(), cli.Error()
   271  }
   272  
   273  func (cli *grpcClient) DeliverTxSync(params types.RequestDeliverTx) (*types.ResponseDeliverTx, error) {
   274  	reqres := cli.DeliverTxAsync(params)
   275  	return reqres.Response.GetDeliverTx(), cli.Error()
   276  }
   277  
   278  func (cli *grpcClient) CheckTxSync(params types.RequestCheckTx) (*types.ResponseCheckTx, error) {
   279  	reqres := cli.CheckTxAsync(params)
   280  	return reqres.Response.GetCheckTx(), cli.Error()
   281  }
   282  
   283  func (cli *grpcClient) QuerySync(req types.RequestQuery) (*types.ResponseQuery, error) {
   284  	reqres := cli.QueryAsync(req)
   285  	return reqres.Response.GetQuery(), cli.Error()
   286  }
   287  
   288  func (cli *grpcClient) CommitSync() (*types.ResponseCommit, error) {
   289  	reqres := cli.CommitAsync()
   290  	return reqres.Response.GetCommit(), cli.Error()
   291  }
   292  
   293  func (cli *grpcClient) InitChainSync(params types.RequestInitChain) (*types.ResponseInitChain, error) {
   294  	reqres := cli.InitChainAsync(params)
   295  	return reqres.Response.GetInitChain(), cli.Error()
   296  }
   297  
   298  func (cli *grpcClient) BeginBlockSync(params types.RequestBeginBlock) (*types.ResponseBeginBlock, error) {
   299  	reqres := cli.BeginBlockAsync(params)
   300  	return reqres.Response.GetBeginBlock(), cli.Error()
   301  }
   302  
   303  func (cli *grpcClient) EndBlockSync(params types.RequestEndBlock) (*types.ResponseEndBlock, error) {
   304  	reqres := cli.EndBlockAsync(params)
   305  	return reqres.Response.GetEndBlock(), cli.Error()
   306  }