Skip to content

Commit

Permalink
internal/ticketdb: update error types.
Browse files Browse the repository at this point in the history
This updates the ticketdb error types to leverage
go 1.13 errors.Is/As functionality as well as
conform to the error infrastructure best practices.
  • Loading branch information
dnldd authored and davecgh committed Dec 16, 2020
1 parent 57ffde8 commit e4e085c
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 125 deletions.
64 changes: 18 additions & 46 deletions blockchain/stake/internal/ticketdb/chainio_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,28 +107,21 @@ func TestDbInfoDeserializeErrors(t *testing.T) {
tests := []struct {
name string
serialized []byte
errCode ErrorCode
err error
}{
{
name: "short read",
serialized: hexToBytes("0000"),
errCode: ErrDatabaseInfoShortRead,
err: ErrDatabaseInfoShortRead,
},
}

var ticketDBErr DBError
for _, test := range tests {
// Ensure the expected error type is returned.
_, err := deserializeDatabaseInfo(test.serialized)
if !errors.As(err, &ticketDBErr) {
t.Errorf("couldn't convert deserializeDatabaseInfo error "+
"to ticket db error (err: %v)", err)
continue
}
if ticketDBErr.GetCode() != test.errCode {
if !errors.Is(err, test.err) {
t.Errorf("deserializeDatabaseInfo (%s): expected error type "+
"does not match - got %v, want %v", test.name,
ticketDBErr.ErrorCode, test.errCode)
"does not match - got %v, want %v", test.name, err, test.err)
continue
}
}
Expand Down Expand Up @@ -200,28 +193,21 @@ func TestBestChainStateDeserializeErrors(t *testing.T) {
tests := []struct {
name string
serialized []byte
errCode ErrorCode
err error
}{
{
name: "short read",
serialized: hexToBytes("0000"),
errCode: ErrChainStateShortRead,
err: ErrChainStateShortRead,
},
}

var ticketDBErr DBError
for _, test := range tests {
// Ensure the expected error type is returned.
_, err := deserializeBestChainState(test.serialized)
if !errors.As(err, &ticketDBErr) {
t.Errorf("couldn't convert deserializeBestChainState error "+
"to ticket db error (err: %v)", err)
continue
}
if ticketDBErr.GetCode() != test.errCode {
if !errors.Is(err, test.err) {
t.Errorf("deserializeBestChainState (%s): expected error type "+
"does not match - got %v, want %v", test.name,
ticketDBErr.ErrorCode, test.errCode)
"does not match - got %v, want %v", test.name, err, test.err)
continue
}
}
Expand Down Expand Up @@ -293,33 +279,26 @@ func TestBlockUndoDataDeserializingErrors(t *testing.T) {
tests := []struct {
name string
serialized []byte
errCode ErrorCode
err error
}{
{
name: "short read",
serialized: hexToBytes("00"),
errCode: ErrUndoDataShortRead,
err: ErrUndoDataShortRead,
},
{
name: "bad size",
serialized: hexToBytes("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
errCode: ErrUndoDataCorrupt,
err: ErrUndoDataCorrupt,
},
}

var ticketDBErr DBError
for _, test := range tests {
// Ensure the expected error type is returned.
_, err := deserializeBlockUndoData(test.serialized)
if !errors.As(err, &ticketDBErr) {
t.Errorf("couldn't convert deserializeBlockUndoData error "+
"to ticket db error (err: %v)", err)
continue
}
if ticketDBErr.GetCode() != test.errCode {
if !errors.Is(err, test.err) {
t.Errorf("deserializeBlockUndoData (%s): expected error type "+
"does not match - got %v, want %v", test.name,
ticketDBErr.ErrorCode, test.errCode)
"does not match - got %v, want %v", test.name, err, test.err)
continue
}
}
Expand Down Expand Up @@ -382,33 +361,26 @@ func TestTicketHashesDeserializingErrors(t *testing.T) {
tests := []struct {
name string
serialized []byte
errCode ErrorCode
err error
}{
{
name: "short read",
serialized: hexToBytes("00"),
errCode: ErrTicketHashesShortRead,
err: ErrTicketHashesShortRead,
},
{
name: "bad size",
serialized: hexToBytes("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
errCode: ErrTicketHashesCorrupt,
err: ErrTicketHashesCorrupt,
},
}

var ticketDBErr DBError
for _, test := range tests {
// Ensure the expected error type is returned.
_, err := deserializeTicketHashes(test.serialized)
if !errors.As(err, &ticketDBErr) {
t.Errorf("couldn't convert deserializeTicketHashes error "+
"to ticket db error (err: %v)", err)
continue
}
if ticketDBErr.GetCode() != test.errCode {
if !errors.Is(err, test.err) {
t.Errorf("deserializeTicketHashes (%s): expected error type "+
"does not match - got %v, want %v", test.name,
ticketDBErr.ErrorCode, test.errCode)
"does not match - got %v, want %v", test.name, err, test.err)
continue
}
}
Expand Down
75 changes: 28 additions & 47 deletions blockchain/stake/internal/ticketdb/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,92 +4,73 @@

package ticketdb

import (
"fmt"
)

// ErrorCode identifies a kind of error.
type ErrorCode int
// ErrorKind identifies a kind of error. It has full support for errors.Is
// and errors.As, so the caller can directly check against an error kind
// when determining the reason for an error.
type ErrorKind string

// These constants are used to identify a specific RuleError.
// These constants are used to identify a specific DBError.
const (
// ErrUndoDataShortRead indicates that the given undo serialized data
// was took small.
ErrUndoDataShortRead = iota
ErrUndoDataShortRead = ErrorKind("ErrUndoDataShortRead")

// ErrUndoDataNoEntries indicates that the data for undoing ticket data
// in a serialized entry was corrupt.
ErrUndoDataCorrupt
ErrUndoDataCorrupt = ErrorKind("ErrUndoDataCorrupt")

// ErrTicketHashesShortRead indicates that the given ticket hashes
// serialized data was took small.
ErrTicketHashesShortRead
ErrTicketHashesShortRead = ErrorKind("ErrTicketHashesShortRead")

// ErrTicketHashesCorrupt indicates that the data for ticket hashes
// in a serialized entry was corrupt.
ErrTicketHashesCorrupt
ErrTicketHashesCorrupt = ErrorKind("ErrTicketHashesCorrupt")

// ErrUninitializedBucket indicates that a database bucket was not
// initialized and therefore could not be written to or read from.
ErrUninitializedBucket
ErrUninitializedBucket = ErrorKind("ErrUninitializedBucket")

// ErrMissingKey indicates that a key was not found in a bucket.
ErrMissingKey
ErrMissingKey = ErrorKind("ErrMissingKey")

// ErrChainStateShortRead indicates that the given chain state data
// was too small.
ErrChainStateShortRead
ErrChainStateShortRead = ErrorKind("ErrChainStateShortRead")

// ErrDatabaseInfoShortRead indicates that the given database information
// was too small.
ErrDatabaseInfoShortRead
ErrDatabaseInfoShortRead = ErrorKind("ErrDatabaseInfoShortRead")

// ErrLoadAllTickets indicates that there was an error loading the tickets
// from the database, presumably at startup.
ErrLoadAllTickets
ErrLoadAllTickets = ErrorKind("ErrLoadAllTickets")
)

// Map of ErrorCode values back to their constant names for pretty printing.
var errorCodeStrings = map[ErrorCode]string{
ErrUndoDataShortRead: "ErrUndoDataShortRead",
ErrUndoDataCorrupt: "ErrUndoDataCorrupt",
ErrTicketHashesShortRead: "ErrTicketHashesShortRead",
ErrTicketHashesCorrupt: "ErrTicketHashesCorrupt",
ErrUninitializedBucket: "ErrUninitializedBucket",
ErrMissingKey: "ErrMissingKey",
ErrChainStateShortRead: "ErrChainStateShortRead",
ErrDatabaseInfoShortRead: "ErrDatabaseInfoShortRead",
ErrLoadAllTickets: "ErrLoadAllTickets",
}

// 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 satisfies the error interface and prints human-readable errors.
func (e ErrorKind) Error() string {
return string(e)
}

// DBError identifies an error in the stake database for tickets.
// The caller can use type assertions to determine if a failure was
// specifically due to a rule violation and access the ErrorCode field to
// ascertain the specific reason for the rule violation.
// DBError identifies an error related to the stake database for tickets. It
// has full support for errors.Is and errors.As, so the caller can ascertain
// the specific reason for the error by checking the underlying error.
type DBError struct {
ErrorCode ErrorCode // Describes the kind of error
Description string // Human readable description of the issue
Description string
Err error
}

// Error satisfies the error interface and prints human-readable errors.
func (e DBError) Error() string {
return e.Description
}

// GetCode satisfies the error interface and prints human-readable errors.
func (e DBError) GetCode() ErrorCode {
return e.ErrorCode
// Unwrap returns the underlying wrapped error.
func (e DBError) Unwrap() error {
return e.Err
}

// DBError creates an DBError given a set of arguments.
func ticketDBError(c ErrorCode, desc string) DBError {
return DBError{ErrorCode: c, Description: desc}
// ticketDBError creates an DBError given a set of arguments.
func ticketDBError(kind ErrorKind, desc string) DBError {
return DBError{Err: kind, Description: desc}
}
Loading

0 comments on commit e4e085c

Please sign in to comment.