Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MsgServer to Configurator for ADR 031 wiring #7584

Merged
merged 17 commits into from
Oct 19, 2020
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ func NewSimApp(

app.mm.RegisterInvariants(&app.CrisisKeeper)
app.mm.RegisterRoutes(app.Router(), app.QueryRouter(), encodingConfig.Amino)
app.mm.RegisterServices(module.NewConfigurator(app.GRPCQueryRouter()))
app.mm.RegisterServices(module.NewConfigurator(app.MsgServiceRouter(), app.GRPCQueryRouter()))

// add test gRPC service for testing gRPC queries in isolation
testdata.RegisterQueryServer(app.GRPCQueryRouter(), testdata.QueryImpl{})
Expand Down
111 changes: 111 additions & 0 deletions tests/mocks/account_retriever.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 14 additions & 2 deletions types/module/configurator.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,32 @@ import "github.com/gogo/protobuf/grpc"
// support module object capabilities isolation as described in
// https://github.com/cosmos/cosmos-sdk/issues/7093
type Configurator interface {
// MsgServer returns a grpc.Server instance which allows registering services
// that will handle TxBody.messages in transactions. These Msg's WILL NOT
// be exposed as gRPC services.
MsgServer() grpc.Server

// QueryServer returns a grpc.Server instance which allows registering services
// that will be exposed as gRPC services as well as ABCI query handlers.
QueryServer() grpc.Server
}

type configurator struct {
msgServer grpc.Server
queryServer grpc.Server
}

// NewConfigurator returns a new Configurator instance
func NewConfigurator(queryServer grpc.Server) Configurator {
return configurator{queryServer: queryServer}
func NewConfigurator(msgServer grpc.Server, queryServer grpc.Server) Configurator {
return configurator{msgServer: msgServer, queryServer: queryServer}
aaronc marked this conversation as resolved.
Show resolved Hide resolved
}

var _ Configurator = configurator{}

func (c configurator) MsgServer() grpc.Server {
amaury1093 marked this conversation as resolved.
Show resolved Hide resolved
return c.msgServer
}

// QueryServer implements the Configurator.QueryServer method
func (c configurator) QueryServer() grpc.Server {
return c.queryServer
Expand Down
3 changes: 2 additions & 1 deletion types/module/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,9 @@ func TestManager_RegisterQueryServices(t *testing.T) {
require.NotNil(t, mm)
require.Equal(t, 2, len(mm.Modules))

msgRouter := mocks.NewMockServer(mockCtrl)
queryRouter := mocks.NewMockServer(mockCtrl)
cfg := module.NewConfigurator(queryRouter)
cfg := module.NewConfigurator(msgRouter, queryRouter)
mockAppModule1.EXPECT().RegisterServices(cfg).Times(1)
mockAppModule2.EXPECT().RegisterServices(cfg).Times(1)

Expand Down
142 changes: 142 additions & 0 deletions x/bank/client/cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ import (
"fmt"
"testing"

"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/client/tx"

"github.com/gogo/protobuf/grpc"
grpc2 "google.golang.org/grpc"

"github.com/gogo/protobuf/proto"
"github.com/stretchr/testify/suite"
tmcli "github.com/tendermint/tendermint/libs/cli"
Expand Down Expand Up @@ -295,6 +302,141 @@ func (s *IntegrationTestSuite) TestNewSendTxCmd() {
}
}

// serviceMsgClientConn is an instance of grpc.ClientConn that is used to test building
// transactions with MsgClient's. It is intended to be replaced by the work in
// https://github.com/cosmos/cosmos-sdk/issues/7541 when that is ready.
type serviceMsgClientConn struct {
msgs []sdk.Msg
}

func (t *serviceMsgClientConn) Invoke(_ context.Context, method string, args, _ interface{}, _ ...grpc2.CallOption) error {
req, ok := args.(sdk.MsgRequest)
if !ok {
return fmt.Errorf("%T should implement %T", args, (*sdk.MsgRequest)(nil))
}

err := req.ValidateBasic()
if err != nil {
return err
}

t.msgs = append(t.msgs, sdk.ServiceMsg{
MethodName: method,
Request: req,
})

return nil
}

func (t *serviceMsgClientConn) NewStream(context.Context, *grpc2.StreamDesc, string, ...grpc2.CallOption) (grpc2.ClientStream, error) {
return nil, fmt.Errorf("not supported")
}

var _ grpc.ClientConn = &serviceMsgClientConn{}
aaronc marked this conversation as resolved.
Show resolved Hide resolved

// newSendTxMsgServiceCmd is just for the purpose of testing ServiceMsg's in an end-to-end case. It is effectively
// NewSendTxCmd but using MsgClient.
func newSendTxMsgServiceCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "send [from_key_or_address] [to_address] [amount]",
Short: `Send funds from one account to another. Note, the'--from' flag is
ignored as it is implied from [from_key_or_address].`,
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
cmd.Flags().Set(flags.FlagFrom, args[0])

clientCtx := client.GetClientContextFromCmd(cmd)
clientCtx, err := client.ReadTxCommandFlags(clientCtx, cmd.Flags())
if err != nil {
return err
}

toAddr, err := sdk.AccAddressFromBech32(args[1])
if err != nil {
return err
}

coins, err := sdk.ParseCoins(args[2])
if err != nil {
return err
}

msg := types.NewMsgSend(clientCtx.GetFromAddress(), toAddr, coins)
svcMsgClientConn := &serviceMsgClientConn{}
bankMsgClient := types.NewMsgClient(svcMsgClientConn)
_, err = bankMsgClient.Send(context.Background(), msg)
if err != nil {
return err
}

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), svcMsgClientConn.msgs...)
},
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}

