github.com/Finschia/finschia-sdk@v0.48.1/types/errors/abci.go (about)

     1  package errors
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  
     7  	abci "github.com/tendermint/tendermint/abci/types"
     8  
     9  	ocabci "github.com/Finschia/ostracon/abci/types"
    10  )
    11  
    12  const (
    13  	// SuccessABCICode declares an ABCI response use 0 to signal that the
    14  	// processing was successful and no error is returned.
    15  	SuccessABCICode = 0
    16  
    17  	// All unclassified errors that do not provide an ABCI code are clubbed
    18  	// under an internal error code and a generic message instead of
    19  	// detailed error string.
    20  	internalABCICodespace        = UndefinedCodespace
    21  	internalABCICode      uint32 = 1
    22  )
    23  
    24  // ABCIInfo returns the ABCI error information as consumed by the tendermint
    25  // client. Returned codespace, code, and log message should be used as a ABCI response.
    26  // Any error that does not provide ABCICode information is categorized as error
    27  // with code 1, codespace UndefinedCodespace
    28  // When not running in a debug mode all messages of errors that do not provide
    29  // ABCICode information are replaced with generic "internal error". Errors
    30  // without an ABCICode information as considered internal.
    31  func ABCIInfo(err error, debug bool) (codespace string, code uint32, log string) {
    32  	if errIsNil(err) {
    33  		return "", SuccessABCICode, ""
    34  	}
    35  
    36  	encode := defaultErrEncoder
    37  	if debug {
    38  		encode = debugErrEncoder
    39  	}
    40  
    41  	return abciCodespace(err), abciCode(err), encode(err)
    42  }
    43  
    44  // ResponseCheckTx returns an ABCI ResponseCheckTx object with fields filled in
    45  // from the given error and gas values.
    46  func ResponseCheckTx(err error, gw, gu uint64, debug bool) ocabci.ResponseCheckTx {
    47  	space, code, log := ABCIInfo(err, debug)
    48  	return ocabci.ResponseCheckTx{
    49  		Codespace: space,
    50  		Code:      code,
    51  		Log:       log,
    52  		GasWanted: int64(gw),
    53  		GasUsed:   int64(gu),
    54  	}
    55  }
    56  
    57  // ResponseCheckTxWithEvents returns an ABCI ResponseCheckTx object with fields filled in
    58  // from the given error, gas values and events.
    59  func ResponseCheckTxWithEvents(err error, gw, gu uint64, events []abci.Event, debug bool) ocabci.ResponseCheckTx {
    60  	space, code, log := ABCIInfo(err, debug)
    61  	return ocabci.ResponseCheckTx{
    62  		Codespace: space,
    63  		Code:      code,
    64  		Log:       log,
    65  		GasWanted: int64(gw),
    66  		GasUsed:   int64(gu),
    67  		Events:    events,
    68  	}
    69  }
    70  
    71  // ResponseDeliverTx returns an ABCI ResponseDeliverTx object with fields filled in
    72  // from the given error and gas values.
    73  func ResponseDeliverTx(err error, gw, gu uint64, debug bool) abci.ResponseDeliverTx {
    74  	space, code, log := ABCIInfo(err, debug)
    75  	return abci.ResponseDeliverTx{
    76  		Codespace: space,
    77  		Code:      code,
    78  		Log:       log,
    79  		GasWanted: int64(gw),
    80  		GasUsed:   int64(gu),
    81  	}
    82  }
    83  
    84  // ResponseDeliverTxWithEvents returns an ABCI ResponseDeliverTx object with fields filled in
    85  // from the given error, gas values and events.
    86  func ResponseDeliverTxWithEvents(err error, gw, gu uint64, events []abci.Event, debug bool) abci.ResponseDeliverTx {
    87  	space, code, log := ABCIInfo(err, debug)
    88  	return abci.ResponseDeliverTx{
    89  		Codespace: space,
    90  		Code:      code,
    91  		Log:       log,
    92  		GasWanted: int64(gw),
    93  		GasUsed:   int64(gu),
    94  		Events:    events,
    95  	}
    96  }
    97  
    98  // QueryResult returns a ResponseQuery from an error. It will try to parse ABCI
    99  // info from the error.
   100  func QueryResult(err error) abci.ResponseQuery {
   101  	space, code, log := ABCIInfo(err, false)
   102  	return abci.ResponseQuery{
   103  		Codespace: space,
   104  		Code:      code,
   105  		Log:       log,
   106  	}
   107  }
   108  
   109  // QueryResultWithDebug returns a ResponseQuery from an error. It will try to parse ABCI
   110  // info from the error. It will use debugErrEncoder if debug parameter is true.
   111  // Starting from v0.46, this function will be removed, and be replaced by `QueryResult`.
   112  func QueryResultWithDebug(err error, debug bool) abci.ResponseQuery {
   113  	space, code, log := ABCIInfo(err, debug)
   114  	return abci.ResponseQuery{
   115  		Codespace: space,
   116  		Code:      code,
   117  		Log:       log,
   118  	}
   119  }
   120  
   121  // The debugErrEncoder encodes the error with a stacktrace.
   122  func debugErrEncoder(err error) string {
   123  	return fmt.Sprintf("%+v", err)
   124  }
   125  
   126  func defaultErrEncoder(err error) string {
   127  	return err.Error()
   128  }
   129  
   130  type coder interface {
   131  	ABCICode() uint32
   132  }
   133  
   134  // abciCode tests if given error contains an ABCI code and returns the value of
   135  // it if available. This function is testing for the causer interface as well
   136  // and unwraps the error.
   137  func abciCode(err error) uint32 {
   138  	if errIsNil(err) {
   139  		return SuccessABCICode
   140  	}
   141  
   142  	for {
   143  		if c, ok := err.(coder); ok {
   144  			return c.ABCICode()
   145  		}
   146  
   147  		if c, ok := err.(causer); ok {
   148  			err = c.Cause()
   149  		} else {
   150  			return internalABCICode
   151  		}
   152  	}
   153  }
   154  
   155  type codespacer interface {
   156  	Codespace() string
   157  }
   158  
   159  // abciCodespace tests if given error contains a codespace and returns the value of
   160  // it if available. This function is testing for the causer interface as well
   161  // and unwraps the error.
   162  func abciCodespace(err error) string {
   163  	if errIsNil(err) {
   164  		return ""
   165  	}
   166  
   167  	for {
   168  		if c, ok := err.(codespacer); ok {
   169  			return c.Codespace()
   170  		}
   171  
   172  		if c, ok := err.(causer); ok {
   173  			err = c.Cause()
   174  		} else {
   175  			return internalABCICodespace
   176  		}
   177  	}
   178  }
   179  
   180  // errIsNil returns true if value represented by the given error is nil.
   181  //
   182  // Most of the time a simple == check is enough. There is a very narrowed
   183  // spectrum of cases (mostly in tests) where a more sophisticated check is
   184  // required.
   185  func errIsNil(err error) bool {
   186  	if err == nil {
   187  		return true
   188  	}
   189  	if val := reflect.ValueOf(err); val.Kind() == reflect.Ptr {
   190  		return val.IsNil()
   191  	}
   192  	return false
   193  }