Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: create a query that directly returns all module accounts without pagination or iteration #987

Merged
merged 13 commits into from
Oct 12, 2022
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* [#956](https://github.com/NibiruChain/nibiru/pull/956) - test(perp): partial liquidate unit test
* [#981](https://github.com/NibiruChain/nibiru/pull/981) - chore(testutil): clean up x/testutil packages
* [#980](https://github.com/NibiruChain/nibiru/pull/980) - test(perp): add `MsgClosePosition`, `MsgAddMargin`, and `MsgRemoveMargin` simulation tests
* [#987](https://github.com/NibiruChain/nibiru/pull/987) - feat: create a query that directly returns all module accounts without pagination or iteration
* [#982](https://github.com/NibiruChain/nibiru/pull/982) - improvements for pricefeed genesis
* [#989](https://github.com/NibiruChain/nibiru/pull/989) - test(perp): cli test for AddMargin

Expand Down
8 changes: 8 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ import (
pricefeedcli "github.com/NibiruChain/nibiru/x/pricefeed/client/cli"
pricefeedkeeper "github.com/NibiruChain/nibiru/x/pricefeed/keeper"
pricefeedtypes "github.com/NibiruChain/nibiru/x/pricefeed/types"
"github.com/NibiruChain/nibiru/x/util"
utiltypes "github.com/NibiruChain/nibiru/x/util/types"
"github.com/NibiruChain/nibiru/x/vpool"
vpoolcli "github.com/NibiruChain/nibiru/x/vpool/client/cli"
vpoolkeeper "github.com/NibiruChain/nibiru/x/vpool/keeper"
Expand Down Expand Up @@ -164,6 +166,7 @@ var (
epochs.AppModuleBasic{},
perp.AppModuleBasic{},
vpool.AppModuleBasic{},
util.AppModule{},
)

// module account permissions
Expand Down Expand Up @@ -495,6 +498,7 @@ func NewNibiruApp(
vpoolModule := vpool.NewAppModule(
appCodec, app.vpoolKeeper, app.pricefeedKeeper,
)
utilModule := util.NewAppModule(app.bankKeeper)

// NOTE: Any module instantiated in the module manager that is later modified
// must be passed by reference here.
Expand Down Expand Up @@ -523,6 +527,7 @@ func NewNibiruApp(
epochsModule,
vpoolModule,
perpModule,
utilModule,

// ibc
evidence.NewAppModule(app.evidenceKeeper),
Expand Down Expand Up @@ -557,6 +562,7 @@ func NewNibiruApp(
epochstypes.ModuleName,
vpooltypes.ModuleName,
perptypes.ModuleName,
utiltypes.ModuleName,
// ibc modules
ibchost.ModuleName,
ibctransfertypes.ModuleName,
Expand All @@ -583,6 +589,7 @@ func NewNibiruApp(
pricefeedtypes.ModuleName,
vpooltypes.ModuleName,
perptypes.ModuleName,
utiltypes.ModuleName,
// ibc
ibchost.ModuleName,
ibctransfertypes.ModuleName,
Expand Down Expand Up @@ -615,6 +622,7 @@ func NewNibiruApp(
epochstypes.ModuleName,
vpooltypes.ModuleName,
perptypes.ModuleName,
utiltypes.ModuleName,
// ibc
ibchost.ModuleName,
ibctransfertypes.ModuleName,
Expand Down
35 changes: 35 additions & 0 deletions proto/util/v1/query.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
syntax = "proto3";

package nibiru.util.v1;

import "gogoproto/gogo.proto";
import "google/api/annotations.proto";
import "cosmos/base/v1beta1/coin.proto";
import "vpool/v1/state.proto";

option go_package = "github.com/NibiruChain/nibiru/x/util/types";

// Query defines the gRPC querier service.
service Query {

// Queries the reserve assets in a given pool, identified by a token pair.
rpc ModuleAccounts(QueryModuleAccountsRequest) returns (QueryModuleAccountsResponse) {
option (google.api.http).get = "/nibiru/util/module_accounts";
}
}

// ----------------------------------------

message QueryModuleAccountsRequest {}

message QueryModuleAccountsResponse {
repeated AccountWithBalance accounts = 1 [(gogoproto.nullable) = false];
}

message AccountWithBalance {
string name = 1;
string address = 2;

repeated cosmos.base.v1beta1.Coin balance = 3
[(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"];
}
58 changes: 58 additions & 0 deletions x/util/client/cli/query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package cli

import (
"fmt"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/spf13/cobra"

utiltypes "github.com/NibiruChain/nibiru/x/util/types"
)

// GetQueryCmd returns the cli query commands for this module
func GetQueryCmd() *cobra.Command {
queryCmd := &cobra.Command{
Use: utiltypes.ModuleName,
Short: fmt.Sprintf(
"Querying commands for the %s module", utiltypes.ModuleName),
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}

for _, cmd := range []*cobra.Command{
CmdQueryModuleAccounts(),
} {
queryCmd.AddCommand(cmd)
}

return queryCmd
}

func CmdQueryModuleAccounts() *cobra.Command {
cmd := &cobra.Command{
Use: "module-accounts",
Short: "shows all the module accounts in the blockchain",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}

queryClient := utiltypes.NewQueryClient(clientCtx)

res, err := queryClient.ModuleAccounts(cmd.Context(), &utiltypes.QueryModuleAccountsRequest{})
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}
18 changes: 18 additions & 0 deletions x/util/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package util

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"

utiltypes "github.com/NibiruChain/nibiru/x/util/types"
)

// NewHandler ...
func NewHandler() sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
errMsg := fmt.Sprintf("unrecognized %s message type: %T", utiltypes.ModuleName, msg)
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg)
}
}
41 changes: 41 additions & 0 deletions x/util/keeper/query_server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package keeper

import (
"context"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/types"

utiltypes "github.com/NibiruChain/nibiru/x/util/types"
)

type queryServer struct {
k utiltypes.BankKeeper
}

func NewQueryServer(k utiltypes.BankKeeper) utiltypes.QueryServer {
return &queryServer{k: k}
}

func (q queryServer) ModuleAccounts(
ctx context.Context,
_ *utiltypes.QueryModuleAccountsRequest,
) (*utiltypes.QueryModuleAccountsResponse, error) {
sdkContext := sdk.UnwrapSDKContext(ctx)

var moduleAccountsWithBalances []utiltypes.AccountWithBalance
for _, acc := range utiltypes.ModuleAccounts {
account := types.NewModuleAddress(acc)

balances := q.k.GetAllBalances(sdkContext, account)

accWithBalance := utiltypes.AccountWithBalance{
Name: acc,
Address: account.String(),
Balance: balances,
}
moduleAccountsWithBalances = append(moduleAccountsWithBalances, accWithBalance)
}

return &utiltypes.QueryModuleAccountsResponse{Accounts: moduleAccountsWithBalances}, nil
}
40 changes: 40 additions & 0 deletions x/util/keeper/query_server_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package keeper_test

import (
"testing"

sdktypes "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"

"github.com/NibiruChain/nibiru/simapp"
"github.com/NibiruChain/nibiru/x/util/keeper"
"github.com/NibiruChain/nibiru/x/util/types"
)

func TestQueryServer_ModuleAccounts(t *testing.T) {
app, ctx := simapp.NewTestNibiruAppAndContext(false)
goCtx := sdktypes.WrapSDKContext(ctx)

qServer := keeper.NewQueryServer(app.BankKeeper)

t.Log("query accounts and check empty balance")
accounts, err := qServer.ModuleAccounts(goCtx, &types.QueryModuleAccountsRequest{})
require.NoError(t, err)
require.Len(t, accounts.Accounts, len(types.ModuleAccounts))
require.Equal(t, accounts.Accounts[0].Balance, sdktypes.Coins{})

t.Log("we send some money")
someModuleAccount := types.ModuleAccounts[0]
err = app.BankKeeper.MintCoins(
ctx,
someModuleAccount,
sdktypes.NewCoins(sdktypes.NewInt64Coin("uniques", 1_000_000)),
)
require.NoError(t, err)

t.Log("we check that it returns some balance")
accounts, err = qServer.ModuleAccounts(goCtx, &types.QueryModuleAccountsRequest{})
require.NoError(t, err)
require.Len(t, accounts.Accounts, len(types.ModuleAccounts))
require.Equal(t, accounts.Accounts[0].Balance, sdktypes.NewCoins(sdktypes.NewInt64Coin("uniques", 1_000_000)))
}
74 changes: 74 additions & 0 deletions x/util/module.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package util

import (
"encoding/json"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/gorilla/mux"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
abci "github.com/tendermint/tendermint/abci/types"

"github.com/NibiruChain/nibiru/x/util/client/cli"
"github.com/NibiruChain/nibiru/x/util/keeper"
utiltypes "github.com/NibiruChain/nibiru/x/util/types"
)

var (
_ module.AppModule = AppModule{}
)

type AppModule struct {
bankKeeper utiltypes.BankKeeper
}

func NewAppModule(bk utiltypes.BankKeeper) *AppModule {
return &AppModule{
bankKeeper: bk,
}
}

func (a AppModule) Name() string {
return "util"
}

func (a AppModule) RegisterLegacyAminoCodec(*codec.LegacyAmino) {}
func (a AppModule) RegisterInterfaces(codectypes.InterfaceRegistry) {}
func (a AppModule) DefaultGenesis(codec.JSONCodec) json.RawMessage { return nil }
func (a AppModule) ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage) error {
return nil
}
func (a AppModule) RegisterRESTRoutes(client.Context, *mux.Router) {}
func (a AppModule) RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux) {}
func (a AppModule) GetTxCmd() *cobra.Command { return nil }
func (a AppModule) GetQueryCmd() *cobra.Command { return cli.GetQueryCmd() }
func (a AppModule) InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage) []abci.ValidatorUpdate {
return nil
}
func (a AppModule) ExportGenesis(sdk.Context, codec.JSONCodec) json.RawMessage {
return nil
}
func (a AppModule) RegisterInvariants(sdk.InvariantRegistry) {}
func (a AppModule) Route() sdk.Route {
return sdk.NewRoute("", NewHandler())
}
func (a AppModule) QuerierRoute() string {
return ""
}
func (a AppModule) LegacyQuerierHandler(*codec.LegacyAmino) sdk.Querier {
return nil
}
func (a AppModule) RegisterServices(cfg module.Configurator) {
utiltypes.RegisterQueryServer(cfg.QueryServer(), keeper.NewQueryServer(a.bankKeeper))
}
func (a AppModule) ConsensusVersion() uint64 {
return 1
}
func (a AppModule) BeginBlock(sdk.Context, abci.RequestBeginBlock) {}
func (a AppModule) EndBlock(sdk.Context, abci.RequestEndBlock) []abci.ValidatorUpdate {
return nil
}
8 changes: 8 additions & 0 deletions x/util/types/expected_keepers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package types

import sdk "github.com/cosmos/cosmos-sdk/types"

// BankKeeper defines the expected interface needed to retrieve account balances.
type BankKeeper interface {
GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
}
6 changes: 6 additions & 0 deletions x/util/types/keys.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package types

const (
ModuleName = "util"
RouterKey = ModuleName
)
14 changes: 14 additions & 0 deletions x/util/types/module_accounts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package types

import (
"github.com/NibiruChain/nibiru/x/common"
perptypes "github.com/NibiruChain/nibiru/x/perp/types"
)

var ModuleAccounts = []string{
perptypes.ModuleName,
perptypes.VaultModuleAccount,
perptypes.PerpEFModuleAccount,
perptypes.FeePoolModuleAccount,
common.TreasuryPoolModuleAccount,
}
Loading