// TestBankMsgService does a basic test of whether or not service Msg's as defined
// in ADR 031 work in the most basic end-to-end case.
func (s *IntegrationTestSuite) TestBankMsgService() {
val := s.network.Validators[0]

testCases := []struct {
name string
from, to sdk.AccAddress
amount sdk.Coins
args []string
expectErr bool
respType proto.Message
expectedCode uint32
rawLogContains string
}{
{
"valid transaction",
val.Address,
val.Address,
sdk.NewCoins(
sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), sdk.NewInt(10)),
sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)),
),
[]string{
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
false,
&sdk.TxResponse{},
0,
"/cosmos.bank.v1beta1.Msg/Send", // indicates we are using ServiceMsg and not a regular Msg
},
}

for _, tc := range testCases {
tc := tc

s.Run(tc.name, func() {
clientCtx := val.ClientCtx

args := []string{tc.from.String(), tc.to.String(), tc.amount.String()}
args = append(args, tc.args...)

bz, err := clitestutil.ExecTestCLICmd(clientCtx, newSendTxMsgServiceCmd(), args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)

s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(bz.Bytes(), tc.respType), bz.String())
txResp := tc.respType.(*sdk.TxResponse)
s.Require().Equal(tc.expectedCode, txResp.Code)
s.Require().Contains(txResp.RawLog, tc.rawLogContains)
}
})
}
}

func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
}
Expand Down
4 changes: 2 additions & 2 deletions x/bank/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,9 @@ type AppModule struct {
accountKeeper types.AccountKeeper
}

// RegisterQueryService registers a GRPC query service to respond to the
// module-specific GRPC queries.
// 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)
}

Expand Down
7 changes: 4 additions & 3 deletions x/crisis/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,10 @@ func (AppModule) QuerierRoute() string { return "" }
// LegacyQuerierHandler returns no sdk.Querier.
func (AppModule) LegacyQuerierHandler(*codec.LegacyAmino) sdk.Querier { return nil }

// RegisterQueryService registers a GRPC query service to respond to the
// module-specific GRPC queries.
func (am AppModule) RegisterServices(module.Configurator) {}
// RegisterServices registers module services.
func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterMsgServer(cfg.MsgServer(), am.keeper)
}

// InitGenesis performs genesis initialization for the crisis module. It returns
// no validator updates.
Expand Down
4 changes: 2 additions & 2 deletions x/distribution/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,9 @@ func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sd
return keeper.NewQuerier(am.keeper, legacyQuerierCdc)
}

// RegisterQueryService registers a GRPC query service to respond to the
// module-specific GRPC queries.
// 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)
}

Expand Down
4 changes: 2 additions & 2 deletions x/evidence/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,9 @@ func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sd
return keeper.NewQuerier(am.keeper, legacyQuerierCdc)
}

// RegisterQueryService registers a GRPC query service to respond to the
// module-specific GRPC queries.
// 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)
}

Expand Down
Loading