Skip to content

Commit

Permalink
Create 'invokeApplier.handleInvokeScriptInvocationError' method.
Browse files Browse the repository at this point in the history
  • Loading branch information
nickeskov committed Jul 1, 2022
1 parent 3e7f7ed commit 65c7a05
Showing 1 changed file with 58 additions and 49 deletions.
107 changes: 58 additions & 49 deletions pkg/state/invoke_applier.go
Original file line number Diff line number Diff line change
Expand Up @@ -839,55 +839,7 @@ func (ia *invokeApplier) applyInvokeScript(tx proto.Transaction, info *fallibleV
// Call script function.
r, err := ia.sc.invokeFunction(tree, tx, info, *scriptAddr)
if err != nil {
// Script returned error, it's OK, but we have to decide is it failed or rejected transaction.
// After activation of RideV6 feature transactions are failed if they are not cheap regardless the error kind.
isCheap := int(ia.sc.recentTxComplexity) <= FailFreeInvokeComplexity
if info.rideV6Activated {
if !info.acceptFailed || isCheap {
return nil, errors.Wrapf(
err, "transaction rejected with spent complexity %d and following call stack:\n%s",
ride.EvaluationErrorSpentComplexity(err),
strings.Join(ride.EvaluationErrorCallStack(err), "\n"),
)
}
res := &invocationResult{failed: true, code: proto.DAppError, text: err.Error(), changes: failedChanges}
return ia.handleInvocationResult(txID, info, res)
}
// Before RideV6 activation in the following cases the transaction is rejected:
// 1) Failing of transactions is not activated yet, reject everything
// 2) The error is ride.InternalInvocationError and correct fail/reject behaviour is activated
// 3) The spent complexity is less than limit
switch ride.GetEvaluationErrorType(err) {
case ride.UserError, ride.RuntimeError:
// Usual script error produced by user code or system functions.
// We reject transaction if spent complexity is less than limit.
if !info.acceptFailed || isCheap { // Reject transaction if no failed transactions or the transaction is cheap
return nil, errors.Wrapf(
err, "transaction rejected with spent complexity %d and following call stack:\n%s",
ride.EvaluationErrorSpentComplexity(err),
strings.Join(ride.EvaluationErrorCallStack(err), "\n"),
)
}
res := &invocationResult{failed: true, code: proto.DAppError, text: err.Error(), changes: failedChanges}
return ia.handleInvocationResult(txID, info, res)
case ride.InternalInvocationError:
// Special script error produced by internal script invocation or application of results.
// Reject transaction after certain height
rejectOnInvocationError := info.checkerInfo.height >= ia.settings.InternalInvokeCorrectFailRejectBehaviourAfterHeight
if !info.acceptFailed || rejectOnInvocationError || isCheap {
return nil, errors.Wrapf(
err, "transaction rejected with spent complexity %d and following call stack:\n%s",
ride.EvaluationErrorSpentComplexity(err),
strings.Join(ride.EvaluationErrorCallStack(err), "\n"),
)
}
res := &invocationResult{failed: true, code: proto.DAppError, text: err.Error(), changes: failedChanges}
return ia.handleInvocationResult(txID, info, res)
case ride.Undefined, ride.EvaluationFailure: // Unhandled or evaluator error
return nil, errors.Wrapf(err, "invocation of transaction '%s' failed", txID.String())
default:
return nil, errors.Wrapf(err, "invocation of transaction '%s' failed", txID.String())
}
return ia.handleInvokeScriptInvocationError(err, txID, failedChanges, info)
}
var scriptRuns uint64 = 0
// After activation of RideV5 (16) feature we don't take extra fee for execution of smart asset scripts.
Expand Down Expand Up @@ -949,6 +901,63 @@ func (ia *invokeApplier) applyInvokeScript(tx proto.Transaction, info *fallibleV
return ia.handleInvocationResult(txID, info, res)
}

func (ia *invokeApplier) handleInvokeScriptInvocationError(
err error,
txID crypto.Digest,
failedChanges txBalanceChanges,
info *fallibleValidationParams,
) (*applicationResult, error) {
// Script returned error, it's OK, but we have to decide is it failed or rejected transaction.
// After activation of RideV6 feature transactions are failed if they are not cheap regardless the error kind.
isCheap := int(ia.sc.recentTxComplexity) <= FailFreeInvokeComplexity
if info.rideV6Activated {
if !info.acceptFailed || isCheap {
return nil, errors.Wrapf(
err, "transaction rejected with spent complexity %d and following call stack:\n%s",
ride.EvaluationErrorSpentComplexity(err),
strings.Join(ride.EvaluationErrorCallStack(err), "\n"),
)
}
res := &invocationResult{failed: true, code: proto.DAppError, text: err.Error(), changes: failedChanges}
return ia.handleInvocationResult(txID, info, res)
}
// Before RideV6 activation in the following cases the transaction is rejected:
// 1) Failing of transactions is not activated yet, reject everything
// 2) The error is ride.InternalInvocationError and correct fail/reject behaviour is activated
// 3) The spent complexity is less than limit
switch ride.GetEvaluationErrorType(err) {
case ride.UserError, ride.RuntimeError:
// Usual script error produced by user code or system functions.
// We reject transaction if spent complexity is less than limit.
if !info.acceptFailed || isCheap { // Reject transaction if no failed transactions or the transaction is cheap
return nil, errors.Wrapf(
err, "transaction rejected with spent complexity %d and following call stack:\n%s",
ride.EvaluationErrorSpentComplexity(err),
strings.Join(ride.EvaluationErrorCallStack(err), "\n"),
)
}
res := &invocationResult{failed: true, code: proto.DAppError, text: err.Error(), changes: failedChanges}
return ia.handleInvocationResult(txID, info, res)
case ride.InternalInvocationError:
// Special script error produced by internal script invocation or application of results.
// Reject transaction after certain height
rejectOnInvocationError := info.checkerInfo.height >= ia.settings.InternalInvokeCorrectFailRejectBehaviourAfterHeight
if !info.acceptFailed || rejectOnInvocationError || isCheap {
return nil, errors.Wrapf(
err, "transaction rejected with spent complexity %d and following call stack:\n%s",
ride.EvaluationErrorSpentComplexity(err),
strings.Join(ride.EvaluationErrorCallStack(err), "\n"),
)
}
res := &invocationResult{failed: true, code: proto.DAppError, text: err.Error(), changes: failedChanges}
return ia.handleInvocationResult(txID, info, res)
case ride.Undefined, ride.EvaluationFailure: // Unhandled or evaluator error
return nil, errors.Wrapf(err, "invocation of transaction '%s' failed", txID.String())
default:
return nil, errors.Wrapf(err, "invocation of transaction '%s' failed", txID.String())
}
}

type invocationResult struct {
failed bool
code proto.TxFailureReason
Expand Down

0 comments on commit 65c7a05

Please sign in to comment.