From ab1474c67b16cd5fa462c4c9f8ba6a118809e497 Mon Sep 17 00:00:00 2001 From: Yun Yeo Date: Mon, 16 Nov 2020 17:36:10 +0900 Subject: [PATCH 1/3] recover from out-of-gas panic --- x/wasm/internal/keeper/querier.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/x/wasm/internal/keeper/querier.go b/x/wasm/internal/keeper/querier.go index 6110ecc5c..09afa5885 100644 --- a/x/wasm/internal/keeper/querier.go +++ b/x/wasm/internal/keeper/querier.go @@ -103,17 +103,26 @@ 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 { + err = sdkerrors.ErrOutOfGas + } + }() + + bz, err = keeper.queryToContract(ctx, params.ContractAddress, params.Msg) + + return } func queryParameters(ctx sdk.Context, keeper Keeper) ([]byte, error) { From 7a2a8277b0ef8f527e1e28bbcb0617a1341f465b Mon Sep 17 00:00:00 2001 From: Yun Yeo Date: Mon, 16 Nov 2020 18:23:33 +0900 Subject: [PATCH 2/3] fix testing for query panic --- x/wasm/internal/keeper/recursive_test.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/x/wasm/internal/keeper/recursive_test.go b/x/wasm/internal/keeper/recursive_test.go index 2877a0493..f03dadd64 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.Equal(t, err, sdkerror.ErrOutOfGas) } else { // otherwise, make sure we get a good success _, err = querier(ctx, []string{types.QueryContractStore}, abci.RequestQuery{Data: []byte(bz)}) From 32bfb4db19aca8c6989801729ffc966b95299a45 Mon Sep 17 00:00:00 2001 From: Yun Yeo Date: Tue, 17 Nov 2020 12:18:18 +0900 Subject: [PATCH 3/3] format recovered error depends on the error type --- x/wasm/internal/keeper/querier.go | 24 +++++++++++++++++++++++- x/wasm/internal/keeper/recursive_test.go | 2 +- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/x/wasm/internal/keeper/querier.go b/x/wasm/internal/keeper/querier.go index 09afa5885..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" @@ -116,7 +119,26 @@ func queryContractStore(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ( // recover from out-of-gas panic defer func() { if r := recover(); r != nil { - err = sdkerrors.ErrOutOfGas + 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 } }() diff --git a/x/wasm/internal/keeper/recursive_test.go b/x/wasm/internal/keeper/recursive_test.go index f03dadd64..ddc7ab9d1 100644 --- a/x/wasm/internal/keeper/recursive_test.go +++ b/x/wasm/internal/keeper/recursive_test.go @@ -254,7 +254,7 @@ func TestGasOnExternalQuery(t *testing.T) { if tc.expectPanic { _, err = querier(ctx, []string{types.QueryContractStore}, abci.RequestQuery{Data: []byte(bz)}) require.Error(t, err) - require.Equal(t, err, sdkerror.ErrOutOfGas) + 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)})