二、服务注册功能
2.1.服务的业务种类
tx服务
type ServiceServer interface {
Simulate(context.Context, *SimulateRequest) (*SimulateResponse, error)
GetTx(context.Context, *GetTxRequest) (*GetTxResponse, error)
BroadcastTx(context.Context, *BroadcastTxRequest) (*BroadcastTxResponse, error)
GetTxsEvent(context.Context, *GetTxsEventRequest) (*GetTxsEventResponse, error)
GetBlockWithTxs(context.Context, *GetBlockWithTxsRequest) (*GetBlockWithTxsResponse, error)
}
tendermint服务
type ServiceServer interface {
GetNodeInfo(context.Context, *GetNodeInfoRequest) (*GetNodeInfoResponse, error)
GetSyncing(context.Context, *GetSyncingRequest) (*GetSyncingResponse, error)
GetLatestBlock(context.Context, *GetLatestBlockRequest) (*GetLatestBlockResponse, error)
GetBlockByHeight(context.Context, *GetBlockByHeightRequest) (*GetBlockByHeightResponse, error)
GetLatestValidatorSet(context.Context, *GetLatestValidatorSetRequest) (*GetLatestValidatorSetResponse, error)
GetValidatorSetByHeight(context.Context, *GetValidatorSetByHeightRequest) (*GetValidatorSetByHeightResponse, error)
ABCIQuery(context.Context, *ABCIQueryRequest) (*ABCIQueryResponse, error)
}
node服务
type ServiceServer interface {
Config(context.Context, *ConfigRequest) (*ConfigResponse, error)
}
模块服务
这里以bank模块为例进行说明,每个模块可分为msg服务和query服务两大类:
msg服务
// MsgServer is the server API for Msg service.
type MsgServer interface {
Send(context.Context, *MsgSend) (*MsgSendResponse, error)
MultiSend(context.Context, *MsgMultiSend) (*MsgMultiSendResponse, error)
}
query服务
// QueryServer is the server API for Query service.
type QueryServer interface {
Balance(context.Context, *QueryBalanceRequest) (*QueryBalanceResponse, error)
AllBalances(context.Context, *QueryAllBalancesRequest) (*QueryAllBalancesResponse, error)
// ...
}
2.2.服务的实现方式
cosmos-sdk对外提供两种服务实现方式:gRPC和gRPC-Gateway(rest)。两者技术比较如下:
Name | Advantages | Disadvantages |
---|---|---|
gRPC | - can use code-generated stubs in various languages - supports streaming and bidirectional communication (HTTP2) - small wire binary sizes, faster transmission | - based on HTTP2, not available in browsers - learning curve (mostly due to Protobuf) |
REST | - ubiquitous - client libraries in all languages, faster implementation | - only supports unary request-response communication (HTTP1.1) - bigger over-the-wire message sizes (JSON) |
注意:在实现层面上,grpc-gateway服务就是gRPC服务代理,即grpc-gateway服务包括了gRPC服务的客户端。
gRPC-Gateway(REST)服务注册
// api route: 就是基于grpc gateway上的rest服务实现
func (app *App) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) {
clientCtx := apiSvr.ClientCtx
// 注册tx服务rest代理
authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
// 注册tendermint服务rest代理
tmservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
// 注册node服务rest代理
nodeservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
// 注册各个模块服务rest代理(调用各个模块的RegisterGRPCGatewayRoutes)
ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
}
gRPC服务注册
// 注册tx服务
func (app *App) RegisterTxService(clientCtx client.Context) {
authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry)
}
// 注册tendermint服务
func (app *App) RegisterTendermintService(clientCtx client.Context) {
tmservice.RegisterTendermintService(
clientCtx,
app.BaseApp.GRPCQueryRouter(),
app.interfaceRegistry,
app.Query,
)
}
// 注册node服务
func (app *App) RegisterNodeService(clientCtx client.Context) {
nodeservice.RegisterNodeService(clientCtx, app.GRPCQueryRouter())
}
这里有一个例外,对于每个模块gRPC服务是在appCreator函数(直接调用app.New方法)中创建,调用具体方法为:
app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter())
app.mm.RegisterServices(app.configurator)
// 从这里可以看到实际是调用每个模块的RegisterServices
func (m *Manager) RegisterServices(cfg Configurator) {
for _, module := range m.Modules {
module.RegisterServices(cfg)
}
}
以bank模块为例, 在这里我们能发现一个关键成果:每个模块gRPC服务(msg和query)实现实际上就指向模块的Keeper而已。
// RegisterServices registers module services.
func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))
types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
// ...
}