Skip to content
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
7 changes: 6 additions & 1 deletion proto/dex/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,9 @@ message Params {
(gogoproto.moretags) = "yaml:\"price_snapshot_retention\"",
(gogoproto.jsontag) = "price_snapshot_retention"
];
}
string sudo_call_gas_price = 2 [
(gogoproto.jsontag) = "sudo_call_gas_price",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}
10 changes: 10 additions & 0 deletions utils/slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,13 @@ func Reduce[I, O any](input []I, reducer func(I, O) O, initial O) O {
}
return initial
}

func Filter[T any](slice []T, lambda func(t T) bool) []T {
res := []T{}
for _, t := range slice {
if lambda(t) {
res = append(res, t)
}
}
return res
}
2 changes: 1 addition & 1 deletion x/dex/contract/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func cacheAndDecorateContext(ctx sdk.Context, env *environment) (sdk.Context, sd
cachedCtx, msCached := store.GetCachedContext(ctx)
goCtx := context.WithValue(cachedCtx.Context(), dexcache.CtxKeyExecTermSignal, env.executionTerminationSignals)
cachedCtx = cachedCtx.WithContext(goCtx)
decoratedCtx := cachedCtx.WithGasMeter(seisync.NewGasWrapper(cachedCtx.GasMeter())).WithBlockGasMeter(
decoratedCtx := cachedCtx.WithGasMeter(seisync.NewGasWrapper(sdk.NewInfiniteGasMeter())).WithBlockGasMeter(
seisync.NewGasWrapper(cachedCtx.BlockGasMeter()),
)
return decoratedCtx, msCached
Expand Down
2 changes: 2 additions & 0 deletions x/dex/contract/whitelist.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/sei-protocol/sei-chain/utils"
"github.com/sei-protocol/sei-chain/x/dex/keeper"
"github.com/sei-protocol/sei-chain/x/dex/types"
)

Expand All @@ -19,6 +20,7 @@ var DexWhitelistedKeys = []string{
types.SettlementEntryKey,
types.NextOrderIDKey,
types.MatchResultKey,
keeper.ContractPrefixKey,
}

var WasmWhitelistedKeys = []string{
Expand Down
18 changes: 18 additions & 0 deletions x/dex/keeper/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,24 @@ func (k Keeper) GetAllContractInfo(ctx sdk.Context) []types.ContractInfoV2 {
return list
}

func (k Keeper) ChargeRentForGas(ctx sdk.Context, contractAddr string, gasUsed uint64) error {
contract, err := k.GetContract(ctx, contractAddr)
if err != nil {
return err
}
params := k.GetParams(ctx)
gasPrice := sdk.NewDec(int64(gasUsed)).Mul(params.SudoCallGasPrice).RoundInt().Int64()
if gasPrice > int64(contract.RentBalance) {
contract.RentBalance = 0
if err := k.SetContract(ctx, &contract); err != nil {
return err
}
return errors.New("insufficient rent")
}
contract.RentBalance -= uint64(gasPrice)
return k.SetContract(ctx, &contract)
}

func contractKey(contractAddr string) []byte {
return []byte(contractAddr)
}
30 changes: 30 additions & 0 deletions x/dex/keeper/contract_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package keeper_test

import (
"testing"

keepertest "github.com/sei-protocol/sei-chain/testutil/keeper"
"github.com/sei-protocol/sei-chain/x/dex/types"
"github.com/stretchr/testify/require"
)

func TestChargeRentForGas(t *testing.T) {
keeper, ctx := keepertest.DexKeeper(t)
err := keeper.SetContract(ctx, &types.ContractInfoV2{
Creator: keepertest.TestAccount,
ContractAddr: keepertest.TestContract,
CodeId: 1,
RentBalance: 1000000,
})
require.Nil(t, err)
err = keeper.ChargeRentForGas(ctx, keepertest.TestContract, 5000000)
require.Nil(t, err)
contract, err := keeper.GetContract(ctx, keepertest.TestContract)
require.Nil(t, err)
require.Equal(t, uint64(500000), contract.RentBalance)
err = keeper.ChargeRentForGas(ctx, keepertest.TestContract, 6000000)
require.NotNil(t, err)
contract, err = keeper.GetContract(ctx, keepertest.TestContract)
require.Nil(t, err)
require.Equal(t, uint64(0), contract.RentBalance)
}
13 changes: 10 additions & 3 deletions x/dex/keeper/utils/wasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,18 @@ func getMsgType(msg interface{}) string {
}
}

func sudo(sdkCtx sdk.Context, k *keeper.Keeper, contractAddress []byte, wasmMsg []byte, msgType string) ([]byte, error) {
func sudo(sdkCtx sdk.Context, k *keeper.Keeper, contractAddress []byte, wasmMsg []byte, msgType string) ([]byte, uint64, error) {
// Measure the time it takes to execute the contract in WASM
defer metrics.MeasureSudoExecutionDuration(time.Now(), msgType)
gasConsumedBefore := sdkCtx.GasMeter().GasConsumed()
data, err := k.WasmKeeper.Sudo(
sdkCtx, contractAddress, wasmMsg,
)
gasConsumedAfter := sdkCtx.GasMeter().GasConsumed()
if hasErrInstantiatingWasmModuleDueToCPUFeature(err) {
panic(utils.DecorateHardFailError(err))
}
return data, err
return data, gasConsumedAfter - gasConsumedBefore, err
}

func hasErrInstantiatingWasmModuleDueToCPUFeature(err error) bool {
Expand All @@ -66,11 +68,16 @@ func CallContractSudo(sdkCtx sdk.Context, k *keeper.Keeper, contractAddr string,
return []byte{}, err
}
msgType := getMsgType(msg)
data, err := sudo(sdkCtx, k, contractAddress, wasmMsg, msgType)
data, gasUsed, err := sudo(sdkCtx, k, contractAddress, wasmMsg, msgType)
if err != nil {
metrics.IncrementSudoFailCount(msgType)
sdkCtx.Logger().Error(err.Error())
return []byte{}, err
}
if err := k.ChargeRentForGas(sdkCtx, contractAddr, gasUsed); err != nil {
metrics.IncrementSudoFailCount(msgType)
sdkCtx.Logger().Error(err.Error())
return []byte{}, err
}
return data, nil
}
1 change: 1 addition & 0 deletions x/dex/migrations/v8_to_v9.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@ func V8ToV9(ctx sdk.Context, dexkeeper keeper.Keeper) error {
}
contractStore.Set(iterator.Key(), bz)
}

return nil
}
3 changes: 2 additions & 1 deletion x/dex/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,8 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw
func (AppModule) ConsensusVersion() uint64 { return 9 }

