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

[TRA-70] Add state migrations for isolated markets #1155

Merged
merged 6 commits into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 3 additions & 1 deletion protocol/app/upgrades.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package app
import (
"fmt"

v5_0_0 "github.com/dydxprotocol/v4-chain/protocol/app/upgrades/v5.0.0"

upgradetypes "cosmossdk.io/x/upgrade/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/dydxprotocol/v4-chain/protocol/app/upgrades"
v5_0_0 "github.com/dydxprotocol/v4-chain/protocol/app/upgrades/v5.0.0"
)

var (
Expand All @@ -29,6 +30,7 @@ func (app *App) setupUpgradeHandlers() {
v5_0_0.CreateUpgradeHandler(
app.ModuleManager,
app.configurator,
app.PerpetualsKeeper,
),
)
}
Expand Down
25 changes: 25 additions & 0 deletions protocol/app/upgrades/v5.0.0/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,44 @@ import (
"context"
"fmt"

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

perptypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types"

upgradetypes "cosmossdk.io/x/upgrade/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/dydxprotocol/v4-chain/protocol/lib"
)

// Set all existing perpetuals to cross market type
func perpetualsUpgrade(
ctx sdk.Context,
perpetualsKeeper perptypes.PerpetualsKeeper,
) {
// Set all perpetuals to cross market type
perpetuals := perpetualsKeeper.GetAllPerpetuals(ctx)
for _, p := range perpetuals {
_, err := perpetualsKeeper.SetPerpetualMarketType(
ctx, p.GetId(),
perptypes.PerpetualMarketType_PERPETUAL_MARKET_TYPE_CROSS)
if err != nil {
panic(fmt.Sprintf("failed to set perpetual market type for perpetual %d: %s", p.GetId(), err))
}
}
}

