You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

506 lines
16 KiB

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