func (am AppModule) getAllContractInfo(ctx sdk.Context) []types.ContractInfoV2 {
return am.keeper.GetAllContractInfo(ctx)
// Do not process any contract that has a non-zero rent balance
return utils.Filter(am.keeper.GetAllContractInfo(ctx), func(c types.ContractInfoV2) bool { return c.RentBalance > 0 })
}

// BeginBlock executes all ABCI BeginBlock logic respective to the capability module.
Expand Down
14 changes: 7 additions & 7 deletions x/dex/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func TestEndBlockMarketOrder(t *testing.T) {
if err != nil {
panic(err)
}
dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: contractAddr.String(), NeedHook: false, NeedOrderMatching: true})
dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: contractAddr.String(), NeedHook: false, NeedOrderMatching: true, RentBalance: 100000000})
dexkeeper.AddRegisteredPair(ctx, contractAddr.String(), pair)
dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, utils.ContractAddress(contractAddr.String()), utils.GetPairString(&pair)).Add(
&types.Order{
Expand Down Expand Up @@ -202,7 +202,7 @@ func TestEndBlockLimitOrder(t *testing.T) {
panic(err)
}

dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: contractAddr.String(), NeedHook: false, NeedOrderMatching: true})
dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: contractAddr.String(), NeedHook: false, NeedOrderMatching: true, RentBalance: 100000000})
dexkeeper.AddRegisteredPair(ctx, contractAddr.String(), pair)
dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, utils.ContractAddress(contractAddr.String()), utils.GetPairString(&pair)).Add(
&types.Order{
Expand Down Expand Up @@ -347,7 +347,7 @@ func TestEndBlockRollback(t *testing.T) {
dexkeeper := testApp.DexKeeper
pair := TEST_PAIR()
// register contract and pair
dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: keepertest.TestContract, NeedHook: false, NeedOrderMatching: true})
dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: keepertest.TestContract, NeedHook: false, NeedOrderMatching: true, RentBalance: 100000000})
dexkeeper.AddRegisteredPair(ctx, keepertest.TestContract, pair)
// place one order to a nonexistent contract
dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, utils.ContractAddress(keepertest.TestContract), utils.GetPairString(&pair)).Add(
Expand Down Expand Up @@ -378,7 +378,7 @@ func TestEndBlockPartialRollback(t *testing.T) {
dexkeeper := testApp.DexKeeper
pair := TEST_PAIR()
// register contract and pair
dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: keepertest.TestContract, NeedHook: false, NeedOrderMatching: true})
dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: keepertest.TestContract, NeedHook: false, NeedOrderMatching: true, RentBalance: 100000000})
dexkeeper.AddRegisteredPair(ctx, keepertest.TestContract, pair)
// place one order to a nonexistent contract
dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, utils.ContractAddress(keepertest.TestContract), utils.GetPairString(&pair)).Add(
Expand Down Expand Up @@ -416,7 +416,7 @@ func TestEndBlockPartialRollback(t *testing.T) {
if err != nil {
panic(err)
}
dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: contractAddr.String(), NeedHook: false, NeedOrderMatching: true})
dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: contractAddr.String(), NeedHook: false, NeedOrderMatching: true, RentBalance: 100000000})
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(
Expand Down Expand Up @@ -480,7 +480,7 @@ func TestBeginBlock(t *testing.T) {
if err != nil {
panic(err)
}
dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: contractAddr.String(), NeedHook: false, NeedOrderMatching: true})
dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: contractAddr.String(), NeedHook: false, NeedOrderMatching: true, RentBalance: 100000000})