func CreateUpgradeHandler(
mm *module.Manager,
configurator module.Configurator,
perpetualsKeeper perptypes.PerpetualsKeeper,
) upgradetypes.UpgradeHandler {
return func(ctx context.Context, plan upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) {
sdkCtx := lib.UnwrapSDKContext(ctx, "app/upgrades")
sdkCtx.Logger().Info(fmt.Sprintf("Running %s Upgrade...", UpgradeName))

// Set all perpetuals to cross market type
perpetualsUpgrade(sdkCtx, perpetualsKeeper)

Comment on lines +42 to +44
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The call to perpetualsUpgrade within CreateUpgradeHandler does not handle potential errors. Consider capturing and handling any errors returned by perpetualsUpgrade to ensure that the upgrade process can respond appropriately to failures.

// TODO(TRA-93): Initialize `x/vault` module.

return mm.RunMigrations(ctx, configurator, vm)
Expand Down
40 changes: 40 additions & 0 deletions protocol/mocks/PerpetualsKeeper.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 38 additions & 4 deletions protocol/x/perpetuals/keeper/perpetual.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func (k Keeper) CreatePerpetual(
}

// Store the new perpetual.
k.setPerpetual(ctx, perpetual)
k.SetPerpetual(ctx, perpetual)

k.SetEmptyPremiumSamples(ctx)
k.SetEmptyPremiumVotes(ctx)
Expand Down Expand Up @@ -165,7 +165,7 @@ func (k Keeper) ModifyPerpetual(
}

// Store the modified perpetual.
k.setPerpetual(ctx, perpetual)
k.SetPerpetual(ctx, perpetual)

// Emit indexer event.
k.GetIndexerEventManager().AddTxnEvent(
Expand All @@ -186,6 +186,40 @@ func (k Keeper) ModifyPerpetual(
return perpetual, nil
}

func (k Keeper) SetPerpetualMarketType(
ctx sdk.Context,
perpetualId uint32,
marketType types.PerpetualMarketType,
) (types.Perpetual, error) {
if marketType == types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_UNSPECIFIED {
return types.Perpetual{}, errorsmod.Wrap(
types.ErrInvalidMarketType,
fmt.Sprintf("invalid market type %v for perpetual %d", marketType, perpetualId),
)
}

// Get perpetual.
perpetual, err := k.GetPerpetual(ctx, perpetualId)
if err != nil {
return perpetual, err
}

if perpetual.Params.MarketType != types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_UNSPECIFIED {
return types.Perpetual{}, errorsmod.Wrap(
types.ErrInvalidMarketType,
fmt.Sprintf("perpetual %d already has market type %v", perpetualId, perpetual.Params.MarketType),
)
}

// Modify perpetual.
perpetual.Params.MarketType = marketType

// Store the modified perpetual.
k.SetPerpetual(ctx, perpetual)

return perpetual, nil
}
Comment on lines +189 to +221
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation of SetPerpetualMarketType function has several aspects to consider:

  • Correctness and Logic: The function correctly checks for an unspecified market type and returns an error if encountered. However, the logic to prevent changing an already specified market type (line 207-212) seems to contradict the PR objectives and previous discussions. The condition checks if the market type is not unspecified and returns an error, which means it's impossible to change the market type once set. This contradicts the intention to migrate perpetuals to a specific market type and the discussion about adding a restriction and then removing it in future releases.
  • Performance: The function performs a GetPerpetual call to fetch the current state of the perpetual before updating it. This is necessary and does not pose a performance issue given the context.
  • Security/PII Leakage: No PII or sensitive data handling is involved in this function.
  • Error Handling: Errors are correctly wrapped with context, providing clarity on the operation that failed.
  • Maintainability: The function is straightforward and maintains consistency with the existing codebase structure. However, the logic might need revisiting based on the intended functionality regarding market type updates.

Consider revisiting the implementation logic concerning the ability to update the market type of a perpetual, especially in light of the discussions and objectives outlined in the PR and previous comments.


// GetPerpetual returns a perpetual from its id.
func (k Keeper) GetPerpetual(
ctx sdk.Context,
Expand Down Expand Up @@ -1181,7 +1215,7 @@ func (k Keeper) ModifyFundingIndex(
bigFundingIndex.Add(bigFundingIndex, bigFundingIndexDelta)

perpetual.FundingIndex = dtypes.NewIntFromBigInt(bigFundingIndex)
k.setPerpetual(ctx, perpetual)
k.SetPerpetual(ctx, perpetual)
return nil
}

Expand All @@ -1207,7 +1241,7 @@ func (k Keeper) SetEmptyPremiumVotes(
)
}

func (k Keeper) setPerpetual(
func (k Keeper) SetPerpetual(
ctx sdk.Context,
perpetual types.Perpetual,
) {
Expand Down
78 changes: 78 additions & 0 deletions protocol/x/perpetuals/keeper/perpetual_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,84 @@ func TestModifyPerpetual_Failure(t *testing.T) {
}
}

func TestSetPerpetualMarketType(t *testing.T) {
tests := map[string]struct {
currType types.PerpetualMarketType
newType types.PerpetualMarketType
errorExpected bool
expectedError error
}{
"success": {
currType: types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_UNSPECIFIED,
newType: types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_CROSS,
errorExpected: false,
},
"failure - setting to unspecified": {
currType: types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_CROSS,
newType: types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_UNSPECIFIED,
errorExpected: true,
expectedError: errorsmod.Wrap(
types.ErrInvalidMarketType,
fmt.Sprintf(
"invalid market type %v for perpetual %d",
types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_UNSPECIFIED, 0,
),
),
},
"failure - market type already set": {
currType: types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_ISOLATED,
newType: types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_CROSS,
errorExpected: true,
expectedError: errorsmod.Wrap(
types.ErrInvalidMarketType,
fmt.Sprintf(
"perpetual %d already has market type %v",
0,
types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_ISOLATED,
),
),
},
}

// Test setup.
for name, tc := range tests {
t.Run(
name, func(t *testing.T) {
pc := keepertest.PerpetualsKeepers(t)
// Create liquidity tiers and perpetuals,
perp := keepertest.CreateLiquidityTiersAndNPerpetuals(
t,
pc.Ctx,
pc.PerpetualsKeeper,
pc.PricesKeeper,
1,
)[0]
perp.Params.MarketType = tc.currType
pc.PerpetualsKeeper.SetPerpetual(pc.Ctx, perp)

_, err := pc.PerpetualsKeeper.SetPerpetualMarketType(
pc.Ctx,
perp.Params.Id,
tc.newType,
)

if tc.errorExpected {
require.EqualError(t, err, tc.expectedError.Error())
} else {
require.NoError(t, err)

rst, err := pc.PerpetualsKeeper.GetPerpetual(
pc.Ctx,
perp.Params.Id,
)
require.NoError(t, err)
require.Equal(t, tc.newType, rst.Params.MarketType)
}
},
)
}
}

func TestGetPerpetual_Success(t *testing.T) {
pc := keepertest.PerpetualsKeepers(t)
// Create liquidity tiers and perpetuals,
Expand Down
8 changes: 8 additions & 0 deletions protocol/x/perpetuals/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,12 @@ type PerpetualsKeeper interface {
ctx sdk.Context,
params Params,
) error
SetPerpetualMarketType(
ctx sdk.Context,
id uint32,
marketType PerpetualMarketType,
) (Perpetual, error)
GetAllPerpetuals(
ctx sdk.Context,
) []Perpetual
}
Loading