Skip to content

Commit a55301b

Browse files
authored
Merge pull request #694 from axone-protocol/fix/out-of-gas-catch
Improve `ErrorOutOfGas` handling in predicate execution
2 parents 0702939 + c242379 commit a55301b

File tree

4 files changed

+39
-25
lines changed

4 files changed

+39
-25
lines changed

x/logic/keeper/grpc_query_ask_test.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ import (
1717

1818
"github.com/cosmos/cosmos-sdk/baseapp"
1919
"github.com/cosmos/cosmos-sdk/testutil"
20+
sdk "github.com/cosmos/cosmos-sdk/types"
2021
moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
2122
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
23+
bankypes "github.com/cosmos/cosmos-sdk/x/bank/types"
2224
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
2325

2426
"github.com/axone-protocol/axoned/v8/x/logic"
@@ -137,16 +139,18 @@ func TestGRPCAsk(t *testing.T) {
137139
maxGas: 1000,
138140
expectedError: "out of gas: logic <ReadPerByte> (1018/1000): limit exceeded",
139141
},
142+
{
143+
query: "bank_balances(X, Y).",
144+
maxGas: 3000,
145+
expectedError: "out of gas: logic <panic: {ValuePerByte}> (4204/3000): limit exceeded",
146+
},
140147
{
141148
query: "block_height(X).",
142149
maxGas: 3000,
143150
predicateCosts: map[string]uint64{
144151
"block_height/1": 10000,
145152
},
146-
expectedAnswer: &types.Answer{
147-
Variables: []string{"X"},
148-
Results: []types.Result{{Error: "error(resource_error(gas(block_height/1,12353,3000)),block_height/1)"}},
149-
},
153+
expectedError: "out of gas: logic <block_height/1> (12353/3000): limit exceeded",
150154
},
151155
{
152156
program: "father(bob, 'élodie').",
@@ -325,6 +329,11 @@ foo(a4).
325329
bankKeeper := logictestutil.NewMockBankKeeper(ctrl)
326330
fsProvider := logictestutil.NewMockFS(ctrl)
327331

332+
bankKeeper.EXPECT().GetAccountsBalances(gomock.Any()).Do(func(ctx gocontext.Context) []bankypes.Balance {
333+
sdk.UnwrapSDKContext(ctx).GasMeter().ConsumeGas(2000, "ValuePerByte")
334+
return nil
335+
}).AnyTimes()
336+
328337
logicKeeper := keeper.NewKeeper(
329338
encCfg.Codec,
330339
key,

x/logic/keeper/interpreter.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func (k Keeper) execute(
6666

6767
answer, err := k.queryInterpreter(ctx, i, query, sdkmath.MinUint(solutionsLimit, *limits.MaxResultCount))
6868
if err != nil {
69-
return nil, errorsmod.Wrapf(types.InvalidArgument, "error executing query: %v", err.Error())
69+
return nil, err
7070
}
7171

7272
return &types.QueryServiceAskResponse{
@@ -107,17 +107,17 @@ func (k Keeper) newInterpreter(ctx context.Context) (*prolog.Interpreter, fmt.St
107107

108108
defer func() {
109109
if r := recover(); r != nil {
110-
if gasError, ok := r.(storetypes.ErrorOutOfGas); ok {
111-
err = engine.ResourceError(prolog2.ResourceGas(gasError.Descriptor, gasMeter.GasConsumed(), gasMeter.Limit()), env)
112-
return
110+
switch rType := r.(type) {
111+
case storetypes.ErrorOutOfGas:
112+
err = errorsmod.Wrapf(
113+
types.LimitExceeded, "out of gas: %s <%s> (%d/%d)",
114+
types.ModuleName, rType.Descriptor, sdkctx.GasMeter().GasConsumed(), sdkctx.GasMeter().Limit())
115+
default:
116+
panic(r)
113117
}
114-
115-
panic(r)
116118
}
117119
}()
118-
119120
gasMeter.ConsumeGas(cost, predicate)
120-
121121
return err
122122
}
123123
}

x/logic/prolog/error.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ package prolog
22

33
import (
44
"github.com/ichiban/prolog/engine"
5-
6-
"cosmossdk.io/store/types"
75
)
86

97
var (
@@ -82,8 +80,6 @@ var (
8280
// The module resource is the representation of the module with which the interaction is made.
8381
// The module resource is denoted as a compound with the name of the module.
8482
AtomResourceModule = engine.NewAtom("resource_module")
85-
// AtomResourceGas is the atom denoting the "gas" resource.
86-
AtomResourceGas = engine.NewAtom("gas")
8783
)
8884

8985
// ResourceContext returns a term representing the context resource.
@@ -96,12 +92,6 @@ func ResourceModule(module string) engine.Term {
9692
return AtomResourceModule.Apply(engine.NewAtom(module))
9793
}
9894

99-
// ResourceGas returns a term representing the gas resource with the given descriptor, consumed and limit at the
100-
// given context.
101-
func ResourceGas(descriptor string, consumed types.Gas, limit types.Gas) engine.Term {
102-
return AtomResourceGas.Apply(engine.NewAtom(descriptor), engine.Integer(int64(consumed)), engine.Integer(int64(limit)))
103-
}
104-
10595
var (
10696
AtomOperationInput = engine.NewAtom("input")
10797
AtomOperationExecute = engine.NewAtom("execute")

x/logic/util/prolog.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,18 @@ package util
22

33
import (
44
"context"
5+
"errors"
56
"strings"
67

78
"github.com/ichiban/prolog"
89
"github.com/ichiban/prolog/engine"
910
"github.com/samber/lo"
1011

12+
errorsmod "cosmossdk.io/errors"
1113
sdkmath "cosmossdk.io/math"
1214

15+
sdk "github.com/cosmos/cosmos-sdk/types"
16+
1317
"github.com/axone-protocol/axoned/v8/x/logic/types"
1418
)
1519

@@ -24,7 +28,7 @@ func QueryInterpreter(
2428
p := engine.NewParser(&i.VM, strings.NewReader(query))
2529
t, err := p.Term()
2630
if err != nil {
27-
return nil, err
31+
return nil, errorsmod.Wrapf(types.InvalidArgument, "error executing query: %v", err.Error())
2832
}
2933

3034
var env *engine.Env
@@ -42,13 +46,24 @@ func QueryInterpreter(
4246

4347
results, err := envsToResults(envs, p.Vars, i)
4448
if err != nil {
45-
return nil, err
49+
return nil, errorsmod.Wrapf(types.InvalidArgument, "error executing query: %v", err.Error())
4650
}
4751

4852
if callErr != nil {
4953
if sdkmath.NewUint(uint64(len(results))).LT(solutionsLimit) {
5054
// error is not part of the look-ahead and should be included in the solutions
51-
results = append(results, types.Result{Error: callErr.Error()})
55+
sdkCtx := sdk.UnwrapSDKContext(ctx)
56+
57+
switch {
58+
case errors.Is(callErr, types.LimitExceeded):
59+
return nil, callErr
60+
case sdkCtx.GasMeter().IsOutOfGas():
61+
return nil, errorsmod.Wrapf(
62+
types.LimitExceeded, "out of gas: %s <%s> (%d/%d)",
63+
types.ModuleName, callErr.Error(), sdkCtx.GasMeter().GasConsumed(), sdkCtx.GasMeter().Limit())
64+
default:
65+
results = append(results, types.Result{Error: callErr.Error()})
66+
}
5267
} else {
5368
// error is part of the look-ahead, so let's consider that there's one more solution
5469
count = count.Incr()

0 commit comments

Comments
 (0)