cosmos-sdk/types/errors.go

306 lines
7.7 KiB
Go
Raw Normal View History

2018-01-18 00:25:23 -08:00
package types
import (
"fmt"
"strings"
"github.com/cosmos/cosmos-sdk/codec"
cmn "github.com/tendermint/tendermint/libs/common"
abci "github.com/tendermint/tendermint/abci/types"
2018-01-18 00:25:23 -08:00
)
2018-11-16 09:12:24 -08:00
// CodeType - ABCI code identifier within codespace
type CodeType uint32
2018-01-26 06:22:56 -08:00
// CodespaceType - codespace identifier
2018-11-16 09:12:24 -08:00
type CodespaceType string
// IsOK - is everything okay?
2018-11-16 09:12:24 -08:00
func (code CodeType) IsOK() bool {
if code == CodeOK {
2018-01-26 06:22:56 -08:00
return true
}
2018-02-04 16:59:11 -08:00
return false
2018-01-26 06:22:56 -08:00
}
2018-04-18 21:49:24 -07:00
// SDK error codes
2018-01-18 00:25:23 -08:00
const (
// Base error codes
2018-03-17 19:42:54 -07:00
CodeOK CodeType = 0
CodeInternal CodeType = 1
CodeTxDecode CodeType = 2
2018-03-17 19:42:54 -07:00
CodeInvalidSequence CodeType = 3
CodeUnauthorized CodeType = 4
CodeInsufficientFunds CodeType = 5
CodeUnknownRequest CodeType = 6
CodeInvalidAddress CodeType = 7
CodeInvalidPubKey CodeType = 8
CodeUnknownAddress CodeType = 9
CodeInsufficientCoins CodeType = 10
CodeInvalidCoins CodeType = 11
2018-05-07 11:28:53 -07:00
CodeOutOfGas CodeType = 12
CodeMemoTooLarge CodeType = 13
CodeInsufficientFee CodeType = 14
CodeTooManySignatures CodeType = 15
2018-02-13 04:30:51 -08:00
// CodespaceRoot is a codespace for error codes in this file only.
2018-07-10 18:40:24 -07:00
// Notice that 0 is an "unset" codespace, which can be overridden with
// Error.WithDefaultCodespace().
2018-11-16 09:12:24 -08:00
CodespaceUndefined CodespaceType = ""
CodespaceRoot CodespaceType = "sdk"
2018-01-18 00:25:23 -08:00
)
func unknownCodeMsg(code CodeType) string {
return fmt.Sprintf("unknown code %d", code)
}
2018-01-18 00:25:23 -08:00
// NOTE: Don't stringer this, we'll put better messages in later.
2018-01-26 06:22:56 -08:00
func CodeToDefaultMsg(code CodeType) string {
2018-01-18 00:25:23 -08:00
switch code {
2018-01-26 04:19:33 -08:00
case CodeInternal:
return "internal error"
case CodeTxDecode:
return "tx parse error"
2018-03-04 00:15:26 -08:00
case CodeInvalidSequence:
return "invalid sequence"
2018-01-18 00:25:23 -08:00
case CodeUnauthorized:
return "unauthorized"
2018-01-18 00:25:23 -08:00
case CodeInsufficientFunds:
return "insufficient funds"
2018-01-18 00:25:23 -08:00
case CodeUnknownRequest:
return "unknown request"
2018-03-17 19:42:54 -07:00
case CodeInvalidAddress:
return "invalid address"
2018-03-17 11:54:18 -07:00
case CodeInvalidPubKey:
return "invalid pubkey"
2018-03-19 15:31:23 -07:00
case CodeUnknownAddress:
return "unknown address"
2018-03-17 19:42:54 -07:00
case CodeInsufficientCoins:
return "insufficient coins"
2018-03-17 19:42:54 -07:00
case CodeInvalidCoins:
return "invalid coins"
2018-05-07 11:28:53 -07:00
case CodeOutOfGas:
return "out of gas"
case CodeMemoTooLarge:
return "memo too large"
case CodeInsufficientFee:
return "insufficient fee"
case CodeTooManySignatures:
return "maximum numer of signatures exceeded"
2018-01-18 00:25:23 -08:00
default:
return unknownCodeMsg(code)
2018-01-18 00:25:23 -08:00
}
}
//--------------------------------------------------------------------------------
// All errors are created via constructors so as to enable us to hijack them
// and inject stack traces if we really want to.
2018-02-04 16:59:11 -08:00
// nolint
2018-01-26 04:19:33 -08:00
func ErrInternal(msg string) Error {
return newErrorWithRootCodespace(CodeInternal, msg)
2018-01-18 00:25:23 -08:00
}
func ErrTxDecode(msg string) Error {
return newErrorWithRootCodespace(CodeTxDecode, msg)
2018-02-06 19:23:30 -08:00
}
2018-03-04 00:15:26 -08:00
func ErrInvalidSequence(msg string) Error {
return newErrorWithRootCodespace(CodeInvalidSequence, msg)
2018-01-18 00:25:23 -08:00
}
2018-01-26 04:19:33 -08:00
func ErrUnauthorized(msg string) Error {
return newErrorWithRootCodespace(CodeUnauthorized, msg)
2018-01-18 00:25:23 -08:00
}
2018-01-26 04:19:33 -08:00
func ErrInsufficientFunds(msg string) Error {
return newErrorWithRootCodespace(CodeInsufficientFunds, msg)
2018-01-18 00:25:23 -08:00
}
2018-01-26 04:19:33 -08:00
func ErrUnknownRequest(msg string) Error {
return newErrorWithRootCodespace(CodeUnknownRequest, msg)
2018-01-18 00:25:23 -08:00
}
2018-03-17 19:42:54 -07:00
func ErrInvalidAddress(msg string) Error {
return newErrorWithRootCodespace(CodeInvalidAddress, msg)
2018-03-17 19:42:54 -07:00
}
func ErrUnknownAddress(msg string) Error {
return newErrorWithRootCodespace(CodeUnknownAddress, msg)
2018-01-26 04:19:33 -08:00
}
2018-03-17 11:54:18 -07:00
func ErrInvalidPubKey(msg string) Error {
return newErrorWithRootCodespace(CodeInvalidPubKey, msg)
2018-01-26 04:19:33 -08:00
}
2018-03-17 19:42:54 -07:00
func ErrInsufficientCoins(msg string) Error {
return newErrorWithRootCodespace(CodeInsufficientCoins, msg)
2018-03-17 19:42:54 -07:00
}
func ErrInvalidCoins(msg string) Error {
return newErrorWithRootCodespace(CodeInvalidCoins, msg)
2018-03-17 19:42:54 -07:00
}
2018-05-07 11:28:53 -07:00
func ErrOutOfGas(msg string) Error {
return newErrorWithRootCodespace(CodeOutOfGas, msg)
}
func ErrMemoTooLarge(msg string) Error {
return newErrorWithRootCodespace(CodeMemoTooLarge, msg)
}
func ErrInsufficientFee(msg string) Error {
return newErrorWithRootCodespace(CodeInsufficientFee, msg)
}
func ErrTooManySignatures(msg string) Error {
return newErrorWithRootCodespace(CodeTooManySignatures, msg)
}
2018-01-18 00:25:23 -08:00
//----------------------------------------
// Error & sdkError
type cmnError = cmn.Error
2018-02-04 16:59:11 -08:00
// sdk Error type
2018-01-18 00:25:23 -08:00
type Error interface {
// Implements cmn.Error
// Error() string
// Stacktrace() cmn.Error
// Trace(offset int, format string, args ...interface{}) cmn.Error
// Data() interface{}
cmnError
// convenience
TraceSDK(format string, args ...interface{}) Error
// set codespace
WithDefaultCodespace(CodespaceType) Error
Code() CodeType
Codespace() CodespaceType
2018-01-18 00:25:23 -08:00
ABCILog() string
Result() Result
QueryResult() abci.ResponseQuery
2018-01-18 00:25:23 -08:00
}
// NewError - create an error.
func NewError(codespace CodespaceType, code CodeType, format string, args ...interface{}) Error {
return newError(codespace, code, format, args...)
2018-01-18 00:25:23 -08:00
}
func newErrorWithRootCodespace(code CodeType, format string, args ...interface{}) *sdkError {
return newError(CodespaceRoot, code, format, args...)
2018-01-18 00:25:23 -08:00
}
func newError(codespace CodespaceType, code CodeType, format string, args ...interface{}) *sdkError {
if format == "" {
format = CodeToDefaultMsg(code)
2018-01-18 00:25:23 -08:00
}
return &sdkError{
codespace: codespace,
code: code,
cmnError: cmn.NewError(format, args...),
2018-01-18 00:25:23 -08:00
}
}
type sdkError struct {
codespace CodespaceType
code CodeType
cmnError
}
// Implements Error.
func (err *sdkError) WithDefaultCodespace(cs CodespaceType) Error {
codespace := err.codespace
if codespace == CodespaceUndefined {
codespace = cs
}
return &sdkError{
codespace: cs,
code: err.code,
cmnError: err.cmnError,
}
}
// Implements ABCIError.
2018-08-31 15:22:37 -07:00
// nolint: errcheck
func (err *sdkError) TraceSDK(format string, args ...interface{}) Error {
err.Trace(1, format, args...)
return err
}
2018-01-18 00:25:23 -08:00
// Implements ABCIError.
func (err *sdkError) Error() string {
2018-08-22 07:15:45 -07:00
return fmt.Sprintf(`ERROR:
2018-11-16 09:12:24 -08:00
Codespace: %s
2018-08-22 07:15:45 -07:00
Code: %d
Message: %#v
`, err.codespace, err.code, err.cmnError.Error())
2018-01-18 00:25:23 -08:00
}
// Implements Error.
func (err *sdkError) Codespace() CodespaceType {
return err.codespace
}
// Implements Error.
func (err *sdkError) Code() CodeType {
2018-01-18 00:25:23 -08:00
return err.code
}
// Implements ABCIError.
func (err *sdkError) ABCILog() string {
cdc := codec.New()
errMsg := err.cmnError.Error()
2018-08-23 03:02:12 -07:00
jsonErr := humanReadableError{
Codespace: err.codespace,
Code: err.code,
Message: errMsg,
2018-08-23 03:02:12 -07:00
}
bz, er := cdc.MarshalJSON(jsonErr)
2018-08-22 07:15:45 -07:00
if er != nil {
panic(er)
}
stringifiedJSON := string(bz)
return stringifiedJSON
2018-01-18 00:25:23 -08:00
}
func (err *sdkError) Result() Result {
return Result{
2018-11-16 09:12:24 -08:00
Code: err.Code(),
Codespace: err.Codespace(),
Log: err.ABCILog(),
2018-01-18 00:25:23 -08:00
}
}
// QueryResult allows us to return sdk.Error.QueryResult() in query responses
func (err *sdkError) QueryResult() abci.ResponseQuery {
return abci.ResponseQuery{
2018-11-16 09:12:24 -08:00
Code: uint32(err.Code()),
Codespace: string(err.Codespace()),
Log: err.ABCILog(),
}
}
2018-08-22 07:15:45 -07:00
//----------------------------------------
// REST error utilities
// appends a message to the head of the given error
func AppendMsgToErr(msg string, err string) string {
msgIdx := strings.Index(err, "message\":\"")
if msgIdx != -1 {
errMsg := err[msgIdx+len("message\":\"") : len(err)-2]
errMsg = fmt.Sprintf("%s; %s", msg, errMsg)
return fmt.Sprintf("%s%s%s",
err[:msgIdx+len("message\":\"")],
errMsg,
err[len(err)-2:],
)
}
return fmt.Sprintf("%s; %s", msg, err)
}
// returns the index of the message in the ABCI Log
func mustGetMsgIndex(abciLog string) int {
msgIdx := strings.Index(abciLog, "message\":\"")
if msgIdx == -1 {
panic(fmt.Sprintf("invalid error format: %s", abciLog))
}
return msgIdx + len("message\":\"")
}
// parses the error into an object-like struct for exporting
2018-08-23 03:02:12 -07:00
type humanReadableError struct {
2018-08-22 07:15:45 -07:00
Codespace CodespaceType `json:"codespace"`
Code CodeType `json:"code"`
Message string `json:"message"`
}