dcrd/wire/error.go
Dave Collins f69247ff24
build: Add errorlint linter.
This adds the errorlint linter to the list of linters and addresses a
few false positives it complains about.
2023-08-28 14:53:30 -05:00

253 lines
8.3 KiB
Go

// Copyright (c) 2013-2015 The btcsuite developers
// Copyright (c) 2015-2023 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package wire
import (
"fmt"
)
// ErrorCode describes a kind of message error.
type ErrorCode int
// These constants are used to identify a specific Error.
const (
// ErrNonCanonicalVarInt is returned when a variable length integer is
// not canonically encoded.
ErrNonCanonicalVarInt ErrorCode = iota
// ErrVarStringTooLong is returned when a variable string exceeds the
// maximum message size allowed.
ErrVarStringTooLong
// ErrVarBytesTooLong is returned when a variable-length byte slice
// exceeds the maximum message size allowed.
ErrVarBytesTooLong
// ErrCmdTooLong is returned when a command exceeds the maximum command
// size allowed.
ErrCmdTooLong
// ErrPayloadTooLarge is returned when a payload exceeds the maximum
// payload size allowed.
ErrPayloadTooLarge
// ErrWrongNetwork is returned when a message intended for a different
// network is received.
ErrWrongNetwork
// ErrMalformedCmd is returned when a malformed command is received.
ErrMalformedCmd
// ErrUnknownCmd is returned when an unknown command is received.
ErrUnknownCmd
// ErrPayloadChecksum is returned when a message with an invalid checksum
// is received.
ErrPayloadChecksum
// ErrTooManyAddrs is returned when an address list exceeds the maximum
// allowed.
ErrTooManyAddrs
// ErrTooManyTxs is returned when a the number of transactions exceed the
// maximum allowed.
ErrTooManyTxs
// ErrMsgInvalidForPVer is returned when a message is invalid for
// the expected protocol version.
ErrMsgInvalidForPVer
// ErrFilterTooLarge is returned when a committed filter exceeds
// the maximum size allowed.
ErrFilterTooLarge
// ErrTooManyProofs is returned when the number of proof hashes
// exceeds the maximum allowed.
ErrTooManyProofs
// ErrTooManyFilterTypes is returned when the number of filter types
// exceeds the maximum allowed.
ErrTooManyFilterTypes
// ErrTooManyLocators is returned when the number of block locators exceed
// the maximum allowed.
ErrTooManyLocators
// ErrTooManyVectors is returned when the number of inventory vectors
// exceed the maximum allowed.
ErrTooManyVectors
// ErrTooManyHeaders is returned when the number of block headers exceed
// the maximum allowed.
ErrTooManyHeaders
// ErrHeaderContainsTxs is returned when a header's transactions
// count is greater than zero.
ErrHeaderContainsTxs
// ErrTooManyVotes is returned when the number of vote hashes exceed the
// maximum allowed.
ErrTooManyVotes
// ErrTooManyBlocks is returned when the number of block hashes exceed the
// maximum allowed.
ErrTooManyBlocks
// ErrMismatchedWitnessCount returned when a transaction has unequal witness
// and prefix txin quantities.
ErrMismatchedWitnessCount
// ErrUnknownTxType is returned when a transaction type is unknown.
ErrUnknownTxType
// ErrReadInPrefixFromWitnessOnlyTx is returned when attempting to read a
// transaction input prefix from a witness only transaction.
ErrReadInPrefixFromWitnessOnlyTx
// ErrInvalidMsg is returned for an invalid message structure.
ErrInvalidMsg
// ErrUserAgentTooLong is returned when the provided user agent exceeds
// the maximum allowed.
ErrUserAgentTooLong
// ErrTooManyFilterHeaders is returned when the number of committed filter
// headers exceed the maximum allowed.
ErrTooManyFilterHeaders
// ErrMalformedStrictString is returned when a string that has strict
// formatting requirements does not conform to the requirements.
ErrMalformedStrictString
// ErrTooManyInitialStateTypes is returned when the number of initial
// state types is larger than the maximum allowed by the protocol.
ErrTooManyInitStateTypes
// ErrInitialStateTypeTooLong is returned when an individual initial
// state type is longer than allowed by the protocol.
ErrInitStateTypeTooLong
// ErrTooManyTSpends is returned when the number of tspend hashes
// exceeds the maximum allowed.
ErrTooManyTSpends
)
// Map of ErrorCode values back to their constant names for pretty printing.
var errorCodeStrings = map[ErrorCode]string{
ErrNonCanonicalVarInt: "ErrNonCanonicalVarInt",
ErrVarStringTooLong: "ErrVarStringTooLong",
ErrVarBytesTooLong: "ErrVarBytesTooLong",
ErrCmdTooLong: "ErrCmdTooLong",
ErrPayloadTooLarge: "ErrPayloadTooLarge",
ErrWrongNetwork: "ErrWrongNetwork",
ErrMalformedCmd: "ErrMalformedCmd",
ErrUnknownCmd: "ErrUnknownCmd",
ErrPayloadChecksum: "ErrPayloadChecksum",
ErrTooManyAddrs: "ErrTooManyAddrs",
ErrTooManyTxs: "ErrTooManyTxs",
ErrMsgInvalidForPVer: "ErrMsgInvalidForPVer",
ErrFilterTooLarge: "ErrFilterTooLarge",
ErrTooManyProofs: "ErrTooManyProofs",
ErrTooManyFilterTypes: "ErrTooManyFilterTypes",
ErrTooManyLocators: "ErrTooManyLocators",
ErrTooManyVectors: "ErrTooManyVectors",
ErrTooManyHeaders: "ErrTooManyHeaders",
ErrHeaderContainsTxs: "ErrHeaderContainsTxs",
ErrTooManyVotes: "ErrTooManyVotes",
ErrTooManyBlocks: "ErrTooManyBlocks",
ErrMismatchedWitnessCount: "ErrMismatchedWitnessCount",
ErrUnknownTxType: "ErrUnknownTxType",
ErrReadInPrefixFromWitnessOnlyTx: "ErrReadInPrefixFromWitnessOnlyTx",
ErrInvalidMsg: "ErrInvalidMsg",
ErrUserAgentTooLong: "ErrUserAgentTooLong",
ErrTooManyFilterHeaders: "ErrTooManyFilterHeaders",
ErrMalformedStrictString: "ErrMalformedStrictString",
ErrTooManyInitStateTypes: "ErrTooManyInitStateTypes",
ErrInitStateTypeTooLong: "ErrInitStateTypeTooLong",
ErrTooManyTSpends: "ErrTooManyTSpends",
}
// String returns the ErrorCode as a human-readable name.
func (e ErrorCode) String() string {
if s := errorCodeStrings[e]; s != "" {
return s
}
return fmt.Sprintf("Unknown ErrorCode (%d)", int(e))
}
// Error implements the error interface.
func (e ErrorCode) Error() string {
return e.String()
}
// Is implements the interface to work with the standard library's errors.Is.
//
// It returns true in the following cases:
// - The target is a *MessageError and the error codes match
// - The target is an ErrorCode and it the error codes match
func (e ErrorCode) Is(target error) bool {
// nolint: errorlint
switch target := target.(type) {
case *MessageError:
return e == target.ErrorCode
case ErrorCode:
return e == target
}
return false
}
// MessageError describes an issue with a message.
// An example of some potential issues are messages from the wrong decred
// network, invalid commands, mismatched checksums, and exceeding max payloads.
//
// This provides a mechanism for the caller to type assert the error to
// differentiate between general io errors such as io.EOF and issues that
// resulted from malformed messages.
type MessageError struct {
Func string // Function name
ErrorCode ErrorCode // Describes the kind of error
Description string // Human readable description of the issue
}
// Error satisfies the error interface and prints human-readable errors.
func (m MessageError) Error() string {
if m.Func != "" {
return fmt.Sprintf("%v: %v", m.Func, m.Description)
}
return m.Description
}
// messageError creates an Error given a set of arguments.
func messageError(funcName string, c ErrorCode, desc string) *MessageError {
return &MessageError{Func: funcName, ErrorCode: c, Description: desc}
}
// Is implements the interface to work with the standard library's errors.Is.
//
// It returns true in the following cases:
// - The target is a *MessageError and the error codes match
// - The target is an ErrorCode and it the error codes match
func (m *MessageError) Is(target error) bool {
// nolint: errorlint
switch target := target.(type) {
case *MessageError:
return m.ErrorCode == target.ErrorCode
case ErrorCode:
return target == m.ErrorCode
}
return false
}
// Unwrap returns the underlying wrapped error if it is not ErrOther.
// Unwrap returns the ErrorCode. Else, it returns nil.
func (m *MessageError) Unwrap() error {
return m.ErrorCode
}