diff --git a/CHANGELOG.md b/CHANGELOG.md index b6ef937b..a99e9bce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ - Ensure feeTokenMetadata initial prices after updateFeeTokenMetadata is picked up from oracle - Use `DecCoins.Validate()` on `RewardPool.ValidateGenesis` to catch malformed denom formats, duplicate denoms, bad ordering - Enforce denom consistency in `GenesisState.Validate` with `Params.TokenDenom` +- Limited tokenfactory queries, removing denial of service possibility +- Indexed admins to reduce query space on tokenfactory denom queries ### Removed diff --git a/app/app.go b/app/app.go index 166f86d4..c3db6222 100644 --- a/app/app.go +++ b/app/app.go @@ -68,7 +68,7 @@ import ( kiiante "github.com/kiichain/kiichain/v7/ante" "github.com/kiichain/kiichain/v7/app/keepers" "github.com/kiichain/kiichain/v7/app/upgrades" - v7_1_mainnet "github.com/kiichain/kiichain/v7/app/upgrades/v7_1_mainnet" + v7_2 "github.com/kiichain/kiichain/v7/app/upgrades/v7_2" "github.com/kiichain/kiichain/v7/client/docs" ) @@ -78,7 +78,7 @@ var ( // Upgrades is a list of all the upgrades that are available for the application. Upgrades = []upgrades.Upgrade{ - v7_1_mainnet.Upgrade, + v7_2.Upgrade, } ) diff --git a/app/upgrades/v7_2/constants.go b/app/upgrades/v7_2/constants.go new file mode 100644 index 00000000..55dfe269 --- /dev/null +++ b/app/upgrades/v7_2/constants.go @@ -0,0 +1,17 @@ +package v720 + +import ( + "github.com/kiichain/kiichain/v7/app/upgrades" +) + +const ( + // UpgradeName is the name of the upgrade + UpgradeName = "v7.2.0" +) + +// Upgrade defines the upgrade, running module migrations to backfill the +// tokenfactory admin secondary index. +var Upgrade = upgrades.Upgrade{ + UpgradeName: UpgradeName, + CreateUpgradeHandler: CreateUpgradeHandler, +} diff --git a/app/upgrades/v7_2/upgrade.go b/app/upgrades/v7_2/upgrade.go new file mode 100644 index 00000000..b1b5d644 --- /dev/null +++ b/app/upgrades/v7_2/upgrade.go @@ -0,0 +1,35 @@ +package v720 + +import ( + "context" + + upgradetypes "cosmossdk.io/x/upgrade/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + + "github.com/kiichain/kiichain/v7/app/keepers" +) + +// CreateUpgradeHandler creates the upgrade handler for the v7.2.0 upgrade. +// It runs all pending module migrations, which includes the tokenfactory v1→v2 +// migration that backfills the secondary admin index. +func CreateUpgradeHandler( + mm *module.Manager, + configurator module.Configurator, + _ *keepers.AppKeepers, +) upgradetypes.UpgradeHandler { + return func(c context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { + ctx := sdk.UnwrapSDKContext(c) + + ctx.Logger().Info("Starting module migrations for v7.2.0...") + + vm, err := mm.RunMigrations(ctx, configurator, vm) + if err != nil { + return vm, err + } + + ctx.Logger().Info("Upgrade v7.2.0 complete") + return vm, nil + } +} diff --git a/proto/kiichain/tokenfactory/v1beta1/query.proto b/proto/kiichain/tokenfactory/v1beta1/query.proto index 08da3550..05c4c087 100644 --- a/proto/kiichain/tokenfactory/v1beta1/query.proto +++ b/proto/kiichain/tokenfactory/v1beta1/query.proto @@ -70,22 +70,26 @@ message QueryDenomAuthorityMetadataResponse { // DenomsFromCreator gRPC query. message QueryDenomsFromCreatorRequest { string creator = 1 [ (gogoproto.moretags) = "yaml:\"creator\"" ]; + cosmos.base.query.v1beta1.PageRequest pagination = 2; } -// QueryDenomsFromCreatorRequest defines the response structure for the +// QueryDenomsFromCreatorResponse defines the response structure for the // DenomsFromCreator gRPC query. message QueryDenomsFromCreatorResponse { repeated string denoms = 1 [ (gogoproto.moretags) = "yaml:\"denoms\"" ]; + cosmos.base.query.v1beta1.PageResponse pagination = 2; } // QueryDenomsFromAdminRequest defines the request structure for the // DenomsFromAdmin gRPC query. message QueryDenomsFromAdminRequest { string admin = 1 [ (gogoproto.moretags) = "yaml:\"admin\"" ]; + cosmos.base.query.v1beta1.PageRequest pagination = 2; } -// QueryDenomsFromAdminRequest defines the response structure for the +// QueryDenomsFromAdminResponse defines the response structure for the // DenomsFromAdmin gRPC query. message QueryDenomsFromAdminResponse { repeated string denoms = 1 [ (gogoproto.moretags) = "yaml:\"denoms\"" ]; + cosmos.base.query.v1beta1.PageResponse pagination = 2; } diff --git a/wasmbinding/tokenfactory/queries.go b/wasmbinding/tokenfactory/queries.go index bdba7226..f25083e8 100644 --- a/wasmbinding/tokenfactory/queries.go +++ b/wasmbinding/tokenfactory/queries.go @@ -135,7 +135,10 @@ func (qp QueryPlugin) GetTokenfactoryDenomsByCreator(ctx context.Context, creato if _, err := sdk.AccAddressFromBech32(creator); err != nil { return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address %q: %v", creator, err) } - denoms := qp.tokenFactoryKeeper.GetDenomsFromCreator(sdk.UnwrapSDKContext(ctx), creator) + denoms, _, err := qp.tokenFactoryKeeper.GetDenomsFromCreator(sdk.UnwrapSDKContext(ctx), creator, nil) + if err != nil { + return nil, err + } return &tfbindingtypes.DenomsByCreatorResponse{Denoms: denoms}, nil } diff --git a/x/tokenfactory/client/cli/query.go b/x/tokenfactory/client/cli/query.go index a8c74ea4..e11219eb 100644 --- a/x/tokenfactory/client/cli/query.go +++ b/x/tokenfactory/client/cli/query.go @@ -101,8 +101,14 @@ func GetCmdDenomsFromCreator() *cobra.Command { } queryClient := types.NewQueryClient(clientCtx) + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + res, err := queryClient.DenomsFromCreator(cmd.Context(), &types.QueryDenomsFromCreatorRequest{ - Creator: args[0], + Creator: args[0], + Pagination: pageReq, }) if err != nil { return err @@ -113,6 +119,7 @@ func GetCmdDenomsFromCreator() *cobra.Command { } flags.AddQueryFlagsToCmd(cmd) + flags.AddPaginationFlagsToCmd(cmd, "denoms-from-creator") return cmd } @@ -129,8 +136,14 @@ func GetCmdDenomsFromAdmin() *cobra.Command { } queryClient := types.NewQueryClient(clientCtx) + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + res, err := queryClient.DenomsFromAdmin(cmd.Context(), &types.QueryDenomsFromAdminRequest{ - Admin: args[0], + Admin: args[0], + Pagination: pageReq, }) if err != nil { return err @@ -141,6 +154,7 @@ func GetCmdDenomsFromAdmin() *cobra.Command { } flags.AddQueryFlagsToCmd(cmd) + flags.AddPaginationFlagsToCmd(cmd, "denoms-from-admin") return cmd } diff --git a/x/tokenfactory/keeper/admins.go b/x/tokenfactory/keeper/admins.go index 8b6c0d33..a027abe1 100644 --- a/x/tokenfactory/keeper/admins.go +++ b/x/tokenfactory/keeper/admins.go @@ -5,7 +5,11 @@ import ( "github.com/cosmos/gogoproto/proto" + "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + query "github.com/cosmos/cosmos-sdk/types/query" "github.com/kiichain/kiichain/v7/x/tokenfactory/types" ) @@ -22,14 +26,25 @@ func (k Keeper) GetAuthorityMetadata(ctx context.Context, denom string) (types.D return metadata, nil } -// setAuthorityMetadata stores authority metadata for a specific denom +// setAuthorityMetadata stores authority metadata for a specific denom and keeps the +// admin secondary index consistent. It reads the current admin so it can remove the +// denom from the old admin's index before inserting it under the new admin func (k Keeper) setAuthorityMetadata(ctx context.Context, denom string, metadata types.DenomAuthorityMetadata) error { err := metadata.Validate() if err != nil { return err } - store := k.GetDenomPrefixStore(sdk.UnwrapSDKContext(ctx), denom) + sdkCtx := sdk.UnwrapSDKContext(ctx) + + // Remove denom from the current admin's index (if any metadata already exists) + oldMetadata, err := k.GetAuthorityMetadata(sdkCtx, denom) + if err != nil { + return err + } + k.removeDenomFromAdmin(sdkCtx, oldMetadata.Admin, denom) + + store := k.GetDenomPrefixStore(sdkCtx, denom) bz, err := proto.Marshal(&metadata) if err != nil { @@ -37,30 +52,53 @@ func (k Keeper) setAuthorityMetadata(ctx context.Context, denom string, metadata } store.Set([]byte(types.DenomAuthorityMetadataKey), bz) + + // Insert denom under the new admin's index. + k.addDenomFromAdmin(sdkCtx, metadata.Admin, denom) + return nil } +// addDenomFromAdmin inserts denom into the secondary index for admin +func (k Keeper) addDenomFromAdmin(ctx context.Context, admin, denom string) { + k.GetAdminPrefixStore(sdk.UnwrapSDKContext(ctx), admin).Set([]byte(denom), []byte(denom)) +} + +// AddDenomFromAdmin is the exported form of addDenomFromAdmin +func (k Keeper) AddDenomFromAdmin(ctx context.Context, admin, denom string) { + k.addDenomFromAdmin(ctx, admin, denom) +} + +// removeDenomFromAdmin removes denom from the secondary index for admin +func (k Keeper) removeDenomFromAdmin(ctx context.Context, admin, denom string) { + k.GetAdminPrefixStore(sdk.UnwrapSDKContext(ctx), admin).Delete([]byte(denom)) +} + func (k Keeper) setAdmin(ctx context.Context, metadata types.DenomAuthorityMetadata, denom string, admin string) error { metadata.Admin = admin return k.setAuthorityMetadata(ctx, denom, metadata) } -// GetDenomsFromAdmin returns all denoms for which the provided address is the admin -func (k Keeper) GetDenomsFromAdmin(ctx context.Context, admin string) ([]string, error) { - iterator := k.GetAllDenomsIterator(ctx) - defer iterator.Close() - - denoms := []string{} - for ; iterator.Valid(); iterator.Next() { - denom := string(iterator.Value()) - metadata, err := k.GetAuthorityMetadata(sdk.UnwrapSDKContext(ctx), denom) - if err != nil { - return nil, err - } - if metadata.Admin == admin { - denoms = append(denoms, denom) - } +// GetDenomsFromAdmin returns a paginated list of denoms the given admin. +// It has maximum of types.MaxPageSize entries per request +func (k Keeper) GetDenomsFromAdmin(ctx context.Context, admin string, req *query.PageRequest) ([]string, *query.PageResponse, error) { + if req == nil { + req = &query.PageRequest{Limit: types.MaxPageSize} + } else if req.Limit > types.MaxPageSize { + return nil, nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, + "page size %d exceeds maximum allowed %d", req.Limit, types.MaxPageSize) + } + + store := k.GetAdminPrefixStore(sdk.UnwrapSDKContext(ctx), admin) + + var denoms []string + pageRes, err := query.Paginate(store, req, func(key, _ []byte) error { + denoms = append(denoms, string(key)) + return nil + }) + if err != nil { + return nil, nil, err } - return denoms, nil + return denoms, pageRes, nil } diff --git a/x/tokenfactory/keeper/admins_test.go b/x/tokenfactory/keeper/admins_test.go index 77892f3d..402e90c8 100644 --- a/x/tokenfactory/keeper/admins_test.go +++ b/x/tokenfactory/keeper/admins_test.go @@ -4,6 +4,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/kiichain/kiichain/v7/x/tokenfactory/types" @@ -584,3 +585,76 @@ func (suite *KeeperTestSuite) TestSetDenomMetaData() { }) } } + +// TestDenomsFromAdminPagination verifies that DenomsFromAdmin pagination works +// correctly and that requests exceeding MaxPageSize are rejected. +func (suite *KeeperTestSuite) TestDenomsFromAdminPagination() { + suite.SetupTest() + + // Create 3 denoms for TestAccs[0] to use as paging targets. + subdenoms := []string{"aaa", "bbb", "ccc"} + for _, sub := range subdenoms { + _, err := suite.msgServer.CreateDenom(suite.Ctx, types.NewMsgCreateDenom(suite.TestAccs[0].String(), sub)) + suite.Require().NoError(err) + } + + // Nil pagination defaults to MaxPageSize limit. + res, err := suite.queryClient.DenomsFromAdmin(suite.Ctx.Context(), &types.QueryDenomsFromAdminRequest{ + Admin: suite.TestAccs[0].String(), + }) + suite.Require().NoError(err) + suite.Require().Len(res.Denoms, 3) + + // Limit=2 returns exactly 2 denoms with a non-nil next key. + res, err = suite.queryClient.DenomsFromAdmin(suite.Ctx.Context(), &types.QueryDenomsFromAdminRequest{ + Admin: suite.TestAccs[0].String(), + Pagination: &query.PageRequest{Limit: 2}, + }) + suite.Require().NoError(err) + suite.Require().Len(res.Denoms, 2) + suite.Require().NotNil(res.Pagination) + suite.Require().NotEmpty(res.Pagination.NextKey) + + // A request with Limit > MaxPageSize must be rejected. + _, err = suite.queryClient.DenomsFromAdmin(suite.Ctx.Context(), &types.QueryDenomsFromAdminRequest{ + Admin: suite.TestAccs[0].String(), + Pagination: &query.PageRequest{Limit: types.MaxPageSize + 1}, + }) + suite.Require().Error(err) +} + +// TestDenomsFromCreatorPagination verifies that DenomsFromCreator pagination works +// correctly and that requests exceeding MaxPageSize are rejected. +func (suite *KeeperTestSuite) TestDenomsFromCreatorPagination() { + suite.SetupTest() + + subdenoms := []string{"aaa", "bbb", "ccc"} + for _, sub := range subdenoms { + _, err := suite.msgServer.CreateDenom(suite.Ctx, types.NewMsgCreateDenom(suite.TestAccs[0].String(), sub)) + suite.Require().NoError(err) + } + + // Nil pagination defaults to MaxPageSize limit. + res, err := suite.queryClient.DenomsFromCreator(suite.Ctx.Context(), &types.QueryDenomsFromCreatorRequest{ + Creator: suite.TestAccs[0].String(), + }) + suite.Require().NoError(err) + suite.Require().Len(res.Denoms, 3) + + // Limit=1 returns exactly 1 denom. + res, err = suite.queryClient.DenomsFromCreator(suite.Ctx.Context(), &types.QueryDenomsFromCreatorRequest{ + Creator: suite.TestAccs[0].String(), + Pagination: &query.PageRequest{Limit: 1}, + }) + suite.Require().NoError(err) + suite.Require().Len(res.Denoms, 1) + suite.Require().NotNil(res.Pagination) + suite.Require().NotEmpty(res.Pagination.NextKey) + + // A request with Limit > MaxPageSize must be rejected. + _, err = suite.queryClient.DenomsFromCreator(suite.Ctx.Context(), &types.QueryDenomsFromCreatorRequest{ + Creator: suite.TestAccs[0].String(), + Pagination: &query.PageRequest{Limit: types.MaxPageSize + 1}, + }) + suite.Require().Error(err) +} diff --git a/x/tokenfactory/keeper/creators.go b/x/tokenfactory/keeper/creators.go index 47b1d53a..b90cdd9e 100644 --- a/x/tokenfactory/keeper/creators.go +++ b/x/tokenfactory/keeper/creators.go @@ -3,9 +3,14 @@ package keeper import ( "context" - "cosmossdk.io/store" + "cosmossdk.io/errors" + cosmosstore "cosmossdk.io/store" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + query "github.com/cosmos/cosmos-sdk/types/query" + + "github.com/kiichain/kiichain/v7/x/tokenfactory/types" ) func (k Keeper) addDenomFromCreator(ctx context.Context, creator, denom string) { @@ -13,19 +18,32 @@ func (k Keeper) addDenomFromCreator(ctx context.Context, creator, denom string) store.Set([]byte(denom), []byte(denom)) } -func (k Keeper) GetDenomsFromCreator(ctx context.Context, creator string) []string { - store := k.GetCreatorPrefixStore(sdk.UnwrapSDKContext(ctx), creator) +// GetDenomsFromCreator returns a paginated list of denoms created by the given +// creator address. It has a maximum of types.MaxPageSize entries +func (k Keeper) GetDenomsFromCreator(ctx context.Context, creator string, req *query.PageRequest) ([]string, *query.PageResponse, error) { + // Use max request size if none provided + if req == nil { + req = &query.PageRequest{Limit: types.MaxPageSize} + } else if req.Limit > types.MaxPageSize { + // If provided request size is above limit, return error + return nil, nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, + "page size %d exceeds maximum allowed %d", req.Limit, types.MaxPageSize) + } - iterator := store.Iterator(nil, nil) - defer iterator.Close() + store := k.GetCreatorPrefixStore(sdk.UnwrapSDKContext(ctx), creator) - denoms := []string{} - for ; iterator.Valid(); iterator.Next() { - denoms = append(denoms, string(iterator.Key())) + // Append denoms from creator until pagination limit + var denoms []string + pageRes, err := query.Paginate(store, req, func(key, _ []byte) error { + denoms = append(denoms, string(key)) + return nil + }) + if err != nil { + return nil, nil, err } - return denoms + return denoms, pageRes, nil } -func (k Keeper) GetAllDenomsIterator(ctx context.Context) store.Iterator { +func (k Keeper) GetAllDenomsIterator(ctx context.Context) cosmosstore.Iterator { return k.GetCreatorsPrefixStore(sdk.UnwrapSDKContext(ctx)).Iterator(nil, nil) } diff --git a/x/tokenfactory/keeper/grpc_query.go b/x/tokenfactory/keeper/grpc_query.go index 362e6b73..e5b38a52 100644 --- a/x/tokenfactory/keeper/grpc_query.go +++ b/x/tokenfactory/keeper/grpc_query.go @@ -30,15 +30,18 @@ func (k Keeper) DenomAuthorityMetadata(ctx context.Context, req *types.QueryDeno func (k Keeper) DenomsFromCreator(ctx context.Context, req *types.QueryDenomsFromCreatorRequest) (*types.QueryDenomsFromCreatorResponse, error) { sdkCtx := sdk.UnwrapSDKContext(ctx) - denoms := k.GetDenomsFromCreator(sdkCtx, req.GetCreator()) - return &types.QueryDenomsFromCreatorResponse{Denoms: denoms}, nil + denoms, pageRes, err := k.GetDenomsFromCreator(sdkCtx, req.GetCreator(), req.GetPagination()) + if err != nil { + return nil, err + } + return &types.QueryDenomsFromCreatorResponse{Denoms: denoms, Pagination: pageRes}, nil } func (k Keeper) DenomsFromAdmin(ctx context.Context, req *types.QueryDenomsFromAdminRequest) (*types.QueryDenomsFromAdminResponse, error) { sdkCtx := sdk.UnwrapSDKContext(ctx) - denoms, err := k.GetDenomsFromAdmin(sdkCtx, req.GetAdmin()) + denoms, pageRes, err := k.GetDenomsFromAdmin(sdkCtx, req.GetAdmin(), req.GetPagination()) if err != nil { return nil, err } - return &types.QueryDenomsFromAdminResponse{Denoms: denoms}, nil + return &types.QueryDenomsFromAdminResponse{Denoms: denoms, Pagination: pageRes}, nil } diff --git a/x/tokenfactory/keeper/keeper.go b/x/tokenfactory/keeper/keeper.go index fe6351cc..c4364528 100644 --- a/x/tokenfactory/keeper/keeper.go +++ b/x/tokenfactory/keeper/keeper.go @@ -98,3 +98,9 @@ func (k Keeper) GetCreatorsPrefixStore(ctx sdk.Context) store.KVStore { store := ctx.KVStore(k.storeKey) return prefix.NewStore(store, types.GetCreatorsPrefix()) } + +// GetAdminPrefixStore returns the substore for a specific admin address +func (k Keeper) GetAdminPrefixStore(ctx sdk.Context, admin string) store.KVStore { + store := ctx.KVStore(k.storeKey) + return prefix.NewStore(store, types.GetAdminPrefix(admin)) +} diff --git a/x/tokenfactory/migrations/v2/migrate.go b/x/tokenfactory/migrations/v2/migrate.go new file mode 100644 index 00000000..3c7eba13 --- /dev/null +++ b/x/tokenfactory/migrations/v2/migrate.go @@ -0,0 +1,34 @@ +// Package v2 contains the state migration from consensus version 1 to 2. +// It backfills the secondary admin index (admin -> []denom) for all existing +// tokenfactory denoms +package v2 + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/kiichain/kiichain/v7/x/tokenfactory/keeper" +) + +// MigrateStore iterates every tokenfactory denom, reads its authority metadata, +// and writes the corresponding entry into the admin secondary index +func MigrateStore(ctx sdk.Context, k keeper.Keeper) error { + logger := ctx.Logger().With("module", "tokenfactory", "migration", "v2") + logger.Info("starting admin index backfill migration") + + iterator := k.GetAllDenomsIterator(ctx) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + denom := string(iterator.Value()) + + metadata, err := k.GetAuthorityMetadata(ctx, denom) + if err != nil { + return err + } + + k.AddDenomFromAdmin(ctx, metadata.Admin, denom) + } + + logger.Info("admin index backfill migration complete") + return nil +} diff --git a/x/tokenfactory/migrations/v2/migrate_test.go b/x/tokenfactory/migrations/v2/migrate_test.go new file mode 100644 index 00000000..d7d7d4cc --- /dev/null +++ b/x/tokenfactory/migrations/v2/migrate_test.go @@ -0,0 +1,89 @@ +package v2_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/kiichain/kiichain/v7/app/apptesting" + v2 "github.com/kiichain/kiichain/v7/x/tokenfactory/migrations/v2" + "github.com/kiichain/kiichain/v7/x/tokenfactory/types" +) + +type MigrateTestSuite struct { + apptesting.KeeperTestHelper +} + +func TestMigrateTestSuite(t *testing.T) { + suite.Run(t, new(MigrateTestSuite)) +} + +// TestMigrateStore verifies that MigrateStore correctly backfills the admin +// secondary index for all existing tokenfactory denoms +func (suite *MigrateTestSuite) TestMigrateStore() { + suite.Setup() + + fundAmount := sdk.NewCoins( + sdk.NewCoin( + types.DefaultParams().DenomCreationFee[0].Denom, + types.DefaultParams().DenomCreationFee[0].Amount.MulRaw(100), + ), + ) + for _, acc := range suite.TestAccs { + suite.FundAcc(acc, fundAmount) + } + + k := suite.App.TokenFactoryKeeper + + // acc0 owns two denoms; acc1 owns one + acc0 := suite.TestAccs[0].String() + acc1 := suite.TestAccs[1].String() + + denom0, err := k.CreateDenom(suite.Ctx, acc0, "akii") + suite.Require().NoError(err) + + denom1, err := k.CreateDenom(suite.Ctx, acc0, "uusdc") + suite.Require().NoError(err) + + denom2, err := k.CreateDenom(suite.Ctx, acc1, "test") + suite.Require().NoError(err) + + // Simulate pre-migration state: remove all admin index entries so the + // index looks as if it was never populated + adminDenoms := map[string][]string{ + acc0: {denom0, denom1}, + acc1: {denom2}, + } + for admin, denoms := range adminDenoms { + for _, denom := range denoms { + k.GetAdminPrefixStore(suite.Ctx, admin).Delete([]byte(denom)) + } + } + + // Confirm the index is empty before the migration + for _, acc := range []string{acc0, acc1} { + denoms, _, err := k.GetDenomsFromAdmin(suite.Ctx, acc, nil) + suite.Require().NoError(err) + suite.Require().Empty(denoms, "admin index should be empty before migration for %s", acc) + } + + // Run the migration + suite.Require().NoError(v2.MigrateStore(suite.Ctx, k)) + + // After migration, each admin must have its denoms back in the index + denoms0, _, err := k.GetDenomsFromAdmin(suite.Ctx, acc0, nil) + suite.Require().NoError(err) + suite.Require().ElementsMatch([]string{denom0, denom1}, denoms0) + + denoms1, _, err := k.GetDenomsFromAdmin(suite.Ctx, acc1, nil) + suite.Require().NoError(err) + suite.Require().ElementsMatch([]string{denom2}, denoms1) +} + +// TestMigrateStore_EmptyState verifies that migrating with no denoms succeeds +func (suite *MigrateTestSuite) TestMigrateStore_EmptyState() { + suite.Setup() + suite.Require().NoError(v2.MigrateStore(suite.Ctx, suite.App.TokenFactoryKeeper)) +} diff --git a/x/tokenfactory/module.go b/x/tokenfactory/module.go index 8eccc890..d4d20030 100644 --- a/x/tokenfactory/module.go +++ b/x/tokenfactory/module.go @@ -29,6 +29,7 @@ import ( "github.com/kiichain/kiichain/v7/x/tokenfactory/client/cli" "github.com/kiichain/kiichain/v7/x/tokenfactory/exported" "github.com/kiichain/kiichain/v7/x/tokenfactory/keeper" + v2 "github.com/kiichain/kiichain/v7/x/tokenfactory/migrations/v2" simulation "github.com/kiichain/kiichain/v7/x/tokenfactory/simulation" "github.com/kiichain/kiichain/v7/x/tokenfactory/types" ) @@ -39,7 +40,7 @@ var ( ) // ConsensusVersion defines the current x/tokenfactory module consensus version. -const ConsensusVersion = 1 +const ConsensusVersion = 2 // ---------------------------------------------------------------------------- // AppModuleBasic @@ -151,6 +152,14 @@ func (AppModule) QuerierRoute() string { return types.QuerierRoute } func (am AppModule) RegisterServices(cfg module.Configurator) { types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) types.RegisterQueryServer(cfg.QueryServer(), am.keeper) + + // Register the migration from consensus version 1 to 2, which backfills the + // secondary admin index introduced in this version. + if err := cfg.RegisterMigration(types.ModuleName, 1, func(ctx sdk.Context) error { + return v2.MigrateStore(ctx, am.keeper) + }); err != nil { + panic(err) + } } // InitGenesis performs the x/tokenfactory module's genesis initialization. It diff --git a/x/tokenfactory/simulation/operations.go b/x/tokenfactory/simulation/operations.go index 16fb66c2..96867bac 100644 --- a/x/tokenfactory/simulation/operations.go +++ b/x/tokenfactory/simulation/operations.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/types/query" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/cosmos/cosmos-sdk/x/simulation" @@ -41,7 +42,7 @@ type TokenfactoryKeeper interface { GetParams(ctx context.Context) (params types.Params) GetAuthorityMetadata(ctx context.Context, denom string) (types.DenomAuthorityMetadata, error) GetAllDenomsIterator(ctx context.Context) sdkstore.Iterator - GetDenomsFromCreator(ctx context.Context, creator string) []string + GetDenomsFromCreator(ctx context.Context, creator string, req *query.PageRequest) ([]string, *query.PageResponse, error) } type BankKeeper interface { @@ -148,7 +149,7 @@ func WeightedOperations( type DenomSelector = func(*rand.Rand, sdk.Context, TokenfactoryKeeper, string) (string, bool) func DefaultSimulationDenomSelector(r *rand.Rand, ctx sdk.Context, tfKeeper TokenfactoryKeeper, creator string) (string, bool) { - denoms := tfKeeper.GetDenomsFromCreator(ctx, creator) + denoms, _, _ := tfKeeper.GetDenomsFromCreator(ctx, creator, nil) if len(denoms) == 0 { return "", false } diff --git a/x/tokenfactory/types/keys.go b/x/tokenfactory/types/keys.go index bb52b5dc..f50d4ef5 100644 --- a/x/tokenfactory/types/keys.go +++ b/x/tokenfactory/types/keys.go @@ -24,7 +24,12 @@ const ( ) // KeySeparator is used to combine parts of the keys in the store -const KeySeparator = "|" +const ( + KeySeparator = "|" + + // MaxPageSize is the hard upper bound for paginated tokenfactory queries. + MaxPageSize = uint64(100) +) var ( DenomAuthorityMetadataKey = "authoritymetadata" @@ -49,3 +54,9 @@ func GetCreatorPrefix(creator string) []byte { func GetCreatorsPrefix() []byte { return []byte(strings.Join([]string{CreatorPrefixKey, ""}, KeySeparator)) } + +// GetAdminPrefix returns the store prefix where the list of denoms administered by a specific +// admin are stored +func GetAdminPrefix(admin string) []byte { + return []byte(strings.Join([]string{AdminPrefixKey, admin, ""}, KeySeparator)) +} diff --git a/x/tokenfactory/types/query.pb.go b/x/tokenfactory/types/query.pb.go index fe41a98d..ed9e83d2 100644 --- a/x/tokenfactory/types/query.pb.go +++ b/x/tokenfactory/types/query.pb.go @@ -6,7 +6,7 @@ package types import ( context "context" fmt "fmt" - _ "github.com/cosmos/cosmos-sdk/types/query" + query "github.com/cosmos/cosmos-sdk/types/query" _ "github.com/cosmos/gogoproto/gogoproto" grpc1 "github.com/cosmos/gogoproto/grpc" proto "github.com/cosmos/gogoproto/proto" @@ -208,7 +208,8 @@ func (m *QueryDenomAuthorityMetadataResponse) GetAuthorityMetadata() DenomAuthor // QueryDenomsFromCreatorRequest defines the request structure for the // DenomsFromCreator gRPC query. type QueryDenomsFromCreatorRequest struct { - Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty" yaml:"creator"` + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty" yaml:"creator"` + Pagination *query.PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` } func (m *QueryDenomsFromCreatorRequest) Reset() { *m = QueryDenomsFromCreatorRequest{} } @@ -251,10 +252,18 @@ func (m *QueryDenomsFromCreatorRequest) GetCreator() string { return "" } -// QueryDenomsFromCreatorRequest defines the response structure for the +func (m *QueryDenomsFromCreatorRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +// QueryDenomsFromCreatorResponse defines the response structure for the // DenomsFromCreator gRPC query. type QueryDenomsFromCreatorResponse struct { - Denoms []string `protobuf:"bytes,1,rep,name=denoms,proto3" json:"denoms,omitempty" yaml:"denoms"` + Denoms []string `protobuf:"bytes,1,rep,name=denoms,proto3" json:"denoms,omitempty" yaml:"denoms"` + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` } func (m *QueryDenomsFromCreatorResponse) Reset() { *m = QueryDenomsFromCreatorResponse{} } @@ -297,10 +306,18 @@ func (m *QueryDenomsFromCreatorResponse) GetDenoms() []string { return nil } +func (m *QueryDenomsFromCreatorResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + // QueryDenomsFromAdminRequest defines the request structure for the // DenomsFromAdmin gRPC query. type QueryDenomsFromAdminRequest struct { - Admin string `protobuf:"bytes,1,opt,name=admin,proto3" json:"admin,omitempty" yaml:"admin"` + Admin string `protobuf:"bytes,1,opt,name=admin,proto3" json:"admin,omitempty" yaml:"admin"` + Pagination *query.PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` } func (m *QueryDenomsFromAdminRequest) Reset() { *m = QueryDenomsFromAdminRequest{} } @@ -343,10 +360,18 @@ func (m *QueryDenomsFromAdminRequest) GetAdmin() string { return "" } -// QueryDenomsFromAdminRequest defines the response structure for the +func (m *QueryDenomsFromAdminRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +// QueryDenomsFromAdminResponse defines the response structure for the // DenomsFromAdmin gRPC query. type QueryDenomsFromAdminResponse struct { - Denoms []string `protobuf:"bytes,1,rep,name=denoms,proto3" json:"denoms,omitempty" yaml:"denoms"` + Denoms []string `protobuf:"bytes,1,rep,name=denoms,proto3" json:"denoms,omitempty" yaml:"denoms"` + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` } func (m *QueryDenomsFromAdminResponse) Reset() { *m = QueryDenomsFromAdminResponse{} } @@ -389,6 +414,13 @@ func (m *QueryDenomsFromAdminResponse) GetDenoms() []string { return nil } +func (m *QueryDenomsFromAdminResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + func init() { proto.RegisterType((*QueryParamsRequest)(nil), "kiichain.tokenfactory.v1beta1.QueryParamsRequest") proto.RegisterType((*QueryParamsResponse)(nil), "kiichain.tokenfactory.v1beta1.QueryParamsResponse") @@ -405,47 +437,50 @@ func init() { } var fileDescriptor_589456711a18ee88 = []byte{ - // 636 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0x4d, 0x6b, 0x13, 0x41, - 0x18, 0xce, 0xaa, 0x8d, 0x74, 0xfc, 0xec, 0x58, 0x44, 0xd7, 0x76, 0xa3, 0x23, 0xd5, 0x56, 0x74, - 0x87, 0x54, 0x0a, 0x52, 0xab, 0xb4, 0xdb, 0x2a, 0x4a, 0x2d, 0xe8, 0x1e, 0x7b, 0x09, 0x93, 0x64, - 0xba, 0x59, 0xda, 0xdd, 0xd9, 0xee, 0x4e, 0xc4, 0x10, 0x72, 0xf1, 0xe2, 0x55, 0xf0, 0xee, 0x5f, - 0xf0, 0x0f, 0xf8, 0x03, 0x7a, 0xf0, 0x50, 0x10, 0xc4, 0x53, 0x90, 0xc4, 0x8b, 0xd7, 0xfc, 0x02, - 0xd9, 0x99, 0x49, 0x9a, 0x66, 0x63, 0x3e, 0xea, 0x69, 0x27, 0xef, 0xc7, 0xf3, 0x3e, 0xcf, 0xfb, - 0x41, 0xc0, 0xc2, 0xae, 0xeb, 0x16, 0x4a, 0xc4, 0xf5, 0x31, 0x67, 0xbb, 0xd4, 0xdf, 0x21, 0x05, - 0xce, 0xc2, 0x0a, 0x7e, 0x9b, 0xcd, 0x53, 0x4e, 0xb2, 0x78, 0xbf, 0x4c, 0xc3, 0x8a, 0x19, 0x84, - 0x8c, 0x33, 0x38, 0xdb, 0x0e, 0x35, 0xbb, 0x43, 0x4d, 0x15, 0xaa, 0x4f, 0x3b, 0xcc, 0x61, 0x22, - 0x12, 0xc7, 0x2f, 0x99, 0xa4, 0xcf, 0x38, 0x8c, 0x39, 0x7b, 0x14, 0x93, 0xc0, 0xc5, 0xc4, 0xf7, - 0x19, 0x27, 0xdc, 0x65, 0x7e, 0xa4, 0xbc, 0xf7, 0x0a, 0x2c, 0xf2, 0x58, 0x84, 0xf3, 0x24, 0xa2, - 0xb2, 0x56, 0xa7, 0x72, 0x40, 0x1c, 0xd7, 0x17, 0xc1, 0x2a, 0x76, 0x69, 0x30, 0x53, 0x52, 0xe6, - 0x25, 0x16, 0xba, 0xbc, 0xb2, 0x45, 0x39, 0x29, 0x12, 0x4e, 0xda, 0x25, 0x06, 0xa7, 0x05, 0x24, - 0x24, 0x9e, 0xa2, 0x83, 0xa6, 0x01, 0x7c, 0x13, 0x93, 0x78, 0x2d, 0x8c, 0x36, 0xdd, 0x2f, 0xd3, - 0x88, 0xa3, 0x6d, 0x70, 0xe5, 0x98, 0x35, 0x0a, 0x98, 0x1f, 0x51, 0xb8, 0x0e, 0xd2, 0x32, 0xf9, - 0x9a, 0x76, 0x53, 0x9b, 0x3f, 0xb7, 0x38, 0x67, 0x0e, 0xec, 0x8f, 0x29, 0xd3, 0xad, 0x33, 0x07, - 0xf5, 0x4c, 0xca, 0x56, 0xa9, 0xe8, 0x15, 0x40, 0x02, 0x7b, 0x83, 0xfa, 0xcc, 0x5b, 0xeb, 0x95, - 0xa0, 0x18, 0xc0, 0x3b, 0x60, 0xa2, 0x18, 0x07, 0x88, 0x4a, 0x93, 0xd6, 0xe5, 0x56, 0x3d, 0x73, - 0xbe, 0x42, 0xbc, 0xbd, 0x65, 0x24, 0xcc, 0xc8, 0x96, 0x6e, 0xf4, 0x45, 0x03, 0xb7, 0x07, 0xc2, - 0x29, 0xea, 0x1f, 0x34, 0x00, 0x3b, 0xfd, 0xca, 0x79, 0xca, 0xad, 0x74, 0x2c, 0x0d, 0xd1, 0xd1, - 0x1f, 0xdb, 0xba, 0x15, 0xeb, 0x6a, 0xd5, 0x33, 0xd7, 0x25, 0xb1, 0x24, 0x3c, 0xb2, 0xa7, 0x12, - 0x33, 0x42, 0x5b, 0x60, 0xf6, 0x88, 0x70, 0xf4, 0x3c, 0x64, 0xde, 0x7a, 0x48, 0x09, 0x67, 0x61, - 0x5b, 0xfa, 0x7d, 0x70, 0xb6, 0x20, 0x2d, 0x4a, 0x3c, 0x6c, 0xd5, 0x33, 0x17, 0x65, 0x0d, 0xe5, - 0x40, 0x76, 0x3b, 0x04, 0x6d, 0x02, 0xe3, 0x5f, 0x70, 0x4a, 0xfa, 0x02, 0x48, 0x8b, 0x5e, 0xc5, - 0x53, 0x3b, 0x3d, 0x3f, 0x69, 0x4d, 0xb5, 0xea, 0x99, 0x0b, 0x5d, 0xbd, 0x8c, 0x90, 0xad, 0x02, - 0xd0, 0x33, 0x70, 0xa3, 0x07, 0x6c, 0xad, 0xe8, 0xb9, 0x7e, 0xd7, 0x50, 0x48, 0xfc, 0x3b, 0x39, - 0x14, 0x61, 0x46, 0xb6, 0x74, 0xa3, 0x97, 0x60, 0xa6, 0x3f, 0xcc, 0xd8, 0x8c, 0x16, 0xbf, 0xa6, - 0xc1, 0x84, 0xc0, 0x82, 0x9f, 0x35, 0x90, 0x96, 0x0b, 0x05, 0xb3, 0x43, 0xe6, 0x95, 0xdc, 0x68, - 0x7d, 0x71, 0x9c, 0x14, 0x49, 0x13, 0x3d, 0x78, 0xff, 0xfd, 0xf7, 0xa7, 0x53, 0x77, 0xe1, 0x1c, - 0x1e, 0xe5, 0xa0, 0xe0, 0x1f, 0x0d, 0x5c, 0xed, 0xbf, 0x29, 0x70, 0x6d, 0x94, 0xea, 0x03, 0x0f, - 0x42, 0xb7, 0xfe, 0x07, 0x42, 0x09, 0x7a, 0x21, 0x04, 0x59, 0x70, 0x75, 0x88, 0x20, 0xd9, 0x7b, - 0x5c, 0x15, 0xdf, 0x1a, 0x4e, 0x2e, 0x36, 0xfc, 0xa1, 0x81, 0xa9, 0xc4, 0xc6, 0xc1, 0x95, 0x91, - 0x39, 0xf6, 0xd9, 0x7b, 0xfd, 0xc9, 0x09, 0xb3, 0x95, 0xb8, 0x0d, 0x21, 0xee, 0x29, 0x5c, 0x19, - 0x49, 0x5c, 0x6e, 0x27, 0x64, 0x5e, 0x4e, 0x1d, 0x11, 0xae, 0xaa, 0x47, 0x0d, 0x7e, 0xd3, 0xc0, - 0xa5, 0x9e, 0xb5, 0x85, 0xcb, 0xe3, 0x11, 0xeb, 0x3e, 0x19, 0xfd, 0xf1, 0x89, 0x72, 0x95, 0xa4, - 0x55, 0x21, 0x69, 0x19, 0x3e, 0x1a, 0x43, 0x92, 0xb8, 0x40, 0x5c, 0x15, 0x9f, 0x9a, 0xb5, 0x79, - 0xd0, 0x30, 0xb4, 0xc3, 0x86, 0xa1, 0xfd, 0x6a, 0x18, 0xda, 0xc7, 0xa6, 0x91, 0x3a, 0x6c, 0x1a, - 0xa9, 0x9f, 0x4d, 0x23, 0xb5, 0x9d, 0x75, 0x5c, 0x5e, 0x2a, 0xe7, 0xcd, 0x02, 0xf3, 0x8e, 0xd0, - 0x3b, 0x8f, 0x77, 0xc7, 0x0b, 0xf1, 0x4a, 0x40, 0xa3, 0x7c, 0x5a, 0xfc, 0x65, 0x3c, 0xfc, 0x1b, - 0x00, 0x00, 0xff, 0xff, 0x57, 0xd1, 0xa0, 0xd6, 0x41, 0x07, 0x00, 0x00, + // 684 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x55, 0x4b, 0x4f, 0x13, 0x41, + 0x1c, 0xef, 0xa0, 0xd4, 0x30, 0x3e, 0x19, 0x89, 0xc1, 0x15, 0xb6, 0x3a, 0x86, 0x97, 0xd1, 0x9d, + 0x14, 0x43, 0x62, 0x10, 0x0d, 0x2c, 0x04, 0x4d, 0xd4, 0x44, 0xf7, 0xc8, 0x85, 0x4c, 0xcb, 0xb0, + 0x6c, 0x60, 0x77, 0x96, 0xdd, 0xa9, 0xb1, 0x21, 0x5c, 0xbc, 0x78, 0x32, 0x31, 0x3e, 0xae, 0x7e, + 0x05, 0xbf, 0x80, 0x1f, 0x80, 0x83, 0x07, 0x12, 0x13, 0xe3, 0xa9, 0x31, 0xe0, 0xc5, 0x6b, 0x3f, + 0x81, 0xd9, 0x99, 0x29, 0x2d, 0x6c, 0xed, 0x03, 0x4d, 0x3c, 0xed, 0xf4, 0xff, 0xfc, 0xfd, 0xfe, + 0xaf, 0xc2, 0x89, 0x75, 0xcf, 0x2b, 0xae, 0x51, 0x2f, 0x20, 0x82, 0xaf, 0xb3, 0x60, 0x95, 0x16, + 0x05, 0x8f, 0xca, 0xe4, 0x79, 0xbe, 0xc0, 0x04, 0xcd, 0x93, 0xcd, 0x12, 0x8b, 0xca, 0x56, 0x18, + 0x71, 0xc1, 0xd1, 0x70, 0xcd, 0xd4, 0x6a, 0x34, 0xb5, 0xb4, 0xa9, 0x31, 0xe0, 0x72, 0x97, 0x4b, + 0x4b, 0x92, 0xbc, 0x94, 0x93, 0x31, 0xe4, 0x72, 0xee, 0x6e, 0x30, 0x42, 0x43, 0x8f, 0xd0, 0x20, + 0xe0, 0x82, 0x0a, 0x8f, 0x07, 0xb1, 0xd6, 0xde, 0x28, 0xf2, 0xd8, 0xe7, 0x31, 0x29, 0xd0, 0x98, + 0xa9, 0x5c, 0x07, 0x99, 0x43, 0xea, 0x7a, 0x81, 0x34, 0xd6, 0xb6, 0x53, 0xad, 0x91, 0xd2, 0x92, + 0x58, 0xe3, 0x91, 0x27, 0xca, 0x4f, 0x98, 0xa0, 0x2b, 0x54, 0xd0, 0x5a, 0x8a, 0xd6, 0x6e, 0x21, + 0x8d, 0xa8, 0xaf, 0xe1, 0xe0, 0x01, 0x88, 0x9e, 0x25, 0x20, 0x9e, 0x4a, 0xa1, 0xc3, 0x36, 0x4b, + 0x2c, 0x16, 0x78, 0x09, 0x5e, 0x3c, 0x24, 0x8d, 0x43, 0x1e, 0xc4, 0x0c, 0xcd, 0xc3, 0xac, 0x72, + 0x1e, 0x04, 0x57, 0xc1, 0xf8, 0xe9, 0xc9, 0x11, 0xab, 0x65, 0x7d, 0x2c, 0xe5, 0x6e, 0x9f, 0xdc, + 0xa9, 0xe4, 0x32, 0x8e, 0x76, 0xc5, 0x8f, 0x21, 0x96, 0xb1, 0x17, 0x58, 0xc0, 0xfd, 0xb9, 0xa3, + 0x14, 0x34, 0x02, 0x34, 0x0a, 0x7b, 0x57, 0x12, 0x03, 0x99, 0xa9, 0xcf, 0xbe, 0x50, 0xad, 0xe4, + 0xce, 0x94, 0xa9, 0xbf, 0x31, 0x8d, 0xa5, 0x18, 0x3b, 0x4a, 0x8d, 0x3f, 0x01, 0x78, 0xbd, 0x65, + 0x38, 0x0d, 0xfd, 0x15, 0x80, 0xe8, 0xa0, 0x5e, 0xcb, 0xbe, 0x56, 0x6b, 0x1e, 0x53, 0x6d, 0x78, + 0x34, 0x8f, 0x6d, 0x5f, 0x4b, 0x78, 0x55, 0x2b, 0xb9, 0xcb, 0x0a, 0x58, 0x3a, 0x3c, 0x76, 0xfa, + 0x53, 0x3d, 0xc2, 0x1f, 0x00, 0x1c, 0xae, 0x23, 0x8e, 0x17, 0x23, 0xee, 0xcf, 0x47, 0x8c, 0x0a, + 0x1e, 0xd5, 0xb8, 0xdf, 0x84, 0xa7, 0x8a, 0x4a, 0xa2, 0xd9, 0xa3, 0x6a, 0x25, 0x77, 0x4e, 0x25, + 0xd1, 0x0a, 0xec, 0xd4, 0x4c, 0xd0, 0x22, 0x84, 0xf5, 0xc1, 0x19, 0xec, 0x91, 0x84, 0x46, 0x2d, + 0x35, 0x65, 0x56, 0x32, 0x65, 0x96, 0x9a, 0xe8, 0x7a, 0x53, 0x5c, 0xa6, 0x33, 0x39, 0x0d, 0x9e, + 0xf8, 0x3d, 0x80, 0xe6, 0x9f, 0x70, 0xe9, 0x22, 0x4e, 0xc0, 0xac, 0xac, 0x7a, 0xd2, 0xff, 0x13, + 0xe3, 0x7d, 0x76, 0x7f, 0xb5, 0x92, 0x3b, 0xdb, 0xd0, 0x95, 0x18, 0x3b, 0xda, 0x00, 0x3d, 0x68, + 0x82, 0x6a, 0xac, 0x2d, 0x2a, 0x95, 0xe7, 0x10, 0xac, 0xd7, 0x00, 0x5e, 0x39, 0x02, 0x6b, 0x6e, + 0xc5, 0xf7, 0x82, 0x86, 0x41, 0xa1, 0xc9, 0xef, 0xf4, 0xa0, 0x48, 0x31, 0x76, 0x94, 0xfa, 0x9f, + 0x95, 0xe9, 0x2d, 0x80, 0x43, 0xcd, 0xf1, 0xfc, 0xbf, 0x22, 0x4d, 0x7e, 0xce, 0xc2, 0x5e, 0x09, + 0x0a, 0x7d, 0x04, 0x30, 0xab, 0xd6, 0x0e, 0xe5, 0xdb, 0x4c, 0x75, 0x7a, 0xef, 0x8d, 0xc9, 0x6e, + 0x5c, 0x14, 0x0e, 0x7c, 0xeb, 0xe5, 0xd7, 0x9f, 0xef, 0x7a, 0xc6, 0xd0, 0x08, 0xe9, 0xe4, 0xec, + 0xa0, 0x5f, 0x00, 0x5e, 0x6a, 0xbe, 0x4f, 0x68, 0xae, 0x93, 0xec, 0x2d, 0xcf, 0x86, 0x61, 0xff, + 0x4d, 0x08, 0x4d, 0xe8, 0xa1, 0x24, 0x64, 0xa3, 0xd9, 0x36, 0x84, 0x54, 0x13, 0xc9, 0x96, 0xfc, + 0x6e, 0x93, 0xf4, 0xfa, 0xa3, 0x6f, 0x00, 0xf6, 0xa7, 0xb6, 0x09, 0xcd, 0x74, 0x8c, 0xb1, 0xc9, + 0x71, 0x30, 0xee, 0x1d, 0xd3, 0x5b, 0x93, 0x5b, 0x90, 0xe4, 0xee, 0xa3, 0x99, 0x8e, 0xc8, 0x2d, + 0xaf, 0x46, 0xdc, 0x5f, 0xd6, 0x97, 0x86, 0x6c, 0xe9, 0xc7, 0x36, 0xfa, 0x02, 0xe0, 0xf9, 0x23, + 0xf3, 0x8f, 0xa6, 0xbb, 0x03, 0xd6, 0xb8, 0xc4, 0xc6, 0xdd, 0x63, 0xf9, 0x6a, 0x4a, 0xb3, 0x92, + 0xd2, 0x34, 0xba, 0xd3, 0x05, 0x25, 0x79, 0x13, 0xc8, 0x96, 0xfc, 0x6c, 0xdb, 0x8f, 0x76, 0xf6, + 0x4c, 0xb0, 0xbb, 0x67, 0x82, 0x1f, 0x7b, 0x26, 0x78, 0xb3, 0x6f, 0x66, 0x76, 0xf7, 0xcd, 0xcc, + 0xf7, 0x7d, 0x33, 0xb3, 0x94, 0x77, 0x3d, 0xb1, 0x56, 0x2a, 0x58, 0x45, 0xee, 0xd7, 0xa3, 0x1f, + 0x3c, 0x5e, 0x1c, 0x4e, 0x24, 0xca, 0x21, 0x8b, 0x0b, 0x59, 0xf9, 0xc7, 0x7a, 0xfb, 0x77, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xe3, 0x3a, 0xdc, 0xe7, 0x67, 0x08, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -791,6 +826,18 @@ func (m *QueryDenomsFromCreatorRequest) MarshalToSizedBuffer(dAtA []byte) (int, _ = i var l int _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } if len(m.Creator) > 0 { i -= len(m.Creator) copy(dAtA[i:], m.Creator) @@ -821,6 +868,18 @@ func (m *QueryDenomsFromCreatorResponse) MarshalToSizedBuffer(dAtA []byte) (int, _ = i var l int _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } if len(m.Denoms) > 0 { for iNdEx := len(m.Denoms) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.Denoms[iNdEx]) @@ -853,6 +912,18 @@ func (m *QueryDenomsFromAdminRequest) MarshalToSizedBuffer(dAtA []byte) (int, er _ = i var l int _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } if len(m.Admin) > 0 { i -= len(m.Admin) copy(dAtA[i:], m.Admin) @@ -883,6 +954,18 @@ func (m *QueryDenomsFromAdminResponse) MarshalToSizedBuffer(dAtA []byte) (int, e _ = i var l int _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } if len(m.Denoms) > 0 { for iNdEx := len(m.Denoms) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.Denoms[iNdEx]) @@ -960,6 +1043,10 @@ func (m *QueryDenomsFromCreatorRequest) Size() (n int) { if l > 0 { n += 1 + l + sovQuery(uint64(l)) } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } return n } @@ -975,6 +1062,10 @@ func (m *QueryDenomsFromCreatorResponse) Size() (n int) { n += 1 + l + sovQuery(uint64(l)) } } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } return n } @@ -988,6 +1079,10 @@ func (m *QueryDenomsFromAdminRequest) Size() (n int) { if l > 0 { n += 1 + l + sovQuery(uint64(l)) } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } return n } @@ -1003,6 +1098,10 @@ func (m *QueryDenomsFromAdminResponse) Size() (n int) { n += 1 + l + sovQuery(uint64(l)) } } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } return n } @@ -1371,6 +1470,42 @@ func (m *QueryDenomsFromCreatorRequest) Unmarshal(dAtA []byte) error { } m.Creator = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) @@ -1453,6 +1588,42 @@ func (m *QueryDenomsFromCreatorResponse) Unmarshal(dAtA []byte) error { } m.Denoms = append(m.Denoms, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageResponse{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) @@ -1535,6 +1706,42 @@ func (m *QueryDenomsFromAdminRequest) Unmarshal(dAtA []byte) error { } m.Admin = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) @@ -1617,6 +1824,42 @@ func (m *QueryDenomsFromAdminResponse) Unmarshal(dAtA []byte) error { } m.Denoms = append(m.Denoms, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageResponse{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) diff --git a/x/tokenfactory/types/query.pb.gw.go b/x/tokenfactory/types/query.pb.gw.go index 986db2f4..49353a0b 100644 --- a/x/tokenfactory/types/query.pb.gw.go +++ b/x/tokenfactory/types/query.pb.gw.go @@ -105,6 +105,10 @@ func local_request_Query_DenomAuthorityMetadata_0(ctx context.Context, marshaler } +var ( + filter_Query_DenomsFromCreator_0 = &utilities.DoubleArray{Encoding: map[string]int{"creator": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + func request_Query_DenomsFromCreator_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryDenomsFromCreatorRequest var metadata runtime.ServerMetadata @@ -127,6 +131,13 @@ func request_Query_DenomsFromCreator_0(ctx context.Context, marshaler runtime.Ma return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "creator", err) } + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_DenomsFromCreator_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := client.DenomsFromCreator(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err @@ -154,11 +165,22 @@ func local_request_Query_DenomsFromCreator_0(ctx context.Context, marshaler runt return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "creator", err) } + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_DenomsFromCreator_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.DenomsFromCreator(ctx, &protoReq) return msg, metadata, err } +var ( + filter_Query_DenomsFromAdmin_0 = &utilities.DoubleArray{Encoding: map[string]int{"admin": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + func request_Query_DenomsFromAdmin_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryDenomsFromAdminRequest var metadata runtime.ServerMetadata @@ -181,6 +203,13 @@ func request_Query_DenomsFromAdmin_0(ctx context.Context, marshaler runtime.Mars return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "admin", err) } + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_DenomsFromAdmin_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := client.DenomsFromAdmin(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err @@ -208,6 +237,13 @@ func local_request_Query_DenomsFromAdmin_0(ctx context.Context, marshaler runtim return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "admin", err) } + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_DenomsFromAdmin_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.DenomsFromAdmin(ctx, &protoReq) return msg, metadata, err