diff --git a/tests/integration/auth/keeper/msg_server_test.go b/tests/integration/auth/keeper/msg_server_test.go new file mode 100644 index 000000000000..119b4b6fb20d --- /dev/null +++ b/tests/integration/auth/keeper/msg_server_test.go @@ -0,0 +1,246 @@ +package keeper_test + +import ( + "context" + "testing" + + "gotest.tools/v3/assert" + + signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1" + "cosmossdk.io/core/appmodule" + "cosmossdk.io/log" + sdkmath "cosmossdk.io/math" + storetypes "cosmossdk.io/store/types" + "cosmossdk.io/x/accounts" + baseaccount "cosmossdk.io/x/accounts/defaults/base" + "cosmossdk.io/x/auth" + authkeeper "cosmossdk.io/x/auth/keeper" + authsims "cosmossdk.io/x/auth/simulation" + "cosmossdk.io/x/auth/types" + authtypes "cosmossdk.io/x/auth/types" + "cosmossdk.io/x/bank" + banktypes "cosmossdk.io/x/bank/types" + minttypes "cosmossdk.io/x/mint/types" + "cosmossdk.io/x/tx/signing" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" + addresscodec "github.com/cosmos/cosmos-sdk/codec/address" + codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/runtime" + "github.com/cosmos/cosmos-sdk/testutil/integration" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + sdk "github.com/cosmos/cosmos-sdk/types" + moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" +) + +type fixture struct { + app *integration.App + + cdc codec.Codec + + authKeeper authkeeper.AccountKeeper + accountsKeeper accounts.Keeper +} + +var _ signing.SignModeHandler = directHandler{} + +type directHandler struct{} + +func (s directHandler) Mode() signingv1beta1.SignMode { + return signingv1beta1.SignMode_SIGN_MODE_DIRECT +} + +func (s directHandler) GetSignBytes(_ context.Context, _ signing.SignerData, _ signing.TxData) ([]byte, error) { + panic("not implemented") +} + +func initFixture(t *testing.T) *fixture { + t.Helper() + keys := storetypes.NewKVStoreKeys( + authtypes.StoreKey, banktypes.StoreKey, accounts.StoreKey, + ) + encodingCfg := moduletestutil.MakeTestEncodingConfig(codectestutil.CodecOptions{}, auth.AppModule{}, bank.AppModule{}) + cdc := encodingCfg.Codec + + logger := log.NewTestLogger(t) + cms := integration.CreateMultiStore(keys, logger) + + newCtx := sdk.NewContext(cms, true, logger) + + router := baseapp.NewMsgServiceRouter() + router.SetInterfaceRegistry(cdc.InterfaceRegistry()) + queryRouter := baseapp.NewGRPCQueryRouter() + queryRouter.SetInterfaceRegistry(cdc.InterfaceRegistry()) + + handler := directHandler{} + account := baseaccount.NewAccount("base", signing.NewHandlerMap(handler)) + accountsKeeper, err := accounts.NewKeeper( + cdc, + runtime.NewEnvironment(runtime.NewKVStoreService(keys[accounts.StoreKey]), log.NewNopLogger()), + addresscodec.NewBech32Codec("cosmos"), + router, + queryRouter, + cdc.InterfaceRegistry(), + account, + ) + assert.NilError(t, err) + + authority := authtypes.NewModuleAddress("gov") + + authKeeper := authkeeper.NewAccountKeeper( + runtime.NewEnvironment(runtime.NewKVStoreService(keys[authtypes.StoreKey]), log.NewNopLogger()), + cdc, + authtypes.ProtoBaseAccount, + accountsKeeper, + map[string][]string{minttypes.ModuleName: {authtypes.Minter}}, + addresscodec.NewBech32Codec(sdk.Bech32MainPrefix), + sdk.Bech32MainPrefix, + authority.String(), + ) + + accountsModule := accounts.NewAppModule(cdc, accountsKeeper) + authModule := auth.NewAppModule(cdc, authKeeper, accountsKeeper, authsims.RandomGenesisAccounts) + + integrationApp := integration.NewIntegrationApp(newCtx, logger, keys, cdc, + encodingCfg.InterfaceRegistry.SigningContext().AddressCodec(), + encodingCfg.InterfaceRegistry.SigningContext().ValidatorAddressCodec(), + map[string]appmodule.AppModule{ + accounts.ModuleName: accountsModule, + authtypes.ModuleName: authModule, + }) + + authtypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), authkeeper.NewMsgServerImpl(authKeeper)) + // banktypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), bankkeeper.NewMsgServerImpl(bankKeeper)) + + return &fixture{ + app: integrationApp, + cdc: cdc, + accountsKeeper: accountsKeeper, + authKeeper: authKeeper, + } +} + +func TestAsyncExec(t *testing.T) { + t.Parallel() + f := initFixture(t) + + addrs := simtestutil.CreateIncrementalAccounts(2) + coins := sdk.NewCoins(sdk.NewCoin("stake", sdkmath.NewInt(10))) + + msg := banktypes.MsgSend{ + FromAddress: addrs[0].String(), + ToAddress: addrs[1].String(), + Amount: coins, + } + msg2 := banktypes.MsgSend{ + FromAddress: addrs[1].String(), + ToAddress: addrs[0].String(), + Amount: coins, + } + failingMsg := banktypes.MsgSend{ + FromAddress: "xyz", // Invalid sender address + ToAddress: "abc", // Invalid recipient address + Amount: sdk.NewCoins(sdk.NewCoin("stake", sdkmath.ZeroInt())), // No amount specified + } + + msgAny, err := codectypes.NewAnyWithValue(&msg) + assert.NilError(t, err) + + msgAny2, err := codectypes.NewAnyWithValue(&msg2) + assert.NilError(t, err) + + failingMsgAny, err := codectypes.NewAnyWithValue(&failingMsg) + assert.NilError(t, err) + + testCases := []struct { + name string + req *types.MsgNonAtomicExec + expectErr bool + expErrMsg string + }{ + { + name: "empty signer address", + req: &types.MsgNonAtomicExec{ + Signer: "", + Msgs: []*codectypes.Any{}, + }, + expectErr: true, + expErrMsg: "empty signer address string is not allowed", + }, + { + name: "invalid signer address", + req: &types.MsgNonAtomicExec{ + Signer: "invalid", + Msgs: []*codectypes.Any{}, + }, + expectErr: true, + expErrMsg: "invalid signer address", + }, + { + name: "empty msgs", + req: &types.MsgNonAtomicExec{ + Signer: addrs[0].String(), + Msgs: []*codectypes.Any{}, + }, + expectErr: true, + expErrMsg: "messages cannot be empty", + }, + { + name: "valid msg", + req: &types.MsgNonAtomicExec{ + Signer: addrs[0].String(), + Msgs: []*codectypes.Any{msgAny}, + }, + expectErr: false, + }, + { + name: "multiple messages being executed", + req: &types.MsgNonAtomicExec{ + Signer: addrs[0].String(), + Msgs: []*codectypes.Any{msgAny, msgAny}, + }, + expectErr: false, + }, + { + name: "multi msg with one failing being executed", + req: &types.MsgNonAtomicExec{ + Signer: addrs[0].String(), + Msgs: []*codectypes.Any{msgAny, failingMsgAny}, + }, + expectErr: false, + }, + { + name: "multiple messages with different signers", + req: &types.MsgNonAtomicExec{ + Signer: addrs[0].String(), + Msgs: []*codectypes.Any{msgAny, msgAny2}, + }, + expectErr: false, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + res, err := f.app.RunMsg( + tc.req, + integration.WithAutomaticFinalizeBlock(), + integration.WithAutomaticCommit(), + ) + if tc.expectErr { + assert.ErrorContains(t, err, tc.expErrMsg) + } else { + assert.NilError(t, err) + assert.Assert(t, res != nil) + + // check the result + result := authtypes.MsgNonAtomicExecResponse{} + err = f.cdc.Unmarshal(res.Value, &result) + assert.NilError(t, err) + + } + }) + } +} diff --git a/x/auth/keeper/msg_server_test.go b/x/auth/keeper/msg_server_test.go index fc23d9d35361..36a9cdbe03e7 100644 --- a/x/auth/keeper/msg_server_test.go +++ b/x/auth/keeper/msg_server_test.go @@ -27,9 +27,9 @@ func (s *KeeperTestSuite) TestAsyncExec() { Amount: coins, } failingMsg := banktypes.MsgSend{ - FromAddress: "", // Invalid sender address - ToAddress: "", // Invalid recipient address - Amount: nil, // No amount specified + FromAddress: "xyz", // Invalid sender address + ToAddress: "abc", // Invalid recipient address + Amount: sdk.NewCoins(sdk.NewCoin("stake", sdkmath.ZeroInt())), // No amount specified } msgAny, err := codectypes.NewAnyWithValue(&msg) @@ -96,7 +96,7 @@ func (s *KeeperTestSuite) TestAsyncExec() { Signer: addrs[0].String(), Msgs: []*codectypes.Any{msgAny, failingMsgAny}, }, - expectErr: true, + expectErr: false, }, { name: "multiple messages with different signers", @@ -104,7 +104,7 @@ func (s *KeeperTestSuite) TestAsyncExec() { Signer: addrs[0].String(), Msgs: []*codectypes.Any{msgAny, msgAny2}, }, - expectErr: true, + expectErr: false, }, }