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:
parent
fc256a3683
commit
3ab1bc2346
|
@ -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:
|
||||
|
|
|
@ -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..
|
||||
|
|
|
@ -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))
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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{}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue