x/feegrant completeness audit updates (#9177)

* Updates to Genesis

* Move grpc_query tests to keeper pkg

* Unify CLI command usage message

* Use timestamp for time based expiration in cli

* Update FlagExpiration

* Update wording

* Add test case for invalid expiration

* Update cli Long description

* Update exp date examples

* Use constants
This commit is contained in:
Marie Gauthier 2021-04-27 15:37:26 +02:00 committed by GitHub
parent fc256a3683
commit 3ab1bc2346
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 287 additions and 270 deletions

View File

@ -186,7 +186,7 @@ Examples:
func NewCmdRevokeAuthorization() *cobra.Command {
cmd := &cobra.Command{
Use: "revoke [grantee_address] [msg_type] --from=[granter_address]",
Use: "revoke [grantee] [msg_type] --from=[granter]",
Short: "revoke authorization",
Long: strings.TrimSpace(
fmt.Sprintf(`revoke authorization from a granter to a grantee:

View File

@ -55,9 +55,9 @@ func NewCmdFeeGrant() *cobra.Command {
ignored as it is implied from [granter].
Examples:
%s tx %s grant cosmos1skjw... cosmos1skjw... --spend-limit 100stake --expiration 36000 or
%s tx %s grant cosmos1skjw... cosmos1skjw... --spend-limit 100stake --expiration 2022-01-30T15:04:05Z or
%s tx %s grant cosmos1skjw... cosmos1skjw... --spend-limit 100stake --period 3600 --period-limit 10stake --expiration 36000 or
%s tx %s grant cosmos1skjw... cosmos1skjw... --spend-limit 100stake --expiration 36000
%s tx %s grant cosmos1skjw... cosmos1skjw... --spend-limit 100stake --expiration 2022-01-30T15:04:05Z
--allowed-messages "/cosmos.gov.v1beta1.Msg/SubmitProposal,/cosmos.gov.v1beta1.Msg/Vote"
`, version.AppName, types.ModuleName, version.AppName, types.ModuleName, version.AppName, types.ModuleName,
),
@ -92,7 +92,7 @@ Examples:
return err
}
exp, err := cmd.Flags().GetInt64(FlagExpiration)
exp, err := cmd.Flags().GetString(FlagExpiration)
if err != nil {
return err
}
@ -101,9 +101,13 @@ Examples:
SpendLimit: limit,
}
if exp != 0 {
expDuration := time.Duration(exp) * time.Second
basic.Expiration = types.ExpiresAtTime(time.Now().Add(expDuration))
var expiresAtTime time.Time
if exp != "" {
expiresAtTime, err = time.Parse(time.RFC3339, exp)
if err != nil {
return err
}
basic.Expiration = types.ExpiresAtTime(expiresAtTime)
}
var grant types.FeeAllowanceI
@ -127,14 +131,15 @@ Examples:
}
if periodClock > 0 && periodLimit != nil {
if exp > 0 && periodClock > exp {
return fmt.Errorf("period(%d) cannot be greater than the expiration(%d)", periodClock, exp)
periodReset := time.Now().Add(time.Duration(periodClock) * time.Second)
if exp != "" && periodReset.Sub(expiresAtTime) > 0 {
return fmt.Errorf("period(%d) cannot reset after expiration(%v)", periodClock, exp)
}
periodic := types.PeriodicFeeAllowance{
Basic: basic,
Period: types.ClockDuration(time.Duration(periodClock) * time.Second),
PeriodReset: types.ExpiresAtTime(time.Now().Add(time.Duration(periodClock) * time.Second)),
PeriodReset: types.ExpiresAtTime(periodReset),
PeriodSpendLimit: periodLimit,
PeriodCanSpend: periodLimit,
}
@ -176,7 +181,7 @@ Examples:
flags.AddTxFlagsToCmd(cmd)
cmd.Flags().StringSlice(FlagAllowedMsgs, []string{}, "Set of allowed messages for fee allowance")
cmd.Flags().Int64(FlagExpiration, 0, "The second unit of time duration which the grant is active for the user")
cmd.Flags().String(FlagExpiration, "", "The RFC 3339 timestamp after which the grant expires for the user")
cmd.Flags().String(FlagSpendLimit, "", "Spend limit specifies the max limit can be used, if not mentioned there is no limit")
cmd.Flags().Int64(FlagPeriod, 0, "period specifies the time duration in which period_spend_limit coins can be spent before that allowance is reset")
cmd.Flags().String(FlagPeriodLimit, "", "period limit specifies the maximum number of coins that can be spent in the period")
@ -187,11 +192,11 @@ Examples:
// NewCmdRevokeFeegrant returns a CLI command handler for creating a MsgRevokeFeeAllowance transaction.
func NewCmdRevokeFeegrant() *cobra.Command {
cmd := &cobra.Command{
Use: "revoke [granter_address] [grantee_address]",
Use: "revoke [granter] [grantee]",
Short: "revoke fee-grant",
Long: strings.TrimSpace(
fmt.Sprintf(`revoke fee grant from a granter to a grantee. Note, the'--from' flag is
ignored as it is implied from [granter_address].
ignored as it is implied from [granter].
Example:
$ %s tx %s revoke cosmos1skj.. cosmos1skj..

View File

@ -1,210 +0,0 @@
package rest_test
import (
"fmt"
"testing"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/rest"
banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
"github.com/cosmos/cosmos-sdk/x/feegrant/client/cli"
"github.com/cosmos/cosmos-sdk/x/feegrant/types"
)
type IntegrationTestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
grantee sdk.AccAddress
}
func (s *IntegrationTestSuite) SetupSuite() {
s.T().Log("setting up integration test suite")
cfg := network.DefaultConfig()
cfg.NumValidators = 1
s.cfg = cfg
s.network = network.New(s.T(), cfg)
val := s.network.Validators[0]
// Create new account in the keyring.
info, _, err := val.ClientCtx.Keyring.NewMnemonic("grantee", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
s.Require().NoError(err)
newAddr := sdk.AccAddress(info.GetPubKey().Address())
// Send some funds to the new account.
_, err = banktestutil.MsgSendExec(
val.ClientCtx,
val.Address,
newAddr,
sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(200))), 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()),
)
s.Require().NoError(err)
s.grantee = newAddr
_, err = s.network.WaitForHeight(1)
s.Require().NoError(err)
}
func (s *IntegrationTestSuite) TearDownSuite() {
s.T().Log("tearing down integration test suite")
s.network.Cleanup()
}
func (s *IntegrationTestSuite) TestQueryFeeAllowance() {
val := s.network.Validators[0]
baseURL := val.APIAddress
testCases := []struct {
name string
url string
expectErr bool
errorMsg string
preRun func()
postRun func(_ types.QueryFeeAllowanceResponse)
}{
{
"fail: invalid granter",
fmt.Sprintf("%s/cosmos/feegrant/v1beta1/fee_allowance/%s/%s", baseURL, "invalid_granter", s.grantee.String()),
true,
"decoding bech32 failed: invalid index of 1: invalid request",
func() {},
func(types.QueryFeeAllowanceResponse) {},
},
{
"fail: invalid grantee",
fmt.Sprintf("%s/cosmos/feegrant/v1beta1/fee_allowance/%s/%s", baseURL, val.Address.String(), "invalid_grantee"),
true,
"decoding bech32 failed: invalid index of 1: invalid request",
func() {},
func(types.QueryFeeAllowanceResponse) {},
},
{
"fail: no grants",
fmt.Sprintf("%s/cosmos/feegrant/v1beta1/fee_allowance/%s/%s", baseURL, val.Address.String(), s.grantee.String()),
true,
"no allowance",
func() {},
func(types.QueryFeeAllowanceResponse) {},
},
{
"valid query: expect single grant",
fmt.Sprintf("%s/cosmos/feegrant/v1beta1/fee_allowance/%s/%s", baseURL, val.Address.String(), s.grantee.String()),
false,
"",
func() {
execFeeAllowance(val, s)
},
func(allowance types.QueryFeeAllowanceResponse) {
s.Require().Equal(allowance.FeeAllowance.Granter, val.Address.String())
s.Require().Equal(allowance.FeeAllowance.Grantee, s.grantee.String())
},
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
tc.preRun()
resp, _ := rest.GetRequest(tc.url)
if tc.expectErr {
s.Require().Contains(string(resp), tc.errorMsg)
} else {
var allowance types.QueryFeeAllowanceResponse
err := val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, &allowance)
s.Require().NoError(err)
tc.postRun(allowance)
}
})
}
}
func (s *IntegrationTestSuite) TestQueryGranteeAllowances() {
val := s.network.Validators[0]
baseURL := val.APIAddress
testCases := []struct {
name string
url string
expectErr bool
errorMsg string
preRun func()
postRun func(_ types.QueryFeeAllowancesResponse)
}{
{
"fail: invalid grantee",
fmt.Sprintf("%s/cosmos/feegrant/v1beta1/fee_allowances/%s", baseURL, "invalid_grantee"),
true,
"decoding bech32 failed: invalid index of 1: invalid request",
func() {},
func(types.QueryFeeAllowancesResponse) {},
},
{
"success: no grants",
fmt.Sprintf("%s/cosmos/feegrant/v1beta1/fee_allowances/%s?pagination.offset=1", baseURL, s.grantee.String()),
false,
"",
func() {},
func(allowances types.QueryFeeAllowancesResponse) {
s.Require().Equal(len(allowances.FeeAllowances), 0)
},
},
{
"valid query: expect single grant",
fmt.Sprintf("%s/cosmos/feegrant/v1beta1/fee_allowances/%s", baseURL, s.grantee.String()),
false,
"",
func() {
execFeeAllowance(val, s)
},
func(allowances types.QueryFeeAllowancesResponse) {
s.Require().Equal(len(allowances.FeeAllowances), 1)
s.Require().Equal(allowances.FeeAllowances[0].Granter, val.Address.String())
s.Require().Equal(allowances.FeeAllowances[0].Grantee, s.grantee.String())
},
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
tc.preRun()
resp, _ := rest.GetRequest(tc.url)
if tc.expectErr {
s.Require().Contains(string(resp), tc.errorMsg)
} else {
var allowance types.QueryFeeAllowancesResponse
err := val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, &allowance)
s.Require().NoError(err)
tc.postRun(allowance)
}
})
}
}
func execFeeAllowance(val *network.Validator, s *IntegrationTestSuite) {
fee := sdk.NewCoin("steak", sdk.NewInt(100))
duration := 365 * 24 * 60 * 60
args := []string{
val.Address.String(),
s.grantee.String(),
fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, fee.String()),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%v", cli.FlagExpiration, duration),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
}
cmd := cli.NewCmdFeeGrant()
_, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args)
s.Require().NoError(err)
}
func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
}

View File

@ -3,6 +3,7 @@ package testutil
import (
"fmt"
"testing"
"time"
"github.com/gogo/protobuf/proto"
"github.com/stretchr/testify/suite"
@ -21,6 +22,12 @@ import (
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
)
const (
oneYear = 365 * 24 * 60 * 60
tenHours = 10 * 60 * 60
oneHour = 60 * 60
)
type IntegrationTestSuite struct {
suite.Suite
@ -59,7 +66,6 @@ func (s *IntegrationTestSuite) SetupSuite() {
}
fee := sdk.NewCoin("stake", sdk.NewInt(100))
duration := 365 * 24 * 60 * 60
args := append(
[]string{
@ -67,7 +73,7 @@ func (s *IntegrationTestSuite) SetupSuite() {
grantee.String(),
fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, fee.String()),
fmt.Sprintf("--%s=%s", flags.FlagFrom, granter),
fmt.Sprintf("--%s=%v", cli.FlagExpiration, duration),
fmt.Sprintf("--%s=%s", cli.FlagExpiration, getFormattedExpiration(oneYear)),
},
commonFlags...,
)
@ -354,7 +360,7 @@ func (s *IntegrationTestSuite) TestNewCmdFeeGrant() {
fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, "100stake"),
fmt.Sprintf("--%s=%s", cli.FlagPeriodLimit, "10stake"),
fmt.Sprintf("--%s=%s", flags.FlagFrom, granter),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, 10*60*60),
fmt.Sprintf("--%s=%s", cli.FlagExpiration, getFormattedExpiration(tenHours)),
},
commonFlags...,
),
@ -367,9 +373,9 @@ func (s *IntegrationTestSuite) TestNewCmdFeeGrant() {
granter.String(),
"cosmos1nph3cfzk6trsmfxkeu943nvach5qw4vwstnvkl",
fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, "100stake"),
fmt.Sprintf("--%s=%d", cli.FlagPeriod, 10*60*60),
fmt.Sprintf("--%s=%d", cli.FlagPeriod, tenHours),
fmt.Sprintf("--%s=%s", flags.FlagFrom, granter),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, 60*60),
fmt.Sprintf("--%s=%s", cli.FlagExpiration, getFormattedExpiration(oneHour)),
},
commonFlags...,
),
@ -382,10 +388,10 @@ func (s *IntegrationTestSuite) TestNewCmdFeeGrant() {
granter.String(),
"cosmos1nph3cfzk6trsmfxkeu943nvach5qw4vwstnvkl",
fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, "100stake"),
fmt.Sprintf("--%s=%d", cli.FlagPeriod, 10*60*60),
fmt.Sprintf("--%s=%d", cli.FlagPeriod, tenHours),
fmt.Sprintf("--%s=%s", cli.FlagPeriodLimit, "10stake"),
fmt.Sprintf("--%s=%s", flags.FlagFrom, granter),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, 60*60),
fmt.Sprintf("--%s=%s", cli.FlagExpiration, getFormattedExpiration(oneHour)),
},
commonFlags...,
),
@ -398,10 +404,10 @@ func (s *IntegrationTestSuite) TestNewCmdFeeGrant() {
granter.String(),
"cosmos1w55kgcf3ltaqdy4ww49nge3klxmrdavrr6frmp",
fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, "100stake"),
fmt.Sprintf("--%s=%d", cli.FlagPeriod, 60*60),
fmt.Sprintf("--%s=%d", cli.FlagPeriod, oneHour),
fmt.Sprintf("--%s=%s", cli.FlagPeriodLimit, "10stake"),
fmt.Sprintf("--%s=%s", flags.FlagFrom, granter),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, 10*60*60),
fmt.Sprintf("--%s=%s", cli.FlagExpiration, getFormattedExpiration(tenHours)),
},
commonFlags...,
),
@ -413,10 +419,10 @@ func (s *IntegrationTestSuite) TestNewCmdFeeGrant() {
[]string{
granter.String(),
"cosmos1vevyks8pthkscvgazc97qyfjt40m6g9xe85ry8",
fmt.Sprintf("--%s=%d", cli.FlagPeriod, 60*60),
fmt.Sprintf("--%s=%d", cli.FlagPeriod, oneHour),
fmt.Sprintf("--%s=%s", cli.FlagPeriodLimit, "10stake"),
fmt.Sprintf("--%s=%s", flags.FlagFrom, granter),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, 10*60*60),
fmt.Sprintf("--%s=%s", cli.FlagExpiration, getFormattedExpiration(tenHours)),
},
commonFlags...,
),
@ -429,7 +435,7 @@ func (s *IntegrationTestSuite) TestNewCmdFeeGrant() {
granter.String(),
"cosmos14cm33pvnrv2497tyt8sp9yavhmw83nwej3m0e8",
fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, "100stake"),
fmt.Sprintf("--%s=%d", cli.FlagPeriod, 60*60),
fmt.Sprintf("--%s=%d", cli.FlagPeriod, oneHour),
fmt.Sprintf("--%s=%s", cli.FlagPeriodLimit, "10stake"),
fmt.Sprintf("--%s=%s", flags.FlagFrom, granter),
},
@ -443,7 +449,7 @@ func (s *IntegrationTestSuite) TestNewCmdFeeGrant() {
[]string{
granter.String(),
"cosmos12nyk4pcf4arshznkpz882e4l4ts0lt0ap8ce54",
fmt.Sprintf("--%s=%d", cli.FlagPeriod, 60*60),
fmt.Sprintf("--%s=%d", cli.FlagPeriod, oneHour),
fmt.Sprintf("--%s=%s", cli.FlagPeriodLimit, "10stake"),
fmt.Sprintf("--%s=%s", flags.FlagFrom, granter),
},
@ -451,6 +457,21 @@ func (s *IntegrationTestSuite) TestNewCmdFeeGrant() {
),
false, 0, &sdk.TxResponse{},
},
{
"invalid expiration",
append(
[]string{
granter.String(),
"cosmos1vevyks8pthkscvgazc97qyfjt40m6g9xe85ry8",
fmt.Sprintf("--%s=%d", cli.FlagPeriod, oneHour),
fmt.Sprintf("--%s=%s", cli.FlagPeriodLimit, "10stake"),
fmt.Sprintf("--%s=%s", flags.FlagFrom, granter),
fmt.Sprintf("--%s=%s", cli.FlagExpiration, "invalid"),
},
commonFlags...,
),
true, 0, nil,
},
}
for _, tc := range testCases {
@ -579,7 +600,6 @@ func (s *IntegrationTestSuite) TestTxWithFeeGrant() {
}
fee := sdk.NewCoin("stake", sdk.NewInt(100))
duration := 365 * 24 * 60 * 60
args := append(
[]string{
@ -587,7 +607,7 @@ func (s *IntegrationTestSuite) TestTxWithFeeGrant() {
grantee.String(),
fmt.Sprintf("--%s=%s", cli.FlagSpendLimit, fee.String()),
fmt.Sprintf("--%s=%s", flags.FlagFrom, granter),
fmt.Sprintf("--%s=%v", cli.FlagExpiration, duration),
fmt.Sprintf("--%s=%s", cli.FlagExpiration, getFormattedExpiration(oneYear)),
},
commonFlags...,
)
@ -786,3 +806,7 @@ func (s *IntegrationTestSuite) TestFilteredFeeAllowance() {
})
}
}
func getFormattedExpiration(duration int64) string {
return time.Now().Add(time.Duration(duration) * time.Second).Format(time.RFC3339)
}

View File

@ -6,17 +6,24 @@ import (
"github.com/cosmos/cosmos-sdk/x/feegrant/types"
)
// GenesisState contains a set of fee allowances, persisted from the store
type GenesisState []types.FeeAllowanceGrant
// InitGenesis will initialize the keeper from a *previously validated* GenesisState
func InitGenesis(ctx sdk.Context, k keeper.Keeper, data *types.GenesisState) error {
for _, f := range data.FeeAllowances {
granter, err := sdk.AccAddressFromBech32(f.Granter)
if err != nil {
return err
}
grantee, err := sdk.AccAddressFromBech32(f.Grantee)
if err != nil {
return err
}
// ValidateBasic ensures all grants in the genesis state are valid
func (g GenesisState) ValidateBasic() error {
for _, f := range g {
grant, err := f.GetFeeGrant()
if err != nil {
return err
}
err = grant.ValidateBasic()
err = k.GrantFeeAllowance(ctx, granter, grantee, grant)
if err != nil {
return err
}
@ -24,30 +31,6 @@ func (g GenesisState) ValidateBasic() error {
return nil
}
// InitGenesis will initialize the keeper from a *previously validated* GenesisState
func InitGenesis(ctx sdk.Context, k keeper.Keeper, data *types.GenesisState) {
for _, f := range data.FeeAllowances {
granter, err := sdk.AccAddressFromBech32(f.Granter)
if err != nil {
panic(err)
}
grantee, err := sdk.AccAddressFromBech32(f.Grantee)
if err != nil {
panic(err)
}
grant, err := f.GetFeeGrant()
if err != nil {
panic(err)
}
err = k.GrantFeeAllowance(ctx, granter, grantee, grant)
if err != nil {
panic(err)
}
}
}
// ExportGenesis will dump the contents of the keeper into a serializable GenesisState
//
// All expiration heights will be thrown off if we dump state and start at a new

View File

@ -6,8 +6,10 @@ import (
"github.com/stretchr/testify/suite"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
feegrant "github.com/cosmos/cosmos-sdk/x/feegrant"
"github.com/cosmos/cosmos-sdk/x/feegrant/keeper"
@ -46,12 +48,60 @@ func (suite *GenesisTestSuite) TestImportExportGenesis() {
suite.Require().NoError(err)
// Clear keeper
suite.keeper.RevokeFeeAllowance(suite.ctx, granterAddr, granteeAddr)
feegrant.InitGenesis(suite.ctx, suite.keeper, genesis)
err = feegrant.InitGenesis(suite.ctx, suite.keeper, genesis)
suite.Require().NoError(err)
newGenesis, err := feegrant.ExportGenesis(suite.ctx, suite.keeper)
suite.Require().NoError(err)
suite.Require().Equal(genesis, newGenesis)
}
func (suite *GenesisTestSuite) TestInitGenesis() {
any, err := codectypes.NewAnyWithValue(&testdata.Dog{})
suite.Require().NoError(err)
testCases := []struct {
name string
feeAllowances []types.FeeAllowanceGrant
}{
{
"invalid granter",
[]types.FeeAllowanceGrant{
{
Granter: "invalid granter",
Grantee: granteeAddr.String(),
},
},
},
{
"invalid grantee",
[]types.FeeAllowanceGrant{
{
Granter: granterAddr.String(),
Grantee: "invalid grantee",
},
},
},
{
"invalid allowance",
[]types.FeeAllowanceGrant{
{
Granter: granterAddr.String(),
Grantee: granteeAddr.String(),
Allowance: any,
},
},
},
}
for _, tc := range testCases {
tc := tc
suite.Run(tc.name, func() {
err := feegrant.InitGenesis(suite.ctx, suite.keeper, &types.GenesisState{FeeAllowances: tc.feeAllowances})
suite.Require().Error(err)
})
}
}
func TestGenesisTestSuite(t *testing.T) {
suite.Run(t, new(GenesisTestSuite))
}

View File

@ -0,0 +1,162 @@
package keeper_test
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/feegrant/types"
)
func (suite *KeeperTestSuite) TestFeeAllowance() {
ctx := suite.ctx
k := suite.app.FeeGrantKeeper
testCases := []struct {
name string
req *types.QueryFeeAllowanceRequest
expectErr bool
preRun func()
postRun func(_ *types.QueryFeeAllowanceResponse)
}{
{
"nil request",
nil,
true,
func() {},
func(*types.QueryFeeAllowanceResponse) {},
},
{
"fail: invalid granter",
&types.QueryFeeAllowanceRequest{
Granter: "invalid_granter",
Grantee: suite.addrs[0].String(),
},
true,
func() {},
func(*types.QueryFeeAllowanceResponse) {},
},
{
"fail: invalid grantee",
&types.QueryFeeAllowanceRequest{
Granter: suite.addrs[0].String(),
Grantee: "invalid_grantee",
},
true,
func() {},
func(*types.QueryFeeAllowanceResponse) {},
},
{
"fail: no grants",
&types.QueryFeeAllowanceRequest{
Granter: suite.addrs[0].String(),
Grantee: suite.addrs[1].String(),
},
true,
func() {},
func(*types.QueryFeeAllowanceResponse) {},
},
{
"valid query: expect single grant",
&types.QueryFeeAllowanceRequest{
Granter: suite.addrs[0].String(),
Grantee: suite.addrs[1].String(),
},
false,
func() {
grantFeeAllowance(suite)
},
func(allowance *types.QueryFeeAllowanceResponse) {
suite.Require().Equal(allowance.FeeAllowance.Granter, suite.addrs[0].String())
suite.Require().Equal(allowance.FeeAllowance.Grantee, suite.addrs[1].String())
},
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
tc.preRun()
resp, err := k.FeeAllowance(sdk.WrapSDKContext(ctx), tc.req)
if tc.expectErr {
suite.Require().Error(err)
} else {
suite.Require().NoError(err)
tc.postRun(resp)
}
})
}
}
func (suite *KeeperTestSuite) TestFeeAllowances() {
ctx := suite.ctx
k := suite.app.FeeGrantKeeper
testCases := []struct {
name string
req *types.QueryFeeAllowancesRequest
expectErr bool
preRun func()
postRun func(_ *types.QueryFeeAllowancesResponse)
}{
{
"nil request",
nil,
true,
func() {},
func(*types.QueryFeeAllowancesResponse) {},
},
{
"fail: invalid grantee",
&types.QueryFeeAllowancesRequest{
Grantee: "invalid_grantee",
},
true,
func() {},
func(*types.QueryFeeAllowancesResponse) {},
},
{
"no grants",
&types.QueryFeeAllowancesRequest{
Grantee: suite.addrs[1].String(),
},
false,
func() {},
func(resp *types.QueryFeeAllowancesResponse) {
suite.Require().Equal(len(resp.FeeAllowances), 0)
},
},
{
"valid query: expect single grant",
&types.QueryFeeAllowancesRequest{
Grantee: suite.addrs[1].String(),
},
false,
func() {
grantFeeAllowance(suite)
},
func(resp *types.QueryFeeAllowancesResponse) {
suite.Require().Equal(len(resp.FeeAllowances), 1)
suite.Require().Equal(resp.FeeAllowances[0].Granter, suite.addrs[0].String())
suite.Require().Equal(resp.FeeAllowances[0].Grantee, suite.addrs[1].String())
},
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
tc.preRun()
resp, err := k.FeeAllowances(sdk.WrapSDKContext(ctx), tc.req)
if tc.expectErr {
suite.Require().Error(err)
} else {
suite.Require().NoError(err)
tc.postRun(resp)
}
})
}
}
func grantFeeAllowance(suite *KeeperTestSuite) {
err := suite.app.FeeGrantKeeper.GrantFeeAllowance(suite.ctx, suite.addrs[0], suite.addrs[1], &types.BasicFeeAllowance{
SpendLimit: sdk.NewCoins(sdk.NewInt64Coin("atom", 555)),
Expiration: types.ExpiresAtHeight(334455),
})
suite.Require().NoError(err)
}

View File

@ -152,7 +152,10 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, bz jso
var gs types.GenesisState
cdc.MustUnmarshalJSON(bz, &gs)
InitGenesis(ctx, am.keeper, &gs)
err := InitGenesis(ctx, am.keeper, &gs)
if err != nil {
panic(err)
}
return []abci.ValidatorUpdate{}
}