refactor(feegrant): collection migration (#16535)
This commit is contained in:
parent
009a152274
commit
e51e74a9df
@ -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`:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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=
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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=
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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=
|
||||
|
||||
@ -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())
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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()
|
||||
}
|
||||
|
||||
@ -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",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -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_key_bytes>: allowance
|
||||
FeeAllowanceKeyPrefix = []byte{0x00}
|
||||
FeeAllowanceKeyPrefix = collections.NewPrefix(0)
|
||||
|
||||
// FeeAllowanceQueueKeyPrefix is the set of the kvstore for fee allowance keys data
|
||||
// - 0x01<allowance_prefix_queue_key_bytes>: <empty value>
|
||||
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><len(grantee_address_bytes)><grantee_address_bytes><len(granter_address_bytes)><granter_address_bytes>
|
||||
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><len(grantee_address_bytes)><grantee_address_bytes>
|
||||
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><exp_bytes><len(grantee_address_bytes)><grantee_address_bytes><len(granter_address_bytes)><granter_address_bytes>
|
||||
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><exp_bytes>
|
||||
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<granteeAddressLen (1 Byte)><granteeAddress_Bytes><granterAddressLen (1 Byte)><granterAddress_Bytes>
|
||||
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><expiration_bytes(fixed length)><granteeAddressLen (1 Byte)><granteeAddress_Bytes><granterAddressLen (1 Byte)><granterAddress_Bytes>
|
||||
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
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
@ -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)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user