// right now just make sure it doesn't crash since it doesn't register any state to be checked against
testApp.BeginBlocker(ctx, abci.RequestBeginBlock{})
Expand Down Expand Up @@ -520,7 +520,7 @@ func TestEndBlockPanicHandling(t *testing.T) {
if err != nil {
panic(err)
}
dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: contractAddr.String(), NeedHook: false, NeedOrderMatching: true})
dexkeeper.SetContract(ctx, &types.ContractInfoV2{CodeId: 123, ContractAddr: contractAddr.String(), NeedHook: false, NeedOrderMatching: true, RentBalance: 100000000})
dexkeeper.AddRegisteredPair(ctx, contractAddr.String(), pair)
dexutils.GetMemState(ctx.Context()).GetBlockOrders(ctx, utils.ContractAddress(contractAddr.String()), utils.GetPairString(&pair)).Add(
&types.Order{
Expand Down
14 changes: 13 additions & 1 deletion x/dex/types/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@ package types
import (
fmt "fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"gopkg.in/yaml.v2"
)

var KeyPriceSnapshotRetention = []byte("PriceSnapshotRetention") // number of epochs to retain price snapshots for
var (
KeyPriceSnapshotRetention = []byte("PriceSnapshotRetention") // number of epochs to retain price snapshots for
KeySudoCallGasPrice = []byte("KeySudoCallGasPrice") // gas price for sudo calls from endblock
)

const (
DefaultPriceSnapshotRetention = 24 * 3600 // default to one day
)

var DefaultSudoCallGasPrice = sdk.NewDecWithPrec(1, 1) // 0.1

var _ paramtypes.ParamSet = (*Params)(nil)

// ParamKeyTable the param key table for launch module
Expand All @@ -29,13 +35,15 @@ func NewParams() Params {
func DefaultParams() Params {
return Params{
PriceSnapshotRetention: DefaultPriceSnapshotRetention,
SudoCallGasPrice: DefaultSudoCallGasPrice,
}
}

// ParamSetPairs get the params.ParamSet
func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {
return paramtypes.ParamSetPairs{
paramtypes.NewParamSetPair(KeyPriceSnapshotRetention, &p.PriceSnapshotRetention, validatePriceSnapshotRetention),
paramtypes.NewParamSetPair(KeySudoCallGasPrice, &p.SudoCallGasPrice, validateSudoCallGasPrice),
}
}

Expand All @@ -62,3 +70,7 @@ func validatePriceSnapshotRetention(i interface{}) error {

return nil
}

func validateSudoCallGasPrice(i interface{}) error {
return nil
}
Loading