github.com/cosmos/cosmos-sdk@v0.50.10/x/authz/keeper/msg_server_test.go (about)

     1  package keeper_test
     2  
     3  import (
     4  	"time"
     5  
     6  	"github.com/golang/mock/gomock"
     7  
     8  	sdkmath "cosmossdk.io/math"
     9  
    10  	"github.com/cosmos/cosmos-sdk/codec/address"
    11  	simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
    12  	sdk "github.com/cosmos/cosmos-sdk/types"
    13  	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
    14  	"github.com/cosmos/cosmos-sdk/x/authz"
    15  	banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
    16  )
    17  
    18  func (suite *TestSuite) createAccounts(accs int) []sdk.AccAddress {
    19  	addrs := simtestutil.CreateIncrementalAccounts(2)
    20  	suite.accountKeeper.EXPECT().GetAccount(gomock.Any(), suite.addrs[0]).Return(authtypes.NewBaseAccountWithAddress(suite.addrs[0])).AnyTimes()
    21  	suite.accountKeeper.EXPECT().GetAccount(gomock.Any(), suite.addrs[1]).Return(authtypes.NewBaseAccountWithAddress(suite.addrs[1])).AnyTimes()
    22  	return addrs
    23  }
    24  
    25  func (suite *TestSuite) TestGrant() {
    26  	ctx := suite.ctx.WithBlockTime(time.Now())
    27  	addrs := suite.createAccounts(2)
    28  	curBlockTime := ctx.BlockTime()
    29  
    30  	suite.accountKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec("cosmos")).AnyTimes()
    31  
    32  	oneHour := curBlockTime.Add(time.Hour)
    33  	oneYear := curBlockTime.AddDate(1, 0, 0)
    34  
    35  	coins := sdk.NewCoins(sdk.NewCoin("steak", sdkmath.NewInt(10)))
    36  
    37  	grantee, granter := addrs[0], addrs[1]
    38  
    39  	testCases := []struct {
    40  		name     string
    41  		malleate func() *authz.MsgGrant
    42  		expErr   bool
    43  		errMsg   string
    44  	}{
    45  		{
    46  			name: "identical grantee and granter",
    47  			malleate: func() *authz.MsgGrant {
    48  				grant, err := authz.NewGrant(curBlockTime, banktypes.NewSendAuthorization(coins, nil), &oneYear)
    49  				suite.Require().NoError(err)
    50  				return &authz.MsgGrant{
    51  					Granter: grantee.String(),
    52  					Grantee: grantee.String(),
    53  					Grant:   grant,
    54  				}
    55  			},
    56  			expErr: true,
    57  			errMsg: "grantee and granter should be different",
    58  		},
    59  		{
    60  			name: "invalid granter",
    61  			malleate: func() *authz.MsgGrant {
    62  				grant, err := authz.NewGrant(curBlockTime, banktypes.NewSendAuthorization(coins, nil), &oneYear)
    63  				suite.Require().NoError(err)
    64  				return &authz.MsgGrant{
    65  					Granter: "invalid",
    66  					Grantee: grantee.String(),
    67  					Grant:   grant,
    68  				}
    69  			},
    70  			expErr: true,
    71  			errMsg: "invalid bech32 string",
    72  		},
    73  		{
    74  			name: "invalid grantee",
    75  			malleate: func() *authz.MsgGrant {
    76  				grant, err := authz.NewGrant(curBlockTime, banktypes.NewSendAuthorization(coins, nil), &oneYear)
    77  				suite.Require().NoError(err)
    78  				return &authz.MsgGrant{
    79  					Granter: granter.String(),
    80  					Grantee: "invalid",
    81  					Grant:   grant,
    82  				}
    83  			},
    84  			expErr: true,
    85  			errMsg: "invalid bech32 string",
    86  		},
    87  		{
    88  			name: "invalid grant",
    89  			malleate: func() *authz.MsgGrant {
    90  				return &authz.MsgGrant{
    91  					Granter: granter.String(),
    92  					Grantee: grantee.String(),
    93  					Grant: authz.Grant{
    94  						Expiration: &oneYear,
    95  					},
    96  				}
    97  			},
    98  			expErr: true,
    99  			errMsg: "authorization is nil: invalid type",
   100  		},
   101  		{
   102  			name: "invalid grant, past time",
   103  			malleate: func() *authz.MsgGrant {
   104  				pastTime := curBlockTime.Add(-time.Hour)
   105  				grant, err := authz.NewGrant(curBlockTime, banktypes.NewSendAuthorization(coins, nil), &oneHour) // we only need the authorization
   106  				suite.Require().NoError(err)
   107  				return &authz.MsgGrant{
   108  					Granter: granter.String(),
   109  					Grantee: grantee.String(),
   110  					Grant: authz.Grant{
   111  						Authorization: grant.Authorization,
   112  						Expiration:    &pastTime,
   113  					},
   114  				}
   115  			},
   116  			expErr: true,
   117  			errMsg: "expiration must be after the current block time",
   118  		},
   119  		{
   120  			name: "grantee account does not exist on chain: valid grant",
   121  			malleate: func() *authz.MsgGrant {
   122  				newAcc := sdk.AccAddress("valid")
   123  				suite.accountKeeper.EXPECT().GetAccount(gomock.Any(), newAcc).Return(nil).AnyTimes()
   124  				acc := authtypes.NewBaseAccountWithAddress(newAcc)
   125  				suite.accountKeeper.EXPECT().NewAccountWithAddress(gomock.Any(), newAcc).Return(acc).AnyTimes()
   126  				suite.accountKeeper.EXPECT().SetAccount(gomock.Any(), acc).Return()
   127  
   128  				grant, err := authz.NewGrant(curBlockTime, banktypes.NewSendAuthorization(coins, nil), &oneYear)
   129  				suite.Require().NoError(err)
   130  				return &authz.MsgGrant{
   131  					Granter: granter.String(),
   132  					Grantee: newAcc.String(),
   133  					Grant:   grant,
   134  				}
   135  			},
   136  		},
   137  		{
   138  			name: "valid grant",
   139  			malleate: func() *authz.MsgGrant {
   140  				grant, err := authz.NewGrant(curBlockTime, banktypes.NewSendAuthorization(coins, nil), &oneYear)
   141  				suite.Require().NoError(err)
   142  				return &authz.MsgGrant{
   143  					Granter: granter.String(),
   144  					Grantee: grantee.String(),
   145  					Grant:   grant,
   146  				}
   147  			},
   148  		},
   149  		{
   150  			name: "valid grant, same grantee, granter pair but different msgType",
   151  			malleate: func() *authz.MsgGrant {
   152  				g, err := authz.NewGrant(curBlockTime, banktypes.NewSendAuthorization(coins, nil), &oneHour)
   153  				suite.Require().NoError(err)
   154  				_, err = suite.msgSrvr.Grant(suite.ctx, &authz.MsgGrant{
   155  					Granter: granter.String(),
   156  					Grantee: grantee.String(),
   157  					Grant:   g,
   158  				})
   159  				suite.Require().NoError(err)
   160  
   161  				grant, err := authz.NewGrant(curBlockTime, authz.NewGenericAuthorization("/cosmos.bank.v1beta1.MsgUpdateParams"), &oneHour)
   162  				suite.Require().NoError(err)
   163  				return &authz.MsgGrant{
   164  					Granter: granter.String(),
   165  					Grantee: grantee.String(),
   166  					Grant:   grant,
   167  				}
   168  			},
   169  		},
   170  		{
   171  			name: "valid grant with allow list",
   172  			malleate: func() *authz.MsgGrant {
   173  				grant, err := authz.NewGrant(curBlockTime, banktypes.NewSendAuthorization(coins, []sdk.AccAddress{granter}), &oneYear)
   174  				suite.Require().NoError(err)
   175  				return &authz.MsgGrant{
   176  					Granter: granter.String(),
   177  					Grantee: grantee.String(),
   178  					Grant:   grant,
   179  				}
   180  			},
   181  		},
   182  		{
   183  			name: "valid grant with nil expiration time",
   184  			malleate: func() *authz.MsgGrant {
   185  				grant, err := authz.NewGrant(curBlockTime, banktypes.NewSendAuthorization(coins, nil), nil)
   186  				suite.Require().NoError(err)
   187  				return &authz.MsgGrant{
   188  					Granter: granter.String(),
   189  					Grantee: grantee.String(),
   190  					Grant:   grant,
   191  				}
   192  			},
   193  		},
   194  	}
   195  
   196  	for _, tc := range testCases {
   197  		suite.Run(tc.name, func() {
   198  			_, err := suite.msgSrvr.Grant(suite.ctx, tc.malleate())
   199  			if tc.expErr {
   200  				suite.Require().Error(err)
   201  				suite.Require().Contains(err.Error(), tc.errMsg)
   202  			} else {
   203  				suite.Require().NoError(err)
   204  			}
   205  		})
   206  	}
   207  }
   208  
   209  func (suite *TestSuite) TestRevoke() {
   210  	addrs := suite.createAccounts(2)
   211  
   212  	grantee, granter := addrs[0], addrs[1]
   213  
   214  	testCases := []struct {
   215  		name     string
   216  		malleate func() *authz.MsgRevoke
   217  		expErr   bool
   218  		errMsg   string
   219  	}{
   220  		{
   221  			name: "identical grantee and granter",
   222  			malleate: func() *authz.MsgRevoke {
   223  				return &authz.MsgRevoke{
   224  					Granter:    grantee.String(),
   225  					Grantee:    grantee.String(),
   226  					MsgTypeUrl: bankSendAuthMsgType,
   227  				}
   228  			},
   229  			expErr: true,
   230  			errMsg: "grantee and granter should be different",
   231  		},
   232  		{
   233  			name: "invalid granter",
   234  			malleate: func() *authz.MsgRevoke {
   235  				return &authz.MsgRevoke{
   236  					Granter:    "invalid",
   237  					Grantee:    grantee.String(),
   238  					MsgTypeUrl: bankSendAuthMsgType,
   239  				}
   240  			},
   241  			expErr: true,
   242  			errMsg: "invalid bech32 string",
   243  		},
   244  		{
   245  			name: "invalid grantee",
   246  			malleate: func() *authz.MsgRevoke {
   247  				return &authz.MsgRevoke{
   248  					Granter:    granter.String(),
   249  					Grantee:    "invalid",
   250  					MsgTypeUrl: bankSendAuthMsgType,
   251  				}
   252  			},
   253  			expErr: true,
   254  			errMsg: "invalid bech32 string",
   255  		},
   256  		{
   257  			name: "no msg given",
   258  			malleate: func() *authz.MsgRevoke {
   259  				return &authz.MsgRevoke{
   260  					Granter:    granter.String(),
   261  					Grantee:    grantee.String(),
   262  					MsgTypeUrl: "",
   263  				}
   264  			},
   265  			expErr: true,
   266  			errMsg: "missing msg method name",
   267  		},
   268  		{
   269  			name: "valid grant",
   270  			malleate: func() *authz.MsgRevoke {
   271  				suite.createSendAuthorization(grantee, granter)
   272  
   273  				return &authz.MsgRevoke{
   274  					Granter:    granter.String(),
   275  					Grantee:    grantee.String(),
   276  					MsgTypeUrl: bankSendAuthMsgType,
   277  				}
   278  			},
   279  		},
   280  		{
   281  			name: "no existing grant to revoke",
   282  			malleate: func() *authz.MsgRevoke {
   283  				return &authz.MsgRevoke{
   284  					Granter:    granter.String(),
   285  					Grantee:    grantee.String(),
   286  					MsgTypeUrl: bankSendAuthMsgType,
   287  				}
   288  			},
   289  			expErr: true,
   290  			errMsg: "authorization not found",
   291  		},
   292  	}
   293  
   294  	for _, tc := range testCases {
   295  		suite.Run(tc.name, func() {
   296  			_, err := suite.msgSrvr.Revoke(suite.ctx, tc.malleate())
   297  			if tc.expErr {
   298  				suite.Require().Error(err)
   299  				suite.Require().Contains(err.Error(), tc.errMsg)
   300  			} else {
   301  				suite.Require().NoError(err)
   302  			}
   303  		})
   304  	}
   305  }
   306  
   307  func (suite *TestSuite) TestExec() {
   308  	addrs := suite.createAccounts(2)
   309  
   310  	grantee, granter := addrs[0], addrs[1]
   311  	coins := sdk.NewCoins(sdk.NewCoin("steak", sdkmath.NewInt(10)))
   312  
   313  	msg := &banktypes.MsgSend{
   314  		FromAddress: granter.String(),
   315  		ToAddress:   grantee.String(),
   316  		Amount:      coins,
   317  	}
   318  
   319  	testCases := []struct {
   320  		name     string
   321  		malleate func() authz.MsgExec
   322  		expErr   bool
   323  		errMsg   string
   324  	}{
   325  		{
   326  			name: "invalid grantee (empty)",
   327  			malleate: func() authz.MsgExec {
   328  				return authz.NewMsgExec(sdk.AccAddress{}, []sdk.Msg{msg})
   329  			},
   330  			expErr: true,
   331  			errMsg: "empty address string is not allowed",
   332  		},
   333  		{
   334  			name: "non existing grant",
   335  			malleate: func() authz.MsgExec {
   336  				return authz.NewMsgExec(grantee, []sdk.Msg{msg})
   337  			},
   338  			expErr: true,
   339  			errMsg: "authorization not found",
   340  		},
   341  		{
   342  			name: "no message case",
   343  			malleate: func() authz.MsgExec {
   344  				return authz.NewMsgExec(grantee, []sdk.Msg{})
   345  			},
   346  			expErr: true,
   347  			errMsg: "messages cannot be empty",
   348  		},
   349  		{
   350  			name: "valid case",
   351  			malleate: func() authz.MsgExec {
   352  				suite.createSendAuthorization(grantee, granter)
   353  				return authz.NewMsgExec(grantee, []sdk.Msg{msg})
   354  			},
   355  		},
   356  	}
   357  
   358  	for _, tc := range testCases {
   359  		suite.Run(tc.name, func() {
   360  			req := tc.malleate()
   361  			_, err := suite.msgSrvr.Exec(suite.ctx, &req)
   362  			if tc.expErr {
   363  				suite.Require().Error(err)
   364  				suite.Require().Contains(err.Error(), tc.errMsg)
   365  			} else {
   366  				suite.Require().NoError(err)
   367  			}
   368  		})
   369  	}
   370  }