diff --git a/x/wasm/internal/keeper/querier.go b/x/wasm/internal/keeper/querier.go index 6110ecc5c..410f16a96 100644 --- a/x/wasm/internal/keeper/querier.go +++ b/x/wasm/internal/keeper/querier.go @@ -1,6 +1,9 @@ package keeper import ( + "fmt" + "runtime/debug" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -103,17 +106,45 @@ func queryRawStore(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byt return res, nil } -func queryContractStore(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) { +func queryContractStore(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) (bz []byte, err error) { // external query gas limit must be specified here ctx = ctx.WithGasMeter(sdk.NewGasMeter(keeper.wasmConfig.ContractQueryGasLimit)) var params types.QueryContractParams - err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) + err = types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } - return keeper.queryToContract(ctx, params.ContractAddress, params.Msg) + // recover from out-of-gas panic + defer func() { + if r := recover(); r != nil { + switch rType := r.(type) { + // TODO: Use ErrOutOfGas instead of ErrorOutOfGas which would allow us + // to keep the stracktrace. + case sdk.ErrorOutOfGas: + err = sdkerrors.Wrap( + sdkerrors.ErrOutOfGas, fmt.Sprintf( + "out of gas in location: %v; gasWanted: %d, gasUsed: %d", + rType.Descriptor, ctx.GasMeter().Limit(), ctx.GasMeter().GasConsumed(), + ), + ) + + default: + err = sdkerrors.Wrap( + sdkerrors.ErrPanic, fmt.Sprintf( + "recovered: %v\nstack:\n%v", r, string(debug.Stack()), + ), + ) + } + + bz = nil + } + }() + + bz, err = keeper.queryToContract(ctx, params.ContractAddress, params.Msg) + + return } func queryParameters(ctx sdk.Context, keeper Keeper) ([]byte, error) { diff --git a/x/wasm/internal/keeper/recursive_test.go b/x/wasm/internal/keeper/recursive_test.go index 2877a0493..ddc7ab9d1 100644 --- a/x/wasm/internal/keeper/recursive_test.go +++ b/x/wasm/internal/keeper/recursive_test.go @@ -14,6 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerror "github.com/cosmos/cosmos-sdk/types/errors" abci "github.com/tendermint/tendermint/abci/types" "github.com/terra-project/core/x/wasm/internal/types" @@ -251,11 +252,9 @@ func TestGasOnExternalQuery(t *testing.T) { require.NoError(t, err) if tc.expectPanic { - require.Panics(t, func() { - // this should run out of gas - _, err = querier(ctx, []string{types.QueryContractStore}, abci.RequestQuery{Data: []byte(bz)}) - t.Logf("%v", err) - }) + _, err = querier(ctx, []string{types.QueryContractStore}, abci.RequestQuery{Data: []byte(bz)}) + require.Error(t, err) + require.Contains(t, err.Error(), sdkerror.ErrOutOfGas.Error()) } else { // otherwise, make sure we get a good success _, err = querier(ctx, []string{types.QueryContractStore}, abci.RequestQuery{Data: []byte(bz)})