From a49a0aa3cd282b992824faf654f47071e9b7d897 Mon Sep 17 00:00:00 2001 From: codchen Date: Wed, 8 Feb 2023 13:43:37 +0800 Subject: [PATCH 1/4] Charge rent for contracts failed in EndBlock --- x/dex/contract/abci.go | 16 +++++++++++ x/dex/module_test.go | 60 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/x/dex/contract/abci.go b/x/dex/contract/abci.go index 10dd6514c5..0662e6663d 100644 --- a/x/dex/contract/abci.go +++ b/x/dex/contract/abci.go @@ -72,6 +72,22 @@ func EndBlockerAtomic(ctx sdk.Context, keeper *keeper.Keeper, validContractsInfo if env.failedContractAddresses.Size() == 0 { msCached.Write() return env.validContractsInfo, ctx, true + } else { + // persistent contract rent charges for failed contracts and discard everything else + for _, failedContractAddress := range env.failedContractAddresses.ToOrderedSlice(datastructures.StringComparator) { + cachedContract, err := keeper.GetContract(cachedCtx, failedContractAddress) + if err != nil { + ctx.Logger().Error(fmt.Sprintf("error %s when getting updated contract %s to persist rent balance", err, failedContractAddress)) + continue + } + contract, err := keeper.GetContract(ctx, failedContractAddress) + if err != nil { + ctx.Logger().Error(fmt.Sprintf("error %s when getting contract %s to persist rent balance", err, failedContractAddress)) + continue + } + contract.RentBalance = cachedContract.RentBalance + keeper.SetContract(ctx, &contract) + } } // restore keeper in-memory state diff --git a/x/dex/module_test.go b/x/dex/module_test.go index ab39ba65fd..88eb1f1b5a 100644 --- a/x/dex/module_test.go +++ b/x/dex/module_test.go @@ -551,3 +551,63 @@ func TestEndBlockPanicHandling(t *testing.T) { _, found := dexkeeper.GetLongBookByPrice(ctx, contractAddr.String(), sdk.MustNewDecFromStr("1"), pair.PriceDenom, pair.AssetDenom) require.False(t, found) } + +func TestEndBlockRollbackWithRentCharge(t *testing.T) { + testApp := keepertest.TestApp() + ctx := testApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) + ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(testApp.GetKey(types.StoreKey)))) + dexkeeper := testApp.DexKeeper + pair := TEST_PAIR() + // GOOD CONTRACT + testAccount, _ := sdk.AccAddressFromBech32("sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx") + amounts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(1000000)), sdk.NewCoin("uusdc", sdk.NewInt(1000000))) + bankkeeper := testApp.BankKeeper + bankkeeper.MintCoins(ctx, minttypes.ModuleName, amounts) + bankkeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, testAccount, amounts) + wasm, err := ioutil.ReadFile("./testdata/mars.wasm") + if err != nil { + panic(err) + } + wasmKeeper := testApp.WasmKeeper + contractKeeper := wasmkeeper.NewDefaultPermissionKeeper(&wasmKeeper) + var perm *wasmtypes.AccessConfig + codeId, err := contractKeeper.Create(ctx, testAccount, wasm, perm) + if err != nil { + panic(err) + } + contractAddr, _, err := contractKeeper.Instantiate(ctx, codeId, testAccount, testAccount, []byte(GOOD_CONTRACT_INSTANTIATE), "test", + sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(100000)))) + if err != nil { + panic(err) + } + dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: contractAddr.String(), NeedHook: false, NeedOrderMatching: true, RentBalance: 1}) + dexkeeper.AddRegisteredPair(ctx, contractAddr.String(), pair) + // place one order to a nonexistent contract + dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, utils.ContractAddress(contractAddr.String()), utils.GetPairString(&pair)).Add( + &types.Order{ + Id: 2, + Account: testAccount.String(), + ContractAddr: contractAddr.String(), + Price: sdk.MustNewDecFromStr("0.0001"), + Quantity: sdk.MustNewDecFromStr("0.0001"), + PriceDenom: pair.PriceDenom, + AssetDenom: pair.AssetDenom, + OrderType: types.OrderType_LIMIT, + PositionDirection: types.PositionDirection_LONG, + Data: "{\"position_effect\":\"Open\",\"leverage\":\"1\"}", + }, + ) + dexutils.GetMemState(ctx.Context()).GetDepositInfo(ctx, utils.ContractAddress(contractAddr.String())).Add( + &types.DepositInfoEntry{ + Creator: testAccount.String(), + Denom: "uusdc", + Amount: sdk.MustNewDecFromStr("10000"), + }, + ) + + ctx = ctx.WithBlockHeight(1) + testApp.EndBlocker(ctx, abci.RequestEndBlock{}) + // no state change should've been persisted for good contract because it should've run out of gas + matchResult, _ := dexkeeper.GetMatchResultState(ctx, contractAddr.String()) + require.Equal(t, 0, len(matchResult.Orders)) +} From a88bac42af317eaba21ee79c4e1238a4865071eb Mon Sep 17 00:00:00 2001 From: codchen Date: Wed, 8 Feb 2023 13:45:01 +0800 Subject: [PATCH 2/4] rebase --- x/dex/module_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x/dex/module_test.go b/x/dex/module_test.go index 88eb1f1b5a..914d1961dc 100644 --- a/x/dex/module_test.go +++ b/x/dex/module_test.go @@ -610,4 +610,8 @@ func TestEndBlockRollbackWithRentCharge(t *testing.T) { // no state change should've been persisted for good contract because it should've run out of gas matchResult, _ := dexkeeper.GetMatchResultState(ctx, contractAddr.String()) require.Equal(t, 0, len(matchResult.Orders)) + // rent should still be charged even if the contract failed + contract, err := dexkeeper.GetContract(ctx, contractAddr.String()) + require.Nil(t, err) + require.Zero(t, contract.RentBalance) } From 5f2e68d971980095c2694fcd503aaaeac28bc81b Mon Sep 17 00:00:00 2001 From: codchen Date: Wed, 8 Feb 2023 13:51:00 +0800 Subject: [PATCH 3/4] udpate log --- x/dex/keeper/utils/wasm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/dex/keeper/utils/wasm.go b/x/dex/keeper/utils/wasm.go index c945ac34fa..8ffb15f712 100644 --- a/x/dex/keeper/utils/wasm.go +++ b/x/dex/keeper/utils/wasm.go @@ -74,7 +74,7 @@ func sudo(sdkCtx sdk.Context, k *keeper.Keeper, contractAddress sdk.AccAddress, func sudoWithoutOutOfGasPanic(ctx sdk.Context, k *keeper.Keeper, contractAddress []byte, wasmMsg []byte, logName string) ([]byte, error) { defer func() { if err := recover(); err != nil { - // only propagate panic if the error is out of gas + // only propagate panic if the error is NOT out of gas if _, ok := err.(sdk.ErrorOutOfGas); !ok { panic(err) } else { From af31384d0c980d6e6868bdf28f329c4ae4fe4680 Mon Sep 17 00:00:00 2001 From: codchen Date: Wed, 8 Feb 2023 15:20:16 +0800 Subject: [PATCH 4/4] linter --- x/dex/contract/abci.go | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/x/dex/contract/abci.go b/x/dex/contract/abci.go index 0662e6663d..74b500f2be 100644 --- a/x/dex/contract/abci.go +++ b/x/dex/contract/abci.go @@ -72,21 +72,25 @@ func EndBlockerAtomic(ctx sdk.Context, keeper *keeper.Keeper, validContractsInfo if env.failedContractAddresses.Size() == 0 { msCached.Write() return env.validContractsInfo, ctx, true - } else { - // persistent contract rent charges for failed contracts and discard everything else - for _, failedContractAddress := range env.failedContractAddresses.ToOrderedSlice(datastructures.StringComparator) { - cachedContract, err := keeper.GetContract(cachedCtx, failedContractAddress) - if err != nil { - ctx.Logger().Error(fmt.Sprintf("error %s when getting updated contract %s to persist rent balance", err, failedContractAddress)) - continue - } - contract, err := keeper.GetContract(ctx, failedContractAddress) - if err != nil { - ctx.Logger().Error(fmt.Sprintf("error %s when getting contract %s to persist rent balance", err, failedContractAddress)) - continue - } - contract.RentBalance = cachedContract.RentBalance - keeper.SetContract(ctx, &contract) + } + + // persistent contract rent charges for failed contracts and discard everything else + for _, failedContractAddress := range env.failedContractAddresses.ToOrderedSlice(datastructures.StringComparator) { + cachedContract, err := keeper.GetContract(cachedCtx, failedContractAddress) + if err != nil { + ctx.Logger().Error(fmt.Sprintf("error %s when getting updated contract %s to persist rent balance", err, failedContractAddress)) + continue + } + contract, err := keeper.GetContract(ctx, failedContractAddress) + if err != nil { + ctx.Logger().Error(fmt.Sprintf("error %s when getting contract %s to persist rent balance", err, failedContractAddress)) + continue + } + contract.RentBalance = cachedContract.RentBalance + err = keeper.SetContract(ctx, &contract) + if err != nil { + ctx.Logger().Error(fmt.Sprintf("error %s when persisting contract %s's rent balance", err, failedContractAddress)) + continue } }