diff --git a/errors/abci.go b/errors/abci.go deleted file mode 100644 index 4341eaef0..000000000 --- a/errors/abci.go +++ /dev/null @@ -1,55 +0,0 @@ -package errors - -import ( - abci "github.com/tendermint/abci/types" -) - -func getABCIError(err error) (ABCIError, bool) { - if err, ok := err.(ABCIError); ok { - return err, true - } - if causer, ok := err.(causer); ok { - err := causer.Cause() - if err, ok := err.(ABCIError); ok { - return err, true - } - } - return nil, false -} - -func ResponseDeliverTxFromErr(err error) *abci.ResponseDeliverTx { - var code = CodeInternalError - var log = CodeToDefaultLog(code) - - abciErr, ok := getABCIError(err) - if ok { - code = abciErr.ABCICode() - log = abciErr.ABCILog() - } - - return &abci.ResponseDeliverTx{ - Code: code, - Data: nil, - Log: log, - Tags: nil, - } -} - -func ResponseCheckTxFromErr(err error) *abci.ResponseCheckTx { - var code = CodeInternalError - var log = CodeToDefaultLog(code) - - abciErr, ok := getABCIError(err) - if ok { - code = abciErr.ABCICode() - log = abciErr.ABCILog() - } - - return &abci.ResponseCheckTx{ - Code: code, - Data: nil, - Log: log, - // Gas: 0, // TODO - // Fee: 0, // TODO - } -} diff --git a/errors/errors.go b/errors/errors.go deleted file mode 100644 index ff9593af8..000000000 --- a/errors/errors.go +++ /dev/null @@ -1,210 +0,0 @@ -package errors - -import ( - "fmt" -) - -const ( - // ABCI Response Codes - // Base SDK reserves 0 ~ 99. - CodeInternalError uint32 = 1 - CodeTxParseError = 2 - CodeBadNonce = 3 - CodeUnauthorized = 4 - CodeInsufficientFunds = 5 - CodeUnknownRequest = 6 - CodeUnrecognizedAddress = 7 -) - -// NOTE: Don't stringer this, we'll put better messages in later. -func CodeToDefaultLog(code uint32) string { - switch code { - case CodeInternalError: - return "Internal error" - case CodeTxParseError: - return "Tx parse error" - case CodeBadNonce: - return "Bad nonce" - case CodeUnauthorized: - return "Unauthorized" - case CodeInsufficientFunds: - return "Insufficent funds" - case CodeUnknownRequest: - return "Unknown request" - case CodeUnrecognizedAddress: - return "Unrecognized address" - default: - return fmt.Sprintf("Unknown code %d", code) - } -} - -//-------------------------------------------------------------------------------- -// All errors are created via constructors so as to enable us to hijack them -// and inject stack traces if we really want to. - -func InternalError(log string) *sdkError { - return newSDKError(CodeInternalError, log) -} - -func TxParseError(log string) *sdkError { - return newSDKError(CodeTxParseError, log) -} - -func BadNonce(log string) *sdkError { - return newSDKError(CodeBadNonce, log) -} - -func Unauthorized(log string) *sdkError { - return newSDKError(CodeUnauthorized, log) -} - -func InsufficientFunds(log string) *sdkError { - return newSDKError(CodeInsufficientFunds, log) -} - -func UnknownRequest(log string) *sdkError { - return newSDKError(CodeUnknownRequest, log) -} - -func UnrecognizedAddress(log string) *sdkError { - return newSDKError(CodeUnrecognizedAddress, log) -} - -//---------------------------------------- -// ABCIError & sdkError - -type ABCIError interface { - ABCICode() uint32 - ABCILog() string - Error() string -} - -func NewABCIError(code uint32, log string) ABCIError { - return newSDKError(code, log) -} - -/* - - This struct is intended to be used with pkg/errors. - - Usage: - - ``` - import sdk "github.com/cosmos/cosmos-sdk" - import "github.com/pkg/errors" - - var err = - if err != nil { - err = sdk.InternalError("").WithCause(err) - err = errors.Wrap(err, "Captured the stack!") - return err - } - ``` - - Then, to get the ABCI code/log, use ABCIErrorCause() - -*/ -type sdkError struct { - code uint32 - log string - cause error - // TODO stacktrace, optional. -} - -func newSDKError(code uint32, log string) *sdkError { - // TODO capture stacktrace if ENV is set. - if log == "" { - log = CodeToDefaultLog(code) - } - return &sdkError{ - code: code, - log: log, - cause: nil, - } -} - -// Implements ABCIError -func (err *sdkError) Error() string { - return fmt.Sprintf("SDKError{%d: %s}", err.code, err.log) -} - -// Implements ABCIError -func (err *sdkError) ABCICode() uint32 { - return err.code -} - -// Implements ABCIError -func (err *sdkError) ABCILog() string { - return err.log -} - -// Implements pkg/errors.causer -func (err *sdkError) Cause() error { - if err.cause != nil { - return err.cause - } - return err -} - -// Creates a cloned *sdkError with specific cause -func (err *sdkError) WithCause(cause error) *sdkError { - copy := *err - copy.cause = cause - return © -} - -//---------------------------------------- - -// HasSameCause returns true if both errors -// have the same cause. -func HasSameCause(err1 error, err2 error) bool { - if err1 != nil || err2 != nil { - panic("HasSomeCause() requires non-nil arguments") - } - return Cause(err1) == Cause(err2) -} - -// Like Cause but stops upon finding an ABCIError. -// If no error in the cause chain is an ABCIError, -// returns nil. -func ABCIErrorCause(err error) ABCIError { - for err != nil { - abciErr, ok := err.(ABCIError) - if ok { - return abciErr - } - cause, ok := err.(causer) - if !ok { - return nil - } - errCause := cause.Cause() - if errCause == nil || errCause == err { - return nil - } - err = errCause - } - return nil -} - -// Identitical to pkg/errors.Cause, except handles .Cause() -// returning itself. -// TODO: Merge https://github.com/pkg/errors/issues/89 and -// delete this. -func Cause(err error) error { - for err != nil { - cause, ok := err.(causer) - if !ok { - return err - } - errCause := cause.Cause() - if errCause == nil || errCause == err { - return err - } - err = errCause - } - return err -} - -type causer interface { - Cause() error -} diff --git a/types/errors.go b/types/errors.go new file mode 100644 index 000000000..4a3e7200e --- /dev/null +++ b/types/errors.go @@ -0,0 +1,165 @@ +package types + +import ( + "fmt" +) + +const ( + // ABCI Response Codes + // Base SDK reserves 0 ~ 99. + CodeInternalError uint32 = 1 + CodeTxParseError = 2 + CodeBadNonce = 3 + CodeUnauthorized = 4 + CodeInsufficientFunds = 5 + CodeUnknownRequest = 6 + CodeUnrecognizedAddress = 7 +) + +// NOTE: Don't stringer this, we'll put better messages in later. +func CodeToDefaultLog(code uint32) string { + switch code { + case CodeInternalError: + return "Internal error" + case CodeTxParseError: + return "Tx parse error" + case CodeBadNonce: + return "Bad nonce" + case CodeUnauthorized: + return "Unauthorized" + case CodeInsufficientFunds: + return "Insufficent funds" + case CodeUnknownRequest: + return "Unknown request" + case CodeUnrecognizedAddress: + return "Unrecognized address" + default: + return fmt.Sprintf("Unknown code %d", code) + } +} + +//-------------------------------------------------------------------------------- +// All errors are created via constructors so as to enable us to hijack them +// and inject stack traces if we really want to. + +func InternalError(log string) Error { + return newError(CodeInternalError, log) +} + +func TxParseError(log string) Error { + return newError(CodeTxParseError, log) +} + +func BadNonce(log string) Error { + return newError(CodeBadNonce, log) +} + +func Unauthorized(log string) Error { + return newError(CodeUnauthorized, log) +} + +func InsufficientFunds(log string) Error { + return newError(CodeInsufficientFunds, log) +} + +func UnknownRequest(log string) Error { + return newError(CodeUnknownRequest, log) +} + +func UnrecognizedAddress(log string) Error { + return newError(CodeUnrecognizedAddress, log) +} + +//---------------------------------------- +// Error & sdkError + +type Error interface { + Error() string + ABCICode() uint32 + ABCILog() string + Trace(msg string) Error + TraceCause(cause error, msg string) Error + Cause() error + Result() Result +} + +func NewError(code uint32, log string) Error { + return newError(code, log) +} + +type traceItem struct { + msg string + filename string + lineno int +} + +type sdkError struct { + code uint32 + log string + cause error + trace []traceItem +} + +func newError(code uint32, log string) *sdkError { + // TODO capture stacktrace if ENV is set. + if log == "" { + log = CodeToDefaultLog(code) + } + return &sdkError{ + code: code, + log: log, + cause: nil, + trace: nil, + } +} + +// Implements ABCIError. +func (err *sdkError) Error() string { + return fmt.Sprintf("Error{%d:%s,%v,%v}", err.code, err.log, err.cause, len(err.trace)) +} + +// Implements ABCIError. +func (err *sdkError) ABCICode() uint32 { + return err.code +} + +// Implements ABCIError. +func (err *sdkError) ABCILog() string { + return err.log +} + +// Add tracing information to log with msg. +func (err *sdkError) Trace(msg string) Error { + // Include file & line number & msg to log. + // Do not include the whole stack trace. + err.trace = append(err.trace, traceItem{ + filename: "todo", // TODO + lineno: -1, // TODO + msg: msg, + }) + return err +} + +// Add tracing information to log with cause and msg. +func (err *sdkError) TraceCause(cause error, msg string) Error { + err.cause = cause + // Include file & line number & cause & msg to log. + // Do not include the whole stack trace. + err.trace = append(err.trace, traceItem{ + filename: "todo", // TODO + lineno: -1, // TODO + msg: msg, + }) + return err +} + +func (err *sdkError) Cause() error { + return err.cause +} + +func (err *sdkError) Result() Result { + return Result{ + Code: err.ABCICode(), + Log: err.ABCILog(), + } +} diff --git a/x/bank/errors.go b/x/bank/errors.go index 49abd54c3..327ca6a0d 100644 --- a/x/bank/errors.go +++ b/x/bank/errors.go @@ -2,9 +2,7 @@ package bank import ( - "fmt" - - "github.com/cosmos/cosmos-sdk/errors" + sdk "github.com/cosmos/cosmos-sdk/types" ) const ( @@ -15,7 +13,8 @@ const ( CodeUnknownAddress uint32 = 104 CodeInsufficientCoins uint32 = 105 CodeInvalidCoins uint32 = 106 - CodeUnknownRequest uint32 = errors.CodeUnknownRequest + CodeInvalidSequence uint32 = 107 + CodeUnknownRequest uint32 = sdk.CodeUnknownRequest ) // NOTE: Don't stringer this, we'll put better messages in later. @@ -33,61 +32,59 @@ func codeToDefaultLog(code uint32) string { return "Insufficient coins" case CodeInvalidCoins: return "Invalid coins" + case CodeInvalidSequence: + return "Invalid sequence" case CodeUnknownRequest: return "Unknown request" default: - return errors.CodeToDefaultLog(code) + return sdk.CodeToDefaultLog(code) } } //---------------------------------------- // Error constructors -func ErrInvalidInput(log string) error { +func ErrInvalidInput(log string) sdk.Error { return newError(CodeInvalidInput, log) } -func ErrInvalidOutput(log string) error { +func ErrNoInputs() sdk.Error { + return newError(CodeInvalidInput, "") +} + +func ErrInvalidOutput(log string) sdk.Error { return newError(CodeInvalidOutput, log) } -func ErrInvalidAddress(log string) error { +func ErrNoOutputs() sdk.Error { + return newError(CodeInvalidOutput, "") +} + +func ErrInvalidSequence(seq int64) sdk.Error { + return newError(CodeInvalidSequence, "") +} + +func ErrInvalidAddress(log string) sdk.Error { return newError(CodeInvalidAddress, log) } -func ErrUnknownAddress(log string) error { +func ErrUnknownAddress(log string) sdk.Error { return newError(CodeUnknownAddress, log) } -func ErrInsufficientCoins(log string) error { +func ErrInsufficientCoins(log string) sdk.Error { return newError(CodeInsufficientCoins, log) } -func ErrInvalidCoins(log string) error { +func ErrInvalidCoins(log string) sdk.Error { return newError(CodeInvalidCoins, log) } -func ErrUnknownRequest(log string) error { +func ErrUnknownRequest(log string) sdk.Error { return newError(CodeUnknownRequest, log) } //---------------------------------------- -// TODO: clean up - -func ErrNoInputs() error { - return fmt.Errorf("No inputs") -} - -func ErrNoOutputs() error { - return fmt.Errorf("No outputs") -} - -func ErrInvalidSequence(seq int64) error { - return fmt.Errorf("Bad sequence %d", seq) -} - -//---------------------------------------- -// Misc func logOrDefaultLog(log string, code uint32) string { if log != "" { @@ -97,7 +94,7 @@ func logOrDefaultLog(log string, code uint32) string { } } -func newError(code uint32, log string) error { +func newError(code uint32, log string) sdk.Error { log = logOrDefaultLog(log, code) - return errors.NewABCIError(code, log) + return sdk.NewError(code, log) }