Skip to content

Commit

Permalink
feat(eibc): Expand list-demand-orders query with more parameters (#851)
Browse files Browse the repository at this point in the history
Co-authored-by: Michael Tsitrin <[email protected]>
  • Loading branch information
zale144 and mtsitrin authored Jun 10, 2024
1 parent 6989843 commit c3d9307
Show file tree
Hide file tree
Showing 15 changed files with 430 additions and 123 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Features

- (delayedack) [#849](https://github.com/dymensionxyz/dymension/issues/849) Add demand order filters: type, rollapp id and limit
- (delayedack) [#850](https://github.com/dymensionxyz/dymension/issues/850) Add type filter for delayedack
- (rollapp) [#829](https://github.com/dymensionxyz/dymension/issues/829) Refactor rollapp cli to be more useful
- (delayedack) [#728](https://github.com/dymensionxyz/dymension/issues/728) Create eibc order on err ack from rollapp
Expand Down
9 changes: 5 additions & 4 deletions ibctesting/eibc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types"
channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types"
ibctesting "github.com/cosmos/ibc-go/v6/testing"

commontypes "github.com/dymensionxyz/dymension/v3/x/common/types"
eibckeeper "github.com/dymensionxyz/dymension/v3/x/eibc/keeper"
eibctypes "github.com/dymensionxyz/dymension/v3/x/eibc/types"
Expand Down Expand Up @@ -230,9 +231,9 @@ func (suite *EIBCTestSuite) TestEIBCDemandOrderFulfillment() {
memo := string(eibcJson)
var IBCDenom string
{
////
// //
// Transfer initial IBC funds to fulfiller account with ibc memo, to give him some funds to use to fulfill stuff
////
// //

packet := suite.TransferRollappToHub(path, IBCSenderAccount, fulfiller.String(), tc.fulfillerInitialIBCDenomBalance, memo, false)
// Finalize rollapp state - at this state no demand order was fulfilled
Expand Down Expand Up @@ -301,7 +302,7 @@ func (suite *EIBCTestSuite) TestEIBCDemandOrderFulfillment() {
rollappPacket, err := delayedAckKeeper.GetRollappPacket(suite.hubChain.GetContext(), lastDemandOrder.TrackingPacketKey)
suite.Require().NoError(err)
var data transfertypes.FungibleTokenPacketData
err = transfertypes.ModuleCdc.UnmarshalJSON(rollappPacket.Packet.GetData(), &data)
err = eibctypes.ModuleCdc.UnmarshalJSON(rollappPacket.Packet.GetData(), &data)
suite.Require().NoError(err)
suite.Require().Equal(msgFulfillDemandOrder.FulfillerAddress, data.Receiver)

Expand All @@ -326,7 +327,7 @@ func (suite *EIBCTestSuite) TestEIBCDemandOrderFulfillment() {
suite.Require().True(fulfillerAccountBalanceAfterFinalization.IsEqual(preFulfillmentAccountBalance.Add(sdk.NewCoin(IBCDenom, sdk.NewInt(eibcTransferFeeInt)))))

// Validate demand order fulfilled and packet status updated
finalizedDemandOrders, err := eibcKeeper.ListDemandOrdersByStatus(suite.hubChain.GetContext(), commontypes.Status_FINALIZED)
finalizedDemandOrders, err := eibcKeeper.ListDemandOrdersByStatus(suite.hubChain.GetContext(), commontypes.Status_FINALIZED, 0)
suite.Require().NoError(err)
var finalizedDemandOrder *eibctypes.DemandOrder
for _, order := range finalizedDemandOrders {
Expand Down
5 changes: 4 additions & 1 deletion proto/dymension/eibc/demand_order.proto
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package dymensionxyz.dymension.eibc;

import "gogoproto/gogo.proto";
import "dymension/common/status.proto";
import "dymension/common/rollapp_packet.proto";
import "cosmos/base/v1beta1/coin.proto";

option go_package = "github.com/dymensionxyz/dymension/v3/x/eibc/types";
Expand All @@ -27,4 +28,6 @@ message DemandOrder {
string recipient = 5;
bool is_fulfilled = 6;
dymensionxyz.dymension.common.Status tracking_packet_status = 8;
}
string rollapp_id = 9;
common.RollappPacket.Type type = 10;
}
12 changes: 10 additions & 2 deletions proto/dymension/eibc/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import "google/api/annotations.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "dymension/eibc/params.proto";
import "dymension/eibc/demand_order.proto";
import "dymension/common/status.proto";
import "dymension/common/rollapp_packet.proto";

option go_package = "github.com/dymensionxyz/dymension/v3/x/eibc/types";

Expand Down Expand Up @@ -42,8 +44,14 @@ message QueryGetDemandOrderRequest {

// QueryDemandOrdersByStatusRequest is the request type for the Query/GetDemandOrdersByStatus RPC method.
message QueryDemandOrdersByStatusRequest {
// id of the demand order to get
string status = 1;
// status of the demand order
common.Status status = 1;
// optional type
common.RollappPacket.Type type = 2;
// optional rollapp_id
string rollapp_id = 3;
// optional limit
int32 limit = 4;
}

// QueryGetDemandOrderResponse is the response type for the Query/GetDemandOrder RPC method.
Expand Down
55 changes: 44 additions & 11 deletions x/eibc/client/cli/query_command_orders.go
Original file line number Diff line number Diff line change
@@ -1,30 +1,63 @@
package cli

import (
"context"
"fmt"
"strconv"
"strings"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/dymensionxyz/dymension/v3/x/eibc/types"
"github.com/spf13/cobra"

commontypes "github.com/dymensionxyz/dymension/v3/x/common/types"
"github.com/dymensionxyz/dymension/v3/x/eibc/types"
)

func CmdListDemandOrdersByStatus() *cobra.Command {
cmd := &cobra.Command{
Use: "list-demand-orders [status]",
Use: "list-demand-orders status [rollapp_id] [type] [limit]",
Short: "List all demand orders with a specific status",
Long: `Query demand orders filtered by status. Examples of status include "pending", "finalized", and "reverted".`,
Args: cobra.ExactArgs(1),
Long: `Query demand orders filtered by status. Examples of status include "pending", "finalized", and "reverted".
Optional arguments include rollapp_id, type (recv, timeout, ack), and limit.`,
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx := client.GetClientContextFromCmd(cmd)
status := args[0]
status, ok := commontypes.Status_value[strings.ToUpper(args[0])]
if !ok {
return fmt.Errorf("invalid status: %s", args[0])
}
request := &types.QueryDemandOrdersByStatusRequest{
Status: commontypes.Status(status),
Type: commontypes.RollappPacket_UNDEFINED, // default to undefined, as '0' is a valid type
}

if len(args) > 1 {
request.RollappId = args[1]
}
if len(args) > 2 {
packetType := strings.ToUpper(args[2])
if !strings.HasPrefix(packetType, "ON_") {
packetType = "ON_" + packetType
}
ptype, ok := commontypes.RollappPacket_Type_value[packetType]
if !ok {
return fmt.Errorf("invalid packet type: %s", args[2])
}
request.Type = commontypes.RollappPacket_Type(ptype)
}
if len(args) > 3 {
limit, err := strconv.ParseInt(args[3], 10, 32)
if err != nil {
return fmt.Errorf("limit must be an integer: %s", args[3])
}
request.Limit = int32(limit)
}

clientCtx := client.GetClientContextFromCmd(cmd)
queryClient := types.NewQueryClient(clientCtx)
res, err := queryClient.DemandOrdersByStatus(context.Background(), &types.QueryDemandOrdersByStatusRequest{
Status: status,
})

res, err := queryClient.DemandOrdersByStatus(cmd.Context(), request)
if err != nil {
return err
return fmt.Errorf("failed to fetch demand orders: %w", err)
}

return clientCtx.PrintProto(res)
Expand Down
7 changes: 4 additions & 3 deletions x/eibc/keeper/demand_order_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"strconv"

"cosmossdk.io/math"

"github.com/dymensionxyz/dymension/v3/app/apptesting"
commontypes "github.com/dymensionxyz/dymension/v3/x/common/types"
"github.com/dymensionxyz/dymension/v3/x/eibc/types"
Expand All @@ -27,7 +28,7 @@ func (suite *KeeperTestSuite) TestListDemandOrdersByStatus() {
suite.Require().NoError(err)
}
// Get the demand orders with status active
demandOrders, err := keeper.ListDemandOrdersByStatus(ctx, commontypes.Status_PENDING)
demandOrders, err := keeper.ListDemandOrdersByStatus(ctx, commontypes.Status_PENDING, 0)
suite.Require().NoError(err)
suite.Equal(demandOrdersNum, len(demandOrders))

Expand All @@ -37,10 +38,10 @@ func (suite *KeeperTestSuite) TestListDemandOrdersByStatus() {
suite.Require().NoError(err)
}
// Retrieve the updated demand orders after status change
updatedDemandOrders, err := keeper.ListDemandOrdersByStatus(ctx, commontypes.Status_FINALIZED)
updatedDemandOrders, err := keeper.ListDemandOrdersByStatus(ctx, commontypes.Status_FINALIZED, 0)
suite.Require().NoError(err)
// Validate that there are exactly demandOrderNum packets in total
pendingDemandOrders, err := keeper.ListDemandOrdersByStatus(ctx, commontypes.Status_PENDING)
pendingDemandOrders, err := keeper.ListDemandOrdersByStatus(ctx, commontypes.Status_PENDING, 0)
suite.Require().NoError(err)
totalDemandOrders := len(updatedDemandOrders) + len(pendingDemandOrders)
suite.Require().Equal(demandOrdersNum, totalDemandOrders)
Expand Down
54 changes: 32 additions & 22 deletions x/eibc/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ package keeper

import (
"context"
"fmt"
"strings"

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

commontypes "github.com/dymensionxyz/dymension/v3/x/common/types"
"github.com/dymensionxyz/dymension/v3/x/eibc/types"

Expand Down Expand Up @@ -56,30 +55,41 @@ func (q Querier) DemandOrdersByStatus(goCtx context.Context, req *types.QueryDem
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if req.Status == "" {
return nil, status.Error(codes.InvalidArgument, "status must be provided")
// Get the demand orders by status, with optional filters
demandOrders, err := q.ListDemandOrdersByStatus(sdk.UnwrapSDKContext(goCtx), req.Status, int(req.Limit), filterOpts(req)...)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
// Construct the response
return &types.QueryDemandOrdersByStatusResponse{DemandOrders: demandOrders}, nil
}

// Convert string status to commontypes.Status
var statusValue commontypes.Status
switch strings.ToUpper(req.Status) {
case "PENDING":
statusValue = commontypes.Status_PENDING
case "FINALIZED":
statusValue = commontypes.Status_FINALIZED
case "REVERTED":
statusValue = commontypes.Status_REVERTED
default:
return nil, fmt.Errorf("invalid demand order status: %s", req.Status)
func filterOpts(req *types.QueryDemandOrdersByStatusRequest) []filterOption {
var opts []filterOption
if req.RollappId != "" {
opts = append(opts, isRollappId(req.RollappId))
}
ctx := sdk.UnwrapSDKContext(goCtx)
if req.Type != commontypes.RollappPacket_UNDEFINED {
opts = append(opts, isOrderType(req.Type))
}
return opts
}

// Get the demand orders by status
demandOrders, err := q.ListDemandOrdersByStatus(ctx, statusValue)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
type filterOption func(order types.DemandOrder) bool

func isRollappId(rollappId string) filterOption {
return func(order types.DemandOrder) bool {
return order.RollappId == rollappId
}
}

// Construct the response
return &types.QueryDemandOrdersByStatusResponse{DemandOrders: demandOrders}, nil
func isOrderType(orderType ...commontypes.RollappPacket_Type) filterOption {
return func(order types.DemandOrder) bool {
for _, ot := range orderType {
if order.Type == ot {
return true
}
}
return false
}
}
5 changes: 3 additions & 2 deletions x/eibc/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/dymensionxyz/dymension/v3/app/apptesting"
commontypes "github.com/dymensionxyz/dymension/v3/x/common/types"
"github.com/dymensionxyz/dymension/v3/x/eibc/types"
Expand Down Expand Up @@ -76,15 +77,15 @@ func (suite *KeeperTestSuite) TestQueryDemandOrdersByStatus() {
suite.Require().NoError(err)

// Query demand orders by status
res, err := suite.queryClient.DemandOrdersByStatus(sdk.WrapSDKContext(suite.Ctx), &types.QueryDemandOrdersByStatusRequest{Status: status.String()})
res, err := suite.queryClient.DemandOrdersByStatus(sdk.WrapSDKContext(suite.Ctx), &types.QueryDemandOrdersByStatusRequest{Status: status})
suite.Require().NoError(err)
suite.Require().NotNil(res.DemandOrders)
suite.Require().Len(res.DemandOrders, 1, fmt.Sprintf("Expected 1 demand order for status %s, but got %d", status, len(res.DemandOrders)))
suite.Require().Equal(demandOrder.Id, res.DemandOrders[0].Id)
}

// Query with invalid status should return an error
res, err := suite.queryClient.DemandOrdersByStatus(sdk.WrapSDKContext(suite.Ctx), &types.QueryDemandOrdersByStatusRequest{Status: "INVALID"})
res, err := suite.queryClient.DemandOrdersByStatus(sdk.WrapSDKContext(suite.Ctx), &types.QueryDemandOrdersByStatusRequest{Status: -1})
suite.Require().Error(err)
suite.Require().Nil(res)
}
7 changes: 4 additions & 3 deletions x/eibc/keeper/invariants.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"

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

commontypes "github.com/dymensionxyz/dymension/v3/x/common/types"
"github.com/dymensionxyz/dymension/v3/x/eibc/types"
)
Expand All @@ -29,17 +30,17 @@ func DemandOrderCountInvariant(k Keeper) sdk.Invariant {
msg += fmt.Sprintf("list all demand orders failed: %v\n", err)
broken = true
}
pendingDemandOrders, err := k.ListDemandOrdersByStatus(ctx, commontypes.Status_PENDING)
pendingDemandOrders, err := k.ListDemandOrdersByStatus(ctx, commontypes.Status_PENDING, 0)
if err != nil {
msg += fmt.Sprintf("list pending demand orders failed: %v\n", err)
broken = true
}
revertedDemandOrders, err := k.ListDemandOrdersByStatus(ctx, commontypes.Status_REVERTED)
revertedDemandOrders, err := k.ListDemandOrdersByStatus(ctx, commontypes.Status_REVERTED, 0)
if err != nil {
msg += fmt.Sprintf("list reverted demand orders failed: %v\n", err)
broken = true
}
finalizedDemandOrders, err := k.ListDemandOrdersByStatus(ctx, commontypes.Status_FINALIZED)
finalizedDemandOrders, err := k.ListDemandOrdersByStatus(ctx, commontypes.Status_FINALIZED, 0)
if err != nil {
msg += fmt.Sprintf("list finalized demand orders failed: %v\n", err)
broken = true
Expand Down
15 changes: 12 additions & 3 deletions x/eibc/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import (
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
commontypes "github.com/dymensionxyz/dymension/v3/x/common/types"
"github.com/tendermint/tendermint/libs/log"

commontypes "github.com/dymensionxyz/dymension/v3/x/common/types"

"github.com/dymensionxyz/dymension/v3/x/eibc/types"
)

Expand Down Expand Up @@ -156,10 +157,10 @@ func (k Keeper) ListAllDemandOrders(
return list, nil
}

func (k Keeper) ListDemandOrdersByStatus(ctx sdk.Context, status commontypes.Status) (list []*types.DemandOrder, err error) {
func (k Keeper) ListDemandOrdersByStatus(ctx sdk.Context, status commontypes.Status, limit int, opts ...filterOption) (list []*types.DemandOrder, err error) {
store := ctx.KVStore(k.storeKey)
var statusPrefix []byte

var statusPrefix []byte
switch status {
case commontypes.Status_PENDING:
statusPrefix = types.PendingDemandOrderKeyPrefix
Expand All @@ -175,8 +176,16 @@ func (k Keeper) ListDemandOrdersByStatus(ctx sdk.Context, status commontypes.Sta
defer iterator.Close() // nolint: errcheck

for ; iterator.Valid(); iterator.Next() {
if limit > 0 && len(list) >= limit {
break
}
var val types.DemandOrder
k.cdc.MustUnmarshal(iterator.Value(), &val)
for _, opt := range opts {
if !opt(val) {
continue
}
}
list = append(list, &val)
}

Expand Down
6 changes: 6 additions & 0 deletions x/eibc/types/demand_order.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

sdk "github.com/cosmos/cosmos-sdk/types"
ibctransfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types"

commontypes "github.com/dymensionxyz/dymension/v3/x/common/types"
)

Expand All @@ -25,6 +26,8 @@ func NewDemandOrder(rollappPacket commontypes.RollappPacket, price, fee math.Int
Recipient: recipient,
IsFulfilled: false,
TrackingPacketStatus: commontypes.Status_PENDING,
RollappId: rollappPacket.RollappId,
Type: rollappPacket.Type,
}
}

Expand Down Expand Up @@ -69,6 +72,9 @@ func (m *DemandOrder) GetEvents() []sdk.Attribute {
sdk.NewAttribute(AttributeKeyFee, m.Fee.String()),
sdk.NewAttribute(AttributeKeyIsFulfilled, strconv.FormatBool(m.IsFulfilled)),
sdk.NewAttribute(AttributeKeyPacketStatus, m.TrackingPacketStatus.String()),
sdk.NewAttribute(AttributeKeyPacketKey, m.TrackingPacketKey),
sdk.NewAttribute(AttributeKeyRollappId, m.RollappId),
sdk.NewAttribute(AttributeKeyRecipient, m.Recipient),
}
return eventAttributes
}
Expand Down
Loading

0 comments on commit c3d9307

Please sign in to comment.