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 }