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

fix(gasless): usage identifier validation and mapping to gas tank IDs #608

Merged
merged 3 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 37 additions & 7 deletions x/gasless/keeper/fee_helper.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package keeper

import (
"errors"
"fmt"
"slices"
"strconv"
"strings"

"cosmossdk.io/collections"
sdkerrors "cosmossdk.io/errors"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/dymensionxyz/dymension-rdk/utils/sliceutils"

"github.com/dymensionxyz/dymension-rdk/x/gasless/types"
)

Expand Down Expand Up @@ -144,10 +148,36 @@ func (k Keeper) GetFeeSource(ctx sdk.Context, sdkTx sdk.Tx, originalFeePayer sdk
err error
)

lastUsedID, err := k.LastUsedGasTankID(ctx, usageIdentifier)
if err != nil {
if !errors.Is(err, collections.ErrNotFound) {
k.EmitFeeConsumptionEvent(ctx, originalFeePayer, []uint64{}, []error{fmt.Errorf("last used gas tank ID: %w", err)}, 0)
return originalFeePayer
}
}

gasTankIds := usageIdentifierToGasTankIds.GasTankIds
for _, gtid := range gasTankIds {
var startIndex int
index := slices.Index(gasTankIds, lastUsedID)
if index == -1 {
startIndex = 0
} else {
startIndex = (index + 1) % len(gasTankIds)
}

n := len(gasTankIds)
for i := 0; i < n; i++ {
idx := (startIndex + i) % n
gtid := gasTankIds[idx]

gasTank, isValid, err = k.CanGasTankBeUsedAsSource(ctx, gtid, tempConsumer, fee)
if isValid {
// update the last used GasTankID
err = k.lastUsedGasTankIDMap.Set(ctx, usageIdentifier, gtid)
if err != nil {
k.EmitFeeConsumptionEvent(ctx, originalFeePayer, failedGtids, []error{fmt.Errorf("update last used gas tank ID: %w", err)}, gtid)
return originalFeePayer
}
break
}
failedGtidErrors = append(failedGtidErrors, err)
Expand Down Expand Up @@ -191,11 +221,11 @@ func (k Keeper) GetFeeSource(ctx sdk.Context, sdkTx sdk.Tx, originalFeePayer sdk
gasConsumer.Consumptions[consumptionIndex].Usage = existingUsage
k.SetGasConsumer(ctx, gasConsumer)

// Move the used gas tank to the end of the list of all gas tanks. This ensures that in the next cycle,
// a different gas tank can be selected for the same usage identifier if available,
// spreading out the usage of fees across different tanks.
usageIdentifierToGasTankIds.GasTankIds = sliceutils.ShiftValueToEnd(usageIdentifierToGasTankIds.GasTankIds, gasTank.Id)
k.SetUsageIdentifierToGasTankIds(ctx, usageIdentifierToGasTankIds)
// Update the last used GasTankID for the UsageIdentifier
if err = k.lastUsedGasTankIDMap.Set(ctx, usageIdentifier, gasTank.Id); err != nil {
k.EmitFeeConsumptionEvent(ctx, originalFeePayer, failedGtids, []error{fmt.Errorf("update last used gas tank ID: %w", err)}, gasTank.Id)
return originalFeePayer
}

feeSource := gasTank.GetGasTankReserveAddress()
k.EmitFeeConsumptionEvent(ctx, feeSource, failedGtids, failedGtidErrors, gasTank.Id)
Expand Down
146 changes: 93 additions & 53 deletions x/gasless/keeper/fee_helper_test.go

Large diffs are not rendered by default.

16 changes: 11 additions & 5 deletions x/gasless/keeper/gasless.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import (

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

"github.com/dymensionxyz/dymension-rdk/utils/sliceutils"
"github.com/dymensionxyz/dymension-rdk/x/gasless/types"
)
Expand Down Expand Up @@ -95,7 +96,9 @@ func (k Keeper) CreateGasTank(ctx sdk.Context, msg *types.MsgCreateGasTank) (typ
return types.GasTank{}, err
}

k.AddGasTankIdToUsageIdentifiers(ctx, gasTank.UsageIdentifiers, gasTank.Id)
if err := k.AddGasTankIdToUsageIdentifiers(ctx, gasTank.UsageIdentifiers, gasTank.Id); err != nil {
return types.GasTank{}, err
}
k.SetGasTank(ctx, gasTank)

ctx.EventManager().EmitEvents(sdk.Events{
Expand Down Expand Up @@ -165,7 +168,6 @@ func (k Keeper) ValidateMsgUpdateGasTankConfig(ctx sdk.Context, msg *types.MsgUp
if !k.IsValidUsageIdentifier(ctx, identifier) {
return sdkerrors.Wrapf(errors.ErrInvalidRequest, "invalid usage identifier - %s", identifier)
}

}
}

Expand All @@ -183,7 +185,9 @@ func (k Keeper) UpdateGasTankConfig(ctx sdk.Context, msg *types.MsgUpdateGasTank
if !gasTank.MaxFeeUsagePerConsumer.Equal(msg.MaxFeeUsagePerConsumer) {
consumerUpdateRequire = true
}
k.RemoveGasTankIdFromUsageIdentifiers(ctx, gasTank.UsageIdentifiers, gasTank.Id)
if err := k.RemoveGasTankIdFromUsageIdentifiers(ctx, gasTank.UsageIdentifiers, gasTank.Id); err != nil {
return gasTank, err
}

gasTank.MaxFeeUsagePerTx = msg.MaxFeeUsagePerTx
gasTank.MaxFeeUsagePerConsumer = msg.MaxFeeUsagePerConsumer
Expand All @@ -193,7 +197,9 @@ func (k Keeper) UpdateGasTankConfig(ctx sdk.Context, msg *types.MsgUpdateGasTank
if consumerUpdateRequire {
k.UpdateConsumerAllowance(ctx, gasTank)
}
k.AddGasTankIdToUsageIdentifiers(ctx, gasTank.UsageIdentifiers, gasTank.Id)
if err := k.AddGasTankIdToUsageIdentifiers(ctx, gasTank.UsageIdentifiers, gasTank.Id); err != nil {
return gasTank, err
}

k.SetGasTank(ctx, gasTank)

Expand Down
7 changes: 3 additions & 4 deletions x/gasless/keeper/gasless_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ import (
sdkerrors "cosmossdk.io/errors"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
errors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/dymensionxyz/dymension-rdk/x/gasless/types"

// _ "github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/types/errors"
"golang.org/x/exp/slices"

"github.com/dymensionxyz/dymension-rdk/x/gasless/types"
)

func (s *KeeperTestSuite) TestCreateGasTank() {
Expand Down
10 changes: 8 additions & 2 deletions x/gasless/keeper/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ func (k Keeper) InitGenesis(ctx sdk.Context, genState types.GenesisState) {
k.SetParams(ctx, genState.Params)

for _, uigids := range genState.UsageIdentifierToGastankIds {
k.SetUsageIdentifierToGasTankIds(ctx, uigids)
if err := k.SetUsageIdentifierToGasTankIds(ctx, uigids); err != nil {
panic(err)
}
}

k.SetLastGasTankID(ctx, genState.LastGasTankId)
Expand All @@ -31,9 +33,13 @@ func (k Keeper) InitGenesis(ctx sdk.Context, genState types.GenesisState) {

// ExportGenesis returns the capability module's exported genesis.
func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState {
gasTankIds, err := k.GetAllUsageIdentifierToGasTankIds(ctx)
if err != nil {
panic(err)
}
return &types.GenesisState{
Params: k.GetParams(ctx),
UsageIdentifierToGastankIds: k.GetAllUsageIdentifierToGasTankIds(ctx),
UsageIdentifierToGastankIds: gasTankIds,
LastGasTankId: k.GetLastGasTankID(ctx),
GasTanks: k.GetAllGasTanks(ctx),
GasConsumers: k.GetAllGasConsumers(ctx),
Expand Down
15 changes: 10 additions & 5 deletions x/gasless/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/cosmos/cosmos-sdk/types/query"
"github.com/dymensionxyz/dymension-rdk/x/gasless/types"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

"github.com/dymensionxyz/dymension-rdk/x/gasless/types"
)

// Querier is used as Keeper will have duplicate methods if used directly, and gRPC names take precedence over keeper.
Expand Down Expand Up @@ -211,11 +212,15 @@ func (k Querier) GasConsumersByGasTankID(goCtx context.Context, req *types.Query

func (k Querier) GasTankIdsForAllUsageIdentifiers(goCtx context.Context, _ *types.QueryGasTankIdsForAllUsageIdentifiersRequest) (*types.QueryGasTankIdsForAllUsageIdentifiersResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
usageIdentifierToGasTankIds := []*types.UsageIdentifierToGasTankIds{}
allusageIdentifierToGasTankIds := k.GetAllUsageIdentifierToGasTankIds(ctx)
for _, val := range allusageIdentifierToGasTankIds {
allUsageIdentifierToGasTankIds, err := k.GetAllUsageIdentifierToGasTankIds(ctx)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}

var usageIdentifierToGasTankIds = make([]*types.UsageIdentifierToGasTankIds, len(allUsageIdentifierToGasTankIds))
for i, val := range allUsageIdentifierToGasTankIds {
gtids := val
usageIdentifierToGasTankIds = append(usageIdentifierToGasTankIds, &gtids)
usageIdentifierToGasTankIds[i] = &gtids
}
return &types.QueryGasTankIdsForAllUsageIdentifiersResponse{
UsageIdentifierToGastankIds: usageIdentifierToGasTankIds,
Expand Down
18 changes: 18 additions & 0 deletions x/gasless/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package keeper
import (
"fmt"

"cosmossdk.io/collections"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
paramstypes "github.com/cosmos/cosmos-sdk/x/params/types"
Expand All @@ -11,6 +12,8 @@ import (
wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
storetypes "github.com/cosmos/cosmos-sdk/store/types"

"github.com/dymensionxyz/dymension-rdk/utils/collcompat"
"github.com/dymensionxyz/dymension-rdk/x/gasless/types"
)

Expand All @@ -24,6 +27,9 @@ type Keeper struct {
// accountKeeper types.AccountKeeper
bankKeeper types.BankKeeper
wasmKeeper *wasmkeeper.Keeper

usageIdentifierToGasTankIDSet collections.KeySet[collections.Pair[string, uint64]]
lastUsedGasTankIDMap collections.Map[string, uint64]
}

// NewKeeper creates a new gasless Keeper instance.
Expand All @@ -46,6 +52,18 @@ func NewKeeper(
interfaceRegistry: interfaceRegistry,
bankKeeper: bankKeeper,
wasmKeeper: wasmKeeper,
usageIdentifierToGasTankIDSet: collections.NewKeySet[collections.Pair[string, uint64]](
collections.NewSchemaBuilder(collcompat.NewKVStoreService(storeKey)),
types.UsageIdentifierToGasTankIdsKeyPrefix,
"usageIdentifierToGasTankID",
collections.PairKeyCodec(collections.StringKey, collections.Uint64Key)),
lastUsedGasTankIDMap: collections.NewMap(
collections.NewSchemaBuilder(collcompat.NewKVStoreService(storeKey)),
types.LastUsedGasTankKey,
"lastUsedGasTankID",
collections.StringKey,
collections.Uint64Value,
),
}
}

Expand Down
Loading
Loading