New error API
This commit is contained in:
parent
85cc4321d4
commit
11cccfaf02
|
@ -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
|
||||
}
|
||||
}
|
210
errors/errors.go
210
errors/errors.go
|
@ -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 = <some causal error>
|
||||
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
|
||||
}
|
|
@ -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(),
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue