diff --git a/engine/access/rpc/backend/backend_scripts.go b/engine/access/rpc/backend/backend_scripts.go index 3158575e098..e3e0d8db3db 100644 --- a/engine/access/rpc/backend/backend_scripts.go +++ b/engine/access/rpc/backend/backend_scripts.go @@ -332,13 +332,14 @@ func convertScriptExecutionError(err error, height uint64) error { return nil } + var failure fvmerrors.CodedFailure + if fvmerrors.As(err, &failure) { + return rpc.ConvertError(err, "failed to execute script", codes.Internal) + } + + // general FVM/ledger errors var coded fvmerrors.CodedError if fvmerrors.As(err, &coded) { - // general FVM/ledger errors - if coded.Code().IsFailure() { - return rpc.ConvertError(err, "failed to execute script", codes.Internal) - } - switch coded.Code() { case fvmerrors.ErrCodeScriptExecutionCancelledError: return status.Errorf(codes.Canceled, "script execution canceled: %v", err) diff --git a/engine/access/rpc/backend/backend_scripts_test.go b/engine/access/rpc/backend/backend_scripts_test.go index 0ea927820d0..43531e3c8e2 100644 --- a/engine/access/rpc/backend/backend_scripts_test.go +++ b/engine/access/rpc/backend/backend_scripts_test.go @@ -34,7 +34,7 @@ var ( expectedResponse = []byte("response_data") cadenceErr = fvmerrors.NewCodedError(fvmerrors.ErrCodeCadenceRunTimeError, "cadence error") - fvmFailureErr = fvmerrors.NewCodedError(fvmerrors.FailureCodeBlockFinderFailure, "fvm error") + fvmFailureErr = fvmerrors.NewCodedFailure(fvmerrors.FailureCodeBlockFinderFailure, "fvm error") ctxCancelErr = fvmerrors.NewCodedError(fvmerrors.ErrCodeScriptExecutionCancelledError, "context canceled error") timeoutErr = fvmerrors.NewCodedError(fvmerrors.ErrCodeScriptExecutionTimedOutError, "timeout error") ) @@ -438,7 +438,7 @@ func (s *BackendScriptsSuite) testExecuteScriptAtLatestBlock(ctx context.Context } else { actual, err := backend.ExecuteScriptAtLatestBlock(ctx, s.failingScript, s.arguments) s.Require().Error(err) - s.Require().Equal(statusCode, status.Code(err)) + s.Require().Equal(statusCode, status.Code(err), "error code mismatch: expected %d, got %d: %s", statusCode, status.Code(err), err) s.Require().Nil(actual) } } @@ -454,7 +454,7 @@ func (s *BackendScriptsSuite) testExecuteScriptAtBlockID(ctx context.Context, ba } else { actual, err := backend.ExecuteScriptAtBlockID(ctx, blockID, s.failingScript, s.arguments) s.Require().Error(err) - s.Require().Equal(statusCode, status.Code(err)) + s.Require().Equal(statusCode, status.Code(err), "error code mismatch: expected %d, got %d: %s", statusCode, status.Code(err), err) s.Require().Nil(actual) } } @@ -470,7 +470,7 @@ func (s *BackendScriptsSuite) testExecuteScriptAtBlockHeight(ctx context.Context } else { actual, err := backend.ExecuteScriptAtBlockHeight(ctx, height, s.failingScript, s.arguments) s.Require().Error(err) - s.Require().Equal(statusCode, status.Code(err)) + s.Require().Equalf(statusCode, status.Code(err), "error code mismatch: expected %d, got %d: %s", statusCode, status.Code(err), err) s.Require().Nil(actual) } } diff --git a/fvm/errors/codes.go b/fvm/errors/codes.go index cdbc734bd3d..9e8069e3a10 100644 --- a/fvm/errors/codes.go +++ b/fvm/errors/codes.go @@ -4,31 +4,30 @@ import "fmt" type ErrorCode uint16 -func (ec ErrorCode) IsFailure() bool { - return ec >= FailureCodeUnknownFailure -} - func (ec ErrorCode) String() string { - if ec.IsFailure() { - return fmt.Sprintf("[Failure Code: %d]", ec) - } return fmt.Sprintf("[Error Code: %d]", ec) } +type FailureCode uint16 + +func (fc FailureCode) String() string { + return fmt.Sprintf("[Failure Code: %d]", fc) +} + const ( - FailureCodeUnknownFailure ErrorCode = 2000 - FailureCodeEncodingFailure ErrorCode = 2001 - FailureCodeLedgerFailure ErrorCode = 2002 - FailureCodeStateMergeFailure ErrorCode = 2003 - FailureCodeBlockFinderFailure ErrorCode = 2004 - // Deprecated: No longer used. - FailureCodeHasherFailure ErrorCode = 2005 - FailureCodeParseRestrictedModeInvalidAccessFailure ErrorCode = 2006 - FailureCodePayerBalanceCheckFailure ErrorCode = 2007 - FailureCodeDerivedDataCacheImplementationFailure ErrorCode = 2008 - FailureCodeRandomSourceFailure ErrorCode = 2009 - // Deprecated: No longer used. - FailureCodeMetaTransactionFailure ErrorCode = 2100 + FailureCodeUnknownFailure FailureCode = 2000 + FailureCodeEncodingFailure FailureCode = 2001 + FailureCodeLedgerFailure FailureCode = 2002 + FailureCodeStateMergeFailure FailureCode = 2003 + FailureCodeBlockFinderFailure FailureCode = 2004 + // Deprecated: No longer used. + FailureCodeHasherFailure FailureCode = 2005 + FailureCodeParseRestrictedModeInvalidAccessFailure FailureCode = 2006 + FailureCodePayerBalanceCheckFailure FailureCode = 2007 + FailureCodeDerivedDataCacheImplementationFailure FailureCode = 2008 + FailureCodeRandomSourceFailure FailureCode = 2009 + // Deprecated: No longer used. + FailureCodeMetaTransactionFailure FailureCode = 2100 ) const ( diff --git a/fvm/errors/errors.go b/fvm/errors/errors.go index 30c6464b2d4..a78907c65d7 100644 --- a/fvm/errors/errors.go +++ b/fvm/errors/errors.go @@ -10,9 +10,15 @@ import ( ) type Unwrappable interface { + error Unwrap() error } +type UnwrappableErrors interface { + error + Unwrap() []error +} + type CodedError interface { Code() ErrorCode @@ -20,6 +26,13 @@ type CodedError interface { error } +type CodedFailure interface { + Code() FailureCode + + Unwrappable + error +} + // Is is a utility function to call std error lib `Is` function for instance equality checks. func Is(err error, target error) bool { return stdErrors.Is(err, target) @@ -33,15 +46,14 @@ func As(err error, target interface{}) bool { return stdErrors.As(err, target) } -// findImportantCodedError recursively unwraps the error to search for important -// coded error: +// findRootCodedError recursively unwraps the error to search for the root (deepest) coded error: // 1. If err is nil, this returns (nil, false), // 2. If err has no error code, this returns (nil, true), -// 3. If err has a failure error code, this returns -// (, false), -// 4. If err has a non-failure error code, this returns -// (, false) -func findImportantCodedError(err error) (CodedError, bool) { +// 3. If err has an error code, this returns +// (, false) +// +// Note: This assumes the caller has already checked if the error contains a CodedFailure. +func findRootCodedError(err error) (CodedError, bool) { if err == nil { return nil, false } @@ -52,10 +64,6 @@ func findImportantCodedError(err error) (CodedError, bool) { } for { - if coded.Code().IsFailure() { - return coded, false - } - var nextCoded CodedError if !As(coded.Unwrap(), &nextCoded) { return coded, false @@ -68,32 +76,45 @@ func findImportantCodedError(err error) (CodedError, bool) { // IsFailure returns true if the error is un-coded, or if the error contains // a failure code. func IsFailure(err error) bool { + return AsFailure(err) != nil +} + +func AsFailure(err error) CodedFailure { if err == nil { - return false + return nil + } + + var failure CodedFailure + if As(err, &failure) { + return failure } - coded, isUnknown := findImportantCodedError(err) - return isUnknown || coded.Code().IsFailure() + var coded CodedError + if !As(err, &coded) { + return NewUnknownFailure(err) + } + + return nil } // SplitErrorTypes splits the error into fatal (failures) and non-fatal errors -func SplitErrorTypes(inp error) (err CodedError, failure CodedError) { +func SplitErrorTypes(inp error) (err CodedError, failure CodedFailure) { if inp == nil { return nil, nil } - coded, isUnknown := findImportantCodedError(inp) - if isUnknown { - return nil, NewUnknownFailure(inp) - } - - if coded.Code().IsFailure() { - return nil, WrapCodedError( - coded.Code(), + if failure = AsFailure(inp); failure != nil { + return nil, WrapCodedFailure( + failure.Code(), inp, "failure caused by") } + coded, isUnknown := findRootCodedError(inp) + if isUnknown { + return nil, NewUnknownFailure(inp) + } + return WrapCodedError( coded.Code(), inp, @@ -118,38 +139,86 @@ func HandleRuntimeError(err error) error { return NewCadenceRuntimeError(runErr) } -// This returns true if the error or one of its nested errors matches the +// HasErrorCode returns true if the error or one of its nested errors matches the // specified error code. func HasErrorCode(err error, code ErrorCode) bool { return Find(err, code) != nil } -// This recursively unwraps the error and returns first CodedError that matches +// HasFailureCode returns true if the error or one of its nested errors matches the +// specified failure code. +func HasFailureCode(err error, code FailureCode) bool { + return FindFailure(err, code) != nil +} + +// Find recursively unwraps the error and returns the first CodedError that matches // the specified error code. func Find(originalErr error, code ErrorCode) CodedError { if originalErr == nil { return nil } - var unwrappable Unwrappable - if !As(originalErr, &unwrappable) { + // Handle non-chained errors + var unwrappedErrs []error + switch err := originalErr.(type) { + case *multierror.Error: + unwrappedErrs = err.WrappedErrors() + case UnwrappableErrors: + unwrappedErrs = err.Unwrap() + + // IMPORTANT: this check needs to run after *multierror.Error because multierror does implement + // the Unwrappable interface, however its implementation only visits the base errors in the list, + // and ignores their descendants. + case Unwrappable: + coded, ok := err.(CodedError) + if ok && coded.Code() == code { + return coded + } + return Find(err.Unwrap(), code) + default: return nil } - coded, ok := unwrappable.(CodedError) - if ok && coded.Code() == code { - return coded + for _, innerErr := range unwrappedErrs { + coded := Find(innerErr, code) + if coded != nil { + return coded + } } - // NOTE: we need to special case multierror.Error since As() will only - // inspect the first error within multierror.Error. - errors, ok := unwrappable.(*multierror.Error) - if !ok { - return Find(unwrappable.Unwrap(), code) + return nil +} + +// FindFailure recursively unwraps the error and returns the first CodedFailure that matches +// the specified error code. +func FindFailure(originalErr error, code FailureCode) CodedFailure { + if originalErr == nil { + return nil } - for _, innerErr := range errors.Errors { - coded = Find(innerErr, code) + // Handle non-chained errors + var unwrappedErrs []error + switch err := originalErr.(type) { + case *multierror.Error: + unwrappedErrs = err.WrappedErrors() + case UnwrappableErrors: + unwrappedErrs = err.Unwrap() + + // IMPORTANT: this check needs to run after *multierror.Error because multierror does implement + // the Unwrappable interface, however its implementation only visits the base errors in the list, + // and ignores their descendants. + case Unwrappable: + coded, ok := err.(CodedFailure) + if ok && coded.Code() == code { + return coded + } + return FindFailure(err.Unwrap(), code) + default: + return nil + } + + for _, innerErr := range unwrappedErrs { + coded := FindFailure(innerErr, code) if coded != nil { return coded } @@ -158,6 +227,8 @@ func Find(originalErr error, code ErrorCode) CodedError { return nil } +var _ CodedError = (*codedError)(nil) + type codedError struct { code ErrorCode @@ -207,6 +278,56 @@ func (err codedError) Code() ErrorCode { return err.code } +var _ CodedFailure = (*codedFailure)(nil) + +type codedFailure struct { + code FailureCode + err error +} + +func newFailure( + code FailureCode, + rootCause error, +) codedFailure { + return codedFailure{ + code: code, + err: rootCause, + } +} + +func WrapCodedFailure( + code FailureCode, + err error, + prefixMsgFormat string, + formatArguments ...interface{}, +) codedFailure { + if prefixMsgFormat != "" { + msg := fmt.Sprintf(prefixMsgFormat, formatArguments...) + err = fmt.Errorf("%s: %w", msg, err) + } + return newFailure(code, err) +} + +func NewCodedFailure( + code FailureCode, + format string, + formatArguments ...interface{}, +) codedFailure { + return newFailure(code, fmt.Errorf(format, formatArguments...)) +} + +func (err codedFailure) Unwrap() error { + return err.err +} + +func (err codedFailure) Error() string { + return fmt.Sprintf("%v %v", err.code, err.err) +} + +func (err codedFailure) Code() FailureCode { + return err.code +} + // NewEventEncodingError construct a new CodedError which indicates // that encoding event has failed func NewEventEncodingError(err error) CodedError { diff --git a/fvm/errors/errors_test.go b/fvm/errors/errors_test.go index d0a262e0147..b634995b617 100644 --- a/fvm/errors/errors_test.go +++ b/fvm/errors/errors_test.go @@ -4,6 +4,11 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-multierror" + "github.com/onflow/cadence/runtime" + cadenceErr "github.com/onflow/cadence/runtime/errors" + "github.com/onflow/cadence/runtime/sema" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/onflow/flow-go/model/flow" @@ -39,7 +44,7 @@ func TestErrorHandling(t *testing.T) { e5 := NewInvalidProposalSignatureError(flow.ProposalKey{}, e4) e6 := fmt.Errorf("wrapped: %w", e5) - expectedErr := WrapCodedError( + expectedErr := WrapCodedFailure( e3.Code(), // The shallowest failure's error code e6, // All the error message detail. "failure caused by") @@ -61,3 +66,334 @@ func TestErrorHandling(t *testing.T) { require.True(t, IsFailure(e1)) }) } + +func TestHandleRuntimeError(t *testing.T) { + baseErr := fmt.Errorf("base error") + tests := []struct { + name string + err error + errorCode ErrorCode + failureCode FailureCode + }{ + { + name: "nil error", + err: nil, + }, + { + name: "unknown error", + err: baseErr, + failureCode: FailureCodeUnknownFailure, + }, + { + name: "runtime error", + err: runtime.Error{Err: baseErr}, + errorCode: ErrCodeCadenceRunTimeError, + }, + { + name: "coded error in Unwrappable error", + err: runtime.Error{ + Err: cadenceErr.ExternalError{ + Recovered: NewScriptExecutionCancelledError(baseErr), + }, + }, + errorCode: ErrCodeScriptExecutionCancelledError, + }, + { + name: "coded error in ParentError error", + err: createCheckerErr([]error{ + fmt.Errorf("first error"), + NewScriptExecutionTimedOutError(), + }), + errorCode: ErrCodeScriptExecutionTimedOutError, + }, + { + name: "first coded error returned", + err: createCheckerErr([]error{ + fmt.Errorf("first error"), + NewScriptExecutionTimedOutError(), + NewScriptExecutionCancelledError(baseErr), + }), + errorCode: ErrCodeScriptExecutionTimedOutError, + }, + { + name: "failure returned", + err: createCheckerErr([]error{ + fmt.Errorf("first error"), + NewLedgerFailure(baseErr), + }), + failureCode: FailureCodeLedgerFailure, + }, + { + name: "error before failure returns failure", + err: createCheckerErr([]error{ + fmt.Errorf("first error"), + NewScriptExecutionTimedOutError(), + NewLedgerFailure(baseErr), + }), + failureCode: FailureCodeLedgerFailure, + }, + { + name: "embedded coded errors return deepest error", + err: createCheckerErr([]error{ + fmt.Errorf("first error"), + NewScriptExecutionCancelledError( + NewScriptExecutionTimedOutError(), + ), + }), + errorCode: ErrCodeScriptExecutionTimedOutError, + }, + { + name: "failure with embedded error returns failure", + err: createCheckerErr([]error{ + fmt.Errorf("first error"), + NewLedgerFailure( + NewScriptExecutionTimedOutError(), + ), + }), + failureCode: FailureCodeLedgerFailure, + }, + { + name: "coded error with embedded failure returns failure", + err: createCheckerErr([]error{ + fmt.Errorf("first error"), + NewScriptExecutionCancelledError( + NewLedgerFailure(baseErr), + ), + }), + failureCode: FailureCodeLedgerFailure, + }, + { + name: "error tree with failure returns failure", + err: createCheckerErr([]error{ + fmt.Errorf("first error"), + NewScriptExecutionCancelledError(baseErr), + createCheckerErr([]error{ + fmt.Errorf("first error"), + NewScriptExecutionCancelledError( + NewLedgerFailure(baseErr), + ), + }), + }), + failureCode: FailureCodeLedgerFailure, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + actual := HandleRuntimeError(tc.err) + if tc.err == nil { + assert.NoError(t, actual) + return + } + + actualCoded, failureCoded := SplitErrorTypes(actual) + + if tc.failureCode != 0 { + assert.NoError(t, actualCoded) + assert.Equalf(t, tc.failureCode, failureCoded.Code(), "error code mismatch: expected %d, got %d", tc.failureCode, failureCoded.Code()) + } else { + assert.NoError(t, failureCoded) + assert.Equalf(t, tc.errorCode, actualCoded.Code(), "error code mismatch: expected %d, got %d", tc.errorCode, actualCoded.Code()) + } + }) + } +} + +func TestFind(t *testing.T) { + targetCode := ErrCodeScriptExecutionCancelledError + baseErr := fmt.Errorf("base error") + + tests := []struct { + name string + err error + found bool + }{ + { + name: "nil error", + err: nil, + found: false, + }, + { + name: "plain error", + err: baseErr, + found: false, + }, + { + name: "wrapped plain error", + err: fmt.Errorf("wrapped: %w", baseErr), + found: false, + }, + { + name: "coded failure", + err: NewLedgerFailure(baseErr), + found: false, + }, + { + name: "incorrect coded error", + err: NewScriptExecutionTimedOutError(), + found: false, + }, + { + name: "found", + err: NewScriptExecutionCancelledError(baseErr), + found: true, + }, + { + name: "found with embedded errors", + err: NewScriptExecutionCancelledError(NewLedgerFailure(NewScriptExecutionTimedOutError())), + found: true, + }, + { + name: "found embedded in error", + err: NewDerivedDataCacheImplementationFailure(NewScriptExecutionCancelledError(baseErr)), + found: true, + }, + { + name: "found embedded in failure", + err: NewLedgerFailure(NewScriptExecutionCancelledError(baseErr)), + found: true, + }, + { + name: "found embedded with multierror", + err: &multierror.Error{ + Errors: []error{ + baseErr, + NewScriptExecutionTimedOutError(), + NewLedgerFailure(NewScriptExecutionCancelledError(baseErr)), + }, + }, + found: true, + }, + { + name: "found within embedded error tree", + err: createCheckerErr([]error{ + fmt.Errorf("first error"), + NewLedgerFailure(baseErr), + createCheckerErr([]error{ + fmt.Errorf("first error"), + NewLedgerFailure( + NewScriptExecutionCancelledError(baseErr), + ), + }), + }), + found: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + actual := Find(tc.err, targetCode) + if !tc.found { + assert.NoError(t, actual) + return + } + + require.Error(t, actual, "expected error but none found") + assert.Equalf(t, targetCode, actual.Code(), "error code mismatch: expected %d, got %d", targetCode, actual.Code()) + }) + } +} + +func TestFindFailure(t *testing.T) { + targetCode := FailureCodeLedgerFailure + baseErr := fmt.Errorf("base error") + tests := []struct { + name string + err error + found bool + }{ + { + name: "nil error", + err: nil, + found: false, + }, + { + name: "plain error", + err: baseErr, + found: false, + }, + { + name: "wrapped plain error", + err: fmt.Errorf("wrapped: %w", baseErr), + found: false, + }, + { + name: "coded error", + err: NewScriptExecutionTimedOutError(), + found: false, + }, + { + name: "incorrect coded failure", + err: NewStateMergeFailure(baseErr), + found: false, + }, + { + name: "found", + err: NewLedgerFailure(baseErr), + found: true, + }, + { + name: "found with embedded errors", + err: NewLedgerFailure(NewScriptExecutionCancelledError(NewScriptExecutionTimedOutError())), + found: true, + }, + { + name: "found embedded in error", + err: NewDerivedDataCacheImplementationFailure(NewLedgerFailure(baseErr)), + found: true, + }, + { + name: "found embedded in failure", + err: NewStateMergeFailure(NewLedgerFailure(baseErr)), + found: true, + }, + { + name: "found embedded with multierror", + err: &multierror.Error{ + Errors: []error{ + baseErr, + NewScriptExecutionTimedOutError(), + NewScriptExecutionCancelledError(NewLedgerFailure(baseErr)), + }, + }, + found: true, + }, + { + name: "found within embedded error tree", + err: createCheckerErr([]error{ + fmt.Errorf("first error"), + NewScriptExecutionCancelledError(baseErr), + createCheckerErr([]error{ + fmt.Errorf("first error"), + NewScriptExecutionCancelledError( + NewLedgerFailure(baseErr), + ), + }), + }), + found: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + actual := FindFailure(tc.err, targetCode) + if !tc.found { + assert.NoError(t, actual) + return + } + + require.Error(t, actual, "expected error but none found") + assert.Equalf(t, targetCode, actual.Code(), "error code mismatch: expected %d, got %d", targetCode, actual.Code()) + }) + } +} + +func createCheckerErr(errs []error) error { + return runtime.Error{ + Err: cadenceErr.ExternalError{ + Recovered: sema.CheckerError{ + Errors: errs, + }, + }, + } +} diff --git a/fvm/errors/execution.go b/fvm/errors/execution.go index d70e47e6b7c..38a78bc8d21 100644 --- a/fvm/errors/execution.go +++ b/fvm/errors/execution.go @@ -76,8 +76,8 @@ func IsInsufficientPayerBalanceError(err error) bool { func NewPayerBalanceCheckFailure( payer flow.Address, err error, -) CodedError { - return WrapCodedError( +) CodedFailure { + return WrapCodedFailure( FailureCodePayerBalanceCheckFailure, err, "failed to check if the payer %s has sufficient balance", @@ -88,8 +88,8 @@ func NewPayerBalanceCheckFailure( // the derived data cache. func NewDerivedDataCacheImplementationFailure( err error, -) CodedError { - return WrapCodedError( +) CodedFailure { + return WrapCodedFailure( FailureCodeDerivedDataCacheImplementationFailure, err, "implementation error in derived data cache") @@ -99,8 +99,8 @@ func NewDerivedDataCacheImplementationFailure( // the random source provider. func NewRandomSourceFailure( err error, -) CodedError { - return WrapCodedError( +) CodedFailure { + return WrapCodedFailure( FailureCodeRandomSourceFailure, err, "implementation error in random source provider") diff --git a/fvm/errors/failures.go b/fvm/errors/failures.go index 322fd0ac117..6ed5dd56225 100644 --- a/fvm/errors/failures.go +++ b/fvm/errors/failures.go @@ -4,8 +4,8 @@ import ( "github.com/onflow/flow-go/module/trace" ) -func NewUnknownFailure(err error) CodedError { - return WrapCodedError( +func NewUnknownFailure(err error) CodedFailure { + return WrapCodedFailure( FailureCodeUnknownFailure, err, "unknown failure") @@ -16,8 +16,8 @@ func NewEncodingFailuref( err error, msg string, args ...interface{}, -) CodedError { - return WrapCodedError( +) CodedFailure { + return WrapCodedFailure( FailureCodeEncodingFailure, err, "encoding failed: "+msg, @@ -26,8 +26,8 @@ func NewEncodingFailuref( // NewLedgerFailure constructs a new CodedError which captures a fatal error // cause by ledger failures. -func NewLedgerFailure(err error) CodedError { - return WrapCodedError( +func NewLedgerFailure(err error) CodedFailure { + return WrapCodedFailure( FailureCodeLedgerFailure, err, "ledger returns unsuccessful") @@ -36,13 +36,13 @@ func NewLedgerFailure(err error) CodedError { // IsLedgerFailure returns true if the error or any of the wrapped errors is // a ledger failure func IsLedgerFailure(err error) bool { - return HasErrorCode(err, FailureCodeLedgerFailure) + return HasFailureCode(err, FailureCodeLedgerFailure) } // NewStateMergeFailure constructs a new CodedError which captures a fatal // caused by state merge. -func NewStateMergeFailure(err error) CodedError { - return WrapCodedError( +func NewStateMergeFailure(err error) CodedFailure { + return WrapCodedFailure( FailureCodeStateMergeFailure, err, "can not merge the state") @@ -50,8 +50,8 @@ func NewStateMergeFailure(err error) CodedError { // NewBlockFinderFailure constructs a new CodedError which captures a fatal // caused by block finder. -func NewBlockFinderFailure(err error) CodedError { - return WrapCodedError( +func NewBlockFinderFailure(err error) CodedFailure { + return WrapCodedFailure( FailureCodeBlockFinderFailure, err, "can not retrieve the block") @@ -62,8 +62,8 @@ func NewBlockFinderFailure(err error) CodedError { // operation while it is parsing programs. func NewParseRestrictedModeInvalidAccessFailure( spanName trace.SpanName, -) CodedError { - return NewCodedError( +) CodedFailure { + return NewCodedFailure( FailureCodeParseRestrictedModeInvalidAccessFailure, "cannot access %s while cadence is in parse restricted mode", spanName) diff --git a/fvm/transactionPayerBalanceChecker_test.go b/fvm/transactionPayerBalanceChecker_test.go index 931f2984bd1..99bf19354a6 100644 --- a/fvm/transactionPayerBalanceChecker_test.go +++ b/fvm/transactionPayerBalanceChecker_test.go @@ -52,7 +52,7 @@ func TestTransactionPayerBalanceChecker(t *testing.T) { d := fvm.TransactionPayerBalanceChecker{} maxFees, err := d.CheckPayerBalanceAndReturnMaxFees(proc, txnState, env) require.Error(t, err) - require.True(t, errors.HasErrorCode(err, errors.FailureCodePayerBalanceCheckFailure)) + require.True(t, errors.HasFailureCode(err, errors.FailureCodePayerBalanceCheckFailure)) require.ErrorIs(t, err, someError) require.Equal(t, uint64(0), maxFees) }) @@ -73,7 +73,7 @@ func TestTransactionPayerBalanceChecker(t *testing.T) { d := fvm.TransactionPayerBalanceChecker{} maxFees, err := d.CheckPayerBalanceAndReturnMaxFees(proc, txnState, env) require.Error(t, err) - require.True(t, errors.HasErrorCode(err, errors.FailureCodePayerBalanceCheckFailure)) + require.True(t, errors.HasFailureCode(err, errors.FailureCodePayerBalanceCheckFailure)) require.Equal(t, uint64(0), maxFees) }) diff --git a/go.mod b/go.mod index 964a9ac2761..599adfc0b90 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,7 @@ require ( github.com/multiformats/go-multiaddr-dns v0.3.1 github.com/multiformats/go-multihash v0.2.3 github.com/onflow/atree v0.6.0 - github.com/onflow/cadence v0.42.7 + github.com/onflow/cadence v0.42.8 github.com/onflow/crypto v0.25.0 github.com/onflow/flow v0.3.4 github.com/onflow/flow-core-contracts/lib/go/contracts v0.15.1-0.20231219201108-fbdb10b0a2da @@ -239,8 +239,8 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect - github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/miekg/dns v1.1.54 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect diff --git a/go.sum b/go.sum index d416631722f..639469ea769 100644 --- a/go.sum +++ b/go.sum @@ -1179,16 +1179,17 @@ github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -1344,8 +1345,8 @@ github.com/onflow/atree v0.1.0-beta1.0.20211027184039-559ee654ece9/go.mod h1:+6x github.com/onflow/atree v0.6.0 h1:j7nQ2r8npznx4NX39zPpBYHmdy45f4xwoi+dm37Jk7c= github.com/onflow/atree v0.6.0/go.mod h1:gBHU0M05qCbv9NN0kijLWMgC47gHVNBIp4KmsVFi0tc= github.com/onflow/cadence v0.20.1/go.mod h1:7mzUvPZUIJztIbr9eTvs+fQjWWHTF8veC+yk4ihcNIA= -github.com/onflow/cadence v0.42.7 h1:Qp9VYX901saO7wPwF/rwV4cMS+0mfWxnm9EqbYElYy4= -github.com/onflow/cadence v0.42.7/go.mod h1:raU8va8QRyTa/eUbhej4mbyW2ETePfSaywoo36MddgE= +github.com/onflow/cadence v0.42.8 h1:6OWhKMjL2Lql6a3L2xeA44uoOAVBp5+cMNE5BDPvo+E= +github.com/onflow/cadence v0.42.8/go.mod h1:1wFd+LiNiN6qoZXof3MBdpM6d8BsxbVIxOA77LbIYmE= github.com/onflow/crypto v0.25.0 h1:BeWbLsh3ZD13Ej+Uky6kg1PL1ZIVBDVX+2MVBNwqddg= github.com/onflow/crypto v0.25.0/go.mod h1:C8FbaX0x8y+FxWjbkHy0Q4EASCDR9bSPWZqlpCLYyVI= github.com/onflow/flow v0.3.4 h1:FXUWVdYB90f/rjNcY0Owo30gL790tiYff9Pb/sycXYE= diff --git a/insecure/go.mod b/insecure/go.mod index 7e6bc5a1bee..79caf6de233 100644 --- a/insecure/go.mod +++ b/insecure/go.mod @@ -182,8 +182,8 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect - github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/miekg/dns v1.1.54 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect @@ -205,7 +205,7 @@ require ( github.com/nxadm/tail v1.4.8 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/onflow/atree v0.6.0 // indirect - github.com/onflow/cadence v0.42.7 // indirect + github.com/onflow/cadence v0.42.8 // indirect github.com/onflow/flow-core-contracts/lib/go/contracts v0.15.1-0.20231219201108-fbdb10b0a2da // indirect github.com/onflow/flow-core-contracts/lib/go/templates v0.15.1-0.20231219201108-fbdb10b0a2da // indirect github.com/onflow/flow-ft/lib/go/contracts v0.7.1-0.20230711213910-baad011d2b13 // indirect diff --git a/insecure/go.sum b/insecure/go.sum index 4872f6e5f04..3614f3ee537 100644 --- a/insecure/go.sum +++ b/insecure/go.sum @@ -1156,16 +1156,17 @@ github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -1320,8 +1321,8 @@ github.com/onflow/atree v0.1.0-beta1.0.20211027184039-559ee654ece9/go.mod h1:+6x github.com/onflow/atree v0.6.0 h1:j7nQ2r8npznx4NX39zPpBYHmdy45f4xwoi+dm37Jk7c= github.com/onflow/atree v0.6.0/go.mod h1:gBHU0M05qCbv9NN0kijLWMgC47gHVNBIp4KmsVFi0tc= github.com/onflow/cadence v0.20.1/go.mod h1:7mzUvPZUIJztIbr9eTvs+fQjWWHTF8veC+yk4ihcNIA= -github.com/onflow/cadence v0.42.7 h1:Qp9VYX901saO7wPwF/rwV4cMS+0mfWxnm9EqbYElYy4= -github.com/onflow/cadence v0.42.7/go.mod h1:raU8va8QRyTa/eUbhej4mbyW2ETePfSaywoo36MddgE= +github.com/onflow/cadence v0.42.8 h1:6OWhKMjL2Lql6a3L2xeA44uoOAVBp5+cMNE5BDPvo+E= +github.com/onflow/cadence v0.42.8/go.mod h1:1wFd+LiNiN6qoZXof3MBdpM6d8BsxbVIxOA77LbIYmE= github.com/onflow/crypto v0.25.0 h1:BeWbLsh3ZD13Ej+Uky6kg1PL1ZIVBDVX+2MVBNwqddg= github.com/onflow/crypto v0.25.0/go.mod h1:C8FbaX0x8y+FxWjbkHy0Q4EASCDR9bSPWZqlpCLYyVI= github.com/onflow/flow-core-contracts/lib/go/contracts v0.15.1-0.20231219201108-fbdb10b0a2da h1:8CEioYNnP0rwjnRbKDgs8SmiQTsdaroeX4d/Q3pQuh4= diff --git a/integration/go.mod b/integration/go.mod index b837825cafd..4429a899093 100644 --- a/integration/go.mod +++ b/integration/go.mod @@ -224,8 +224,8 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect - github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/miekg/dns v1.1.54 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect @@ -366,7 +366,7 @@ replace github.com/onflow/flow-go/insecure => ../insecure // the replaces below should not be needed once flow-go and all the repos are updated // to use Cadence 1.0 -replace github.com/onflow/cadence => github.com/onflow/cadence v0.42.7 +replace github.com/onflow/cadence => github.com/onflow/cadence v0.42.8 replace github.com/onflow/flow-ft/lib/go/contracts => github.com/onflow/flow-ft/lib/go/contracts v0.7.1-0.20230711213910-baad011d2b13 diff --git a/integration/go.sum b/integration/go.sum index 915266fe312..9367f85a1f8 100644 --- a/integration/go.sum +++ b/integration/go.sum @@ -875,6 +875,8 @@ github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/ github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= +github.com/itchyny/gojq v0.12.14/go.mod h1:y1G7oO7XkcR1LPZO59KyoCRy08T3j9vDYRV0GgYSS+s= +github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8= github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= @@ -1245,17 +1247,17 @@ github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0= github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= @@ -1422,8 +1424,8 @@ github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6 github.com/onflow/atree v0.6.0/go.mod h1:gBHU0M05qCbv9NN0kijLWMgC47gHVNBIp4KmsVFi0tc= github.com/onflow/atree v0.6.1-0.20230711151834-86040b30171f h1:Z8/PgTqOgOg02MTRpTBYO2k16FE6z4wEOtaC2WBR9Xo= github.com/onflow/atree v0.6.1-0.20230711151834-86040b30171f/go.mod h1:xvP61FoOs95K7IYdIYRnNcYQGf4nbF/uuJ0tHf4DRuM= -github.com/onflow/cadence v0.42.7 h1:Qp9VYX901saO7wPwF/rwV4cMS+0mfWxnm9EqbYElYy4= -github.com/onflow/cadence v0.42.7/go.mod h1:raU8va8QRyTa/eUbhej4mbyW2ETePfSaywoo36MddgE= +github.com/onflow/cadence v0.42.8 h1:6OWhKMjL2Lql6a3L2xeA44uoOAVBp5+cMNE5BDPvo+E= +github.com/onflow/cadence v0.42.8/go.mod h1:1wFd+LiNiN6qoZXof3MBdpM6d8BsxbVIxOA77LbIYmE= github.com/onflow/crypto v0.25.0 h1:BeWbLsh3ZD13Ej+Uky6kg1PL1ZIVBDVX+2MVBNwqddg= github.com/onflow/crypto v0.25.0/go.mod h1:C8FbaX0x8y+FxWjbkHy0Q4EASCDR9bSPWZqlpCLYyVI= github.com/onflow/flow-core-contracts/lib/go/contracts v0.15.1-0.20231219201108-fbdb10b0a2da h1:8CEioYNnP0rwjnRbKDgs8SmiQTsdaroeX4d/Q3pQuh4=