|
6 | 6 | "github.com/wavesplatform/gowaves/pkg/types"
|
7 | 7 | )
|
8 | 8 |
|
| 9 | +// invokeCallComplexityV5 is invoke() or reentrantInvoke() functions cost for RideV5 |
| 10 | +const invokeCallComplexityV5 = 75 |
| 11 | + |
9 | 12 | func CallVerifier(env environment, tree *ast.Tree) (Result, error) {
|
10 | 13 | e, err := treeVerifierEvaluator(env, tree)
|
11 | 14 | if err != nil {
|
@@ -33,26 +36,17 @@ func CallFunction(env environment, tree *ast.Tree, name string, args proto.Argum
|
33 | 36 | // Evaluation failed we have to return a DAppResult that contains spent execution complexity
|
34 | 37 | // Produced actions are not stored for failed transactions, no need to return them here
|
35 | 38 | et := GetEvaluationErrorType(err)
|
| 39 | + complexity := complexityInCaseOfEvaluationError(et, e, env) |
36 | 40 | if et == Undefined {
|
37 |
| - return nil, EvaluationErrorAddComplexity( |
38 |
| - et.Wrap(err, "unhandled error"), |
39 |
| - // Error was not handled in wrapped state properly, |
40 |
| - // so we need to add both complexity from current evaluation and from internal invokes |
41 |
| - e.complexity()+wrappedStateComplexity(env.state()), |
42 |
| - ) |
43 |
| - } |
44 |
| - complexity := e.complexity() + wrappedStateComplexity(env.state()) |
45 |
| - if env.rideV5Activated() && !env.rideV6Activated() && et == InternalInvocationError { |
46 |
| - ws := env.state().(*WrappedState) |
47 |
| - // TODO: this should be handled only when err == ride.InternalInvocationError |
| 41 | + return nil, EvaluationErrorAddComplexity(et.Wrap(err, "unhandled error"), complexity) |
48 | 42 | }
|
49 | 43 | return nil, EvaluationErrorAddComplexity(err, complexity)
|
50 | 44 | }
|
51 | 45 | dAppResult, ok := rideResult.(DAppResult)
|
52 | 46 | if !ok { // Unexpected result type
|
53 | 47 | return nil, EvaluationErrorAddComplexity(
|
54 | 48 | EvaluationFailure.Errorf("invalid result of call function '%s'", name),
|
55 |
| - // New error, both complexities should be added |
| 49 | + // New error, both complexities should be added (also see comment in complexityInCaseOfEvaluationError) |
56 | 50 | e.complexity()+wrappedStateComplexity(env.state()),
|
57 | 51 | )
|
58 | 52 | }
|
@@ -93,3 +87,22 @@ func wrappedStateActions(state types.SmartState) []proto.ScriptAction {
|
93 | 87 | }
|
94 | 88 | return ws.act
|
95 | 89 | }
|
| 90 | + |
| 91 | +func complexityInCaseOfEvaluationError(et EvaluationError, e *treeEvaluator, env environment) int { |
| 92 | + // Error was not handled in wrapped state properly, |
| 93 | + // so we need to add both complexity from current evaluation and from internal invokes |
| 94 | + complexity := e.complexity() + wrappedStateComplexity(env.state()) |
| 95 | + // reproduce scala's node buggy behaviour |
| 96 | + if ws, ok := env.state().(*WrappedState); ok && env.rideV5Activated() && !env.rideV6Activated() && et == InternalInvocationError { |
| 97 | + // if invoke script tx nesting level is 2 or less ==> complexity should be set to 0 |
| 98 | + // invCount() is calls count of invoke() or reentrantInvoke() functions ==> txNestingLevel = 1 + invCount() |
| 99 | + if txNestingLevel := 1 + ws.invCount(); txNestingLevel <= 2 { |
| 100 | + complexity = 0 |
| 101 | + } else { |
| 102 | + // if nesting level is 3 or greater, then we should sub last two invoke complexities plus |
| 103 | + // cost of the last invoke() or reentrantInvoke() function call |
| 104 | + complexity -= ws.lastTwoInvokeComplexities.sum() + invokeCallComplexityV5 |
| 105 | + } |
| 106 | + } |
| 107 | + return complexity |
| 108 | +} |
0 commit comments