From 15a7dc610e57e22f35b879c9710650c605a55d85 Mon Sep 17 00:00:00 2001 From: Kevin Davis Date: Wed, 16 Sep 2020 14:58:11 -0400 Subject: [PATCH] [R4R] feat: Fetch auctions from historical state (#649) * feat: query old blocks for auctions * fix: add next auction id to querier * fix: set boolean when found * fix: use correct query route and params * apply suggestions from review comments --- x/auction/alias.go | 7 +++ x/auction/client/cli/query.go | 15 +---- x/auction/client/common/query.go | 94 ++++++++++++++++++++++++++++++++ x/auction/client/rest/query.go | 18 +----- x/auction/keeper/querier.go | 12 ++++ x/auction/types/querier.go | 9 +++ 6 files changed, 127 insertions(+), 28 deletions(-) create mode 100644 x/auction/client/common/query.go diff --git a/x/auction/alias.go b/x/auction/alias.go index f0ae986b..bcff20f3 100644 --- a/x/auction/alias.go +++ b/x/auction/alias.go @@ -17,6 +17,8 @@ const ( AttributeKeyLot = types.AttributeKeyLot AttributeKeyMaxBid = types.AttributeKeyMaxBid AttributeValueCategory = types.AttributeValueCategory + CollateralAuctionType = types.CollateralAuctionType + DebtAuctionType = types.DebtAuctionType DefaultBidDuration = types.DefaultBidDuration DefaultMaxAuctionDuration = types.DefaultMaxAuctionDuration DefaultNextAuctionID = types.DefaultNextAuctionID @@ -24,13 +26,17 @@ const ( EventTypeAuctionBid = types.EventTypeAuctionBid EventTypeAuctionClose = types.EventTypeAuctionClose EventTypeAuctionStart = types.EventTypeAuctionStart + ForwardAuctionPhase = types.ForwardAuctionPhase ModuleName = types.ModuleName QuerierRoute = types.QuerierRoute QueryGetAuction = types.QueryGetAuction QueryGetAuctions = types.QueryGetAuctions QueryGetParams = types.QueryGetParams + QueryNextAuctionID = types.QueryNextAuctionID + ReverseAuctionPhase = types.ReverseAuctionPhase RouterKey = types.RouterKey StoreKey = types.StoreKey + SurplusAuctionType = types.SurplusAuctionType ) var ( @@ -52,6 +58,7 @@ var ( NewMsgPlaceBid = types.NewMsgPlaceBid NewParams = types.NewParams NewQueryAllAuctionParams = types.NewQueryAllAuctionParams + NewQueryAuctionParams = types.NewQueryAuctionParams NewSurplusAuction = types.NewSurplusAuction NewWeightedAddresses = types.NewWeightedAddresses ParamKeyTable = types.ParamKeyTable diff --git a/x/auction/client/cli/query.go b/x/auction/client/cli/query.go index 37910226..97c4ce6c 100644 --- a/x/auction/client/cli/query.go +++ b/x/auction/client/cli/query.go @@ -13,6 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/kava-labs/kava/x/auction/client/common" "github.com/kava-labs/kava/x/auction/types" ) @@ -54,22 +55,12 @@ func QueryGetAuctionCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { if err != nil { return fmt.Errorf("auction-id '%s' not a valid uint", args[0]) } - bz, err := cdc.MarshalJSON(types.QueryAuctionParams{ - AuctionID: id, - }) + + auction, height, err := common.QueryAuctionByID(cliCtx, cdc, queryRoute, id) if err != nil { return err } - // Query - res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetAuction), bz) - if err != nil { - return err - } - - // Decode and print results - var auction types.Auction - cdc.MustUnmarshalJSON(res, &auction) auctionWithPhase := types.NewAuctionWithPhase(auction) cliCtx = cliCtx.WithHeight(height) diff --git a/x/auction/client/common/query.go b/x/auction/client/common/query.go new file mode 100644 index 00000000..b4083012 --- /dev/null +++ b/x/auction/client/common/query.go @@ -0,0 +1,94 @@ +package common + +import ( + "fmt" + "strings" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + + "github.com/kava-labs/kava/x/auction/types" +) + +const ( + defaultPage = 1 + defaultLimit = 100 +) + +// QueryAuctionByID returns an auction from state if present or falls back to searching old blocks +func QueryAuctionByID(cliCtx context.CLIContext, cdc *codec.Codec, queryRoute string, auctionID uint64) (types.Auction, int64, error) { + bz, err := cdc.MarshalJSON(types.NewQueryAuctionParams(auctionID)) + if err != nil { + return nil, 0, err + } + + res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetAuction), bz) + + if err == nil { + var auction types.Auction + cdc.MustUnmarshalJSON(res, &auction) + + return auction, height, nil + } + + if err != nil && !strings.Contains(err.Error(), "auction not found") { + return nil, 0, err + } + + res, height, err = cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryNextAuctionID), nil) + if err != nil { + return nil, 0, err + } + + var nextAuctionID uint64 + cdc.MustUnmarshalJSON(res, &nextAuctionID) + + if auctionID >= nextAuctionID { + return nil, 0, sdkerrors.Wrapf(types.ErrAuctionNotFound, "%d", auctionID) + } + + events := []string{ + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, "place_bid"), + fmt.Sprintf("%s.%s='%s'", types.EventTypeAuctionBid, types.AttributeKeyAuctionID, []byte(fmt.Sprintf("%d", auctionID))), + } + + // if the auction is closed, query for previous bid transactions + // note, will only fetch a maximum of 100 bids, so if an auction had more than that this + // query may fail to retreive the final state of the auction + searchResult, err := utils.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit) + if err != nil { + return nil, 0, err + } + + maxHeight := int64(0) + found := false + + for _, info := range searchResult.Txs { + for _, msg := range info.Tx.GetMsgs() { + if msg.Type() == "place_bid" { + found = true + if info.Height > maxHeight { + maxHeight = info.Height + } + } + } + } + + if !found { + return nil, 0, sdkerrors.Wrapf(types.ErrAuctionNotFound, "%d", auctionID) + } + + queryCLIContext := cliCtx.WithHeight(maxHeight) + res, height, err = queryCLIContext.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetAuction), bz) + if err != nil { + return nil, 0, err + } + + // Decode and print results + var auction types.Auction + cdc.MustUnmarshalJSON(res, &auction) + return auction, height, nil +} diff --git a/x/auction/client/rest/query.go b/x/auction/client/rest/query.go index f14c3e29..a3a9ef17 100644 --- a/x/auction/client/rest/query.go +++ b/x/auction/client/rest/query.go @@ -11,6 +11,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" + "github.com/kava-labs/kava/x/auction/client/common" "github.com/kava-labs/kava/x/auction/types" ) @@ -41,28 +42,13 @@ func queryAuctionHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { if !ok { return } - bz, err := cliCtx.Codec.MarshalJSON(types.QueryAuctionParams{AuctionID: auctionID}) + auction, height, err := common.QueryAuctionByID(cliCtx, cliCtx.Codec, types.ModuleName, auctionID) if err != nil { rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } - - // Query - res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", types.ModuleName, types.QueryGetAuction), bz) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - // Decode and return results cliCtx = cliCtx.WithHeight(height) - - var auction types.Auction - err = cliCtx.Codec.UnmarshalJSON(res, &auction) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } auctionWithPhase := types.NewAuctionWithPhase(auction) rest.PostProcessResponse(w, cliCtx, cliCtx.Codec.MustMarshalJSON(auctionWithPhase)) } diff --git a/x/auction/keeper/querier.go b/x/auction/keeper/querier.go index c65a0ef6..afb8598a 100644 --- a/x/auction/keeper/querier.go +++ b/x/auction/keeper/querier.go @@ -21,6 +21,8 @@ func NewQuerier(keeper Keeper) sdk.Querier { return queryAuctions(ctx, req, keeper) case types.QueryGetParams: return queryGetParams(ctx, req, keeper) + case types.QueryNextAuctionID: + return queryNextAuctionID(ctx, req, keeper) default: return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint", types.ModuleName) } @@ -122,3 +124,13 @@ func filterAuctions(ctx sdk.Context, auctions types.Auctions, params types.Query return filteredAuctions } + +func queryNextAuctionID(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) { + nextAuctionID, _ := keeper.GetNextAuctionID(ctx) + + bz, err := types.ModuleCdc.MarshalJSON(nextAuctionID) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + return bz, nil +} diff --git a/x/auction/types/querier.go b/x/auction/types/querier.go index 48721fdb..1fbdc711 100644 --- a/x/auction/types/querier.go +++ b/x/auction/types/querier.go @@ -7,6 +7,8 @@ const ( QueryGetAuctions = "auctions" // QueryGetParams is the query path for querying the global auction params QueryGetParams = "params" + // QueryNextAuctionID is the query path for querying the id of the next auction + QueryNextAuctionID = "next-auction-id" ) // QueryAuctionParams params for query /auction/auction @@ -14,6 +16,13 @@ type QueryAuctionParams struct { AuctionID uint64 } +// NewQueryAuctionParams returns a new QueryAuctionParams +func NewQueryAuctionParams(id uint64) QueryAuctionParams { + return QueryAuctionParams{ + AuctionID: id, + } +} + // QueryAllAuctionParams is the params for an auctions query type QueryAllAuctionParams struct { Page int `json:"page" yaml:"page"`