diff --git a/CHANGELOG.md b/CHANGELOG.md index 3673ee7544..fa0fe324d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking Changes +* (x/feegrant) [16535](https://github.com/cosmos/cosmos-sdk/pull/16535) Use collections for `FeeAllowance`, `FeeAllowanceQueue`. * (x/staking) [17063](https://github.com/cosmos/cosmos-sdk/pull/17063) Use collections for `HistoricalInfo`: * remove `Keeper`: `GetHistoricalInfo`, `SetHistoricalInfo`, * (x/staking) [17062](https://github.com/cosmos/cosmos-sdk/pull/17062) Use collections for `ValidatorUpdates`: diff --git a/simapp/go.mod b/simapp/go.mod index d8c8d17af3..188de8bc6a 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( cosmossdk.io/api v0.7.0 cosmossdk.io/client/v2 v2.0.0-20230630094428-02b760776860 - cosmossdk.io/collections v0.3.0 + cosmossdk.io/collections v0.3.1-0.20230727092431-f0f777fa3cb7 cosmossdk.io/core v0.9.0 cosmossdk.io/depinject v1.0.0-alpha.3 cosmossdk.io/log v1.1.1-0.20230704160919-88f2c830b0ca diff --git a/simapp/go.sum b/simapp/go.sum index 0d956fce25..bbea7814db 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -189,8 +189,8 @@ cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1V cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= cosmossdk.io/api v0.7.0 h1:QsEMIWuv9xWDbF2HZnW4Lpu1/SejCztPu0LQx7t6MN4= cosmossdk.io/api v0.7.0/go.mod h1:kJFAEMLN57y0viszHDPLMmieF0471o5QAwwApa+270M= -cosmossdk.io/collections v0.3.0 h1:v0eEqLBxebAV+t+Ahwf9tSJOu95HVLINwROXx2TTZ08= -cosmossdk.io/collections v0.3.0/go.mod h1:CHE1+niUElL9ikCpevRZcp0yqQ4TU0TrEEGirN0mvIg= +cosmossdk.io/collections v0.3.1-0.20230727092431-f0f777fa3cb7 h1:4XhcAIVBXPwCFTT9abOzZZaEadbRaVws8A6UTr2KGIE= +cosmossdk.io/collections v0.3.1-0.20230727092431-f0f777fa3cb7/go.mod h1:+KJND4gZHilxE3meopEl/Uet6IAw3PyiSbgeOrFzAZE= cosmossdk.io/core v0.9.0 h1:30ScAOHDIUOCg1DKAwqkho9wuQJnu7GUrMcg0XLioic= cosmossdk.io/core v0.9.0/go.mod h1:NFgl5r41Q36+RixTvyrfsS6qQ65agCbZ1FTpnN7/G1Y= cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z+zfw= diff --git a/tests/go.mod b/tests/go.mod index 8eb7d3576b..3c07730331 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -4,7 +4,7 @@ go 1.20 require ( cosmossdk.io/api v0.7.0 - cosmossdk.io/collections v0.3.0 + cosmossdk.io/collections v0.3.1-0.20230727092431-f0f777fa3cb7 cosmossdk.io/core v0.9.0 cosmossdk.io/depinject v1.0.0-alpha.3 cosmossdk.io/errors v1.0.0 diff --git a/tests/go.sum b/tests/go.sum index 65b1ae8241..4c59db89ab 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -189,8 +189,8 @@ cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1V cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= cosmossdk.io/api v0.7.0 h1:QsEMIWuv9xWDbF2HZnW4Lpu1/SejCztPu0LQx7t6MN4= cosmossdk.io/api v0.7.0/go.mod h1:kJFAEMLN57y0viszHDPLMmieF0471o5QAwwApa+270M= -cosmossdk.io/collections v0.3.0 h1:v0eEqLBxebAV+t+Ahwf9tSJOu95HVLINwROXx2TTZ08= -cosmossdk.io/collections v0.3.0/go.mod h1:CHE1+niUElL9ikCpevRZcp0yqQ4TU0TrEEGirN0mvIg= +cosmossdk.io/collections v0.3.1-0.20230727092431-f0f777fa3cb7 h1:4XhcAIVBXPwCFTT9abOzZZaEadbRaVws8A6UTr2KGIE= +cosmossdk.io/collections v0.3.1-0.20230727092431-f0f777fa3cb7/go.mod h1:+KJND4gZHilxE3meopEl/Uet6IAw3PyiSbgeOrFzAZE= cosmossdk.io/core v0.9.0 h1:30ScAOHDIUOCg1DKAwqkho9wuQJnu7GUrMcg0XLioic= cosmossdk.io/core v0.9.0/go.mod h1:NFgl5r41Q36+RixTvyrfsS6qQ65agCbZ1FTpnN7/G1Y= cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z+zfw= diff --git a/x/feegrant/go.mod b/x/feegrant/go.mod index 6eb90a4664..f4da2bb71f 100644 --- a/x/feegrant/go.mod +++ b/x/feegrant/go.mod @@ -4,6 +4,7 @@ go 1.20 require ( cosmossdk.io/api v0.7.0 + cosmossdk.io/collections v0.3.1-0.20230727092431-f0f777fa3cb7 cosmossdk.io/core v0.9.0 cosmossdk.io/depinject v1.0.0-alpha.3 cosmossdk.io/errors v1.0.0 @@ -12,7 +13,7 @@ require ( cosmossdk.io/store v1.0.0-alpha.1 github.com/cometbft/cometbft v0.38.0-rc3 github.com/cosmos/cosmos-proto v1.0.0-beta.3 - github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230713093628-90d9a75d4125 + github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230727092431-f0f777fa3cb7 github.com/cosmos/gogoproto v1.4.10 github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.3 @@ -26,7 +27,6 @@ require ( ) require ( - cosmossdk.io/collections v0.3.0 // indirect cosmossdk.io/x/tx v0.9.1 // indirect filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect diff --git a/x/feegrant/go.sum b/x/feegrant/go.sum index 6a78cd322c..b951cffcdd 100644 --- a/x/feegrant/go.sum +++ b/x/feegrant/go.sum @@ -37,8 +37,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= cosmossdk.io/api v0.7.0 h1:QsEMIWuv9xWDbF2HZnW4Lpu1/SejCztPu0LQx7t6MN4= cosmossdk.io/api v0.7.0/go.mod h1:kJFAEMLN57y0viszHDPLMmieF0471o5QAwwApa+270M= -cosmossdk.io/collections v0.3.0 h1:v0eEqLBxebAV+t+Ahwf9tSJOu95HVLINwROXx2TTZ08= -cosmossdk.io/collections v0.3.0/go.mod h1:CHE1+niUElL9ikCpevRZcp0yqQ4TU0TrEEGirN0mvIg= +cosmossdk.io/collections v0.3.1-0.20230727092431-f0f777fa3cb7 h1:4XhcAIVBXPwCFTT9abOzZZaEadbRaVws8A6UTr2KGIE= +cosmossdk.io/collections v0.3.1-0.20230727092431-f0f777fa3cb7/go.mod h1:+KJND4gZHilxE3meopEl/Uet6IAw3PyiSbgeOrFzAZE= cosmossdk.io/core v0.9.0 h1:30ScAOHDIUOCg1DKAwqkho9wuQJnu7GUrMcg0XLioic= cosmossdk.io/core v0.9.0/go.mod h1:NFgl5r41Q36+RixTvyrfsS6qQ65agCbZ1FTpnN7/G1Y= cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z+zfw= @@ -173,8 +173,8 @@ github.com/cosmos/cosmos-db v1.0.0 h1:EVcQZ+qYag7W6uorBKFPvX6gRjw6Uq2hIh4hCWjuQ0 github.com/cosmos/cosmos-db v1.0.0/go.mod h1:iBvi1TtqaedwLdcrZVYRSSCb6eSy61NLj4UNmdIgs0U= github.com/cosmos/cosmos-proto v1.0.0-beta.3 h1:VitvZ1lPORTVxkmF2fAp3IiA61xVwArQYKXTdEcpW6o= github.com/cosmos/cosmos-proto v1.0.0-beta.3/go.mod h1:t8IASdLaAq+bbHbjq4p960BvcTqtwuAxid3b/2rOD6I= -github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230713093628-90d9a75d4125 h1:2aGCqfxWf2AAvLOUHaRiByle6n0FPRdeOF/62JTldh0= -github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230713093628-90d9a75d4125/go.mod h1:LME6v5XztqVK7/1uTQj/G6ZJdosJEz24rKaPYk+WbqI= +github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230727092431-f0f777fa3cb7 h1:ZbRIti9b4rTLuLB9ZM5XAMev1AYi9eOoo0ide5vIstM= +github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230727092431-f0f777fa3cb7/go.mod h1:fKr/+xe4ZSzj38HwFBvxz/+LZ6v4e9bknD7vq6AJXzY= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/feegrant/keeper/grpc_query.go b/x/feegrant/keeper/grpc_query.go index 7dde415171..2250d84140 100644 --- a/x/feegrant/keeper/grpc_query.go +++ b/x/feegrant/keeper/grpc_query.go @@ -1,18 +1,16 @@ package keeper import ( - "bytes" "context" "github.com/cosmos/gogoproto/proto" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "cosmossdk.io/store/prefix" + "cosmossdk.io/collections" "cosmossdk.io/x/feegrant" codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" ) @@ -72,23 +70,16 @@ func (q Keeper) Allowances(c context.Context, req *feegrant.QueryAllowancesReque return nil, err } - ctx := sdk.UnwrapSDKContext(c) - var grants []*feegrant.Grant - store := q.storeService.OpenKVStore(ctx) - grantsStore := prefix.NewStore(runtime.KVStoreAdapter(store), feegrant.FeeAllowancePrefixByGrantee(granteeAddr)) - - pageRes, err := query.Paginate(grantsStore, req.Pagination, func(key, value []byte) error { - var grant feegrant.Grant - - if err := q.cdc.Unmarshal(value, &grant); err != nil { - return err - } - - grants = append(grants, &grant) - return nil - }) + _, pageRes, err := query.CollectionFilteredPaginate(c, q.FeeAllowance, req.Pagination, + func(key collections.Pair[sdk.AccAddress, sdk.AccAddress], grant feegrant.Grant) (include bool, err error) { + grants = append(grants, &grant) + return true, nil + }, func(_ collections.Pair[sdk.AccAddress, sdk.AccAddress], value feegrant.Grant) (*feegrant.Grant, error) { + return &value, nil + }, query.WithCollectionPaginationPairPrefix[sdk.AccAddress, sdk.AccAddress](granteeAddr), + ) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } @@ -107,21 +98,20 @@ func (q Keeper) AllowancesByGranter(c context.Context, req *feegrant.QueryAllowa return nil, err } - ctx := sdk.UnwrapSDKContext(c) + var grants []*feegrant.Grant + _, pageRes, err := query.CollectionFilteredPaginate(c, q.FeeAllowance, req.Pagination, + func(key collections.Pair[sdk.AccAddress, sdk.AccAddress], grant feegrant.Grant) (include bool, err error) { + if !sdk.AccAddress(granterAddr).Equals(key.K2()) { + return false, nil + } - store := q.storeService.OpenKVStore(ctx) - prefixStore := prefix.NewStore(runtime.KVStoreAdapter(store), feegrant.FeeAllowanceKeyPrefix) - grants, pageRes, err := query.GenericFilteredPaginate(q.cdc, prefixStore, req.Pagination, func(key []byte, grant *feegrant.Grant) (*feegrant.Grant, error) { - // ParseAddressesFromFeeAllowanceKey expects the full key including the prefix. - granter, _ := feegrant.ParseAddressesFromFeeAllowanceKey(append(feegrant.FeeAllowanceKeyPrefix, key...)) - if !bytes.Equal(granter, granterAddr) { - return nil, nil - } - - return grant, nil - }, func() *feegrant.Grant { - return &feegrant.Grant{} - }) + grants = append(grants, &grant) + return true, nil + }, + func(_ collections.Pair[sdk.AccAddress, sdk.AccAddress], grant feegrant.Grant) (*feegrant.Grant, error) { + return &grant, nil + }, + ) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } diff --git a/x/feegrant/keeper/keeper.go b/x/feegrant/keeper/keeper.go index 13718020cd..e54390d9a2 100644 --- a/x/feegrant/keeper/keeper.go +++ b/x/feegrant/keeper/keeper.go @@ -2,9 +2,11 @@ package keeper import ( "context" + "errors" "fmt" "time" + "cosmossdk.io/collections" "cosmossdk.io/core/store" errorsmod "cosmossdk.io/errors" "cosmossdk.io/log" @@ -21,19 +23,38 @@ import ( // Keeper manages state of all fee grants, as well as calculating approval. // It must have a codec with all available allowances registered. type Keeper struct { - cdc codec.BinaryCodec - storeService store.KVStoreService - authKeeper feegrant.AccountKeeper + cdc codec.BinaryCodec + storeService store.KVStoreService + authKeeper feegrant.AccountKeeper + Schema collections.Schema + FeeAllowance collections.Map[collections.Pair[sdk.AccAddress, sdk.AccAddress], feegrant.Grant] + FeeAllowanceQueue collections.Map[collections.Triple[time.Time, sdk.AccAddress, sdk.AccAddress], bool] } var _ ante.FeegrantKeeper = &Keeper{} // NewKeeper creates a feegrant Keeper func NewKeeper(cdc codec.BinaryCodec, storeService store.KVStoreService, ak feegrant.AccountKeeper) Keeper { + sb := collections.NewSchemaBuilder(storeService) + return Keeper{ cdc: cdc, storeService: storeService, authKeeper: ak, + FeeAllowance: collections.NewMap( + sb, + feegrant.FeeAllowanceKeyPrefix, + "allowances", + collections.PairKeyCodec(sdk.LengthPrefixedAddressKey(sdk.AccAddressKey), sdk.LengthPrefixedAddressKey(sdk.AccAddressKey)), // nolint: staticcheck // sdk.LengthPrefixedAddressKey is needed to retain state compatibility + codec.CollValue[feegrant.Grant](cdc), + ), + FeeAllowanceQueue: collections.NewMap( + sb, + feegrant.FeeAllowanceQueueKeyPrefix, + "allowances_queue", + collections.TripleKeyCodec(sdk.TimeKey, sdk.LengthPrefixedAddressKey(sdk.AccAddressKey), sdk.LengthPrefixedAddressKey(sdk.AccAddressKey)), // nolint: staticcheck // sdk.LengthPrefixedAddressKey is needed to retain state compatibility + collections.BoolValue, + ), } } @@ -56,9 +77,6 @@ func (k Keeper) GrantAllowance(ctx context.Context, granter, grantee sdk.AccAddr k.authKeeper.SetAccount(ctx, granteeAcc) } - store := k.storeService.OpenKVStore(ctx) - key := feegrant.FeeAllowanceKey(granter, grantee) - exp, err := feeAllowance.ExpiresAt() if err != nil { return err @@ -72,9 +90,7 @@ func (k Keeper) GrantAllowance(ctx context.Context, granter, grantee sdk.AccAddr // if expiry is not nil, add the new key to pruning queue. if exp != nil { - // `key` formed here with the prefix of `FeeAllowanceKeyPrefix` (which is `0x00`) - // remove the 1st byte and reuse the remaining key as it is - err = k.addToFeeAllowanceQueue(ctx, key[1:], exp) + err = k.FeeAllowanceQueue.Set(ctx, collections.Join3(*exp, grantee, granter), true) if err != nil { return err } @@ -85,13 +101,7 @@ func (k Keeper) GrantAllowance(ctx context.Context, granter, grantee sdk.AccAddr return err } - bz, err := k.cdc.Marshal(&grant) - if err != nil { - return err - } - - err = store.Set(key, bz) - if err != nil { + if err := k.FeeAllowance.Set(ctx, collections.Join(grantee, granter), grant); err != nil { return err } @@ -108,9 +118,6 @@ func (k Keeper) GrantAllowance(ctx context.Context, granter, grantee sdk.AccAddr // UpdateAllowance updates the existing grant. func (k Keeper) UpdateAllowance(ctx context.Context, granter, grantee sdk.AccAddress, feeAllowance feegrant.FeeAllowanceI) error { - store := k.storeService.OpenKVStore(ctx) - key := feegrant.FeeAllowanceKey(granter, grantee) - _, err := k.getGrant(ctx, granter, grantee) if err != nil { return err @@ -121,13 +128,7 @@ func (k Keeper) UpdateAllowance(ctx context.Context, granter, grantee sdk.AccAdd return err } - bz, err := k.cdc.Marshal(&grant) - if err != nil { - return err - } - - err = store.Set(key, bz) - if err != nil { + if err := k.FeeAllowance.Set(ctx, collections.Join(grantee, granter), grant); err != nil { return err } @@ -149,10 +150,7 @@ func (k Keeper) revokeAllowance(ctx context.Context, granter, grantee sdk.AccAdd return err } - store := k.storeService.OpenKVStore(ctx) - key := feegrant.FeeAllowanceKey(granter, grantee) - err = store.Delete(key) - if err != nil { + if err := k.FeeAllowance.Remove(ctx, collections.Join(grantee, granter)); err != nil { return err } @@ -162,7 +160,7 @@ func (k Keeper) revokeAllowance(ctx context.Context, granter, grantee sdk.AccAdd } if exp != nil { - if err := store.Delete(feegrant.FeeAllowancePrefixQueue(exp, feegrant.FeeAllowanceKey(grantee, granter)[1:])); err != nil { + if err := k.FeeAllowanceQueue.Remove(ctx, collections.Join3(*exp, grantee, granter)); err != nil { return err } } @@ -181,7 +179,7 @@ func (k Keeper) revokeAllowance(ctx context.Context, granter, grantee sdk.AccAdd // If there is none, it returns nil, nil. // Returns an error on parsing issues func (k Keeper) GetAllowance(ctx context.Context, granter, grantee sdk.AccAddress) (feegrant.FeeAllowanceI, error) { - grant, err := k.getGrant(ctx, granter, grantee) + grant, err := k.FeeAllowance.Get(ctx, collections.Join(grantee, granter)) if err != nil { return nil, err } @@ -191,22 +189,11 @@ func (k Keeper) GetAllowance(ctx context.Context, granter, grantee sdk.AccAddres // getGrant returns entire grant between both accounts func (k Keeper) getGrant(ctx context.Context, granter, grantee sdk.AccAddress) (*feegrant.Grant, error) { - store := k.storeService.OpenKVStore(ctx) - key := feegrant.FeeAllowanceKey(granter, grantee) - bz, err := store.Get(key) + feegrant, err := k.FeeAllowance.Get(ctx, collections.Join(grantee, granter)) if err != nil { return nil, err } - if len(bz) == 0 { - return nil, sdkerrors.ErrNotFound.Wrap("fee-grant not found") - } - - var feegrant feegrant.Grant - if err := k.cdc.Unmarshal(bz, &feegrant); err != nil { - return nil, err - } - return &feegrant, nil } @@ -218,14 +205,12 @@ func (k Keeper) IterateAllFeeAllowances(ctx context.Context, cb func(grant feegr iter := storetypes.KVStorePrefixIterator(runtime.KVStoreAdapter(store), feegrant.FeeAllowanceKeyPrefix) defer iter.Close() - stop := false - for ; iter.Valid() && !stop; iter.Next() { - bz := iter.Value() - var feeGrant feegrant.Grant - if err := k.cdc.Unmarshal(bz, &feeGrant); err != nil { - return err - } - stop = cb(feeGrant) + err := k.FeeAllowance.Walk(ctx, nil, func(key collections.Pair[sdk.AccAddress, sdk.AccAddress], grant feegrant.Grant) (stop bool, err error) { + return cb(grant), nil + }) + + if err != nil && !errors.Is(err, collections.ErrInvalidIterator) { + return err } return nil @@ -312,32 +297,28 @@ func (k Keeper) ExportGenesis(ctx context.Context) (*feegrant.GenesisState, erro }, err } -func (k Keeper) addToFeeAllowanceQueue(ctx context.Context, grantKey []byte, exp *time.Time) error { - store := k.storeService.OpenKVStore(ctx) - return store.Set(feegrant.FeeAllowancePrefixQueue(exp, grantKey), []byte{}) -} - // RemoveExpiredAllowances iterates grantsByExpiryQueue and deletes the expired grants. func (k Keeper) RemoveExpiredAllowances(ctx context.Context) error { exp := sdk.UnwrapSDKContext(ctx).BlockTime() - store := k.storeService.OpenKVStore(ctx) - iterator, err := store.Iterator(feegrant.FeeAllowanceQueueKeyPrefix, storetypes.InclusiveEndBytes(feegrant.AllowanceByExpTimeKey(&exp))) - if err != nil { + rng := collections.NewPrefixUntilTripleRange[time.Time, sdk.AccAddress, sdk.AccAddress](exp) + + err := k.FeeAllowanceQueue.Walk(ctx, rng, func(key collections.Triple[time.Time, sdk.AccAddress, sdk.AccAddress], value bool) (stop bool, err error) { + grantee, granter := key.K2(), key.K3() + + if err := k.FeeAllowance.Remove(ctx, collections.Join(grantee, granter)); err != nil { + return true, err + } + + if err := k.FeeAllowanceQueue.Remove(ctx, key); err != nil { + return true, err + } + + return false, nil + }) + + if err != nil && !errors.Is(err, collections.ErrInvalidIterator) { return err } - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { - err = store.Delete(iterator.Key()) - if err != nil { - return err - } - - granter, grantee := feegrant.ParseAddressesFromFeeAllowanceQueueKey(iterator.Key()) - err = store.Delete(feegrant.FeeAllowanceKey(granter, grantee)) - if err != nil { - return err - } - } return nil } diff --git a/x/feegrant/keeper/keeper_test.go b/x/feegrant/keeper/keeper_test.go index 91a4a2c508..b1222ce817 100644 --- a/x/feegrant/keeper/keeper_test.go +++ b/x/feegrant/keeper/keeper_test.go @@ -291,7 +291,7 @@ func (suite *KeeperTestSuite) TestUseGrantedFee() { // verify: feegrant is revoked _, err = suite.feegrantKeeper.GetAllowance(ctx, suite.addrs[0], suite.addrs[2]) suite.Error(err) - suite.Contains(err.Error(), "fee-grant not found") + suite.Contains(err.Error(), "not found") } func (suite *KeeperTestSuite) TestIterateGrants() { @@ -323,6 +323,7 @@ func (suite *KeeperTestSuite) TestIterateGrants() { func (suite *KeeperTestSuite) TestPruneGrants() { eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 123)) now := suite.ctx.BlockTime() + oneDay := now.AddDate(0, 0, 1) oneYearExpiry := now.AddDate(1, 0, 0) testCases := []struct { @@ -336,24 +337,35 @@ func (suite *KeeperTestSuite) TestPruneGrants() { postRun func() }{ { - name: "grant not pruned from state", - ctx: suite.ctx, - granter: suite.addrs[0], - grantee: suite.addrs[1], + name: "grant pruned from state after a block: error", + ctx: suite.ctx, + granter: suite.addrs[0], + grantee: suite.addrs[1], + expErrMsg: "not found", allowance: &feegrant.BasicAllowance{ SpendLimit: suite.atom, Expiration: &now, }, }, { - name: "grant pruned from state after a block: error", + name: "grant not pruned from state before expiration: no error", + ctx: suite.ctx, + granter: suite.addrs[2], + grantee: suite.addrs[1], + allowance: &feegrant.BasicAllowance{ + SpendLimit: eth, + Expiration: &oneDay, + }, + }, + { + name: "grant pruned from state after a day: error", ctx: suite.ctx.WithBlockTime(now.AddDate(0, 0, 1)), - granter: suite.addrs[2], - grantee: suite.addrs[1], + granter: suite.addrs[1], + grantee: suite.addrs[0], expErrMsg: "not found", allowance: &feegrant.BasicAllowance{ SpendLimit: eth, - Expiration: &now, + Expiration: &oneDay, }, }, { @@ -368,7 +380,7 @@ func (suite *KeeperTestSuite) TestPruneGrants() { }, { name: "grant pruned from state after a year: error", - ctx: suite.ctx.WithBlockTime(now.AddDate(1, 0, 1)), + ctx: suite.ctx.WithBlockTime(now.AddDate(1, 0, 0)), granter: suite.addrs[1], grantee: suite.addrs[2], expErrMsg: "not found", @@ -384,7 +396,6 @@ func (suite *KeeperTestSuite) TestPruneGrants() { grantee: suite.addrs[2], allowance: &feegrant.BasicAllowance{ SpendLimit: eth, - Expiration: &oneYearExpiry, }, }, } @@ -399,13 +410,16 @@ func (suite *KeeperTestSuite) TestPruneGrants() { suite.NoError(err) err = suite.feegrantKeeper.RemoveExpiredAllowances(tc.ctx) suite.NoError(err) + grant, err := suite.feegrantKeeper.GetAllowance(tc.ctx, tc.granter, tc.grantee) if tc.expErrMsg != "" { suite.Error(err) suite.Contains(err.Error(), tc.expErrMsg) } else { + suite.NoError(err) suite.NotNil(grant) } + if tc.postRun != nil { tc.postRun() } diff --git a/x/feegrant/keeper/msg_server_test.go b/x/feegrant/keeper/msg_server_test.go index 5f0ed6862e..e6b0307c0e 100644 --- a/x/feegrant/keeper/msg_server_test.go +++ b/x/feegrant/keeper/msg_server_test.go @@ -227,7 +227,7 @@ func (suite *KeeperTestSuite) TestRevokeAllowance() { }, func() {}, true, - "fee-grant not found", + "not found", }, { "success: revoke fee allowance", @@ -269,7 +269,7 @@ func (suite *KeeperTestSuite) TestRevokeAllowance() { }, func() {}, true, - "fee-grant not found", + "not found", }, } diff --git a/x/feegrant/key.go b/x/feegrant/key.go index 066ddf5c89..837435128c 100644 --- a/x/feegrant/key.go +++ b/x/feegrant/key.go @@ -1,10 +1,7 @@ package feegrant import ( - time "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/address" + "cosmossdk.io/collections" ) const ( @@ -24,72 +21,9 @@ const ( var ( // FeeAllowanceKeyPrefix is the set of the kvstore for fee allowance data // - 0x00: allowance - FeeAllowanceKeyPrefix = []byte{0x00} + FeeAllowanceKeyPrefix = collections.NewPrefix(0) // FeeAllowanceQueueKeyPrefix is the set of the kvstore for fee allowance keys data // - 0x01: - FeeAllowanceQueueKeyPrefix = []byte{0x01} + FeeAllowanceQueueKeyPrefix = collections.NewPrefix(1) ) - -// FeeAllowanceKey is the canonical key to store a grant from granter to grantee -// We store by grantee first to allow searching by everyone who granted to you -// -// Key format: -// - <0x00> -func FeeAllowanceKey(granter, grantee sdk.AccAddress) []byte { - return append(FeeAllowancePrefixByGrantee(grantee), address.MustLengthPrefix(granter.Bytes())...) -} - -// FeeAllowancePrefixByGrantee returns a prefix to scan for all grants to this given address. -// -// Key format: -// - <0x00> -func FeeAllowancePrefixByGrantee(grantee sdk.AccAddress) []byte { - return append(FeeAllowanceKeyPrefix, address.MustLengthPrefix(grantee.Bytes())...) -} - -// FeeAllowancePrefixQueue is the canonical key to store grant key. -// -// Key format: -// - <0x01> -func FeeAllowancePrefixQueue(exp *time.Time, key []byte) []byte { - allowanceByExpTimeKey := AllowanceByExpTimeKey(exp) - return append(allowanceByExpTimeKey, key...) -} - -// AllowanceByExpTimeKey returns a key with `FeeAllowanceQueueKeyPrefix`, expiry -// -// Key format: -// - <0x01> -func AllowanceByExpTimeKey(exp *time.Time) []byte { - // no need of appending len(exp_bytes) here, `FormatTimeBytes` gives const length everytime. - return append(FeeAllowanceQueueKeyPrefix, sdk.FormatTimeBytes(*exp)...) -} - -// ParseAddressesFromFeeAllowanceKey extracts and returns the granter, grantee from the given key. -func ParseAddressesFromFeeAllowanceKey(key []byte) (granter, grantee []byte) { - // key is of format: - // 0x00 - granterAddrLen, granterAddrLenEndIndex := sdk.ParseLengthPrefixedBytes(key, 1, 1) // ignore key[0] since it is a prefix key - grantee, granterAddrEndIndex := sdk.ParseLengthPrefixedBytes(key, granterAddrLenEndIndex+1, int(granterAddrLen[0])) - - granteeAddrLen, granteeAddrLenEndIndex := sdk.ParseLengthPrefixedBytes(key, granterAddrEndIndex+1, 1) - granter, _ = sdk.ParseLengthPrefixedBytes(key, granteeAddrLenEndIndex+1, int(granteeAddrLen[0])) - - return granter, grantee -} - -// ParseAddressesFromFeeAllowanceQueueKey extracts and returns the granter, grantee from the given key. -func ParseAddressesFromFeeAllowanceQueueKey(key []byte) (granter, grantee []byte) { - lenTime := len(sdk.FormatTimeBytes(time.Now())) - - // key is of format: - // <0x01> - granterAddrLen, granterAddrLenEndIndex := sdk.ParseLengthPrefixedBytes(key, 1+lenTime, 1) // ignore key[0] since it is a prefix key - grantee, granterAddrEndIndex := sdk.ParseLengthPrefixedBytes(key, granterAddrLenEndIndex+1, int(granterAddrLen[0])) - - granteeAddrLen, granteeAddrLenEndIndex := sdk.ParseLengthPrefixedBytes(key, granterAddrEndIndex+1, 1) - granter, _ = sdk.ParseLengthPrefixedBytes(key, granteeAddrLenEndIndex+1, int(granteeAddrLen[0])) - - return granter, grantee -} diff --git a/x/feegrant/key_test.go b/x/feegrant/key_test.go deleted file mode 100644 index 45eae077d7..0000000000 --- a/x/feegrant/key_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package feegrant_test - -import ( - "testing" - "time" - - "github.com/stretchr/testify/require" - - "cosmossdk.io/x/feegrant" - - codecaddress "github.com/cosmos/cosmos-sdk/codec/address" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -func TestMarshalAndUnmarshalFeegrantKey(t *testing.T) { - addressCodec := codecaddress.NewBech32Codec("cosmos") - grantee, err := addressCodec.StringToBytes("cosmos1qk93t4j0yyzgqgt6k5qf8deh8fq6smpn3ntu3x") - require.NoError(t, err) - granter, err := addressCodec.StringToBytes("cosmos1p9qh4ldfd6n0qehujsal4k7g0e37kel90rc4ts") - require.NoError(t, err) - - key := feegrant.FeeAllowanceKey(granter, grantee) - require.Len(t, key, len(grantee)+len(granter)+3) - require.Equal(t, feegrant.FeeAllowancePrefixByGrantee(grantee), key[:len(grantee)+2]) - - g1, g2 := feegrant.ParseAddressesFromFeeAllowanceKey(key) - require.Equal(t, granter, g1) - require.Equal(t, grantee, g2) -} - -func TestMarshalAndUnmarshalFeegrantKeyQueueKey(t *testing.T) { - addressCodec := codecaddress.NewBech32Codec("cosmos") - grantee, err := addressCodec.StringToBytes("cosmos1qk93t4j0yyzgqgt6k5qf8deh8fq6smpn3ntu3x") - require.NoError(t, err) - granter, err := addressCodec.StringToBytes("cosmos1p9qh4ldfd6n0qehujsal4k7g0e37kel90rc4ts") - require.NoError(t, err) - - exp := time.Now() - expBytes := sdk.FormatTimeBytes(exp) - - key := feegrant.FeeAllowancePrefixQueue(&exp, feegrant.FeeAllowanceKey(granter, grantee)[1:]) - require.Len(t, key, len(grantee)+len(granter)+3+len(expBytes)) - - granter1, grantee1 := feegrant.ParseAddressesFromFeeAllowanceQueueKey(key) - require.Equal(t, granter, granter1) - require.Equal(t, grantee, grantee1) -} diff --git a/x/feegrant/module/abci_test.go b/x/feegrant/module/abci_test.go index f34bb700bf..6e7bc0a41a 100644 --- a/x/feegrant/module/abci_test.go +++ b/x/feegrant/module/abci_test.go @@ -89,7 +89,7 @@ func TestFeegrantPruning(t *testing.T) { }) require.NoError(t, err) require.NotNil(t, res) - require.Len(t, res.Allowances, 3) + require.Len(t, res.Allowances, 2) testCtx.Ctx = testCtx.Ctx.WithBlockTime(now.AddDate(0, 0, 2)) module.EndBlocker(testCtx.Ctx, feegrantKeeper)