refactor(authz): move ValidateBasic logic to msgServer (#15754)

This commit is contained in:
Julien Robert 2023-04-08 14:57:51 +02:00 committed by GitHub
parent d09068f529
commit cdc03fa66e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 186 additions and 577 deletions

View File

@ -197,7 +197,7 @@ func (s *E2ETestSuite) TestQueryGranterGrantsGRPC() {
fmt.Sprintf("%s/cosmos/authz/v1beta1/grants/granter/%s", val.APIAddress, val.Address.String()),
false,
"",
8,
7,
},
}
for _, tc := range testCases {

View File

@ -234,7 +234,7 @@ func (s *E2ETestSuite) TestQueryGranterGrants() {
},
false,
"",
8,
7,
},
{
"valid case with pagination",

View File

@ -167,366 +167,6 @@ var (
typeMsgSubmitProposal = sdk.MsgTypeURL(&govv1.MsgSubmitProposal{})
)
func (s *E2ETestSuite) TestCLITxGrantAuthorization() {
val := s.network.Validators[0]
grantee := s.grantee[0]
twoHours := time.Now().Add(time.Minute * 120).Unix()
pastHour := time.Now().Add(-time.Minute * 60).Unix()
testCases := []struct {
name string
args []string
expectedCode uint32
expectErr bool
expErrMsg string
}{
{
"Invalid granter Address",
[]string{
"grantee_addr",
"send",
fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
fmt.Sprintf("--%s=%s", flags.FlagFrom, "granter"),
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
},
0,
true,
"key not found",
},
{
"Invalid grantee Address",
[]string{
"grantee_addr",
"send",
fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
},
0,
true,
"invalid separator index",
},
{
"Invalid expiration time",
[]string{
grantee.String(),
"send",
fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=true", flags.FlagBroadcastMode),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, pastHour),
},
0,
true,
"",
},
{
"fail with error invalid msg-type",
[]string{
grantee.String(),
"generic",
fmt.Sprintf("--%s=invalid-msg-type", cli.FlagMsgType),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
},
0x1d,
false,
"",
},
{
"failed with error both validators not allowed",
[]string{
grantee.String(),
"delegate",
fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
fmt.Sprintf("--%s=%s", cli.FlagDenyValidators, val.ValAddress.String()),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
0,
true,
"cannot set both allowed & deny list",
},
{
"invalid bond denom for tx delegate authorization allowed validators",
[]string{
grantee.String(),
"delegate",
fmt.Sprintf("--%s=100xyz", cli.FlagSpendLimit),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
0,
true,
"invalid denom",
},
{
"invalid bond denom for tx delegate authorization deny validators",
[]string{
grantee.String(),
"delegate",
fmt.Sprintf("--%s=100xyz", cli.FlagSpendLimit),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", cli.FlagDenyValidators, val.ValAddress.String()),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
0,
true,
"invalid denom",
},
{
"invalid bond denom for tx undelegate authorization",
[]string{
grantee.String(),
"unbond",
fmt.Sprintf("--%s=100xyz", cli.FlagSpendLimit),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
0,
true,
"invalid denom",
},
{
"invalid bond denon for tx redelegate authorization",
[]string{
grantee.String(),
"redelegate",
fmt.Sprintf("--%s=100xyz", cli.FlagSpendLimit),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
0,
true,
"invalid denom",
},
{
"invalid decimal coin expression with more than single coin",
[]string{
grantee.String(),
"delegate",
fmt.Sprintf("--%s=100stake,20xyz", cli.FlagSpendLimit),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
0,
true,
"invalid decimal coin expression",
},
{
"valid tx delegate authorization allowed validators",
[]string{
grantee.String(),
"delegate",
fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
0,
false,
"",
},
{
"valid tx delegate authorization deny validators",
[]string{
grantee.String(),
"delegate",
fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", cli.FlagDenyValidators, val.ValAddress.String()),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
0,
false,
"",
},
{
"valid tx undelegate authorization",
[]string{
grantee.String(),
"unbond",
fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
0,
false,
"",
},
{
"valid tx redelegate authorization",
[]string{
grantee.String(),
"redelegate",
fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
0,
false,
"",
},
{
"Valid tx send authorization",
[]string{
grantee.String(),
"send",
fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
0,
false,
"",
},
{
"Valid tx send authorization with allow list",
[]string{
grantee.String(),
"send",
fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
fmt.Sprintf("--%s=%s", cli.FlagAllowList, s.grantee[1]),
},
0,
false,
"",
},
{
"Invalid tx send authorization with duplicate allow list",
[]string{
grantee.String(),
"send",
fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
fmt.Sprintf("--%s=%s", cli.FlagAllowList, fmt.Sprintf("%s,%s", s.grantee[1], s.grantee[1])),
},
0,
true,
"duplicate entry",
},
{
"Valid tx generic authorization",
[]string{
grantee.String(),
"generic",
fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
0,
false,
"",
},
{
"fail when granter = grantee",
[]string{
grantee.String(),
"generic",
fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote),
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
0,
true,
"grantee and granter should be different",
},
{
"Valid tx with amino",
[]string{
grantee.String(),
"generic",
fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
},
0,
false,
"",
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
out, err := authzclitestutil.CreateGrant(val.ClientCtx, tc.args)
if tc.expectErr {
s.Require().Error(err, out)
s.Require().Contains(err.Error(), tc.expErrMsg)
} else {
var txResp sdk.TxResponse
s.Require().NoError(err)
s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &txResp), out.String())
s.Require().NoError(clitestutil.CheckTxCode(s.network, val.ClientCtx, txResp.TxHash, tc.expectedCode))
}
})
}
}
func execDelegate(val *network.Validator, args []string) (testutil.BufferWriter, error) {
cmd := stakingcli.NewDelegateCmd()
clientCtx := val.ClientCtx

View File

@ -53,6 +53,10 @@ func (g Grant) GetAuthorization() (Authorization, error) {
}
func (g Grant) ValidateBasic() error {
if g.Authorization == nil {
return sdkerrors.ErrInvalidType.Wrap("authorization is nil")
}
av := g.Authorization.GetCachedValue()
a, ok := av.(Authorization)
if !ok {

View File

@ -73,6 +73,10 @@ Examples:
return err
}
if strings.EqualFold(args[0], clientCtx.GetFromAddress().String()) {
return errors.New("grantee and granter should be different")
}
grantee, err := ac.StringToBytes(args[0])
if err != nil {
return err
@ -100,6 +104,15 @@ Examples:
return err
}
// check for duplicates
for i := 0; i < len(allowList); i++ {
for j := i + 1; j < len(allowList); j++ {
if allowList[i] == allowList[j] {
return fmt.Errorf("duplicate address %s in allow-list", allowList[i])
}
}
}
allowed, err := bech32toAccAddresses(allowList, ac)
if err != nil {
return err

View File

@ -375,7 +375,7 @@ func (s *CLITestSuite) TestCLITxGrantAuthorization() {
fmt.Sprintf("--%s=%s", cli.FlagAllowList, fmt.Sprintf("%s,%s", s.grantee[1], s.grantee[1])),
},
true,
"duplicate entry",
"duplicate address",
},
{
"Valid tx generic authorization",

View File

@ -3,6 +3,7 @@ package keeper
import (
"context"
"errors"
"strings"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
@ -13,24 +14,32 @@ var _ authz.MsgServer = Keeper{}
// Grant implements the MsgServer.Grant method to create a new grant.
func (k Keeper) Grant(goCtx context.Context, msg *authz.MsgGrant) (*authz.MsgGrantResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
grantee, err := k.authKeeper.StringToBytes(msg.Grantee)
if err != nil {
return nil, err
if strings.EqualFold(msg.Grantee, msg.Granter) {
return nil, authz.ErrGranteeIsGranter
}
// create the account if it is not in account state
granteeAcc := k.authKeeper.GetAccount(ctx, grantee)
if granteeAcc == nil {
granteeAcc = k.authKeeper.NewAccountWithAddress(ctx, grantee)
k.authKeeper.SetAccount(ctx, granteeAcc)
grantee, err := k.authKeeper.StringToBytes(msg.Grantee)
if err != nil {
return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid grantee address: %s", err)
}
granter, err := k.authKeeper.StringToBytes(msg.Granter)
if err != nil {
return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid grantee address: %s", err)
}
if err := msg.Grant.ValidateBasic(); err != nil {
return nil, err
}
// create the account if it is not in account state
ctx := sdk.UnwrapSDKContext(goCtx)
granteeAcc := k.authKeeper.GetAccount(ctx, grantee)
if granteeAcc == nil {
granteeAcc = k.authKeeper.NewAccountWithAddress(ctx, grantee)
k.authKeeper.SetAccount(ctx, granteeAcc)
}
authorization, err := msg.GetAuthorization()
if err != nil {
return nil, err
@ -51,18 +60,26 @@ func (k Keeper) Grant(goCtx context.Context, msg *authz.MsgGrant) (*authz.MsgGra
// Revoke implements the MsgServer.Revoke method.
func (k Keeper) Revoke(goCtx context.Context, msg *authz.MsgRevoke) (*authz.MsgRevokeResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
grantee, err := k.authKeeper.StringToBytes(msg.Grantee)
if err != nil {
return nil, err
}
granter, err := k.authKeeper.StringToBytes(msg.Granter)
if err != nil {
return nil, err
if strings.EqualFold(msg.Grantee, msg.Granter) {
return nil, authz.ErrGranteeIsGranter
}
err = k.DeleteGrant(ctx, grantee, granter, msg.MsgTypeUrl)
grantee, err := k.authKeeper.StringToBytes(msg.Grantee)
if err != nil {
return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid grantee address: %s", err)
}
granter, err := k.authKeeper.StringToBytes(msg.Granter)
if err != nil {
return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid granter address: %s", err)
}
if msg.MsgTypeUrl == "" {
return nil, sdkerrors.ErrInvalidRequest.Wrap("missing msg method name")
}
ctx := sdk.UnwrapSDKContext(goCtx)
if err = k.DeleteGrant(ctx, grantee, granter, msg.MsgTypeUrl); err != nil {
return nil, err
}
@ -75,9 +92,14 @@ func (k Keeper) Exec(goCtx context.Context, msg *authz.MsgExec) (*authz.MsgExecR
if msg.Grantee == "" {
return nil, errors.New("empty address string is not allowed")
}
grantee, err := k.authKeeper.StringToBytes(msg.Grantee)
if err != nil {
return nil, err
return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid grantee address: %s", err)
}
if len(msg.Msgs) == 0 {
return nil, sdkerrors.ErrInvalidRequest.Wrapf("messages cannot be empty")
}
msgs, err := msg.GetMessages()
@ -85,6 +107,10 @@ func (k Keeper) Exec(goCtx context.Context, msg *authz.MsgExec) (*authz.MsgExecR
return nil, err
}
if err := validateMsgs(msgs); err != nil {
return nil, err
}
results, err := k.DispatchActions(ctx, grantee, msgs)
if err != nil {
return nil, err
@ -92,3 +118,18 @@ func (k Keeper) Exec(goCtx context.Context, msg *authz.MsgExec) (*authz.MsgExecR
return &authz.MsgExecResponse{Results: results}, nil
}
func validateMsgs(msgs []sdk.Msg) error {
for _, msg := range msgs {
m, ok := msg.(sdk.HasValidateBasic)
if !ok {
continue
}
if err := m.ValidateBasic(); err != nil {
return err
}
}
return nil
}

View File

@ -41,6 +41,20 @@ func (suite *TestSuite) TestGrant() {
expErr bool
errMsg string
}{
{
name: "indentical grantee and granter",
malleate: func() *authz.MsgGrant {
grant, err := authz.NewGrant(curBlockTime, banktypes.NewSendAuthorization(coins, nil), &oneYear)
suite.Require().NoError(err)
return &authz.MsgGrant{
Granter: grantee.String(),
Grantee: grantee.String(),
Grant: grant,
}
},
expErr: true,
errMsg: "grantee and granter should be different",
},
{
name: "invalid granter",
malleate: func() *authz.MsgGrant {
@ -69,6 +83,38 @@ func (suite *TestSuite) TestGrant() {
expErr: true,
errMsg: "invalid bech32 string",
},
{
name: "invalid grant",
malleate: func() *authz.MsgGrant {
return &authz.MsgGrant{
Granter: granter.String(),
Grantee: grantee.String(),
Grant: authz.Grant{
Expiration: &oneYear,
},
}
},
expErr: true,
errMsg: "authorization is nil: invalid type",
},
{
name: "invalid grant, past time",
malleate: func() *authz.MsgGrant {
pastTime := curBlockTime.Add(-time.Hour)
grant, err := authz.NewGrant(curBlockTime, banktypes.NewSendAuthorization(coins, nil), &oneHour) // we only need the authorization
suite.Require().NoError(err)
return &authz.MsgGrant{
Granter: granter.String(),
Grantee: grantee.String(),
Grant: authz.Grant{
Authorization: grant.Authorization,
Expiration: &pastTime,
},
}
},
expErr: true,
errMsg: "expiration must be after the current block time",
},
{
name: "grantee account does not exist on chain: valid grant",
malleate: func() *authz.MsgGrant {
@ -132,6 +178,18 @@ func (suite *TestSuite) TestGrant() {
}
},
},
{
name: "valid grant with nil expiration time",
malleate: func() *authz.MsgGrant {
grant, err := authz.NewGrant(curBlockTime, banktypes.NewSendAuthorization(coins, nil), nil)
suite.Require().NoError(err)
return &authz.MsgGrant{
Granter: granter.String(),
Grantee: grantee.String(),
Grant: grant,
}
},
},
}
for _, tc := range testCases {
@ -158,6 +216,18 @@ func (suite *TestSuite) TestRevoke() {
expErr bool
errMsg string
}{
{
name: "indentical grantee and granter",
malleate: func() *authz.MsgRevoke {
return &authz.MsgRevoke{
Granter: grantee.String(),
Grantee: grantee.String(),
MsgTypeUrl: bankSendAuthMsgType,
}
},
expErr: true,
errMsg: "grantee and granter should be different",
},
{
name: "invalid granter",
malleate: func() *authz.MsgRevoke {
@ -182,6 +252,18 @@ func (suite *TestSuite) TestRevoke() {
expErr: true,
errMsg: "invalid bech32 string",
},
{
name: "no msg given",
malleate: func() *authz.MsgRevoke {
return &authz.MsgRevoke{
Granter: granter.String(),
Grantee: grantee.String(),
MsgTypeUrl: "",
}
},
expErr: true,
errMsg: "missing msg method name",
},
{
name: "valid grant",
malleate: func() *authz.MsgRevoke {
@ -240,7 +322,7 @@ func (suite *TestSuite) TestExec() {
errMsg string
}{
{
name: "invalid grantee",
name: "invalid grantee (empty)",
malleate: func() authz.MsgExec {
return authz.NewMsgExec(sdk.AccAddress{}, []sdk.Msg{msg})
},
@ -255,6 +337,14 @@ func (suite *TestSuite) TestExec() {
expErr: true,
errMsg: "authorization not found",
},
{
name: "no message case",
malleate: func() authz.MsgExec {
return authz.NewMsgExec(grantee, []sdk.Msg{})
},
expErr: true,
errMsg: "messages cannot be empty",
},
{
name: "valid case",
malleate: func() authz.MsgExec {
@ -262,6 +352,19 @@ func (suite *TestSuite) TestExec() {
return authz.NewMsgExec(grantee, []sdk.Msg{msg})
},
},
{
name: "invalid nested msg",
malleate: func() authz.MsgExec {
return authz.NewMsgExec(grantee, []sdk.Msg{
&banktypes.MsgSend{
Amount: sdk.NewCoins(sdk.NewInt64Coin("steak", 2)),
FromAddress: "invalid_from_address",
ToAddress: grantee.String(),
}})
},
expErr: true,
errMsg: "invalid from address",
},
}
for _, tc := range testCases {

View File

@ -47,23 +47,6 @@ func (msg MsgGrant) GetSigners() []sdk.AccAddress {
return []sdk.AccAddress{granter}
}
// ValidateBasic implements Msg
func (msg MsgGrant) ValidateBasic() error {
granter, err := sdk.AccAddressFromBech32(msg.Granter)
if err != nil {
return sdkerrors.ErrInvalidAddress.Wrapf("invalid granter address: %s", err)
}
grantee, err := sdk.AccAddressFromBech32(msg.Grantee)
if err != nil {
return sdkerrors.ErrInvalidAddress.Wrapf("invalid grantee address: %s", err)
}
if granter.Equals(grantee) {
return ErrGranteeIsGranter
}
return msg.Grant.ValidateBasic()
}
// GetSignBytes implements the LegacyMsg.GetSignBytes method.
func (msg MsgGrant) GetSignBytes() []byte {
return sdk.MustSortJSON(authzcodec.Amino.MustMarshalJSON(&msg))
@ -121,28 +104,6 @@ func (msg MsgRevoke) GetSigners() []sdk.AccAddress {
return []sdk.AccAddress{granter}
}
// ValidateBasic implements MsgRequest.ValidateBasic
func (msg MsgRevoke) ValidateBasic() error {
granter, err := sdk.AccAddressFromBech32(msg.Granter)
if err != nil {
return sdkerrors.ErrInvalidAddress.Wrapf("invalid granter address: %s", err)
}
grantee, err := sdk.AccAddressFromBech32(msg.Grantee)
if err != nil {
return sdkerrors.ErrInvalidAddress.Wrapf("invalid grantee address: %s", err)
}
if granter.Equals(grantee) {
return ErrGranteeIsGranter
}
if msg.MsgTypeUrl == "" {
return sdkerrors.ErrInvalidRequest.Wrap("missing method name")
}
return nil
}
// GetSignBytes implements the LegacyMsg.GetSignBytes method.
func (msg MsgRevoke) GetSignBytes() []byte {
return sdk.MustSortJSON(authzcodec.Amino.MustMarshalJSON(&msg))
@ -186,34 +147,6 @@ func (msg MsgExec) GetSigners() []sdk.AccAddress {
return []sdk.AccAddress{grantee}
}
// ValidateBasic implements Msg
func (msg MsgExec) ValidateBasic() error {
if _, err := sdk.AccAddressFromBech32(msg.Grantee); err != nil {
return sdkerrors.ErrInvalidAddress.Wrapf("invalid grantee address: %s", err)
}
if len(msg.Msgs) == 0 {
return sdkerrors.ErrInvalidRequest.Wrapf("messages cannot be empty")
}
msgs, err := msg.GetMessages()
if err != nil {
return err
}
for _, msg := range msgs {
m, ok := msg.(sdk.HasValidateBasic)
if !ok {
continue
}
if err = m.ValidateBasic(); err != nil {
return err
}
}
return nil
}
// GetSignBytes implements the LegacyMsg.GetSignBytes method.
func (msg MsgExec) GetSignBytes() []byte {
return sdk.MustSortJSON(authzcodec.Amino.MustMarshalJSON(&msg))

View File

@ -16,132 +16,6 @@ import (
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
var (
coinsPos = sdk.NewCoins(sdk.NewInt64Coin("steak", 100))
granter = sdk.AccAddress("_______granter______")
grantee = sdk.AccAddress("_______grantee______")
)
func TestMsgExecAuthorized(t *testing.T) {
tests := []struct {
title string
grantee sdk.AccAddress
msgs []sdk.Msg
expectPass bool
}{
{"nil grantee address", nil, []sdk.Msg{}, false},
{"zero-messages test: should fail", grantee, []sdk.Msg{}, false},
{"invalid nested msg", grantee, []sdk.Msg{
&banktypes.MsgSend{
Amount: sdk.NewCoins(sdk.NewInt64Coin("steak", 2)),
FromAddress: "invalid_from_address",
ToAddress: grantee.String(),
},
}, false},
{"valid test: msg type", grantee, []sdk.Msg{
&banktypes.MsgSend{
Amount: sdk.NewCoins(sdk.NewInt64Coin("steak", 2)),
FromAddress: granter.String(),
ToAddress: grantee.String(),
},
}, true},
}
for i, tc := range tests {
msg := authz.NewMsgExec(tc.grantee, tc.msgs)
if tc.expectPass {
require.NoError(t, msg.ValidateBasic(), "test: %v", i)
} else {
require.Error(t, msg.ValidateBasic(), "test: %v", i)
}
}
}
func TestMsgRevokeAuthorization(t *testing.T) {
tests := []struct {
title string
granter, grantee sdk.AccAddress
msgType string
expectPass bool
}{
{"nil Granter address", nil, grantee, "hello", false},
{"nil Grantee address", granter, nil, "hello", false},
{"nil Granter and Grantee address", nil, nil, "hello", false},
{"valid test case", granter, grantee, "hello", true},
}
for i, tc := range tests {
msg := authz.NewMsgRevoke(tc.granter, tc.grantee, tc.msgType)
if tc.expectPass {
require.NoError(t, msg.ValidateBasic(), "test: %v", i)
} else {
require.Error(t, msg.ValidateBasic(), "test: %v", i)
}
}
}
// add time interval to a time object and returns a pointer
func addDatePtr(t *time.Time, months, days int) *time.Time {
t2 := t.AddDate(0, months, days)
return &t2
}
func TestMsgGrantAuthorization(t *testing.T) {
now := time.Now()
tests := []struct {
name string
granter, grantee sdk.AccAddress
authorization authz.Authorization
expiration *time.Time
expectErr bool
valBasic bool
}{
{
"nil granter address",
nil, grantee, &banktypes.SendAuthorization{SpendLimit: coinsPos}, &now, false, false,
},
{
"nil grantee address",
granter, nil, &banktypes.SendAuthorization{SpendLimit: coinsPos}, &now, false, false,
},
{
"nil granter and grantee address",
nil, nil, &banktypes.SendAuthorization{SpendLimit: coinsPos}, &now, false, false,
},
{
"nil authorization should fail",
granter, grantee, nil, &now, true, false,
},
{
"valid test case",
granter, grantee, &banktypes.SendAuthorization{SpendLimit: coinsPos}, addDatePtr(&now, 1, 0), false, true,
},
{
"valid test case with nil expire time",
granter, grantee, &banktypes.SendAuthorization{SpendLimit: coinsPos}, nil, false, true,
},
// we don't access the block time / nor time.Now, so we don't know if it's in the past at this level.
{
"past expire time should not fail",
granter, grantee, &banktypes.SendAuthorization{SpendLimit: coinsPos}, addDatePtr(&now, 0, -1), false, true,
},
}
for _, tc := range tests {
msg, err := authz.NewMsgGrant(
tc.granter, tc.grantee, tc.authorization, tc.expiration,
)
if !tc.expectErr {
require.NoError(t, err, "test: %v", tc.name)
} else {
require.Error(t, err, "test: %v", tc.name)
continue
}
if tc.valBasic {
require.NoError(t, msg.ValidateBasic(), "test: %v", tc.name)
} else {
require.Error(t, msg.ValidateBasic(), "test: %v", tc.name)
}
}
}
func TestMsgGrantGetAuthorization(t *testing.T) {
require := require.New(t)

View File

@ -2,6 +2,7 @@ package keeper
import (
"context"
"strings"
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -26,7 +27,7 @@ var _ feegrant.MsgServer = msgServer{}
// GrantAllowance grants an allowance from the granter's funds to be used by the grantee.
func (k msgServer) GrantAllowance(goCtx context.Context, msg *feegrant.MsgGrantAllowance) (*feegrant.MsgGrantAllowanceResponse, error) {
if msg.Grantee == msg.Granter {
if strings.EqualFold(msg.Grantee, msg.Granter) {
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "cannot self-grant fee authorization")
}