Skip to content

Commit

Permalink
Merge PR cosmos#4821: Port weave errors package
Browse files Browse the repository at this point in the history
  • Loading branch information
ethanfrey authored and alexanderbez committed Jul 31, 2019
1 parent 7c70912 commit 68dd969
Show file tree
Hide file tree
Showing 9 changed files with 1,069 additions and 0 deletions.
1 change: 1 addition & 0 deletions .clog.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ tags:
- cli
- modules
- simulation
- types
2 changes: 2 additions & 0 deletions .pending/improvements/types/4821-types-errors-pa
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#4821 types/errors package added with support for stacktraces
Meant as a more feature-rich replacement for sdk.Errors in the mid-term
130 changes: 130 additions & 0 deletions types/errors/abci.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package errors

import (
"errors"
"fmt"
"reflect"
)

const (
// SuccessABCICode declares an ABCI response use 0 to signal that the
// processing was successful and no error is returned.
SuccessABCICode = 0

// All unclassified errors that do not provide an ABCI code are clubbed
// under an internal error code and a generic message instead of
// detailed error string.
internalABCICodespace = UndefinedCodespace
internalABCICode uint32 = 1
internalABCILog string = "internal error"
// multiErrorABCICode uint32 = 1000
)

// ABCIInfo returns the ABCI error information as consumed by the tendermint
// client. Returned codespace, code, and log message should be used as a ABCI response.
// Any error that does not provide ABCICode information is categorized as error
// with code 1, codespace UndefinedCodespace
// When not running in a debug mode all messages of errors that do not provide
// ABCICode information are replaced with generic "internal error". Errors
// without an ABCICode information as considered internal.
func ABCIInfo(err error, debug bool) (codespace string, code uint32, log string) {
if errIsNil(err) {
return "", SuccessABCICode, ""
}

encode := defaultErrEncoder
if debug {
encode = debugErrEncoder
}

return abciCodespace(err), abciCode(err), encode(err)
}

// The debugErrEncoder encodes the error with a stacktrace.
func debugErrEncoder(err error) string {
return fmt.Sprintf("%+v", err)
}

// The defaultErrEncoder applies Redact on the error before encoding it with its internal error message.
func defaultErrEncoder(err error) string {
return Redact(err).Error()
}

type coder interface {
ABCICode() uint32
}

// abciCode test if given error contains an ABCI code and returns the value of
// it if available. This function is testing for the causer interface as well
// and unwraps the error.
func abciCode(err error) uint32 {
if errIsNil(err) {
return SuccessABCICode
}

for {
if c, ok := err.(coder); ok {
return c.ABCICode()
}

if c, ok := err.(causer); ok {
err = c.Cause()
} else {
return internalABCICode
}
}
}

type codespacer interface {
Codespace() string
}

// abciCodespace tests if given error contains a codespace and returns the value of
// it if available. This function is testing for the causer interface as well
// and unwraps the error.
func abciCodespace(err error) string {
if errIsNil(err) {
return ""
}

for {
if c, ok := err.(codespacer); ok {
return c.Codespace()
}

if c, ok := err.(causer); ok {
err = c.Cause()
} else {
return internalABCICodespace
}
}
}

// errIsNil returns true if value represented by the given error is nil.
//
// Most of the time a simple == check is enough. There is a very narrowed
// spectrum of cases (mostly in tests) where a more sophisticated check is
// required.
func errIsNil(err error) bool {
if err == nil {
return true
}
if val := reflect.ValueOf(err); val.Kind() == reflect.Ptr {
return val.IsNil()
}
return false
}

// Redact replace all errors that do not initialize with a weave error with a
// generic internal error instance. This function is supposed to hide
// implementation details errors and leave only those that weave framework
// originates.
func Redact(err error) error {
if ErrPanic.Is(err) {
return errors.New(internalABCILog)
}
if abciCode(err) == internalABCICode {
return errors.New(internalABCILog)
}
return err
}
Loading

0 comments on commit 68dd969

Please sign in to comment.