From 1e1c812de20b2370fc8d05c8edc0514af3ea31b8 Mon Sep 17 00:00:00 2001 From: MD Aleem <72057206+aleem1314@users.noreply.github.com> Date: Wed, 5 May 2021 21:59:22 +0530 Subject: [PATCH] x/feegrant remove height base expiration (#9206) * remove height from proto files * remove PrepareForExport * fix basic fee * fix periodic fee * fix errors * fix error * fix errors * add tests * review changes * fix errors * fix tests * fix lint error * Update x/feegrant/types/basic_fee.go Co-authored-by: technicallyty <48813565+technicallyty@users.noreply.github.com> * fix errors * fix keeper tests * Update x/feegrant/keeper/keeper_test.go Co-authored-by: Marie Gauthier * review changes * review changes * fix tests * run make proto-gen * fix errors * Update x/feegrant/keeper/keeper_test.go Co-authored-by: atheeshp <59333759+atheeshp@users.noreply.github.com> * Update x/feegrant/keeper/keeper_test.go * update ADR * add test * review changes * review changes Co-authored-by: technicallyty <48813565+technicallyty@users.noreply.github.com> Co-authored-by: Marie Gauthier Co-authored-by: atheeshp <59333759+atheeshp@users.noreply.github.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- docs/architecture/adr-029-fee-grant-module.md | 102 ++- docs/core/proto-docs.md | 42 +- proto/cosmos/feegrant/v1beta1/feegrant.proto | 26 +- x/feegrant/client/cli/tx.go | 16 +- x/feegrant/genesis.go | 11 +- x/feegrant/genesis_test.go | 3 +- x/feegrant/keeper/grpc_query_test.go | 3 +- x/feegrant/keeper/keeper_test.go | 61 +- x/feegrant/keeper/msg_server_test.go | 13 +- x/feegrant/simulation/genesis.go | 2 +- x/feegrant/simulation/operations.go | 4 +- x/feegrant/simulation/operations_test.go | 7 +- x/feegrant/types/basic_fee.go | 26 +- x/feegrant/types/basic_fee_test.go | 215 ++--- x/feegrant/types/expected_keepers.go | 1 - x/feegrant/types/expiration.go | 138 ---- x/feegrant/types/expiration_test.go | 153 ---- x/feegrant/types/feegrant.pb.go | 740 ++---------------- x/feegrant/types/fees.go | 9 +- x/feegrant/types/filtered_fee.go | 19 - x/feegrant/types/grant.go | 33 - x/feegrant/types/grant_test.go | 53 +- x/feegrant/types/msgs_test.go | 65 +- x/feegrant/types/periodic_fee.go | 41 +- x/feegrant/types/periodic_fee_test.go | 251 +----- 25 files changed, 358 insertions(+), 1676 deletions(-) delete mode 100644 x/feegrant/types/expiration.go delete mode 100644 x/feegrant/types/expiration_test.go diff --git a/docs/architecture/adr-029-fee-grant-module.md b/docs/architecture/adr-029-fee-grant-module.md index 8ef0f722fa..6fa1cd32ff 100644 --- a/docs/architecture/adr-029-fee-grant-module.md +++ b/docs/architecture/adr-029-fee-grant-module.md @@ -3,6 +3,7 @@ ## Changelog - 2020/08/18: Initial Draft +- 2021/05/05: Removed height based expiration support and simplified naming. ## Status @@ -38,87 +39,76 @@ Fee allowances are defined by the extensible `FeeAllowanceI` interface: ```go type FeeAllowanceI { - // Accept can use fee payment requested as well as timestamp/height of the current block - // to determine whether or not to process this. This is checked in - // Keeper.UseGrantedFees and the return values should match how it is handled there. - // - // If it returns an error, the fee payment is rejected, otherwise it is accepted. - // The FeeAllowance implementation is expected to update it's internal state - // and will be saved again after an acceptance. - // - // If remove is true (regardless of the error), the FeeAllowance will be deleted from storage - // (eg. when it is used up). (See call to RevokeFeeAllowance in Keeper.UseGrantedFees) - Accept(fee sdk.Coins, blockTime time.Time, blockHeight int64) (remove bool, err error) + // Accept can use fee payment requested as well as timestamp of the current block + // to determine whether or not to process this. This is checked in + // Keeper.UseGrantedFees and the return values should match how it is handled there. + // + // If it returns an error, the fee payment is rejected, otherwise it is accepted. + // The FeeAllowance implementation is expected to update it's internal state + // and will be saved again after an acceptance. + // + // If remove is true (regardless of the error), the FeeAllowance will be deleted from storage + // (eg. when it is used up). (See call to RevokeFeeAllowance in Keeper.UseGrantedFees) + Accept(ctx sdk.Context, fee sdk.Coins, msgs []sdk.Msg) (remove bool, err error) + + // ValidateBasic should evaluate this FeeAllowance for internal consistency. + // Don't allow negative amounts, or negative periods for example. + ValidateBasic() error } ``` -Two basic fee allowance types, `BasicFeeAllowance` and `PeriodicFeeAllowance` are defined to support known use cases: +Two basic fee allowance types, `BasicAllowance` and `PeriodicAllowance` are defined to support known use cases: ```proto -// BasicFeeAllowance implements FeeAllowance with a one-time grant of tokens +// BasicAllowance implements FeeAllowanceI with a one-time grant of tokens // that optionally expires. The delegatee can use up to SpendLimit to cover fees. -message BasicFeeAllowance { - // spend_limit specifies the maximum amount of tokens that can be spent - // by this allowance and will be updated as tokens are spent. If it is - // empty, there is no spend limit and any amount of coins can be spent. - repeated cosmos_sdk.v1.Coin spend_limit = 1; +message BasicAllowance { + // spend_limit specifies the maximum amount of tokens that can be spent + // by this allowance and will be updated as tokens are spent. If it is + // empty, there is no spend limit and any amount of coins can be spent. + repeated cosmos_sdk.v1.Coin spend_limit = 1; - // expires_at specifies an optional time when this allowance expires - ExpiresAt expiration = 2; + // expiration specifies an optional time when this allowance expires + google.protobuf.Timestamp expiration = 2; } -// PeriodicFeeAllowance extends FeeAllowance to allow for both a maximum cap, +// PeriodicAllowance extends FeeAllowanceI to allow for both a maximum cap, // as well as a limit per time period. -message PeriodicFeeAllowance { - BasicFeeAllowance basic = 1; +message PeriodicAllowance { + BasicAllowance basic = 1; - // period specifies the time duration in which period_spend_limit coins can - // be spent before that allowance is reset - Duration period = 2; - - // period_spend_limit specifies the maximum number of coins that can be spent - // in the period - repeated cosmos_sdk.v1.Coin period_spend_limit = 3; + // period specifies the time duration in which period_spend_limit coins can + // be spent before that allowance is reset + google.protobuf.Duration period = 2; - // period_can_spend is the number of coins left to be spent before the period_reset time - repeated cosmos_sdk.v1.Coin period_can_spend = 4; - - // period_reset is the time at which this period resets and a new one begins, - // it is calculated from the start time of the first transaction after the - // last period ended - ExpiresAt period_reset = 5; -} + // period_spend_limit specifies the maximum number of coins that can be spent + // in the period + repeated cosmos_sdk.v1.Coin period_spend_limit = 3; -// ExpiresAt is a point in time where something expires. -// It may be *either* block time or block height -message ExpiresAt { - oneof sum { - google.protobuf.Timestamp time = 1; - uint64 height = 2; - } - } + // period_can_spend is the number of coins left to be spent before the period_reset time + repeated cosmos_sdk.v1.Coin period_can_spend = 4; -// Duration is a repeating unit of either clock time or number of blocks. -message Duration { - oneof sum { - google.protobuf.Duration duration = 1; - uint64 blocks = 2; - } + // period_reset is the time at which this period resets and a new one begins, + // it is calculated from the start time of the first transaction after the + // last period ended + google.protobuf.Timestamp period_reset = 5; } ``` -Allowances can be granted and revoked using `MsgGrantFeeAllowance` and `MsgRevokeFeeAllowance`: +Allowances can be granted and revoked using `MsgGrantAllowance` and `MsgRevokeAllowance`: ```proto -message MsgGrantFeeAllowance { +// MsgGrantAllowance adds permission for Grantee to spend up to Allowance +// of fees from the account of Granter. +message MsgGrantAllowance { string granter = 1; string grantee = 2; google.protobuf.Any allowance = 3; } - // MsgRevokeFeeAllowance removes any existing FeeAllowance from Granter to Grantee. - message MsgRevokeFeeAllowance { + // MsgRevokeAllowance removes any existing FeeAllowance from Granter to Grantee. + message MsgRevokeAllowance { string granter = 1; string grantee = 2; } diff --git a/docs/core/proto-docs.md b/docs/core/proto-docs.md index 1e7ce1136d..82652f8fd1 100644 --- a/docs/core/proto-docs.md +++ b/docs/core/proto-docs.md @@ -309,8 +309,6 @@ - [cosmos/feegrant/v1beta1/feegrant.proto](#cosmos/feegrant/v1beta1/feegrant.proto) - [AllowedMsgAllowance](#cosmos.feegrant.v1beta1.AllowedMsgAllowance) - [BasicAllowance](#cosmos.feegrant.v1beta1.BasicAllowance) - - [Duration](#cosmos.feegrant.v1beta1.Duration) - - [ExpiresAt](#cosmos.feegrant.v1beta1.ExpiresAt) - [Grant](#cosmos.feegrant.v1beta1.Grant) - [PeriodicAllowance](#cosmos.feegrant.v1beta1.PeriodicAllowance) @@ -4571,41 +4569,7 @@ that optionally expires. The grantee can use up to SpendLimit to cover fees. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `spend_limit` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | spend_limit specifies the maximum amount of tokens that can be spent by this allowance and will be updated as tokens are spent. If it is empty, there is no spend limit and any amount of coins can be spent. | -| `expiration` | [ExpiresAt](#cosmos.feegrant.v1beta1.ExpiresAt) | | expiration specifies an optional time when this allowance expires | - - - - - - - - -### Duration -Duration is a span of a clock time or number of blocks. -This is designed to be added to an ExpiresAt struct. - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `duration` | [google.protobuf.Duration](#google.protobuf.Duration) | | | -| `blocks` | [uint64](#uint64) | | | - - - - - - - - -### ExpiresAt -ExpiresAt is a point in time where something expires. -It may be *either* block time or block height - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `time` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | | -| `height` | [int64](#int64) | | | +| `expiration` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | expiration specifies an optional time when this allowance expires | @@ -4639,10 +4603,10 @@ as well as a limit per time period. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `basic` | [BasicAllowance](#cosmos.feegrant.v1beta1.BasicAllowance) | | basic specifies a struct of `BasicAllowance` | -| `period` | [Duration](#cosmos.feegrant.v1beta1.Duration) | | period specifies the time duration in which period_spend_limit coins can be spent before that allowance is reset | +| `period` | [google.protobuf.Duration](#google.protobuf.Duration) | | period specifies the time duration in which period_spend_limit coins can be spent before that allowance is reset | | `period_spend_limit` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | period_spend_limit specifies the maximum number of coins that can be spent in the period | | `period_can_spend` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | period_can_spend is the number of coins left to be spent before the period_reset time | -| `period_reset` | [ExpiresAt](#cosmos.feegrant.v1beta1.ExpiresAt) | | period_reset is the time at which this period resets and a new one begins, it is calculated from the start time of the first transaction after the last period ended | +| `period_reset` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | period_reset is the time at which this period resets and a new one begins, it is calculated from the start time of the first transaction after the last period ended | diff --git a/proto/cosmos/feegrant/v1beta1/feegrant.proto b/proto/cosmos/feegrant/v1beta1/feegrant.proto index 9ecec0d66a..4fddf904c7 100644 --- a/proto/cosmos/feegrant/v1beta1/feegrant.proto +++ b/proto/cosmos/feegrant/v1beta1/feegrant.proto @@ -22,7 +22,7 @@ message BasicAllowance { [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; // expiration specifies an optional time when this allowance expires - ExpiresAt expiration = 2 [(gogoproto.nullable) = false]; + google.protobuf.Timestamp expiration = 2 [(gogoproto.stdtime) = true]; } // PeriodicAllowance extends Allowance to allow for both a maximum cap, @@ -35,7 +35,7 @@ message PeriodicAllowance { // period specifies the time duration in which period_spend_limit coins can // be spent before that allowance is reset - Duration period = 2 [(gogoproto.nullable) = false]; + google.protobuf.Duration period = 2 [(gogoproto.stdduration) = true, (gogoproto.nullable) = false]; // period_spend_limit specifies the maximum number of coins that can be spent // in the period @@ -49,7 +49,7 @@ message PeriodicAllowance { // period_reset is the time at which this period resets and a new one begins, // it is calculated from the start time of the first transaction after the // last period ended - ExpiresAt period_reset = 5 [(gogoproto.nullable) = false]; + google.protobuf.Timestamp period_reset = 5 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; } // AllowedMsgAllowance creates allowance only for specified message types. @@ -64,26 +64,6 @@ message AllowedMsgAllowance { repeated string allowed_messages = 2; } -// Duration is a span of a clock time or number of blocks. -// This is designed to be added to an ExpiresAt struct. -message Duration { - // sum is the oneof that represents either duration or block - oneof sum { - google.protobuf.Duration duration = 1 [(gogoproto.stdduration) = true]; - uint64 blocks = 2; - } -} - -// ExpiresAt is a point in time where something expires. -// It may be *either* block time or block height -message ExpiresAt { - // sum is the oneof that represents either time or height - oneof sum { - google.protobuf.Timestamp time = 1 [(gogoproto.stdtime) = true]; - int64 height = 2; - } -} - // Grant is stored in the KVStore to record a grant with full context message Grant { // granter is the address of the user granting an allowance of their funds. diff --git a/x/feegrant/client/cli/tx.go b/x/feegrant/client/cli/tx.go index 6c7ebc1c9d..ce4920bc06 100644 --- a/x/feegrant/client/cli/tx.go +++ b/x/feegrant/client/cli/tx.go @@ -107,7 +107,7 @@ Examples: if err != nil { return err } - basic.Expiration = types.ExpiresAtTime(expiresAtTime) + basic.Expiration = &expiresAtTime } var grant types.FeeAllowanceI @@ -131,15 +131,15 @@ Examples: } if periodClock > 0 && periodLimit != nil { - periodReset := time.Now().Add(time.Duration(periodClock) * time.Second) + periodReset := getPeriodReset(periodClock) if exp != "" && periodReset.Sub(expiresAtTime) > 0 { return fmt.Errorf("period(%d) cannot reset after expiration(%v)", periodClock, exp) } periodic := types.PeriodicAllowance{ Basic: basic, - Period: types.ClockDuration(time.Duration(periodClock) * time.Second), - PeriodReset: types.ExpiresAtTime(periodReset), + Period: getPeriod(periodClock), + PeriodReset: getPeriodReset(periodClock), PeriodSpendLimit: periodLimit, PeriodCanSpend: periodLimit, } @@ -230,3 +230,11 @@ Example: flags.AddTxFlagsToCmd(cmd) return cmd } + +func getPeriodReset(duration int64) time.Time { + return time.Now().Add(getPeriod(duration)) +} + +func getPeriod(duration int64) time.Duration { + return time.Duration(duration) * time.Second +} diff --git a/x/feegrant/genesis.go b/x/feegrant/genesis.go index 6adb987295..d5cec0aaca 100644 --- a/x/feegrant/genesis.go +++ b/x/feegrant/genesis.go @@ -31,19 +31,12 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, data *types.GenesisState) err return nil } -// 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 -// chain at height 0. Thus, we allow the Allowances to "prepare themselves" -// for export, like if they have expiry at 5000 and current is 4000, they export with -// expiry of 1000. Every FeeAllowance has a method `PrepareForExport` that allows -// them to perform any changes needed prior to export. +// ExportGenesis will dump the contents of the keeper into a serializable GenesisState. func ExportGenesis(ctx sdk.Context, k keeper.Keeper) (*types.GenesisState, error) { - time, height := ctx.BlockTime(), ctx.BlockHeight() var grants []types.Grant err := k.IterateAllFeeAllowances(ctx, func(grant types.Grant) bool { - grants = append(grants, grant.PrepareForExport(time, height)) + grants = append(grants, grant) return false }) diff --git a/x/feegrant/genesis_test.go b/x/feegrant/genesis_test.go index 7172f7e1db..ffccd4663d 100644 --- a/x/feegrant/genesis_test.go +++ b/x/feegrant/genesis_test.go @@ -39,9 +39,10 @@ var ( func (suite *GenesisTestSuite) TestImportExportGenesis() { coins := sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(1_000))) now := suite.ctx.BlockHeader().Time + oneYear := now.AddDate(1, 0, 0) msgSrvr := keeper.NewMsgServerImpl(suite.keeper) - allowance := &types.BasicAllowance{SpendLimit: coins, Expiration: types.ExpiresAtTime(now.AddDate(1, 0, 0))} + allowance := &types.BasicAllowance{SpendLimit: coins, Expiration: &oneYear} err := suite.keeper.GrantAllowance(suite.ctx, granterAddr, granteeAddr, allowance) suite.Require().NoError(err) diff --git a/x/feegrant/keeper/grpc_query_test.go b/x/feegrant/keeper/grpc_query_test.go index 6011c0152b..55432ae0cb 100644 --- a/x/feegrant/keeper/grpc_query_test.go +++ b/x/feegrant/keeper/grpc_query_test.go @@ -149,9 +149,10 @@ func (suite *KeeperTestSuite) TestFeeAllowances() { } func grantFeeAllowance(suite *KeeperTestSuite) { + exp := suite.sdkCtx.BlockTime().AddDate(1, 0, 0) err := suite.app.FeeGrantKeeper.GrantAllowance(suite.sdkCtx, suite.addrs[0], suite.addrs[1], &types.BasicAllowance{ SpendLimit: sdk.NewCoins(sdk.NewInt64Coin("atom", 555)), - Expiration: types.ExpiresAtHeight(334455), + Expiration: &exp, }) suite.Require().NoError(err) } diff --git a/x/feegrant/keeper/keeper_test.go b/x/feegrant/keeper/keeper_test.go index 63493ebd04..4c63b1b917 100644 --- a/x/feegrant/keeper/keeper_test.go +++ b/x/feegrant/keeper/keeper_test.go @@ -3,7 +3,6 @@ package keeper_test import ( "context" "testing" - "time" "github.com/stretchr/testify/suite" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -46,14 +45,15 @@ func (suite *KeeperTestSuite) SetupTest() { func (suite *KeeperTestSuite) TestKeeperCrud() { // some helpers eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 123)) + exp := suite.sdkCtx.BlockTime().AddDate(1, 0, 0) basic := &types.BasicAllowance{ SpendLimit: suite.atom, - Expiration: types.ExpiresAtHeight(334455), + Expiration: &exp, } basic2 := &types.BasicAllowance{ SpendLimit: eth, - Expiration: types.ExpiresAtHeight(172436), + Expiration: &exp, } // let's set up some initial state here @@ -149,24 +149,20 @@ func (suite *KeeperTestSuite) TestKeeperCrud() { func (suite *KeeperTestSuite) TestUseGrantedFee() { eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 123)) + blockTime := suite.sdkCtx.BlockTime() + oneYear := blockTime.AddDate(1, 0, 0) + future := &types.BasicAllowance{ SpendLimit: suite.atom, - Expiration: types.ExpiresAtHeight(5678), - } - - expired := &types.BasicAllowance{ - SpendLimit: eth, - Expiration: types.ExpiresAtHeight(55), + Expiration: &oneYear, } // for testing limits of the contract hugeAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 9999)) - _ = hugeAtom smallAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 1)) - _ = smallAtom futureAfterSmall := &types.BasicAllowance{ SpendLimit: sdk.NewCoins(sdk.NewInt64Coin("atom", 554)), - Expiration: types.ExpiresAtHeight(5678), + Expiration: &oneYear, } // then lots of queries @@ -184,13 +180,6 @@ func (suite *KeeperTestSuite) TestUseGrantedFee() { allowed: true, final: nil, }, - "expired and removed": { - granter: suite.addrs[0], - grantee: suite.addrs[2], - fee: eth, - allowed: false, - final: nil, - }, "too high": { granter: suite.addrs[0], grantee: suite.addrs[1], @@ -210,16 +199,9 @@ func (suite *KeeperTestSuite) TestUseGrantedFee() { for name, tc := range cases { tc := tc suite.Run(name, func() { - // let's set up some initial state here - // addr -> addr2 (future) - // addr -> addr3 (expired) - err := suite.keeper.GrantAllowance(suite.sdkCtx, suite.addrs[0], suite.addrs[1], future) suite.Require().NoError(err) - err = suite.keeper.GrantAllowance(suite.sdkCtx, suite.addrs[0], suite.addrs[3], expired) - suite.Require().NoError(err) - err = suite.keeper.UseGrantedFees(suite.sdkCtx, tc.granter, tc.grantee, tc.fee, []sdk.Msg{}) if tc.allowed { suite.NoError(err) @@ -228,22 +210,43 @@ func (suite *KeeperTestSuite) TestUseGrantedFee() { } loaded, _ := suite.keeper.GetAllowance(suite.sdkCtx, tc.granter, tc.grantee) - suite.Equal(tc.final, loaded) }) } + + expired := &types.BasicAllowance{ + SpendLimit: eth, + Expiration: &blockTime, + } + // creating expired feegrant + ctx := suite.sdkCtx.WithBlockTime(oneYear) + err := suite.keeper.GrantAllowance(ctx, suite.addrs[0], suite.addrs[2], expired) + suite.Require().NoError(err) + + // expect error: feegrant expired + err = suite.keeper.UseGrantedFees(ctx, suite.addrs[0], suite.addrs[2], eth, []sdk.Msg{}) + suite.Error(err) + suite.Contains(err.Error(), "fee allowance expired") + + // verify: feegrant is revoked + _, err = suite.keeper.GetAllowance(ctx, suite.addrs[0], suite.addrs[2]) + suite.Error(err) + suite.Contains(err.Error(), "fee-grant not found") + } func (suite *KeeperTestSuite) TestIterateGrants() { eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 123)) + exp := suite.sdkCtx.BlockTime().AddDate(1, 0, 0) + allowance := &types.BasicAllowance{ SpendLimit: suite.atom, - Expiration: types.ExpiresAtHeight(5678), + Expiration: &exp, } allowance1 := &types.BasicAllowance{ SpendLimit: eth, - Expiration: types.ExpiresAtTime(suite.sdkCtx.BlockTime().Add(24 * time.Hour)), + Expiration: &exp, } suite.keeper.GrantAllowance(suite.sdkCtx, suite.addrs[0], suite.addrs[1], allowance) diff --git a/x/feegrant/keeper/msg_server_test.go b/x/feegrant/keeper/msg_server_test.go index 05a2f6b8d9..e00f618ffd 100644 --- a/x/feegrant/keeper/msg_server_test.go +++ b/x/feegrant/keeper/msg_server_test.go @@ -7,6 +7,8 @@ import ( ) func (suite *KeeperTestSuite) TestGrantFeeAllowance() { + oneYear := suite.sdkCtx.BlockTime().AddDate(1, 0, 0) + testCases := []struct { name string req func() *types.MsgGrantAllowance @@ -46,7 +48,7 @@ func (suite *KeeperTestSuite) TestGrantFeeAllowance() { func() *types.MsgGrantAllowance { any, err := codectypes.NewAnyWithValue(&types.BasicAllowance{ SpendLimit: suite.atom, - Expiration: types.ExpiresAtTime(suite.sdkCtx.BlockTime().AddDate(1, 0, 0)), + Expiration: &oneYear, }) suite.Require().NoError(err) return &types.MsgGrantAllowance{ @@ -63,7 +65,7 @@ func (suite *KeeperTestSuite) TestGrantFeeAllowance() { func() *types.MsgGrantAllowance { any, err := codectypes.NewAnyWithValue(&types.BasicAllowance{ SpendLimit: suite.atom, - Expiration: types.ExpiresAtTime(suite.sdkCtx.BlockTime().AddDate(1, 0, 0)), + Expiration: &oneYear, }) suite.Require().NoError(err) return &types.MsgGrantAllowance{ @@ -81,7 +83,7 @@ func (suite *KeeperTestSuite) TestGrantFeeAllowance() { any, err := codectypes.NewAnyWithValue(&types.PeriodicAllowance{ Basic: types.BasicAllowance{ SpendLimit: suite.atom, - Expiration: types.ExpiresAtTime(suite.sdkCtx.BlockTime().AddDate(1, 0, 0)), + Expiration: &oneYear, }, }) suite.Require().NoError(err) @@ -100,7 +102,7 @@ func (suite *KeeperTestSuite) TestGrantFeeAllowance() { any, err := codectypes.NewAnyWithValue(&types.PeriodicAllowance{ Basic: types.BasicAllowance{ SpendLimit: suite.atom, - Expiration: types.ExpiresAtTime(suite.sdkCtx.BlockTime().AddDate(1, 0, 0)), + Expiration: &oneYear, }, }) suite.Require().NoError(err) @@ -126,6 +128,7 @@ func (suite *KeeperTestSuite) TestGrantFeeAllowance() { } func (suite *KeeperTestSuite) TestRevokeFeeAllowance() { + oneYear := suite.sdkCtx.BlockTime().AddDate(1, 0, 0) testCases := []struct { name string @@ -179,7 +182,7 @@ func (suite *KeeperTestSuite) TestRevokeFeeAllowance() { any, err := codectypes.NewAnyWithValue(&types.PeriodicAllowance{ Basic: types.BasicAllowance{ SpendLimit: suite.atom, - Expiration: types.ExpiresAtTime(suite.sdkCtx.BlockTime().AddDate(1, 0, 0)), + Expiration: &oneYear, }, }) suite.Require().NoError(err) diff --git a/x/feegrant/simulation/genesis.go b/x/feegrant/simulation/genesis.go index b078a4abd9..5d4e837e39 100644 --- a/x/feegrant/simulation/genesis.go +++ b/x/feegrant/simulation/genesis.go @@ -43,7 +43,7 @@ func generateRandomAllowances(granter, grantee sdk.AccAddress, r *rand.Rand) typ periodicAllowance, err := types.NewGrant(granter, grantee, &types.PeriodicAllowance{ Basic: basic, PeriodSpendLimit: periodSpendLimit, - Period: types.ClockDuration(time.Hour), + Period: time.Hour, }) if err != nil { panic(err) diff --git a/x/feegrant/simulation/operations.go b/x/feegrant/simulation/operations.go index f15b98c455..441f888c22 100644 --- a/x/feegrant/simulation/operations.go +++ b/x/feegrant/simulation/operations.go @@ -3,7 +3,6 @@ package simulation import ( "context" "math/rand" - "time" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" @@ -91,9 +90,10 @@ func SimulateMsgGrantFeeAllowance(ak types.AccountKeeper, bk types.BankKeeper, k return simtypes.NoOpMsg(types.ModuleName, TypeMsgGrantFeeAllowance, "unable to grant empty coins as SpendLimit"), nil, nil } + oneYear := ctx.BlockTime().AddDate(1, 0, 0) msg, err := types.NewMsgGrantAllowance(&types.BasicAllowance{ SpendLimit: spendableCoins, - Expiration: types.ExpiresAtTime(ctx.BlockTime().Add(30 * time.Hour)), + Expiration: &oneYear, }, granter.Address, grantee.Address) if err != nil { diff --git a/x/feegrant/simulation/operations_test.go b/x/feegrant/simulation/operations_test.go index eff68b2eb5..e721ed1bf1 100644 --- a/x/feegrant/simulation/operations_test.go +++ b/x/feegrant/simulation/operations_test.go @@ -31,7 +31,9 @@ func (suite *SimTestSuite) SetupTest() { checkTx := false app := simapp.Setup(checkTx) suite.app = app - suite.ctx = app.BaseApp.NewContext(checkTx, tmproto.Header{}) + suite.ctx = app.BaseApp.NewContext(checkTx, tmproto.Header{ + Time: time.Now(), + }) suite.protoCdc = codec.NewProtoCodec(suite.app.InterfaceRegistry()) } @@ -139,13 +141,14 @@ func (suite *SimTestSuite) TestSimulateMsgRevokeFeeAllowance() { granter, grantee := accounts[0], accounts[1] + oneYear := ctx.BlockTime().AddDate(1, 0, 0) err := app.FeeGrantKeeper.GrantAllowance( ctx, granter.Address, grantee.Address, &types.BasicAllowance{ SpendLimit: feeCoins, - Expiration: types.ExpiresAtTime(ctx.BlockTime().Add(30 * time.Hour)), + Expiration: &oneYear, }, ) require.NoError(err) diff --git a/x/feegrant/types/basic_fee.go b/x/feegrant/types/basic_fee.go index 0843f81183..d48823af9c 100644 --- a/x/feegrant/types/basic_fee.go +++ b/x/feegrant/types/basic_fee.go @@ -1,15 +1,13 @@ package types import ( - "time" - sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) var _ FeeAllowanceI = (*BasicAllowance)(nil) -// Accept can use fee payment requested as well as timestamp/height of the current block +// Accept can use fee payment requested as well as timestamp of the current block // to determine whether or not to process this. This is checked in // Keeper.UseGrantedFees and the return values should match how it is handled there. // @@ -20,10 +18,7 @@ var _ FeeAllowanceI = (*BasicAllowance)(nil) // If remove is true (regardless of the error), the FeeAllowance will be deleted from storage // (eg. when it is used up). (See call to RevokeFeeAllowance in Keeper.UseGrantedFees) func (a *BasicAllowance) Accept(ctx sdk.Context, fee sdk.Coins, _ []sdk.Msg) (bool, error) { - blockTime := ctx.BlockTime() - blockHeight := ctx.BlockHeight() - - if a.Expiration.IsExpired(&blockTime, blockHeight) { + if a.Expiration != nil && a.Expiration.Before(ctx.BlockTime()) { return true, sdkerrors.Wrap(ErrFeeLimitExpired, "basic allowance") } @@ -40,16 +35,6 @@ func (a *BasicAllowance) Accept(ctx sdk.Context, fee sdk.Coins, _ []sdk.Msg) (bo return false, nil } -// PrepareForExport will adjust the expiration based on export time. In particular, -// it will subtract the dumpHeight from any height-based expiration to ensure that -// the elapsed number of blocks this allowance is valid for is fixed. -func (a *BasicAllowance) PrepareForExport(dumpTime time.Time, dumpHeight int64) FeeAllowanceI { - return &BasicAllowance{ - SpendLimit: a.SpendLimit, - Expiration: a.Expiration.PrepareForExport(dumpTime, dumpHeight), - } -} - // ValidateBasic implements FeeAllowance and enforces basic sanity checks func (a BasicAllowance) ValidateBasic() error { if a.SpendLimit != nil { @@ -60,5 +45,10 @@ func (a BasicAllowance) ValidateBasic() error { return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, "spend limit must be positive") } } - return a.Expiration.ValidateBasic() + + if a.Expiration != nil && a.Expiration.Unix() < 0 { + return sdkerrors.Wrap(ErrInvalidDuration, "expiration time cannot be negative") + } + + return nil } diff --git a/x/feegrant/types/basic_fee_test.go b/x/feegrant/types/basic_fee_test.go index e93e2e4d73..818c48f2df 100644 --- a/x/feegrant/types/basic_fee_test.go +++ b/x/feegrant/types/basic_fee_test.go @@ -16,24 +16,37 @@ import ( func TestBasicFeeValidAllow(t *testing.T) { app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, tmproto.Header{}) + badTime := ctx.BlockTime().AddDate(0, 0, -1) + allowace := &types.BasicAllowance{ + Expiration: &badTime, + } + require.Error(t, allowace.ValidateBasic()) + + ctx = app.BaseApp.NewContext(false, tmproto.Header{ + Time: time.Now(), + }) eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 10)) atom := sdk.NewCoins(sdk.NewInt64Coin("atom", 555)) smallAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 43)) bigAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 1000)) leftAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 512)) + now := ctx.BlockTime() + oneHour := now.Add(1 * time.Hour) cases := map[string]struct { allowance *types.BasicAllowance // all other checks are ignored if valid=false - fee sdk.Coins - blockHeight int64 - accept bool - remove bool - remains sdk.Coins + fee sdk.Coins + blockTime time.Time + valid bool + accept bool + remove bool + remains sdk.Coins }{ "empty": { - allowance: &types.BasicAllowance{}, - accept: true, + allowance: &types.BasicAllowance{}, + accept: true, }, "small fee without expire": { allowance: &types.BasicAllowance{ @@ -62,48 +75,53 @@ func TestBasicFeeValidAllow(t *testing.T) { "non-expired": { allowance: &types.BasicAllowance{ SpendLimit: atom, - Expiration: types.ExpiresAtHeight(100), + Expiration: &oneHour, }, - fee: smallAtom, - blockHeight: 85, - accept: true, - remove: false, - remains: leftAtom, + valid: true, + fee: smallAtom, + blockTime: now, + accept: true, + remove: false, + remains: leftAtom, }, "expired": { allowance: &types.BasicAllowance{ SpendLimit: atom, - Expiration: types.ExpiresAtHeight(100), + Expiration: &now, }, - fee: smallAtom, - blockHeight: 121, - accept: false, - remove: true, + valid: true, + fee: smallAtom, + blockTime: oneHour, + accept: false, + remove: true, }, "fee more than allowed": { allowance: &types.BasicAllowance{ SpendLimit: atom, - Expiration: types.ExpiresAtHeight(100), + Expiration: &oneHour, }, - fee: bigAtom, - blockHeight: 85, - accept: false, + valid: true, + fee: bigAtom, + blockTime: now, + accept: false, }, "with out spend limit": { allowance: &types.BasicAllowance{ - Expiration: types.ExpiresAtHeight(100), + Expiration: &oneHour, }, - fee: bigAtom, - blockHeight: 85, - accept: true, + valid: true, + fee: bigAtom, + blockTime: now, + accept: true, }, "expired no spend limit": { allowance: &types.BasicAllowance{ - Expiration: types.ExpiresAtHeight(100), + Expiration: &now, }, - fee: bigAtom, - blockHeight: 120, - accept: false, + valid: true, + fee: bigAtom, + blockTime: oneHour, + accept: false, }, } @@ -113,7 +131,7 @@ func TestBasicFeeValidAllow(t *testing.T) { err := tc.allowance.ValidateBasic() require.NoError(t, err) - ctx := app.BaseApp.NewContext(false, tmproto.Header{}).WithBlockHeight(tc.blockHeight) + ctx := app.BaseApp.NewContext(false, tmproto.Header{}).WithBlockTime(tc.blockTime) // now try to deduct removed, err := tc.allowance.Accept(ctx, tc.fee, []sdk.Msg{}) @@ -130,138 +148,3 @@ func TestBasicFeeValidAllow(t *testing.T) { }) } } - -func TestBasicFeeAllowTime(t *testing.T) { - app := simapp.Setup(false) - - eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 10)) - atom := sdk.NewCoins(sdk.NewInt64Coin("atom", 555)) - smallAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 43)) - bigAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 1000)) - leftAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 512)) - - now := time.Now() - oneHour := now.Add(1 * time.Hour) - - cases := map[string]struct { - allow *types.BasicAllowance - // all other checks are ignored if valid=false - fee sdk.Coins - blockTime time.Time - valid bool - accept bool - remove bool - remains sdk.Coins - }{ - "empty": { - allow: &types.BasicAllowance{}, - valid: true, - accept: true, - }, - "small fee without expire": { - allow: &types.BasicAllowance{ - SpendLimit: atom, - }, - valid: true, - fee: smallAtom, - accept: true, - remove: false, - remains: leftAtom, - }, - "all fee without expire": { - allow: &types.BasicAllowance{ - SpendLimit: smallAtom, - }, - valid: true, - fee: smallAtom, - accept: true, - remove: true, - }, - "wrong fee": { - allow: &types.BasicAllowance{ - SpendLimit: smallAtom, - }, - valid: true, - fee: eth, - accept: false, - }, - "non-expired": { - allow: &types.BasicAllowance{ - SpendLimit: atom, - Expiration: types.ExpiresAtTime(oneHour), - }, - valid: true, - fee: smallAtom, - blockTime: now, - accept: true, - remove: false, - remains: leftAtom, - }, - "expired": { - allow: &types.BasicAllowance{ - SpendLimit: atom, - Expiration: types.ExpiresAtTime(now), - }, - valid: true, - fee: smallAtom, - blockTime: oneHour, - accept: false, - remove: true, - }, - "fee more than allowed": { - allow: &types.BasicAllowance{ - SpendLimit: atom, - Expiration: types.ExpiresAtTime(oneHour), - }, - valid: true, - fee: bigAtom, - blockTime: now, - accept: false, - }, - "without spend limit": { - allow: &types.BasicAllowance{ - Expiration: types.ExpiresAtTime(oneHour), - }, - valid: true, - fee: bigAtom, - blockTime: now, - accept: true, - }, - "expired no spend limit": { - allow: &types.BasicAllowance{ - Expiration: types.ExpiresAtTime(now), - }, - valid: true, - fee: bigAtom, - blockTime: oneHour, - accept: false, - }, - } - - for name, stc := range cases { - tc := stc // to make scopelint happy - t.Run(name, func(t *testing.T) { - err := tc.allow.ValidateBasic() - if !tc.valid { - require.Error(t, err) - return - } - require.NoError(t, err) - - ctx := app.BaseApp.NewContext(false, tmproto.Header{}).WithBlockTime(tc.blockTime) - - // now try to deduct - remove, err := tc.allow.Accept(ctx, tc.fee, []sdk.Msg{}) - if !tc.accept { - require.Error(t, err) - return - } - require.NoError(t, err) - - require.Equal(t, tc.remove, remove) - if !remove { - assert.Equal(t, tc.allow.SpendLimit, tc.remains) - } - }) - } -} diff --git a/x/feegrant/types/expected_keepers.go b/x/feegrant/types/expected_keepers.go index 40966b06d4..25dc974d2e 100644 --- a/x/feegrant/types/expected_keepers.go +++ b/x/feegrant/types/expected_keepers.go @@ -3,7 +3,6 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" auth "github.com/cosmos/cosmos-sdk/x/auth/types" - // supply "github.com/cosmos/cosmos-sdk/x/supply/exported" ) // AccountKeeper defines the expected auth Account Keeper (noalias) diff --git a/x/feegrant/types/expiration.go b/x/feegrant/types/expiration.go deleted file mode 100644 index 4922b6d481..0000000000 --- a/x/feegrant/types/expiration.go +++ /dev/null @@ -1,138 +0,0 @@ -package types - -import ( - "time" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -// ExpiresAtTime creates an expiration at the given time -func ExpiresAtTime(t time.Time) ExpiresAt { - return ExpiresAt{ - Sum: &ExpiresAt_Time{ - Time: &t, - }, - } -} - -// ExpiresAtHeight creates an expiration at the given height -func ExpiresAtHeight(h int64) ExpiresAt { - return ExpiresAt{ - &ExpiresAt_Height{ - Height: h, - }, - } -} - -// ValidateBasic performs basic sanity checks. -// Note that empty expiration is allowed -func (e ExpiresAt) ValidateBasic() error { - if e.HasDefinedTime() && e.GetHeight() != 0 { - return sdkerrors.Wrap(ErrInvalidDuration, "both time and height are set") - } - if e.GetHeight() < 0 { - return sdkerrors.Wrap(ErrInvalidDuration, "negative height") - } - return nil -} - -// Undefined returns true for an uninitialized struct -func (e ExpiresAt) Undefined() bool { - return (e.GetTime() == nil || e.GetTime().Unix() <= 0) && e.GetHeight() == 0 -} - -// HasDefinedTime returns true if `ExpiresAt` has valid time -func (e ExpiresAt) HasDefinedTime() bool { - t := e.GetTime() - return t != nil && t.Unix() > 0 -} - -// FastForward produces a new Expiration with the time or height set to the -// new value, depending on what was set on the original expiration -func (e ExpiresAt) FastForward(t time.Time, h int64) ExpiresAt { - if e.HasDefinedTime() { - return ExpiresAtTime(t) - } - return ExpiresAtHeight(h) -} - -// IsExpired returns if the time or height is *equal to* or greater -// than the defined expiration point. Note that it is expired upon -// an exact match. -// -// Note a "zero" ExpiresAt is never expired -func (e ExpiresAt) IsExpired(t *time.Time, h int64) bool { - if e.HasDefinedTime() && t.After(*e.GetTime()) { - return true - } - - return e.GetHeight() != 0 && h >= e.GetHeight() -} - -// IsCompatible returns true iff the two use the same units. -// If false, they cannot be added. -func (e ExpiresAt) IsCompatible(d Duration) bool { - if e.HasDefinedTime() { - return d.GetDuration() != nil && d.GetDuration().Seconds() > float64(0) - } - return d.GetBlocks() > 0 -} - -// Step will increase the expiration point by one Duration -// It returns an error if the Duration is incompatible -func (e ExpiresAt) Step(d Duration) (ExpiresAt, error) { - if !e.IsCompatible(d) { - return ExpiresAt{}, sdkerrors.Wrap(ErrInvalidDuration, "expiration time and provided duration have different units") - } - if e.HasDefinedTime() { - return ExpiresAtTime(e.GetTime().Add(*d.GetDuration())), nil - } - return ExpiresAtHeight(e.GetHeight() + int64(d.GetBlocks())), nil -} - -// MustStep is like Step, but panics on error -func (e ExpiresAt) MustStep(d Duration) ExpiresAt { - res, err := e.Step(d) - if err != nil { - panic(err) - } - return res -} - -// PrepareForExport will deduct the dumpHeight from the expiration, so when this is -// reloaded after a hard fork, the actual number of allowed blocks is constant -func (e ExpiresAt) PrepareForExport(dumpTime time.Time, dumpHeight int64) ExpiresAt { - if e.GetHeight() != 0 { - return ExpiresAtHeight(e.GetHeight() - dumpHeight) - } - return ExpiresAt{} -} - -// ClockDuration creates an Duration by clock time -func ClockDuration(d time.Duration) Duration { - return Duration{Sum: &Duration_Duration{ - Duration: &d, - }} -} - -// BlockDuration creates an Duration by block height -func BlockDuration(h uint64) Duration { - return Duration{Sum: &Duration_Blocks{ - Blocks: h, - }} -} - -// ValidateBasic performs basic sanity checks -// Note that exactly one must be set and it must be positive -func (d Duration) ValidateBasic() error { - if d.GetBlocks() == 0 && d.GetDuration() == nil { - return sdkerrors.Wrap(ErrInvalidDuration, "neither time and height are set") - } - if d.GetBlocks() != 0 && d.GetDuration() != nil && d.GetDuration().Seconds() != float64(0) { - return sdkerrors.Wrap(ErrInvalidDuration, "both time and height are set") - } - if d.GetDuration() != nil && d.GetDuration().Seconds() < 0 { - return sdkerrors.Wrap(ErrInvalidDuration, "negative clock step") - } - return nil -} diff --git a/x/feegrant/types/expiration_test.go b/x/feegrant/types/expiration_test.go deleted file mode 100644 index 3465dc1b4b..0000000000 --- a/x/feegrant/types/expiration_test.go +++ /dev/null @@ -1,153 +0,0 @@ -package types_test - -import ( - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/x/feegrant/types" -) - -func TestExpiresAt(t *testing.T) { - now := time.Now() - - cases := map[string]struct { - expires types.ExpiresAt - zero bool - before types.ExpiresAt - after types.ExpiresAt - }{ - "basic": { - expires: types.ExpiresAtHeight(100), - before: types.ExpiresAtHeight(50), - after: types.ExpiresAtHeight(122), - }, - "zero": { - expires: types.ExpiresAt{}, - zero: true, - before: types.ExpiresAtHeight(1), - }, - "match height": { - expires: types.ExpiresAtHeight(1000), - before: types.ExpiresAtHeight(999), - after: types.ExpiresAtHeight(1000), - }, - "match time": { - expires: types.ExpiresAtTime(now), - before: types.ExpiresAtTime(now.Add(-1 * time.Second)), - after: types.ExpiresAtTime(now.Add(1 * time.Second)), - }, - } - - for name, stc := range cases { - tc := stc // to make scopelint happy - t.Run(name, func(t *testing.T) { - err := tc.expires.ValidateBasic() - assert.Equal(t, tc.zero, tc.expires.Undefined()) - require.NoError(t, err) - - if !tc.before.Undefined() { - assert.Equal(t, false, tc.expires.IsExpired(tc.before.GetTime(), tc.before.GetHeight())) - } - if !tc.after.Undefined() { - assert.Equal(t, true, tc.expires.IsExpired(tc.after.GetTime(), tc.after.GetHeight())) - } - }) - } -} - -func TestDurationValid(t *testing.T) { - now := time.Now() - - cases := map[string]struct { - period types.Duration - valid bool - compatible types.ExpiresAt - incompatible types.ExpiresAt - }{ - "basic height": { - period: types.BlockDuration(100), - valid: true, - compatible: types.ExpiresAtHeight(50), - incompatible: types.ExpiresAtTime(now), - }, - "basic time": { - period: types.ClockDuration(time.Hour), - valid: true, - compatible: types.ExpiresAtTime(now), - incompatible: types.ExpiresAtHeight(50), - }, - "zero": { - period: types.Duration{}, - valid: false, - }, - "negative clock": { - period: types.ClockDuration(-1 * time.Hour), - valid: false, - }, - } - - for name, stc := range cases { - tc := stc // to make scopelint happy - t.Run(name, func(t *testing.T) { - err := tc.period.ValidateBasic() - if !tc.valid { - require.Error(t, err) - return - } - require.NoError(t, err) - - assert.Equal(t, true, tc.compatible.IsCompatible(tc.period)) - assert.Equal(t, false, tc.incompatible.IsCompatible(tc.period)) - }) - } -} - -func TestDurationStep(t *testing.T) { - now := time.Now() - - cases := map[string]struct { - expires types.ExpiresAt - period types.Duration - valid bool - result types.ExpiresAt - }{ - "add height": { - expires: types.ExpiresAtHeight(789), - period: types.BlockDuration(100), - valid: true, - result: types.ExpiresAtHeight(889), - }, - "add time": { - expires: types.ExpiresAtTime(now), - period: types.ClockDuration(time.Hour), - valid: true, - result: types.ExpiresAtTime(now.Add(time.Hour)), - }, - "mismatch": { - expires: types.ExpiresAtHeight(789), - period: types.ClockDuration(time.Hour), - valid: false, - }, - } - - for name, stc := range cases { - tc := stc // to make scopelint happy - t.Run(name, func(t *testing.T) { - err := tc.period.ValidateBasic() - require.NoError(t, err) - err = tc.expires.ValidateBasic() - require.NoError(t, err) - - next, err := tc.expires.Step(tc.period) - if !tc.valid { - require.Error(t, err) - return - } - require.NoError(t, err) - require.Equal(t, tc.result, next) - }) - } -} diff --git a/x/feegrant/types/feegrant.pb.go b/x/feegrant/types/feegrant.pb.go index 16e8d9cba3..e12af45e46 100644 --- a/x/feegrant/types/feegrant.pb.go +++ b/x/feegrant/types/feegrant.pb.go @@ -40,7 +40,7 @@ type BasicAllowance struct { // empty, there is no spend limit and any amount of coins can be spent. SpendLimit github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=spend_limit,json=spendLimit,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"spend_limit"` // expiration specifies an optional time when this allowance expires - Expiration ExpiresAt `protobuf:"bytes,2,opt,name=expiration,proto3" json:"expiration"` + Expiration *time.Time `protobuf:"bytes,2,opt,name=expiration,proto3,stdtime" json:"expiration,omitempty"` } func (m *BasicAllowance) Reset() { *m = BasicAllowance{} } @@ -83,11 +83,11 @@ func (m *BasicAllowance) GetSpendLimit() github_com_cosmos_cosmos_sdk_types.Coin return nil } -func (m *BasicAllowance) GetExpiration() ExpiresAt { +func (m *BasicAllowance) GetExpiration() *time.Time { if m != nil { return m.Expiration } - return ExpiresAt{} + return nil } // PeriodicAllowance extends Allowance to allow for both a maximum cap, @@ -97,7 +97,7 @@ type PeriodicAllowance struct { Basic BasicAllowance `protobuf:"bytes,1,opt,name=basic,proto3" json:"basic"` // period specifies the time duration in which period_spend_limit coins can // be spent before that allowance is reset - Period Duration `protobuf:"bytes,2,opt,name=period,proto3" json:"period"` + Period time.Duration `protobuf:"bytes,2,opt,name=period,proto3,stdduration" json:"period"` // period_spend_limit specifies the maximum number of coins that can be spent // in the period PeriodSpendLimit github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=period_spend_limit,json=periodSpendLimit,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"period_spend_limit"` @@ -106,7 +106,7 @@ type PeriodicAllowance struct { // period_reset is the time at which this period resets and a new one begins, // it is calculated from the start time of the first transaction after the // last period ended - PeriodReset ExpiresAt `protobuf:"bytes,5,opt,name=period_reset,json=periodReset,proto3" json:"period_reset"` + PeriodReset time.Time `protobuf:"bytes,5,opt,name=period_reset,json=periodReset,proto3,stdtime" json:"period_reset"` } func (m *PeriodicAllowance) Reset() { *m = PeriodicAllowance{} } @@ -149,11 +149,11 @@ func (m *PeriodicAllowance) GetBasic() BasicAllowance { return BasicAllowance{} } -func (m *PeriodicAllowance) GetPeriod() Duration { +func (m *PeriodicAllowance) GetPeriod() time.Duration { if m != nil { return m.Period } - return Duration{} + return 0 } func (m *PeriodicAllowance) GetPeriodSpendLimit() github_com_cosmos_cosmos_sdk_types.Coins { @@ -170,11 +170,11 @@ func (m *PeriodicAllowance) GetPeriodCanSpend() github_com_cosmos_cosmos_sdk_typ return nil } -func (m *PeriodicAllowance) GetPeriodReset() ExpiresAt { +func (m *PeriodicAllowance) GetPeriodReset() time.Time { if m != nil { return m.PeriodReset } - return ExpiresAt{} + return time.Time{} } // AllowedMsgAllowance creates allowance only for specified message types. @@ -218,184 +218,6 @@ func (m *AllowedMsgAllowance) XXX_DiscardUnknown() { var xxx_messageInfo_AllowedMsgAllowance proto.InternalMessageInfo -// Duration is a span of a clock time or number of blocks. -// This is designed to be added to an ExpiresAt struct. -type Duration struct { - // sum is the oneof that represents either duration or block - // - // Types that are valid to be assigned to Sum: - // *Duration_Duration - // *Duration_Blocks - Sum isDuration_Sum `protobuf_oneof:"sum"` -} - -func (m *Duration) Reset() { *m = Duration{} } -func (m *Duration) String() string { return proto.CompactTextString(m) } -func (*Duration) ProtoMessage() {} -func (*Duration) Descriptor() ([]byte, []int) { - return fileDescriptor_7279582900c30aea, []int{3} -} -func (m *Duration) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Duration) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_Duration.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *Duration) XXX_Merge(src proto.Message) { - xxx_messageInfo_Duration.Merge(m, src) -} -func (m *Duration) XXX_Size() int { - return m.Size() -} -func (m *Duration) XXX_DiscardUnknown() { - xxx_messageInfo_Duration.DiscardUnknown(m) -} - -var xxx_messageInfo_Duration proto.InternalMessageInfo - -type isDuration_Sum interface { - isDuration_Sum() - MarshalTo([]byte) (int, error) - Size() int -} - -type Duration_Duration struct { - Duration *time.Duration `protobuf:"bytes,1,opt,name=duration,proto3,oneof,stdduration" json:"duration,omitempty"` -} -type Duration_Blocks struct { - Blocks uint64 `protobuf:"varint,2,opt,name=blocks,proto3,oneof" json:"blocks,omitempty"` -} - -func (*Duration_Duration) isDuration_Sum() {} -func (*Duration_Blocks) isDuration_Sum() {} - -func (m *Duration) GetSum() isDuration_Sum { - if m != nil { - return m.Sum - } - return nil -} - -func (m *Duration) GetDuration() *time.Duration { - if x, ok := m.GetSum().(*Duration_Duration); ok { - return x.Duration - } - return nil -} - -func (m *Duration) GetBlocks() uint64 { - if x, ok := m.GetSum().(*Duration_Blocks); ok { - return x.Blocks - } - return 0 -} - -// XXX_OneofWrappers is for the internal use of the proto package. -func (*Duration) XXX_OneofWrappers() []interface{} { - return []interface{}{ - (*Duration_Duration)(nil), - (*Duration_Blocks)(nil), - } -} - -// ExpiresAt is a point in time where something expires. -// It may be *either* block time or block height -type ExpiresAt struct { - // sum is the oneof that represents either time or height - // - // Types that are valid to be assigned to Sum: - // *ExpiresAt_Time - // *ExpiresAt_Height - Sum isExpiresAt_Sum `protobuf_oneof:"sum"` -} - -func (m *ExpiresAt) Reset() { *m = ExpiresAt{} } -func (m *ExpiresAt) String() string { return proto.CompactTextString(m) } -func (*ExpiresAt) ProtoMessage() {} -func (*ExpiresAt) Descriptor() ([]byte, []int) { - return fileDescriptor_7279582900c30aea, []int{4} -} -func (m *ExpiresAt) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ExpiresAt) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ExpiresAt.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *ExpiresAt) XXX_Merge(src proto.Message) { - xxx_messageInfo_ExpiresAt.Merge(m, src) -} -func (m *ExpiresAt) XXX_Size() int { - return m.Size() -} -func (m *ExpiresAt) XXX_DiscardUnknown() { - xxx_messageInfo_ExpiresAt.DiscardUnknown(m) -} - -var xxx_messageInfo_ExpiresAt proto.InternalMessageInfo - -type isExpiresAt_Sum interface { - isExpiresAt_Sum() - MarshalTo([]byte) (int, error) - Size() int -} - -type ExpiresAt_Time struct { - Time *time.Time `protobuf:"bytes,1,opt,name=time,proto3,oneof,stdtime" json:"time,omitempty"` -} -type ExpiresAt_Height struct { - Height int64 `protobuf:"varint,2,opt,name=height,proto3,oneof" json:"height,omitempty"` -} - -func (*ExpiresAt_Time) isExpiresAt_Sum() {} -func (*ExpiresAt_Height) isExpiresAt_Sum() {} - -func (m *ExpiresAt) GetSum() isExpiresAt_Sum { - if m != nil { - return m.Sum - } - return nil -} - -func (m *ExpiresAt) GetTime() *time.Time { - if x, ok := m.GetSum().(*ExpiresAt_Time); ok { - return x.Time - } - return nil -} - -func (m *ExpiresAt) GetHeight() int64 { - if x, ok := m.GetSum().(*ExpiresAt_Height); ok { - return x.Height - } - return 0 -} - -// XXX_OneofWrappers is for the internal use of the proto package. -func (*ExpiresAt) XXX_OneofWrappers() []interface{} { - return []interface{}{ - (*ExpiresAt_Time)(nil), - (*ExpiresAt_Height)(nil), - } -} - // Grant is stored in the KVStore to record a grant with full context type Grant struct { // granter is the address of the user granting an allowance of their funds. @@ -410,7 +232,7 @@ func (m *Grant) Reset() { *m = Grant{} } func (m *Grant) String() string { return proto.CompactTextString(m) } func (*Grant) ProtoMessage() {} func (*Grant) Descriptor() ([]byte, []int) { - return fileDescriptor_7279582900c30aea, []int{5} + return fileDescriptor_7279582900c30aea, []int{3} } func (m *Grant) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -464,8 +286,6 @@ func init() { proto.RegisterType((*BasicAllowance)(nil), "cosmos.feegrant.v1beta1.BasicAllowance") proto.RegisterType((*PeriodicAllowance)(nil), "cosmos.feegrant.v1beta1.PeriodicAllowance") proto.RegisterType((*AllowedMsgAllowance)(nil), "cosmos.feegrant.v1beta1.AllowedMsgAllowance") - proto.RegisterType((*Duration)(nil), "cosmos.feegrant.v1beta1.Duration") - proto.RegisterType((*ExpiresAt)(nil), "cosmos.feegrant.v1beta1.ExpiresAt") proto.RegisterType((*Grant)(nil), "cosmos.feegrant.v1beta1.Grant") } @@ -474,48 +294,43 @@ func init() { } var fileDescriptor_7279582900c30aea = []byte{ - // 645 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xbf, 0x6f, 0xd3, 0x40, - 0x14, 0xb6, 0xeb, 0xa4, 0x34, 0x17, 0x28, 0xed, 0x51, 0x84, 0xdb, 0xc1, 0x29, 0x19, 0x20, 0x0c, - 0xb5, 0x69, 0x91, 0x18, 0x2a, 0x21, 0x54, 0x97, 0xd2, 0x22, 0xa8, 0x84, 0x0c, 0x13, 0x4b, 0x74, - 0xb6, 0xaf, 0xae, 0xa9, 0xed, 0xb3, 0x7c, 0x17, 0x68, 0x56, 0x26, 0xc6, 0x8e, 0x4c, 0x88, 0x99, - 0x99, 0x3f, 0xa2, 0x62, 0xaa, 0x98, 0x90, 0x90, 0x28, 0x6a, 0x46, 0xfe, 0x09, 0xe4, 0xbb, 0xb3, - 0x1d, 0x12, 0x82, 0x04, 0xea, 0x64, 0xbf, 0x7b, 0xef, 0xfb, 0xbe, 0xf7, 0xeb, 0x0e, 0xdc, 0xf0, - 0x08, 0x8d, 0x09, 0xb5, 0xf6, 0x30, 0x0e, 0x32, 0x94, 0x30, 0xeb, 0xd5, 0xaa, 0x8b, 0x19, 0x5a, - 0x2d, 0x0f, 0xcc, 0x34, 0x23, 0x8c, 0xc0, 0x6b, 0x22, 0xce, 0x2c, 0x8f, 0x65, 0xdc, 0xd2, 0x42, - 0x40, 0x02, 0xc2, 0x63, 0xac, 0xfc, 0x4f, 0x84, 0x2f, 0x2d, 0x06, 0x84, 0x04, 0x11, 0xb6, 0xb8, - 0xe5, 0xf6, 0xf6, 0x2c, 0x94, 0xf4, 0x0b, 0x97, 0x60, 0xea, 0x0a, 0x8c, 0xa4, 0x15, 0x2e, 0x43, - 0x26, 0xe3, 0x22, 0x8a, 0xcb, 0x44, 0x3c, 0x12, 0x26, 0xd2, 0xdf, 0x1a, 0x65, 0x65, 0x61, 0x8c, - 0x29, 0x43, 0x71, 0x5a, 0x10, 0x8c, 0x06, 0xf8, 0xbd, 0x0c, 0xb1, 0x90, 0x48, 0x82, 0xf6, 0x37, - 0x15, 0xcc, 0xda, 0x88, 0x86, 0xde, 0x46, 0x14, 0x91, 0xd7, 0x28, 0xf1, 0x30, 0x8c, 0x40, 0x93, - 0xa6, 0x38, 0xf1, 0xbb, 0x51, 0x18, 0x87, 0x4c, 0x57, 0x97, 0xb5, 0x4e, 0x73, 0x6d, 0xd1, 0x94, - 0x79, 0xe5, 0x99, 0x14, 0xa5, 0x9a, 0x9b, 0x24, 0x4c, 0xec, 0xdb, 0xc7, 0xdf, 0x5b, 0xca, 0xc7, - 0xd3, 0x56, 0x27, 0x08, 0xd9, 0x7e, 0xcf, 0x35, 0x3d, 0x12, 0xcb, 0x22, 0xe4, 0x67, 0x85, 0xfa, - 0x07, 0x16, 0xeb, 0xa7, 0x98, 0x72, 0x00, 0x75, 0x00, 0xe7, 0x7f, 0x92, 0xd3, 0xc3, 0x1d, 0x00, - 0xf0, 0x61, 0x1a, 0x8a, 0xa4, 0xf4, 0xa9, 0x65, 0xb5, 0xd3, 0x5c, 0x6b, 0x9b, 0x13, 0x7a, 0x6b, - 0x6e, 0xe5, 0xa1, 0x98, 0x6e, 0x30, 0xbb, 0x96, 0xab, 0x3a, 0x43, 0xd8, 0xf5, 0xf9, 0x2f, 0x9f, - 0x56, 0x2e, 0x3d, 0xc4, 0xb8, 0xac, 0xe4, 0x51, 0xfb, 0xa7, 0x06, 0xe6, 0x9f, 0xe2, 0x2c, 0x24, - 0xfe, 0x70, 0x81, 0x9b, 0xa0, 0xee, 0xe6, 0x25, 0xeb, 0x2a, 0x57, 0xbb, 0x39, 0x51, 0xed, 0xf7, - 0xc6, 0x48, 0x49, 0x81, 0x85, 0xf7, 0xc1, 0x74, 0xca, 0x99, 0x65, 0xce, 0xd7, 0x27, 0xb2, 0x3c, - 0x90, 0x1d, 0x97, 0x78, 0x09, 0x83, 0x7d, 0x00, 0xc5, 0x5f, 0x77, 0xb8, 0xdb, 0xda, 0xf9, 0x77, - 0x7b, 0x4e, 0xc8, 0x3c, 0xab, 0x7a, 0xde, 0x03, 0xf2, 0xac, 0xeb, 0xa1, 0x44, 0xc8, 0xeb, 0xb5, - 0xf3, 0x17, 0x9e, 0x15, 0x22, 0x9b, 0x28, 0xe1, 0xda, 0xf0, 0x31, 0xb8, 0x28, 0x65, 0x33, 0x4c, - 0x31, 0xd3, 0xeb, 0xff, 0x38, 0xec, 0xa6, 0x40, 0x3b, 0x39, 0xf8, 0x4f, 0xd3, 0x7e, 0xaf, 0x82, - 0x2b, 0xdc, 0xc4, 0xfe, 0x2e, 0x0d, 0xaa, 0x79, 0x6f, 0x81, 0x06, 0x2a, 0x0c, 0x39, 0xf3, 0x05, - 0x53, 0xdc, 0x0b, 0xb3, 0xb8, 0x17, 0xe6, 0x46, 0xd2, 0xb7, 0xe7, 0x3f, 0x8f, 0x72, 0x3a, 0x15, - 0x12, 0xde, 0x02, 0x73, 0x48, 0xb0, 0x77, 0x63, 0x4c, 0x29, 0x0a, 0x30, 0xd5, 0xa7, 0x96, 0xb5, - 0x4e, 0xc3, 0xb9, 0x2c, 0xcf, 0x77, 0xe5, 0xf1, 0xfa, 0xd5, 0xb7, 0x1f, 0x5a, 0xca, 0x78, 0x82, - 0x2f, 0xc1, 0x4c, 0xb1, 0x0c, 0xf0, 0x1e, 0x98, 0x29, 0xae, 0xa2, 0xcc, 0x69, 0x71, 0x2c, 0xa7, - 0x6a, 0x73, 0xde, 0x9d, 0xb6, 0xd4, 0x1d, 0xc5, 0x29, 0x21, 0x50, 0x07, 0xd3, 0x6e, 0x44, 0xbc, - 0x03, 0xca, 0xd7, 0xaf, 0xb6, 0xa3, 0x38, 0xd2, 0xb6, 0xeb, 0x40, 0xa3, 0xbd, 0xb8, 0xed, 0x83, - 0x46, 0xd9, 0x3f, 0x78, 0x17, 0xd4, 0xf2, 0x87, 0x41, 0x0a, 0x2d, 0x8d, 0x09, 0x3d, 0x2f, 0x5e, - 0x0d, 0xbb, 0x76, 0x24, 0x94, 0x78, 0x7c, 0xae, 0xb2, 0x8f, 0xc3, 0x60, 0x9f, 0x71, 0x15, 0x2d, - 0x57, 0x11, 0x76, 0xa1, 0xf2, 0x46, 0x05, 0xf5, 0xed, 0x7c, 0x68, 0x50, 0x07, 0x17, 0xf8, 0xf4, - 0x70, 0xc6, 0x55, 0x1a, 0x4e, 0x61, 0x56, 0x1e, 0xcc, 0x59, 0x4a, 0xcf, 0xc8, 0x60, 0xb4, 0xff, - 0x1d, 0x8c, 0xbd, 0x7d, 0x7c, 0x66, 0xa8, 0x27, 0x67, 0x86, 0xfa, 0xe3, 0xcc, 0x50, 0x8f, 0x06, - 0x86, 0x72, 0x32, 0x30, 0x94, 0xaf, 0x03, 0x43, 0x79, 0xb1, 0xf2, 0xd7, 0x5d, 0x3d, 0xac, 0xde, - 0x78, 0xbe, 0xb6, 0xee, 0x34, 0x17, 0xbd, 0xf3, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x5a, 0x4c, 0xb0, - 0x35, 0x03, 0x06, 0x00, 0x00, + // 564 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0x3f, 0x6f, 0xd3, 0x40, + 0x14, 0x8f, 0x9b, 0xa4, 0x90, 0x0b, 0x94, 0xc6, 0x14, 0xe1, 0x64, 0x70, 0xa2, 0x0e, 0x10, 0x86, + 0x9c, 0x69, 0xd9, 0xca, 0x42, 0x1d, 0x20, 0x42, 0xa2, 0x12, 0x32, 0x4c, 0x2c, 0xd1, 0xd9, 0x79, + 0x35, 0x27, 0x62, 0x9f, 0xe5, 0xbb, 0x40, 0xb3, 0x32, 0x31, 0x76, 0x64, 0x42, 0xcc, 0xcc, 0x7c, + 0x88, 0x8a, 0xa9, 0x82, 0x85, 0x89, 0xa2, 0xe4, 0x8b, 0x20, 0xdf, 0x9d, 0x93, 0x90, 0xf0, 0x47, + 0x42, 0x9d, 0xe2, 0xbb, 0xf7, 0x7e, 0xff, 0xde, 0x3b, 0x05, 0xdd, 0x08, 0x18, 0x8f, 0x18, 0x77, + 0x0e, 0x01, 0xc2, 0x94, 0xc4, 0xc2, 0x79, 0xb5, 0xe3, 0x83, 0x20, 0x3b, 0xb3, 0x0b, 0x9c, 0xa4, + 0x4c, 0x30, 0xf3, 0xba, 0xea, 0xc3, 0xb3, 0x6b, 0xdd, 0xd7, 0xd8, 0x0a, 0x59, 0xc8, 0x64, 0x8f, + 0x93, 0x7d, 0xa9, 0xf6, 0x46, 0x3d, 0x64, 0x2c, 0x1c, 0x82, 0x23, 0x4f, 0xfe, 0xe8, 0xd0, 0x21, + 0xf1, 0x38, 0x2f, 0x29, 0xa6, 0xbe, 0xc2, 0x68, 0x5a, 0x55, 0xb2, 0xb5, 0x19, 0x9f, 0x70, 0x98, + 0x19, 0x09, 0x18, 0x8d, 0x75, 0xbd, 0xb9, 0xcc, 0x2a, 0x68, 0x04, 0x5c, 0x90, 0x28, 0xc9, 0x09, + 0x96, 0x1b, 0x06, 0xa3, 0x94, 0x08, 0xca, 0x34, 0xc1, 0xf6, 0x57, 0x03, 0x6d, 0xb8, 0x84, 0xd3, + 0x60, 0x7f, 0x38, 0x64, 0xaf, 0x49, 0x1c, 0x80, 0x39, 0x44, 0x55, 0x9e, 0x40, 0x3c, 0xe8, 0x0f, + 0x69, 0x44, 0x85, 0x65, 0xb4, 0x8a, 0xed, 0xea, 0x6e, 0x1d, 0x6b, 0x5f, 0x99, 0x93, 0x3c, 0x2a, + 0xee, 0x32, 0x1a, 0xbb, 0xb7, 0x4f, 0xbe, 0x37, 0x0b, 0x1f, 0xcf, 0x9a, 0xed, 0x90, 0x8a, 0x17, + 0x23, 0x1f, 0x07, 0x2c, 0xd2, 0x21, 0xf4, 0x4f, 0x87, 0x0f, 0x5e, 0x3a, 0x62, 0x9c, 0x00, 0x97, + 0x00, 0xee, 0x21, 0xc9, 0xff, 0x38, 0xa3, 0x37, 0xef, 0x21, 0x04, 0x47, 0x09, 0x55, 0xa6, 0xac, + 0xb5, 0x96, 0xd1, 0xae, 0xee, 0x36, 0xb0, 0x72, 0x8d, 0x73, 0xd7, 0xf8, 0x59, 0x1e, 0xcb, 0x2d, + 0x1d, 0x9f, 0x35, 0x0d, 0x6f, 0x01, 0xb3, 0x57, 0xfb, 0xf2, 0xa9, 0x73, 0xf9, 0x21, 0xc0, 0x2c, + 0xc1, 0xa3, 0xed, 0x69, 0x11, 0xd5, 0x9e, 0x40, 0x4a, 0xd9, 0x60, 0x31, 0x58, 0x17, 0x95, 0xfd, + 0x2c, 0xaa, 0x65, 0x48, 0x95, 0x9b, 0xf8, 0x0f, 0x1b, 0xc4, 0xbf, 0x0e, 0xc4, 0x2d, 0x65, 0x01, + 0x3d, 0x85, 0x35, 0xef, 0xa2, 0xf5, 0x44, 0x32, 0x6b, 0xaf, 0xf5, 0x15, 0xaf, 0xf7, 0xf5, 0x84, + 0xdd, 0x8b, 0x19, 0xee, 0x5d, 0x66, 0x57, 0x43, 0xcc, 0x31, 0x32, 0xd5, 0x57, 0x7f, 0x71, 0xc2, + 0xc5, 0xf3, 0x9f, 0xf0, 0xa6, 0x92, 0x79, 0x3a, 0x9f, 0xf3, 0x08, 0xe9, 0xbb, 0x7e, 0x40, 0x62, + 0x25, 0x6f, 0x95, 0xce, 0x5f, 0x78, 0x43, 0x89, 0x74, 0x49, 0x2c, 0xb5, 0xcd, 0x1e, 0xba, 0xa4, + 0x65, 0x53, 0xe0, 0x20, 0xac, 0xf2, 0x3f, 0x17, 0x2c, 0xa7, 0x26, 0x97, 0x5c, 0x55, 0x48, 0x2f, + 0x03, 0xfe, 0x6e, 0xcb, 0xef, 0x0d, 0x74, 0x55, 0x1e, 0x61, 0x70, 0xc0, 0xc3, 0xf9, 0x9e, 0x1f, + 0xa0, 0x0a, 0xc9, 0x0f, 0x7a, 0xd7, 0x5b, 0x2b, 0x82, 0xfb, 0xf1, 0xd8, 0xad, 0x7d, 0x5e, 0xe6, + 0xf4, 0xe6, 0x48, 0xf3, 0x16, 0xda, 0x24, 0x8a, 0xbd, 0x1f, 0x01, 0xe7, 0x24, 0x04, 0x6e, 0xad, + 0xb5, 0x8a, 0xed, 0x8a, 0x77, 0x45, 0xdf, 0x1f, 0xe8, 0xeb, 0xbd, 0x6b, 0x6f, 0x3f, 0x34, 0x0b, + 0xab, 0x06, 0xdf, 0x18, 0xa8, 0xdc, 0xcb, 0x5e, 0x96, 0x69, 0xa1, 0x0b, 0xf2, 0x89, 0x41, 0x2a, + 0x0d, 0x55, 0xbc, 0xfc, 0x38, 0xaf, 0x80, 0x7c, 0x50, 0xb3, 0xca, 0x52, 0x8c, 0xe2, 0xff, 0xc6, + 0x70, 0x7b, 0x27, 0x13, 0xdb, 0x38, 0x9d, 0xd8, 0xc6, 0x8f, 0x89, 0x6d, 0x1c, 0x4f, 0xed, 0xc2, + 0xe9, 0xd4, 0x2e, 0x7c, 0x9b, 0xda, 0x85, 0xe7, 0x9d, 0xbf, 0x6e, 0xf5, 0x68, 0xfe, 0x0f, 0x28, + 0x17, 0xec, 0xaf, 0x4b, 0xd1, 0x3b, 0x3f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x34, 0xef, 0x7e, 0x35, + 0x21, 0x05, 0x00, 0x00, } func (m *BasicAllowance) Marshal() (dAtA []byte, err error) { @@ -538,16 +353,16 @@ func (m *BasicAllowance) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - { - size, err := m.Expiration.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + if m.Expiration != nil { + n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.Expiration, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(*m.Expiration):]) + if err1 != nil { + return 0, err1 } - i -= size - i = encodeVarintFeegrant(dAtA, i, uint64(size)) + i -= n1 + i = encodeVarintFeegrant(dAtA, i, uint64(n1)) + i-- + dAtA[i] = 0x12 } - i-- - dAtA[i] = 0x12 if len(m.SpendLimit) > 0 { for iNdEx := len(m.SpendLimit) - 1; iNdEx >= 0; iNdEx-- { { @@ -585,14 +400,12 @@ func (m *PeriodicAllowance) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - { - size, err := m.PeriodReset.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintFeegrant(dAtA, i, uint64(size)) + n2, err2 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.PeriodReset, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.PeriodReset):]) + if err2 != nil { + return 0, err2 } + i -= n2 + i = encodeVarintFeegrant(dAtA, i, uint64(n2)) i-- dAtA[i] = 0x2a if len(m.PeriodCanSpend) > 0 { @@ -623,14 +436,12 @@ func (m *PeriodicAllowance) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x1a } } - { - size, err := m.Period.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintFeegrant(dAtA, i, uint64(size)) + n3, err3 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.Period, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.Period):]) + if err3 != nil { + return 0, err3 } + i -= n3 + i = encodeVarintFeegrant(dAtA, i, uint64(n3)) i-- dAtA[i] = 0x12 { @@ -690,132 +501,6 @@ func (m *AllowedMsgAllowance) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *Duration) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Duration) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Duration) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Sum != nil { - { - size := m.Sum.Size() - i -= size - if _, err := m.Sum.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - } - } - return len(dAtA) - i, nil -} - -func (m *Duration_Duration) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Duration_Duration) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.Duration != nil { - n6, err6 := github_com_gogo_protobuf_types.StdDurationMarshalTo(*m.Duration, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(*m.Duration):]) - if err6 != nil { - return 0, err6 - } - i -= n6 - i = encodeVarintFeegrant(dAtA, i, uint64(n6)) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} -func (m *Duration_Blocks) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Duration_Blocks) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - i = encodeVarintFeegrant(dAtA, i, uint64(m.Blocks)) - i-- - dAtA[i] = 0x10 - return len(dAtA) - i, nil -} -func (m *ExpiresAt) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *ExpiresAt) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ExpiresAt) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Sum != nil { - { - size := m.Sum.Size() - i -= size - if _, err := m.Sum.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - } - } - return len(dAtA) - i, nil -} - -func (m *ExpiresAt_Time) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ExpiresAt_Time) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.Time != nil { - n7, err7 := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(*m.Time):]) - if err7 != nil { - return 0, err7 - } - i -= n7 - i = encodeVarintFeegrant(dAtA, i, uint64(n7)) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} -func (m *ExpiresAt_Height) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ExpiresAt_Height) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - i = encodeVarintFeegrant(dAtA, i, uint64(m.Height)) - i-- - dAtA[i] = 0x10 - return len(dAtA) - i, nil -} func (m *Grant) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -888,8 +573,10 @@ func (m *BasicAllowance) Size() (n int) { n += 1 + l + sovFeegrant(uint64(l)) } } - l = m.Expiration.Size() - n += 1 + l + sovFeegrant(uint64(l)) + if m.Expiration != nil { + l = github_com_gogo_protobuf_types.SizeOfStdTime(*m.Expiration) + n += 1 + l + sovFeegrant(uint64(l)) + } return n } @@ -901,7 +588,7 @@ func (m *PeriodicAllowance) Size() (n int) { _ = l l = m.Basic.Size() n += 1 + l + sovFeegrant(uint64(l)) - l = m.Period.Size() + l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.Period) n += 1 + l + sovFeegrant(uint64(l)) if len(m.PeriodSpendLimit) > 0 { for _, e := range m.PeriodSpendLimit { @@ -915,7 +602,7 @@ func (m *PeriodicAllowance) Size() (n int) { n += 1 + l + sovFeegrant(uint64(l)) } } - l = m.PeriodReset.Size() + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.PeriodReset) n += 1 + l + sovFeegrant(uint64(l)) return n } @@ -939,72 +626,6 @@ func (m *AllowedMsgAllowance) Size() (n int) { return n } -func (m *Duration) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Sum != nil { - n += m.Sum.Size() - } - return n -} - -func (m *Duration_Duration) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Duration != nil { - l = github_com_gogo_protobuf_types.SizeOfStdDuration(*m.Duration) - n += 1 + l + sovFeegrant(uint64(l)) - } - return n -} -func (m *Duration_Blocks) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - n += 1 + sovFeegrant(uint64(m.Blocks)) - return n -} -func (m *ExpiresAt) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Sum != nil { - n += m.Sum.Size() - } - return n -} - -func (m *ExpiresAt_Time) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Time != nil { - l = github_com_gogo_protobuf_types.SizeOfStdTime(*m.Time) - n += 1 + l + sovFeegrant(uint64(l)) - } - return n -} -func (m *ExpiresAt_Height) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - n += 1 + sovFeegrant(uint64(m.Height)) - return n -} func (m *Grant) Size() (n int) { if m == nil { return 0 @@ -1124,7 +745,10 @@ func (m *BasicAllowance) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Expiration.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if m.Expiration == nil { + m.Expiration = new(time.Time) + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(m.Expiration, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1240,7 +864,7 @@ func (m *PeriodicAllowance) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Period.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.Period, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1341,7 +965,7 @@ func (m *PeriodicAllowance) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.PeriodReset.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.PeriodReset, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1484,216 +1108,6 @@ func (m *AllowedMsgAllowance) Unmarshal(dAtA []byte) error { } return nil } -func (m *Duration) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowFeegrant - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Duration: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Duration: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Duration", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowFeegrant - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthFeegrant - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthFeegrant - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - v := new(time.Duration) - if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(v, dAtA[iNdEx:postIndex]); err != nil { - return err - } - m.Sum = &Duration_Duration{v} - iNdEx = postIndex - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Blocks", wireType) - } - var v uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowFeegrant - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Sum = &Duration_Blocks{v} - default: - iNdEx = preIndex - skippy, err := skipFeegrant(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthFeegrant - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *ExpiresAt) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowFeegrant - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ExpiresAt: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ExpiresAt: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Time", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowFeegrant - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthFeegrant - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthFeegrant - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - v := new(time.Time) - if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(v, dAtA[iNdEx:postIndex]); err != nil { - return err - } - m.Sum = &ExpiresAt_Time{v} - iNdEx = postIndex - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) - } - var v int64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowFeegrant - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Sum = &ExpiresAt_Height{v} - default: - iNdEx = preIndex - skippy, err := skipFeegrant(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthFeegrant - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func (m *Grant) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/feegrant/types/fees.go b/x/feegrant/types/fees.go index d4b5348579..33073929c7 100644 --- a/x/feegrant/types/fees.go +++ b/x/feegrant/types/fees.go @@ -1,15 +1,13 @@ package types import ( - "time" - sdk "github.com/cosmos/cosmos-sdk/types" ) // FeeAllowance implementations are tied to a given fee delegator and delegatee, // and are used to enforce fee grant limits. type FeeAllowanceI interface { - // Accept can use fee payment requested as well as timestamp/height of the current block + // Accept can use fee payment requested as well as timestamp of the current block // to determine whether or not to process this. This is checked in // Keeper.UseGrantedFees and the return values should match how it is handled there. // @@ -21,11 +19,6 @@ type FeeAllowanceI interface { // (eg. when it is used up). (See call to RevokeFeeAllowance in Keeper.UseGrantedFees) Accept(ctx sdk.Context, fee sdk.Coins, msgs []sdk.Msg) (remove bool, err error) - // If we export fee allowances the timing info will be quite off (eg. go from height 100000 to 0) - // This callback allows the fee-allowance to change it's state and return a copy that is adjusted - // given the time and height of the actual dump (may safely return self if no changes needed) - PrepareForExport(dumpTime time.Time, dumpHeight int64) FeeAllowanceI - // ValidateBasic should evaluate this FeeAllowance for internal consistency. // Don't allow negative amounts, or negative periods for example. ValidateBasic() error diff --git a/x/feegrant/types/filtered_fee.go b/x/feegrant/types/filtered_fee.go index 02de763928..b9da865d0f 100644 --- a/x/feegrant/types/filtered_fee.go +++ b/x/feegrant/types/filtered_fee.go @@ -1,8 +1,6 @@ package types import ( - "time" - "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -88,23 +86,6 @@ func (a *AllowedMsgAllowance) allMsgTypesAllowed(ctx sdk.Context, msgs []sdk.Msg return true } -// PrepareForExport will adjust the expiration based on export time. In particular, -// it will subtract the dumpHeight from any height-based expiration to ensure that -// the elapsed number of blocks this allowance is valid for is fixed. -func (a *AllowedMsgAllowance) PrepareForExport(dumpTime time.Time, dumpHeight int64) FeeAllowanceI { - allowance, err := a.GetAllowance() - if err != nil { - panic("failed to get allowance") - } - - f, err := NewAllowedMsgAllowance(allowance.PrepareForExport(dumpTime, dumpHeight), a.AllowedMessages) - if err != nil { - panic("failed to export filtered fee allowance") - } - - return f -} - // ValidateBasic implements FeeAllowance and enforces basic sanity checks func (a *AllowedMsgAllowance) ValidateBasic() error { if a.Allowance == nil { diff --git a/x/feegrant/types/grant.go b/x/feegrant/types/grant.go index 3834ba5df5..2f2dffde33 100644 --- a/x/feegrant/types/grant.go +++ b/x/feegrant/types/grant.go @@ -1,8 +1,6 @@ package types import ( - "time" - "github.com/gogo/protobuf/proto" "github.com/cosmos/cosmos-sdk/codec/types" @@ -70,34 +68,3 @@ func (a Grant) UnpackInterfaces(unpacker types.AnyUnpacker) error { var allowance FeeAllowanceI return unpacker.UnpackAny(a.Allowance, &allowance) } - -// PrepareForExport will make all needed changes to the allowance to prepare to be -// re-imported at height 0, and return a copy of this grant. -func (a Grant) PrepareForExport(dumpTime time.Time, dumpHeight int64) Grant { - f, err := a.GetGrant() - if err != nil { - return Grant{} - } - - feegrant := f.PrepareForExport(dumpTime, dumpHeight) - if feegrant == nil { - return Grant{} - } - - granter, err := sdk.AccAddressFromBech32(a.Granter) - if err != nil { - return Grant{} - } - - grantee, err := sdk.AccAddressFromBech32(a.Grantee) - if err != nil { - return Grant{} - } - - grant, err := NewGrant(granter, grantee, feegrant) - if err != nil { - return Grant{} - } - - return grant -} diff --git a/x/feegrant/types/grant_test.go b/x/feegrant/types/grant_test.go index a0b630aa4f..17b3b5f229 100644 --- a/x/feegrant/types/grant_test.go +++ b/x/feegrant/types/grant_test.go @@ -5,6 +5,7 @@ import ( "time" "github.com/stretchr/testify/require" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" @@ -18,57 +19,56 @@ func TestGrant(t *testing.T) { addr2, err := sdk.AccAddressFromBech32("cosmos1p9qh4ldfd6n0qehujsal4k7g0e37kel90rc4ts") require.NoError(t, err) atom := sdk.NewCoins(sdk.NewInt64Coin("atom", 555)) + ctx := app.BaseApp.NewContext(false, tmproto.Header{ + Time: time.Now(), + }) + now := ctx.BlockTime() + oneYear := now.AddDate(1, 0, 0) + zeroAtoms := sdk.NewCoins(sdk.NewInt64Coin("atom", 0)) cdc := app.AppCodec() cases := map[string]struct { granter sdk.AccAddress grantee sdk.AccAddress - limit sdk.Coins - expires types.ExpiresAt - valid bool + limit sdk.Coins + expires time.Time + valid bool }{ "good": { granter: addr2, grantee: addr, - limit: atom, - expires: types.ExpiresAtHeight(100), - valid: true, + limit: atom, + expires: oneYear, + valid: true, }, "no grantee": { granter: addr2, grantee: nil, - limit: atom, - expires: types.ExpiresAtHeight(100), - valid: false, + limit: atom, + expires: oneYear, + valid: false, }, "no granter": { granter: nil, grantee: addr, - limit: atom, - expires: types.ExpiresAtHeight(100), - valid: false, + limit: atom, + expires: oneYear, + valid: false, }, "self-grant": { granter: addr2, grantee: addr2, - limit: atom, - expires: types.ExpiresAtHeight(100), - valid: false, - }, - "bad height": { - granter: addr2, - grantee: addr, - limit: atom, - expires: types.ExpiresAtHeight(-100), - valid: false, + limit: atom, + expires: oneYear, + valid: false, }, "zero allowance": { granter: addr2, grantee: addr, - limit: zeroAtoms, - expires: types.ExpiresAtTime(time.Now().Add(3 * time.Hour)), - valid: false, + limit: zeroAtoms, + expires: oneYear, + valid: false, }, } @@ -77,7 +77,7 @@ func TestGrant(t *testing.T) { t.Run(name, func(t *testing.T) { grant, err := types.NewGrant(tc.granter, tc.grantee, &types.BasicAllowance{ SpendLimit: tc.limit, - Expiration: tc.expires, + Expiration: &tc.expires, }) require.NoError(t, err) err = grant.ValidateBasic() @@ -97,6 +97,7 @@ func TestGrant(t *testing.T) { err = loaded.ValidateBasic() require.NoError(t, err) + require.Equal(t, grant, loaded) }) } diff --git a/x/feegrant/types/msgs_test.go b/x/feegrant/types/msgs_test.go index 05ac101f94..344a970039 100644 --- a/x/feegrant/types/msgs_test.go +++ b/x/feegrant/types/msgs_test.go @@ -1,13 +1,14 @@ package types_test import ( + "testing" + "time" + "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/feegrant/types" "github.com/stretchr/testify/require" - "testing" - "time" ) func TestMsgGrantFeeAllowance(t *testing.T) { @@ -15,43 +16,45 @@ func TestMsgGrantFeeAllowance(t *testing.T) { addr, _ := sdk.AccAddressFromBech32("cosmos1aeuqja06474dfrj7uqsvukm6rael982kk89mqr") addr2, _ := sdk.AccAddressFromBech32("cosmos1nph3cfzk6trsmfxkeu943nvach5qw4vwstnvkl") atom := sdk.NewCoins(sdk.NewInt64Coin("atom", 555)) + threeHours := time.Now().Add(3 * time.Hour) basic := &types.BasicAllowance{ SpendLimit: atom, - Expiration: types.ExpiresAtTime(time.Now().Add(3 * time.Hour)), + Expiration: &threeHours, } + cases := map[string]struct { grantee sdk.AccAddress granter sdk.AccAddress - grant *types.BasicAllowance - valid bool + grant *types.BasicAllowance + valid bool }{ - "valid":{ + "valid": { grantee: addr, granter: addr2, - grant: basic, - valid: true, + grant: basic, + valid: true, }, "no grantee": { granter: addr2, grantee: sdk.AccAddress{}, - grant: basic, - valid: false, + grant: basic, + valid: false, }, "no granter": { granter: sdk.AccAddress{}, grantee: addr, - grant: basic, - valid: false, + grant: basic, + valid: false, }, - "grantee == granter":{ + "grantee == granter": { grantee: addr, granter: addr, - grant: basic, - valid: false, + grant: basic, + valid: false, }, } - for _,tc := range cases { + for _, tc := range cases { msg, err := types.NewMsgGrantAllowance(tc.grant, tc.granter, tc.grantee) require.NoError(t, err) err = msg.ValidateBasic() @@ -78,43 +81,45 @@ func TestMsgRevokeFeeAllowance(t *testing.T) { addr, _ := sdk.AccAddressFromBech32("cosmos1aeuqja06474dfrj7uqsvukm6rael982kk89mqr") addr2, _ := sdk.AccAddressFromBech32("cosmos1nph3cfzk6trsmfxkeu943nvach5qw4vwstnvkl") atom := sdk.NewCoins(sdk.NewInt64Coin("atom", 555)) + threeHours := time.Now().Add(3 * time.Hour) + basic := &types.BasicAllowance{ SpendLimit: atom, - Expiration: types.ExpiresAtTime(time.Now().Add(3 * time.Hour)), + Expiration: &threeHours, } cases := map[string]struct { grantee sdk.AccAddress granter sdk.AccAddress - grant *types.BasicAllowance - valid bool + grant *types.BasicAllowance + valid bool }{ - "valid":{ + "valid": { grantee: addr, granter: addr2, - grant: basic, - valid: true, + grant: basic, + valid: true, }, "no grantee": { granter: addr2, grantee: sdk.AccAddress{}, - grant: basic, - valid: false, + grant: basic, + valid: false, }, "no granter": { granter: sdk.AccAddress{}, grantee: addr, - grant: basic, - valid: false, + grant: basic, + valid: false, }, - "grantee == granter":{ + "grantee == granter": { grantee: addr, granter: addr, - grant: basic, - valid: false, + grant: basic, + valid: false, }, } - for _,tc := range cases { + for _, tc := range cases { msg := types.NewMsgRevokeAllowance(tc.granter, tc.grantee) err := msg.ValidateBasic() if tc.valid { diff --git a/x/feegrant/types/periodic_fee.go b/x/feegrant/types/periodic_fee.go index b62127ef98..eb1edd044e 100644 --- a/x/feegrant/types/periodic_fee.go +++ b/x/feegrant/types/periodic_fee.go @@ -9,7 +9,7 @@ import ( var _ FeeAllowanceI = (*PeriodicAllowance)(nil) -// Accept can use fee payment requested as well as timestamp/height of the current block +// Accept can use fee payment requested as well as timestamp of the current block // to determine whether or not to process this. This is checked in // Keeper.UseGrantedFees and the return values should match how it is handled there. // @@ -21,13 +21,12 @@ var _ FeeAllowanceI = (*PeriodicAllowance)(nil) // (eg. when it is used up). (See call to RevokeFeeAllowance in Keeper.UseGrantedFees) func (a *PeriodicAllowance) Accept(ctx sdk.Context, fee sdk.Coins, _ []sdk.Msg) (bool, error) { blockTime := ctx.BlockTime() - blockHeight := ctx.BlockHeight() - if a.Basic.Expiration.IsExpired(&blockTime, blockHeight) { + if a.Basic.Expiration != nil && blockTime.After(*a.Basic.Expiration) { return true, sdkerrors.Wrap(ErrFeeLimitExpired, "absolute limit") } - a.tryResetPeriod(blockTime, blockHeight) + a.tryResetPeriod(blockTime) // deduct from both the current period and the max amount var isNeg bool @@ -54,8 +53,8 @@ func (a *PeriodicAllowance) Accept(ctx sdk.Context, fee sdk.Coins, _ []sdk.Msg) // It will also update the PeriodReset. If we are within one Period, it will update from the // last PeriodReset (eg. if you always do one tx per day, it will always reset the same time) // If we are more then one period out (eg. no activity in a week), reset is one Period from the execution of this method -func (a *PeriodicAllowance) tryResetPeriod(blockTime time.Time, blockHeight int64) { - if !a.PeriodReset.Undefined() && !a.PeriodReset.IsExpired(&blockTime, blockHeight) { +func (a *PeriodicAllowance) tryResetPeriod(blockTime time.Time) { + if blockTime.Before(a.PeriodReset) { return } // set CanSpend to the lesser of PeriodSpendLimit and the TotalLimit @@ -67,26 +66,9 @@ func (a *PeriodicAllowance) tryResetPeriod(blockTime time.Time, blockHeight int6 // If we are within the period, step from expiration (eg. if you always do one tx per day, it will always reset the same time) // If we are more then one period out (eg. no activity in a week), reset is one period from this time - a.PeriodReset = a.PeriodReset.MustStep(a.Period) - if a.PeriodReset.IsExpired(&blockTime, blockHeight) { - a.PeriodReset = a.PeriodReset.FastForward(blockTime, blockHeight).MustStep(a.Period) - } -} - -// PrepareForExport will adjust the expiration based on export time. In particular, -// it will subtract the dumpHeight from any height-based expiration to ensure that -// the elapsed number of blocks this allowance is valid for is fixed. -// (For PeriodReset and Basic.Expiration) -func (a *PeriodicAllowance) PrepareForExport(dumpTime time.Time, dumpHeight int64) FeeAllowanceI { - return &PeriodicAllowance{ - Basic: BasicAllowance{ - SpendLimit: a.Basic.SpendLimit, - Expiration: a.Basic.Expiration.PrepareForExport(dumpTime, dumpHeight), - }, - PeriodSpendLimit: a.PeriodSpendLimit, - PeriodCanSpend: a.PeriodCanSpend, - Period: a.Period, - PeriodReset: a.PeriodReset.PrepareForExport(dumpTime, dumpHeight), + a.PeriodReset = a.PeriodReset.Add(a.Period) + if blockTime.After(a.PeriodReset) { + a.PeriodReset = blockTime.Add(a.Period) } } @@ -116,8 +98,9 @@ func (a PeriodicAllowance) ValidateBasic() error { } // check times - if err := a.Period.ValidateBasic(); err != nil { - return err + if a.Period.Seconds() < 0 { + return sdkerrors.Wrap(ErrInvalidDuration, "negative clock step") } - return a.PeriodReset.ValidateBasic() + + return nil } diff --git a/x/feegrant/types/periodic_fee_test.go b/x/feegrant/types/periodic_fee_test.go index 5b0e60f6f8..8d5273f9ac 100644 --- a/x/feegrant/types/periodic_fee_test.go +++ b/x/feegrant/types/periodic_fee_test.go @@ -15,209 +15,20 @@ import ( func TestPeriodicFeeValidAllow(t *testing.T) { app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, tmproto.Header{ + Time: time.Now(), + }) + atom := sdk.NewCoins(sdk.NewInt64Coin("atom", 555)) smallAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 43)) leftAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 512)) oneAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 1)) eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 1)) - cases := map[string]struct { - allowance types.PeriodicAllowance - // all other checks are ignored if valid=false - fee sdk.Coins - blockHeight int64 - valid bool - accept bool - remove bool - remains sdk.Coins - remainsPeriod sdk.Coins - periodReset types.ExpiresAt - }{ - "empty": { - allowance: types.PeriodicAllowance{}, - valid: false, - }, - "only basic": { - allowance: types.PeriodicAllowance{ - Basic: types.BasicAllowance{ - SpendLimit: atom, - Expiration: types.ExpiresAtHeight(100), - }, - }, - valid: false, - }, - "empty basic": { - allowance: types.PeriodicAllowance{ - Period: types.BlockDuration(10), - PeriodSpendLimit: smallAtom, - PeriodReset: types.ExpiresAtHeight(70), - }, - blockHeight: 75, - valid: true, - accept: true, - remove: false, - periodReset: types.ExpiresAtHeight(80), - }, - "mismatched currencies": { - allowance: types.PeriodicAllowance{ - Basic: types.BasicAllowance{ - SpendLimit: atom, - Expiration: types.ExpiresAtHeight(100), - }, - Period: types.BlockDuration(10), - PeriodSpendLimit: eth, - }, - valid: false, - }, - "first time": { - allowance: types.PeriodicAllowance{ - Basic: types.BasicAllowance{ - SpendLimit: atom, - Expiration: types.ExpiresAtHeight(100), - }, - Period: types.BlockDuration(10), - PeriodSpendLimit: smallAtom, - }, - valid: true, - fee: smallAtom, - blockHeight: 75, - accept: true, - remove: false, - remainsPeriod: nil, - remains: leftAtom, - periodReset: types.ExpiresAtHeight(85), - }, - "same period": { - allowance: types.PeriodicAllowance{ - Basic: types.BasicAllowance{ - SpendLimit: atom, - Expiration: types.ExpiresAtHeight(100), - }, - Period: types.BlockDuration(10), - PeriodReset: types.ExpiresAtHeight(80), - PeriodSpendLimit: leftAtom, - PeriodCanSpend: smallAtom, - }, - valid: true, - fee: smallAtom, - blockHeight: 75, - accept: true, - remove: false, - remainsPeriod: nil, - remains: leftAtom, - periodReset: types.ExpiresAtHeight(80), - }, - "step one period": { - allowance: types.PeriodicAllowance{ - Basic: types.BasicAllowance{ - SpendLimit: atom, - Expiration: types.ExpiresAtHeight(100), - }, - Period: types.BlockDuration(10), - PeriodReset: types.ExpiresAtHeight(70), - PeriodSpendLimit: leftAtom, - }, - valid: true, - fee: leftAtom, - blockHeight: 75, - accept: true, - remove: false, - remainsPeriod: nil, - remains: smallAtom, - periodReset: types.ExpiresAtHeight(80), // one step from last reset, not now - }, - "step limited by global allowance": { - allowance: types.PeriodicAllowance{ - Basic: types.BasicAllowance{ - SpendLimit: smallAtom, - Expiration: types.ExpiresAtHeight(100), - }, - Period: types.BlockDuration(10), - PeriodReset: types.ExpiresAtHeight(70), - PeriodSpendLimit: atom, - }, - valid: true, - fee: oneAtom, - blockHeight: 75, - accept: true, - remove: false, - remainsPeriod: smallAtom.Sub(oneAtom), - remains: smallAtom.Sub(oneAtom), - periodReset: types.ExpiresAtHeight(80), // one step from last reset, not now - }, - "expired": { - allowance: types.PeriodicAllowance{ - Basic: types.BasicAllowance{ - SpendLimit: atom, - Expiration: types.ExpiresAtHeight(100), - }, - Period: types.BlockDuration(10), - PeriodSpendLimit: smallAtom, - }, - valid: true, - fee: smallAtom, - blockHeight: 101, - accept: false, - remove: true, - }, - "over period limit": { - allowance: types.PeriodicAllowance{ - Basic: types.BasicAllowance{ - SpendLimit: atom, - Expiration: types.ExpiresAtHeight(100), - }, - Period: types.BlockDuration(10), - PeriodReset: types.ExpiresAtHeight(80), - PeriodSpendLimit: leftAtom, - PeriodCanSpend: smallAtom, - }, - valid: true, - fee: leftAtom, - blockHeight: 70, - accept: false, - remove: true, - }, - } - - for name, stc := range cases { - tc := stc // to make scopelint happy - t.Run(name, func(t *testing.T) { - err := tc.allowance.ValidateBasic() - if !tc.valid { - require.Error(t, err) - return - } - require.NoError(t, err) - - ctx := app.BaseApp.NewContext(false, tmproto.Header{}).WithBlockHeight(tc.blockHeight) - // now try to deduct - removed, err := tc.allowance.Accept(ctx, tc.fee, []sdk.Msg{}) - if !tc.accept { - require.Error(t, err) - return - } - require.NoError(t, err) - - require.Equal(t, tc.remove, removed) - if !removed { - assert.Equal(t, tc.remains, tc.allowance.Basic.SpendLimit) - assert.Equal(t, tc.remainsPeriod, tc.allowance.PeriodCanSpend) - assert.Equal(t, tc.periodReset, tc.allowance.PeriodReset) - } - }) - } -} - -func TestPeriodicFeeValidAllowTime(t *testing.T) { - app := simapp.Setup(false) - atom := sdk.NewCoins(sdk.NewInt64Coin("atom", 555)) - smallAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 43)) - leftAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 512)) - oneAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 1)) - eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 1)) - - now := time.Now() + now := ctx.BlockTime() oneHour := now.Add(1 * time.Hour) + twoHours := now.Add(2 * time.Hour) + tenMinutes := time.Duration(10) * time.Minute cases := map[string]struct { allow types.PeriodicAllowance @@ -229,7 +40,7 @@ func TestPeriodicFeeValidAllowTime(t *testing.T) { remove bool remains sdk.Coins remainsPeriod sdk.Coins - periodReset types.ExpiresAt + periodReset time.Time }{ "empty": { allow: types.PeriodicAllowance{}, @@ -239,30 +50,30 @@ func TestPeriodicFeeValidAllowTime(t *testing.T) { allow: types.PeriodicAllowance{ Basic: types.BasicAllowance{ SpendLimit: atom, - Expiration: types.ExpiresAtTime(oneHour), + Expiration: &oneHour, }, }, valid: false, }, "empty basic": { allow: types.PeriodicAllowance{ - Period: types.ClockDuration(time.Duration(10) * time.Minute), + Period: tenMinutes, PeriodSpendLimit: smallAtom, - PeriodReset: types.ExpiresAtTime(now.Add(30 * time.Minute)), + PeriodReset: now.Add(30 * time.Minute), }, blockTime: now, valid: true, accept: true, remove: false, - periodReset: types.ExpiresAtTime(now.Add(30 * time.Minute)), + periodReset: now.Add(30 * time.Minute), }, "mismatched currencies": { allow: types.PeriodicAllowance{ Basic: types.BasicAllowance{ SpendLimit: atom, - Expiration: types.ExpiresAtTime(oneHour), + Expiration: &oneHour, }, - Period: types.ClockDuration(10 * time.Minute), + Period: tenMinutes, PeriodSpendLimit: eth, }, valid: false, @@ -271,10 +82,10 @@ func TestPeriodicFeeValidAllowTime(t *testing.T) { allow: types.PeriodicAllowance{ Basic: types.BasicAllowance{ SpendLimit: atom, - Expiration: types.ExpiresAtTime(now.Add(2 * time.Hour)), + Expiration: &twoHours, }, - Period: types.ClockDuration(10), - PeriodReset: types.ExpiresAtTime(now.Add(1 * time.Hour)), + Period: tenMinutes, + PeriodReset: now.Add(1 * time.Hour), PeriodSpendLimit: leftAtom, PeriodCanSpend: smallAtom, }, @@ -285,16 +96,16 @@ func TestPeriodicFeeValidAllowTime(t *testing.T) { remove: false, remainsPeriod: nil, remains: leftAtom, - periodReset: types.ExpiresAtTime(now.Add(1 * time.Hour)), + periodReset: now.Add(1 * time.Hour), }, "step one period": { allow: types.PeriodicAllowance{ Basic: types.BasicAllowance{ SpendLimit: atom, - Expiration: types.ExpiresAtTime(now.Add(2 * time.Hour)), + Expiration: &twoHours, }, - Period: types.ClockDuration(10 * time.Minute), - PeriodReset: types.ExpiresAtTime(now), + Period: tenMinutes, + PeriodReset: now, PeriodSpendLimit: leftAtom, }, valid: true, @@ -304,16 +115,16 @@ func TestPeriodicFeeValidAllowTime(t *testing.T) { remove: false, remainsPeriod: nil, remains: smallAtom, - periodReset: types.ExpiresAtTime(oneHour.Add(10 * time.Minute)), // one step from last reset, not now + periodReset: oneHour.Add(10 * time.Minute), // one step from last reset, not now }, "step limited by global allowance": { allow: types.PeriodicAllowance{ Basic: types.BasicAllowance{ SpendLimit: smallAtom, - Expiration: types.ExpiresAtTime(now.Add(2 * time.Hour)), + Expiration: &twoHours, }, - Period: types.ClockDuration(10 * time.Minute), - PeriodReset: types.ExpiresAtTime(now), + Period: tenMinutes, + PeriodReset: now, PeriodSpendLimit: atom, }, valid: true, @@ -323,15 +134,15 @@ func TestPeriodicFeeValidAllowTime(t *testing.T) { remove: false, remainsPeriod: smallAtom.Sub(oneAtom), remains: smallAtom.Sub(oneAtom), - periodReset: types.ExpiresAtTime(oneHour.Add(10 * time.Minute)), // one step from last reset, not now + periodReset: oneHour.Add(10 * time.Minute), // one step from last reset, not now }, "expired": { allow: types.PeriodicAllowance{ Basic: types.BasicAllowance{ SpendLimit: atom, - Expiration: types.ExpiresAtTime(now), + Expiration: &now, }, - Period: types.ClockDuration(time.Hour), + Period: time.Hour, PeriodSpendLimit: smallAtom, }, valid: true, @@ -344,10 +155,10 @@ func TestPeriodicFeeValidAllowTime(t *testing.T) { allow: types.PeriodicAllowance{ Basic: types.BasicAllowance{ SpendLimit: atom, - Expiration: types.ExpiresAtHeight(100), + Expiration: &now, }, - Period: types.ClockDuration(time.Hour), - PeriodReset: types.ExpiresAtTime(now.Add(1 * time.Hour)), + Period: time.Hour, + PeriodReset: now.Add(1 * time.Hour), PeriodSpendLimit: leftAtom, PeriodCanSpend: smallAtom, },