decred.org/dcrwallet/v3@v3.1.0/errors/errors.go (about) 1 // Copyright (c) 2018-2019 The Decred developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 // API originally inspired by https://commandcenter.blogspot.com/2017/12/error-handling-in-upspin.html. 6 // Currently, dcrwallet is in the process of converting to the new Go 1.13 error 7 // wrapping features. 8 9 /* 10 Package errors provides error creation and matching for all wallet systems. It 11 is imported as errors and takes over the roll of the standard library errors 12 package. 13 */ 14 package errors 15 16 import ( 17 "errors" 18 "fmt" 19 "runtime/debug" 20 "strings" 21 ) 22 23 // Separator is inserted between nested errors when formatting as strings. The 24 // default separator produces easily readable multiline errors. Separator may 25 // be modified at init time to create error strings appropriate for logging 26 // errors on a single line. 27 var Separator = ":\n\t" 28 29 // Error describes an error condition raised within the wallet process. Errors 30 // may optionally provide details regarding the operation and class of error for 31 // assistance in debugging and runtime matching of errors. 32 type Error struct { 33 Op Op 34 Kind Kind 35 Err error 36 37 stack []byte 38 bottom bool 39 } 40 41 // Op describes the operation, method, or RPC in which an error condition was 42 // raised. 43 type Op string 44 45 // Opf returns a formatted Op. 46 func Opf(format string, a ...interface{}) Op { 47 return Op(fmt.Sprintf(format, a...)) 48 } 49 50 // Kind describes the class of error. 51 type Kind int 52 53 // Error kinds. 54 const ( 55 Other Kind = iota // Unclassified error -- does not appear in error strings 56 Bug // Error is known to be a result of our bug 57 Invalid // Invalid operation 58 Permission // Permission denied 59 IO // I/O error 60 Exist // Item already exists 61 NotExist // Item does not exist 62 Encoding // Invalid encoding 63 Crypto // Encryption or decryption error 64 Locked // Wallet is locked 65 Passphrase // Invalid passphrase 66 Seed // Invalid seed 67 WatchingOnly // Missing private keys 68 InsufficientBalance // Insufficient balance to create transaction (perhaps due to UTXO selection requirements) 69 ScriptFailure // Transaction scripts do not execute (usually due to missing sigs) 70 Policy // Transaction rejected by wallet policy 71 Consensus // Consensus violation 72 DoubleSpend // Transaction is a double spend 73 Protocol // Protocol violation 74 NoPeers // Decred network is unreachable due to lack of peers or dcrd RPC connections 75 Deployment // Inactive consensus deployment 76 ) 77 78 func (k Kind) String() string { 79 switch k { 80 case Other: 81 return "unclassified error" 82 case Bug: 83 return "internal wallet error" 84 case Invalid: 85 return "invalid operation" 86 case Permission: 87 return "permission denied" 88 case IO: 89 return "I/O error" 90 case Exist: 91 return "item already exists" 92 case NotExist: 93 return "item does not exist" 94 case Encoding: 95 return "invalid encoding" 96 case Crypto: 97 return "encryption/decryption error" 98 case Locked: 99 return "wallet locked" 100 case Passphrase: 101 return "invalid passphrase" 102 case Seed: 103 return "invalid seed" 104 case WatchingOnly: 105 return "watching only wallet" 106 case InsufficientBalance: 107 return "insufficient balance" 108 case ScriptFailure: 109 return "transaction script fails to execute" 110 case Policy: 111 return "policy violation" 112 case Consensus: 113 return "consensus violation" 114 case DoubleSpend: 115 return "double spend" 116 case Protocol: 117 return "protocol violation" 118 case NoPeers: 119 return "Decred network is unreachable" 120 case Deployment: 121 return "inactive deployment" 122 default: 123 return "unknown error kind" 124 } 125 } 126 127 func (k Kind) Error() string { 128 return k.String() 129 } 130 131 // As implements the interface to work with the standard library's errors.As. 132 // If k is Other, this always returns false and target is not assigned. 133 // If target points to an *Error (i.e. target has type **Error), target is 134 // assigned an *Error using k as its Kind. 135 // If target points to a Kind, target is assigned the kind and As returns true. 136 // Else, target is not assinged and As returns false. 137 func (k Kind) As(target interface{}) bool { 138 if k == Other { 139 return false 140 } 141 switch target := target.(type) { 142 case **Error: 143 *target = &Error{Kind: k} 144 return true 145 case *Kind: 146 *target = k 147 return true 148 } 149 return false 150 } 151 152 // New creates a simple error from a string. New is identical to "errors".New 153 // from the standard library. 154 func New(text string) error { 155 return errors.New(text) 156 } 157 158 // Errorf wraps fmt.Errorf as a convenience for creating formatted error 159 // strings. 160 func Errorf(format string, args ...interface{}) error { 161 return fmt.Errorf(format, args...) 162 } 163 164 // E creates an *Error from one or more arguments. 165 // 166 // Each argument type is inspected when constructing the error. If multiple 167 // args of similar type are passed, the final arg is recorded. The following 168 // types are recognized: 169 // 170 // errors.Op 171 // The operation, method, or RPC which was invoked. 172 // errors.Kind 173 // The class of error. 174 // string 175 // Description of the error condition. String types populate the 176 // Err field and overwrite, and are overwritten by, other arguments 177 // which implement the error interface. 178 // error 179 // The underlying error. If the error is an *Error, the Op and Kind 180 // will be promoted to the newly created error if not set to another 181 // value in the args. 182 // 183 // If another *Error is passed as an argument and no other arguments differ from 184 // the wrapped error, instead of wrapping the error, the errors are collapsed 185 // and fields of the passed *Error are promoted to the returned error. 186 // 187 // Panics if no arguments are passed. 188 func E(args ...interface{}) error { 189 if len(args) == 0 { 190 panic("errors.E: no args") 191 } 192 193 var e Error 194 e.bottom = true 195 var prev *Error 196 for _, arg := range args { 197 switch arg := arg.(type) { 198 case Op: 199 e.Op = arg 200 case Kind: 201 e.Kind = arg 202 case string: 203 e.Err = New(arg) 204 e.bottom = true 205 case *Error: 206 prev = arg 207 if e.Kind == 0 { 208 e.Kind = arg.Kind 209 } 210 e.Err = arg 211 e.bottom = false 212 case error: 213 e.Err = arg 214 e.bottom = false 215 } 216 } 217 218 // Promote the Op and Kind of the nested Error to the newly created error, 219 // if these fields were not part of the args. This improves matching 220 // capabilities as well as improving the order of these fields in the 221 // formatted error. 222 if e.Err == prev && prev != nil { 223 if e.Op == "" { 224 e.Op = prev.Op 225 } 226 if e.Kind == 0 { 227 e.Kind = prev.Kind 228 } 229 230 // Remove the previous error from error chain if it does not have any 231 // unique fields. 232 if (prev.Op == "" || e.Op == prev.Op) && (prev.Kind == 0 || e.Kind == prev.Kind) { 233 e.Err = prev.Err 234 e.bottom = prev.bottom 235 if e.stack == nil { 236 e.stack = prev.stack 237 } 238 } 239 } 240 241 return &e 242 } 243 244 // WithStack is identical to E but includes a stacktrace with the error. Stack 245 // traces do not appear in formatted error strings and are not compared when 246 // matching errors. Stack traces are extracted from errors using Stacks. 247 func WithStack(args ...interface{}) error { 248 err := E(args...).(*Error) 249 err.stack = debug.Stack() 250 return err 251 } 252 253 func (e *Error) Error() string { 254 var b strings.Builder 255 256 // Record the last added fields to the string to avoid duplication. 257 var last Error 258 259 for { 260 pad := false // whether to pad/separate next field 261 if e.Op != "" && e.Op != last.Op { 262 b.WriteString(string(e.Op)) 263 pad = true 264 last.Op = e.Op 265 } 266 if e.Kind != 0 && e.Kind != last.Kind { 267 if pad { 268 b.WriteString(": ") 269 } 270 b.WriteString(e.Kind.String()) 271 pad = true 272 last.Kind = e.Kind 273 } 274 if e.Err == nil { 275 break 276 } 277 if err, ok := e.Err.(*Error); ok { 278 if pad { 279 b.WriteString(Separator) 280 } 281 e = err 282 continue 283 } 284 if pad { 285 b.WriteString(": ") 286 } 287 b.WriteString(e.Err.Error()) 288 break 289 } 290 291 s := b.String() 292 if s == "" { 293 return Other.String() 294 } 295 return s 296 } 297 298 // Unwrap returns the underlying wrapped error if it is not nil. 299 // Otherwise, if the Kind is not Other, Unwrap returns the Kind. 300 // Else, it returns nil. 301 func (e *Error) Unwrap() error { 302 if e.Err != nil { 303 return e.Err 304 } 305 if e.Kind != Other { 306 return e.Kind 307 } 308 return nil 309 } 310 311 // As implements the interface to work with the standard library's errors.As. 312 // If target points to an *Error (i.e. target has type **Error), target is 313 // assigned e and As returns true. 314 // If target points to a Kind and e's Kind is not Other, target is assigned 315 // the kind and As returns true. 316 // Else, target is not assinged and As returns false. 317 func (e *Error) As(target interface{}) bool { 318 switch target := target.(type) { 319 case **Error: 320 *target = e 321 return true 322 case *Kind: 323 if e.Kind != Other { 324 *target = e.Kind 325 return true 326 } 327 } 328 return false 329 } 330 331 // Is implements the interface to work with the standard library's errors.Is. 332 // If target is an *Error, Is returns true if every top-level and wrapped 333 // non-zero fields of target are equal to the same fields of e. 334 // If target is a Kind, Is returns true if the Kinds match and are nonzero. 335 // Else, Is returns false. 336 func (e *Error) Is(target error) bool { 337 switch target := target.(type) { 338 case *Error: 339 return match(target, e) 340 case Kind: 341 return e.Kind != Other && e.Kind == target 342 } 343 return false 344 } 345 346 // Is returns whether err equals or wraps target. 347 func Is(err, target error) bool { 348 return errors.Is(err, target) 349 } 350 351 // As attempts to assign the error pointed to by target with the first error in 352 // err's error chain with a compatible type. Returns true if target is 353 // assigned. 354 func As(err error, target interface{}) bool { 355 return errors.As(err, target) 356 } 357 358 func match(err1, err2 error) bool { 359 e1, ok := err1.(*Error) 360 if !ok { 361 return false 362 } 363 e2, ok := err2.(*Error) 364 if !ok { 365 return false 366 } 367 368 if e1.Op != "" && e1.Op != e2.Op { 369 return false 370 } 371 if e1.Kind != 0 && e1.Kind != e2.Kind { 372 return false 373 } 374 if e1.Err == nil { 375 return true 376 } 377 if e1.Err == e2.Err { 378 return true 379 } 380 if _, ok := e1.Err.(*Error); ok { 381 return match(e1.Err, e2.Err) 382 } 383 // Although errors do not cross the process boundary, comparing error 384 // strings is performed to compare formatted errors which would have 385 // different allocations. 386 return e1.Err.Error() == e2.Err.Error() 387 } 388 389 // Cause returns the most deeply-nested error from an error chain. 390 // Cause never returns nil unless the argument is nil. 391 func Cause(err error) error { 392 for { 393 wrapper, ok := err.(interface{ Unwrap() error }) 394 if !ok { 395 return err 396 } 397 e := wrapper.Unwrap() 398 if e == nil { 399 return err 400 } 401 err = e 402 } 403 } 404 405 // Stacks extracts all stacktraces from err, sorted from top-most to bottom-most 406 // error. 407 func Stacks(err error) [][]byte { 408 var stacks [][]byte 409 e, _ := err.(*Error) 410 for e != nil { 411 if e.stack != nil { 412 stacks = append(stacks, e.stack) 413 } 414 e, _ = e.Err.(*Error) 415 } 416 return stacks 417 }