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
23 changes: 17 additions & 6 deletions x/dex/keeper/abci/begin_block_new_block_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package abci_test

import (
"context"
"testing"
"time"

wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/sei-protocol/sei-chain/x/dex/keeper"
keepertest "github.com/sei-protocol/sei-chain/testutil/keeper"
dexcache "github.com/sei-protocol/sei-chain/x/dex/cache"
"github.com/sei-protocol/sei-chain/x/dex/keeper/abci"
"github.com/sei-protocol/sei-chain/x/dex/types"
dexutils "github.com/sei-protocol/sei-chain/x/dex/utils"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
)

const (
Expand All @@ -17,9 +22,15 @@ const (
func TestHandleBBNewBlock(t *testing.T) {
// this test only ensures that HandleBBNewBlock doesn't crash. The actual logic
// is tested in module_test.go where an actual wasm file is deployed and invoked.
wasmkeeper.TestingStakeParams.MinCommissionRate = sdk.NewDecWithPrec(5, 2)
ctx, wasmkeepers := wasmkeeper.CreateTestInput(t, false, SupportedFeatures)
dexKeeper := keeper.Keeper{WasmKeeper: *wasmkeepers.WasmKeeper}
wrapper := abci.KeeperWrapper{Keeper: &dexKeeper}
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))))
keeper := testApp.DexKeeper
ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
keeper.SetContract(ctx, &types.ContractInfoV2{
ContractAddr: TestContract,
RentBalance: 100000000,
})
wrapper := abci.KeeperWrapper{Keeper: &keeper}
wrapper.HandleBBNewBlock(ctx, TestContract, 1)
}
25 changes: 20 additions & 5 deletions x/dex/keeper/utils/wasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,33 @@ func sudo(sdkCtx sdk.Context, k *keeper.Keeper, contractAddress []byte, wasmMsg
// Measure the time it takes to execute the contract in WASM
defer metrics.MeasureSudoExecutionDuration(time.Now(), msgType)
// set up a tmp context to prevent race condition in reading gas consumed
tmpCtx := sdkCtx.WithGasMeter(sdk.NewInfiniteGasMeter())
data, err := k.WasmKeeper.Sudo(
tmpCtx, contractAddress, wasmMsg,
)
// Note that the limit will effectively serve as a soft limit since it's
// possible for the actual computation to go above the specified limit, but
// the associated contract would be charged corresponding rent.
tmpCtx := sdkCtx.WithGasMeter(sdk.NewGasMeter(sdkCtx.GasMeter().Limit()))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Where is this gas limit determined for begin / end block?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Copy link
Collaborator

Choose a reason for hiding this comment

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

This doesn't account for the already spent gas though, right? because lets say gas limit is 1000, but the beginblock already spent 250, and the wasm contract needs 800. Then with this current PR, it would allow a total consumption of 1050 gas, right? or is that fine since we're only looking to mitigate the infinite gas issue?

Copy link
Collaborator Author

@codchen codchen Dec 19, 2022

Choose a reason for hiding this comment

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

that's intentional. We don't want to take into account already spent gas because otherwise it may cause non-determinism - contract A may be processed and consume most gas in val 1 and contract B would fail because it only has little gas remaining whereas it could be opposite in val 2.

Copy link
Contributor

Choose a reason for hiding this comment

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

So IUCC in some cases (example Uday listed above) may perform more computation than the original gas limit but it will still fail later when we check the gas consumed?

	gasConsumed := tmpCtx.GasMeter().GasConsumed()
	if gasConsumed > 0 {
		sdkCtx.GasMeter().ConsumeGas(gasConsumed, "sudo")
	}

If so, it might be useful to add a comment here for future reference.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think it would fail later because of greater than expected gas consumption, because the gas being consumed by contracts is on a new meter, so doesn't actually affect the original gas meter. I was just wondering whether that was ok considering that gas is generally tied to compute cost but this seems fine.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yeah the gas limit is more like "no individual call can exceed it", but a soft limit overall. I'll add a comment for this

data, err := sudoWithoutOutOfGasPanic(tmpCtx, k, contractAddress, wasmMsg)
gasConsumed := tmpCtx.GasMeter().GasConsumed()
sdkCtx.GasMeter().ConsumeGas(gasConsumed, "sudo")
if gasConsumed > 0 {
sdkCtx.GasMeter().ConsumeGas(gasConsumed, "sudo")
}
if hasErrInstantiatingWasmModuleDueToCPUFeature(err) {
panic(utils.DecorateHardFailError(err))
}
return data, gasConsumed, err
}

func sudoWithoutOutOfGasPanic(ctx sdk.Context, k *keeper.Keeper, contractAddress []byte, wasmMsg []byte) ([]byte, error) {
defer func() {
if err := recover(); err != nil {
// only propagate panic if the error is out of gas
if _, ok := err.(sdk.ErrorOutOfGas); !ok {
panic(err)
}
}
}()
return k.WasmKeeper.Sudo(ctx, contractAddress, wasmMsg)
}

func hasErrInstantiatingWasmModuleDueToCPUFeature(err error) bool {
if err == nil {
return false
Expand Down
4 changes: 2 additions & 2 deletions x/oracle/simulation/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func WeightedOperations(
}

// SimulateMsgAggregateExchangeRateVote generates a MsgAggregateExchangeRateVote with random values.
//nolint: funlen
// nolint: funlen
func SimulateMsgAggregateExchangeRateVote(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation {
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
Expand Down Expand Up @@ -122,7 +122,7 @@ func SimulateMsgAggregateExchangeRateVote(ak types.AccountKeeper, bk types.BankK
}

// SimulateMsgDelegateFeedConsent generates a MsgDelegateFeedConsent with random values.
//nolint: funlen
// nolint: funlen
func SimulateMsgDelegateFeedConsent(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation {
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
Expand Down