github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/errors/errors.go (about)

     1  package errors
     2  
     3  import (
     4  	stdErrors "errors"
     5  	"fmt"
     6  
     7  	"github.com/hashicorp/go-multierror"
     8  	"github.com/onflow/cadence/runtime"
     9  	"github.com/onflow/cadence/runtime/errors"
    10  )
    11  
    12  type Unwrappable interface {
    13  	error
    14  	Unwrap() error
    15  }
    16  
    17  type UnwrappableErrors interface {
    18  	error
    19  	Unwrap() []error
    20  }
    21  
    22  type CodedError interface {
    23  	Code() ErrorCode
    24  
    25  	Unwrappable
    26  	error
    27  }
    28  
    29  type CodedFailure interface {
    30  	Code() FailureCode
    31  
    32  	Unwrappable
    33  	error
    34  }
    35  
    36  // Is is a utility function to call std error lib `Is` function for instance equality checks.
    37  func Is(err error, target error) bool {
    38  	return stdErrors.Is(err, target)
    39  }
    40  
    41  // As is a utility function to call std error lib `As` function.
    42  // As finds the first error in err's chain that matches target,
    43  // and if so, sets target to that error value and returns true. Otherwise, it returns false.
    44  // The chain consists of err itself followed by the sequence of errors obtained by repeatedly calling Unwrap.
    45  func As(err error, target interface{}) bool {
    46  	return stdErrors.As(err, target)
    47  }
    48  
    49  // findRootCodedError recursively unwraps the error to search for the root (deepest) coded error:
    50  //  1. If err is nil, this returns (nil, false),
    51  //  2. If err has no error code, this returns (nil, true),
    52  //  3. If err has an error code, this returns
    53  //     (<the deepest, aka root cause, coded error>, false)
    54  //
    55  // Note: This assumes the caller has already checked if the error contains a CodedFailure.
    56  func findRootCodedError(err error) (CodedError, bool) {
    57  	if err == nil {
    58  		return nil, false
    59  	}
    60  
    61  	var coded CodedError
    62  	if !As(err, &coded) {
    63  		return nil, true
    64  	}
    65  
    66  	for {
    67  		var nextCoded CodedError
    68  		if !As(coded.Unwrap(), &nextCoded) {
    69  			return coded, false
    70  		}
    71  
    72  		coded = nextCoded
    73  	}
    74  }
    75  
    76  // IsFailure returns true if the error is un-coded, or if the error contains
    77  // a failure code.
    78  func IsFailure(err error) bool {
    79  	return AsFailure(err) != nil
    80  }
    81  
    82  func AsFailure(err error) CodedFailure {
    83  	if err == nil {
    84  		return nil
    85  	}
    86  
    87  	var failure CodedFailure
    88  	if As(err, &failure) {
    89  		return failure
    90  	}
    91  
    92  	var coded CodedError
    93  	if !As(err, &coded) {
    94  		return NewUnknownFailure(err)
    95  	}
    96  
    97  	return nil
    98  }
    99  
   100  // SplitErrorTypes splits the error into fatal (failures) and non-fatal errors
   101  func SplitErrorTypes(inp error) (err CodedError, failure CodedFailure) {
   102  	if inp == nil {
   103  		return nil, nil
   104  	}
   105  
   106  	if failure = AsFailure(inp); failure != nil {
   107  		return nil, WrapCodedFailure(
   108  			failure.Code(),
   109  			inp,
   110  			"failure caused by")
   111  	}
   112  
   113  	coded, isUnknown := findRootCodedError(inp)
   114  	if isUnknown {
   115  		return nil, NewUnknownFailure(inp)
   116  	}
   117  
   118  	return WrapCodedError(
   119  		coded.Code(),
   120  		inp,
   121  		"error caused by"), nil
   122  }
   123  
   124  // HandleRuntimeError handles runtime errors and separates
   125  // errors generated by runtime from fvm errors (e.g. environment errors)
   126  func HandleRuntimeError(err error) error {
   127  	if err == nil {
   128  		return nil
   129  	}
   130  
   131  	// if is not a runtime error return as vm error
   132  	// this should never happen unless a bug in the code
   133  	runErr, ok := err.(runtime.Error)
   134  	if !ok {
   135  		return NewUnknownFailure(err)
   136  	}
   137  
   138  	// All other errors are non-fatal Cadence errors.
   139  	return NewCadenceRuntimeError(runErr)
   140  }
   141  
   142  // HasErrorCode returns true if the error or one of its nested errors matches the
   143  // specified error code.
   144  func HasErrorCode(err error, code ErrorCode) bool {
   145  	return Find(err, code) != nil
   146  }
   147  
   148  // HasFailureCode returns true if the error or one of its nested errors matches the
   149  // specified failure code.
   150  func HasFailureCode(err error, code FailureCode) bool {
   151  	return FindFailure(err, code) != nil
   152  }
   153  
   154  // Find recursively unwraps the error and returns the first CodedError that matches
   155  // the specified error code.
   156  func Find(originalErr error, code ErrorCode) CodedError {
   157  	if originalErr == nil {
   158  		return nil
   159  	}
   160  
   161  	// Handle non-chained errors
   162  	var unwrappedErrs []error
   163  	switch err := originalErr.(type) {
   164  	case *multierror.Error:
   165  		unwrappedErrs = err.WrappedErrors()
   166  	case UnwrappableErrors:
   167  		unwrappedErrs = err.Unwrap()
   168  
   169  	// IMPORTANT: this check needs to run after *multierror.Error because multierror does implement
   170  	// the Unwrappable interface, however its implementation only visits the base errors in the list,
   171  	// and ignores their descendants.
   172  	case Unwrappable:
   173  		coded, ok := err.(CodedError)
   174  		if ok && coded.Code() == code {
   175  			return coded
   176  		}
   177  		return Find(err.Unwrap(), code)
   178  	default:
   179  		return nil
   180  	}
   181  
   182  	for _, innerErr := range unwrappedErrs {
   183  		coded := Find(innerErr, code)
   184  		if coded != nil {
   185  			return coded
   186  		}
   187  	}
   188  
   189  	return nil
   190  }
   191  
   192  // FindFailure recursively unwraps the error and returns the first CodedFailure that matches
   193  // the specified error code.
   194  func FindFailure(originalErr error, code FailureCode) CodedFailure {
   195  	if originalErr == nil {
   196  		return nil
   197  	}
   198  
   199  	// Handle non-chained errors
   200  	var unwrappedErrs []error
   201  	switch err := originalErr.(type) {
   202  	case *multierror.Error:
   203  		unwrappedErrs = err.WrappedErrors()
   204  	case UnwrappableErrors:
   205  		unwrappedErrs = err.Unwrap()
   206  
   207  	// IMPORTANT: this check needs to run after *multierror.Error because multierror does implement
   208  	// the Unwrappable interface, however its implementation only visits the base errors in the list,
   209  	// and ignores their descendants.
   210  	case Unwrappable:
   211  		coded, ok := err.(CodedFailure)
   212  		if ok && coded.Code() == code {
   213  			return coded
   214  		}
   215  		return FindFailure(err.Unwrap(), code)
   216  	default:
   217  		return nil
   218  	}
   219  
   220  	for _, innerErr := range unwrappedErrs {
   221  		coded := FindFailure(innerErr, code)
   222  		if coded != nil {
   223  			return coded
   224  		}
   225  	}
   226  
   227  	return nil
   228  }
   229  
   230  var _ CodedError = (*codedError)(nil)
   231  
   232  type codedError struct {
   233  	code ErrorCode
   234  
   235  	err error
   236  }
   237  
   238  func newError(
   239  	code ErrorCode,
   240  	rootCause error,
   241  ) codedError {
   242  	return codedError{
   243  		code: code,
   244  		err:  rootCause,
   245  	}
   246  }
   247  
   248  func WrapCodedError(
   249  	code ErrorCode,
   250  	err error,
   251  	prefixMsgFormat string,
   252  	formatArguments ...interface{},
   253  ) codedError {
   254  	if prefixMsgFormat != "" {
   255  		msg := fmt.Sprintf(prefixMsgFormat, formatArguments...)
   256  		err = fmt.Errorf("%s: %w", msg, err)
   257  	}
   258  	return newError(code, err)
   259  }
   260  
   261  func NewCodedError(
   262  	code ErrorCode,
   263  	format string,
   264  	formatArguments ...interface{},
   265  ) codedError {
   266  	return newError(code, fmt.Errorf(format, formatArguments...))
   267  }
   268  
   269  func (err codedError) Unwrap() error {
   270  	return err.err
   271  }
   272  
   273  func (err codedError) Error() string {
   274  	return fmt.Sprintf("%v %v", err.code, err.err)
   275  }
   276  
   277  func (err codedError) Code() ErrorCode {
   278  	return err.code
   279  }
   280  
   281  var _ CodedFailure = (*codedFailure)(nil)
   282  
   283  type codedFailure struct {
   284  	code FailureCode
   285  	err  error
   286  }
   287  
   288  func newFailure(
   289  	code FailureCode,
   290  	rootCause error,
   291  ) codedFailure {
   292  	return codedFailure{
   293  		code: code,
   294  		err:  rootCause,
   295  	}
   296  }
   297  
   298  func WrapCodedFailure(
   299  	code FailureCode,
   300  	err error,
   301  	prefixMsgFormat string,
   302  	formatArguments ...interface{},
   303  ) codedFailure {
   304  	if prefixMsgFormat != "" {
   305  		msg := fmt.Sprintf(prefixMsgFormat, formatArguments...)
   306  		err = fmt.Errorf("%s: %w", msg, err)
   307  	}
   308  	return newFailure(code, err)
   309  }
   310  
   311  func NewCodedFailure(
   312  	code FailureCode,
   313  	format string,
   314  	formatArguments ...interface{},
   315  ) codedFailure {
   316  	return newFailure(code, fmt.Errorf(format, formatArguments...))
   317  }
   318  
   319  func (err codedFailure) Unwrap() error {
   320  	return err.err
   321  }
   322  
   323  func (err codedFailure) Error() string {
   324  	return fmt.Sprintf("%v %v", err.code, err.err)
   325  }
   326  
   327  func (err codedFailure) Code() FailureCode {
   328  	return err.code
   329  }
   330  
   331  // NewEventEncodingError construct a new CodedError which indicates
   332  // that encoding event has failed
   333  func NewEventEncodingError(err error) CodedError {
   334  	return NewCodedError(
   335  		ErrCodeEventEncodingError,
   336  		"error while encoding emitted event: %w ", err)
   337  }
   338  
   339  // EVMError needs to satisfy the user error interface
   340  // in order for Cadence to correctly handle the error
   341  var _ errors.UserError = &(EVMError{})
   342  
   343  // EVMError captures any non-fatal EVM error
   344  type EVMError struct {
   345  	CodedError
   346  }
   347  
   348  func (e EVMError) IsUserError() {}
   349  
   350  // NewEVMError constructs a new CodedError which captures a
   351  // collection of errors provided by (non-fatal) evm runtime.
   352  func NewEVMError(err error) EVMError {
   353  	return EVMError{
   354  		WrapCodedError(
   355  			ErrEVMExecutionError,
   356  			err,
   357  			"evm runtime error"),
   358  	}
   359  }
   360  
   361  // IsEVMError returns true if error is an EVM error
   362  func IsEVMError(err error) bool {
   363  	return HasErrorCode(err, ErrEVMExecutionError)
   364  }