From 92afaf6ca089fd4870bc9ca56473af7ed0e800b1 Mon Sep 17 00:00:00 2001 From: Kevin Davis Date: Thu, 21 Jan 2021 10:36:51 -0700 Subject: [PATCH] add query for all current prices (#768) --- x/pricefeed/client/cli/query.go | 26 ++++++++++++++++++++++++++ x/pricefeed/client/rest/query.go | 19 +++++++++++++++++++ x/pricefeed/keeper/keeper.go | 25 +++++++++++++++++++++++++ x/pricefeed/keeper/querier.go | 11 +++++++++++ x/pricefeed/types/querier.go | 2 ++ 5 files changed, 83 insertions(+) diff --git a/x/pricefeed/client/cli/query.go b/x/pricefeed/client/cli/query.go index 73ae9796..e433ef23 100644 --- a/x/pricefeed/client/cli/query.go +++ b/x/pricefeed/client/cli/query.go @@ -27,6 +27,7 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { pricefeedQueryCmd.AddCommand(flags.GetCommands( GetCmdPrice(queryRoute, cdc), + GetCmdQueryPrices(queryRoute, cdc), GetCmdRawPrices(queryRoute, cdc), GetCmdOracles(queryRoute, cdc), GetCmdMarkets(queryRoute, cdc), @@ -94,6 +95,31 @@ func GetCmdPrice(queryRoute string, cdc *codec.Codec) *cobra.Command { } } +// GetCmdQueryPrices queries the pricefeed module for current prices +func GetCmdQueryPrices(queryRoute string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "prices", + Short: "get the current price of each market", + Long: "Get the current prices of each market in the pricefeed module.", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + + // Query + route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryPrices) + res, _, err := cliCtx.QueryWithData(route, nil) + if err != nil { + return err + } + + // Decode and print results + var out types.CurrentPrices + cdc.MustUnmarshalJSON(res, &out) + return cliCtx.PrintOutput(out) + }, + } +} + // GetCmdRawPrices queries the current price of an asset func GetCmdRawPrices(queryRoute string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ diff --git a/x/pricefeed/client/rest/query.go b/x/pricefeed/client/rest/query.go index b99cec96..4da6ce8a 100644 --- a/x/pricefeed/client/rest/query.go +++ b/x/pricefeed/client/rest/query.go @@ -19,6 +19,7 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) { r.HandleFunc(fmt.Sprintf("/%s/oracles/{%s}", types.ModuleName, RestMarketID), queryOraclesHandlerFn(cliCtx)).Methods("GET") r.HandleFunc(fmt.Sprintf("/%s/rawprices/{%s}", types.ModuleName, RestMarketID), queryRawPricesHandlerFn(cliCtx)).Methods("GET") r.HandleFunc(fmt.Sprintf("/%s/price/{%s}", types.ModuleName, RestMarketID), queryPriceHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc(fmt.Sprintf("/%s/prices", types.ModuleName), queryPricesHandlerFn(cliCtx)).Methods("GET") } func queryRawPricesHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { @@ -77,6 +78,24 @@ func queryPriceHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } } +func queryPricesHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + // Parse the query height + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", types.ModuleName, types.QueryPrices), nil) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + cliCtx = cliCtx.WithHeight(height) + rest.PostProcessResponse(w, cliCtx, res) + } +} + func queryMarketsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // Parse the query height diff --git a/x/pricefeed/keeper/keeper.go b/x/pricefeed/keeper/keeper.go index 3a3c0a57..999b723c 100644 --- a/x/pricefeed/keeper/keeper.go +++ b/x/pricefeed/keeper/keeper.go @@ -8,6 +8,7 @@ import ( "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/params/subspace" @@ -201,6 +202,30 @@ func (k Keeper) GetCurrentPrice(ctx sdk.Context, marketID string) (types.Current return price, nil } +// IterateCurrentPrices iterates over all current price objects in the store and performs a callback function +func (k Keeper) IterateCurrentPrices(ctx sdk.Context, cb func(cp types.CurrentPrice) (stop bool)) { + store := prefix.NewStore(ctx.KVStore(k.key), types.CurrentPricePrefix) + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var cp types.CurrentPrice + k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &cp) + if cb(cp) { + break + } + } +} + +// GetCurrentPrices returns all current price objects from the store +func (k Keeper) GetCurrentPrices(ctx sdk.Context) types.CurrentPrices { + cps := types.CurrentPrices{} + k.IterateCurrentPrices(ctx, func(cp types.CurrentPrice) (stop bool) { + cps = append(cps, cp) + return false + }) + return cps +} + // GetRawPrices fetches the set of all prices posted by oracles for an asset func (k Keeper) GetRawPrices(ctx sdk.Context, marketID string) (types.PostedPrices, error) { store := ctx.KVStore(k.key) diff --git a/x/pricefeed/keeper/querier.go b/x/pricefeed/keeper/querier.go index cef65d4c..db610e23 100644 --- a/x/pricefeed/keeper/querier.go +++ b/x/pricefeed/keeper/querier.go @@ -16,6 +16,8 @@ func NewQuerier(keeper Keeper) sdk.Querier { switch path[0] { case types.QueryPrice: return queryPrice(ctx, req, keeper) + case types.QueryPrices: + return queryPrices(ctx, req, keeper) case types.QueryRawPrices: return queryRawPrices(ctx, req, keeper) case types.QueryOracles: @@ -53,6 +55,15 @@ func queryPrice(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) (res []by return bz, nil } +func queryPrices(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) (res []byte, sdkErr error) { + currentPrices := keeper.GetCurrentPrices(ctx) + bz, err := codec.MarshalJSONIndent(types.ModuleCdc, currentPrices) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + return bz, nil +} + func queryRawPrices(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) (res []byte, sdkErr error) { var requestParams types.QueryWithMarketIDParams err := types.ModuleCdc.UnmarshalJSON(req.Data, &requestParams) diff --git a/x/pricefeed/types/querier.go b/x/pricefeed/types/querier.go index c1b7bd76..0991fae3 100644 --- a/x/pricefeed/types/querier.go +++ b/x/pricefeed/types/querier.go @@ -15,6 +15,8 @@ const ( QueryRawPrices = "rawprices" // QueryPrice command for price queries QueryPrice = "price" + // QueryPrices command for quering all prices + QueryPrices = "prices" ) // QueryWithMarketIDParams fields for querying information from a specific market