Skip to content

Commit

Permalink
multi: update database error types.
Browse files Browse the repository at this point in the history
This updates the database error types to leverage
go 1.13 errors.Is/As functionality as well as confirm
to the error infrastructure best practices.
  • Loading branch information
dnldd committed Jul 14, 2020
1 parent 5616620 commit ebe1cf9
Show file tree
Hide file tree
Showing 20 changed files with 363 additions and 401 deletions.
46 changes: 15 additions & 31 deletions blockchain/chainio.go
Original file line number Diff line number Diff line change
Expand Up @@ -793,12 +793,9 @@ func dbFetchSpendJournalEntry(dbTx database.Tx, block *dcrutil.Block) ([]spentTx
// Ensure any deserialization errors are returned as database
// corruption errors.
if isDeserializeErr(err) {
return nil, database.Error{
ErrorCode: database.ErrCorruption,
Description: fmt.Sprintf("corrupt spend "+
"information for %v: %v", block.Hash(),
err),
}
str := fmt.Sprintf("corrupt spend information for %v: %v",
block.Hash(), err)
return nil, database.MakeError(database.ErrCorruption, str)
}

return nil, err
Expand Down Expand Up @@ -1164,11 +1161,8 @@ func dbFetchUtxoEntry(dbTx database.Tx, hash *chainhash.Hash) (*UtxoEntry, error
// Ensure any deserialization errors are returned as database
// corruption errors.
if isDeserializeErr(err) {
return nil, database.Error{
ErrorCode: database.ErrCorruption,
Description: fmt.Sprintf("corrupt utxo entry "+
"for %v: %v", hash, err),
}
str := fmt.Sprintf("corrupt utxo entry for %v: %v", hash, err)
return nil, database.MakeError(database.ErrCorruption, str)
}

return nil, err
Expand Down Expand Up @@ -1211,11 +1205,8 @@ func dbFetchUtxoStats(dbTx database.Tx) (*UtxoStats, error) {
// Ensure any deserialization errors are returned as database
// corruption errors.
if isDeserializeErr(err) {
return nil, database.Error{
ErrorCode: database.ErrCorruption,
Description: fmt.Sprintf("corrupt utxo entry "+
"for %v: %v", hash, err),
}
str := fmt.Sprintf("corrupt utxo entry for %v: %v", hash, err)
return nil, database.MakeError(database.ErrCorruption, str)
}

return nil, err
Expand Down Expand Up @@ -1312,11 +1303,8 @@ func dbFetchGCSFilter(dbTx database.Tx, blockHash *chainhash.Hash) (*gcs.FilterV

filter, err := gcs.FromBytesV2(blockcf2.B, blockcf2.M, serialized)
if err != nil {
return nil, database.Error{
ErrorCode: database.ErrCorruption,
Description: fmt.Sprintf("corrupt filter for %v: %v", blockHash,
err),
}
str := fmt.Sprintf("corrupt filter for %v: %v", blockHash, err)
return nil, database.MakeError(database.ErrCorruption, str)
}

return filter, nil
Expand Down Expand Up @@ -1511,11 +1499,9 @@ func deserializeBestChainState(serializedData []byte) (bestChainState, error) {
// and work sum length.
expectedMinLen := chainhash.HashSize + 4 + 8 + 8 + 4
if len(serializedData) < expectedMinLen {
return bestChainState{}, database.Error{
ErrorCode: database.ErrCorruption,
Description: fmt.Sprintf("corrupt best chain state size; min %v "+
"got %v", expectedMinLen, len(serializedData)),
}
str := fmt.Sprintf("corrupt best chain state size; min %v got %v",
expectedMinLen, len(serializedData))
return bestChainState{}, database.MakeError(database.ErrCorruption, str)
}

state := bestChainState{}
Expand All @@ -1536,11 +1522,9 @@ func deserializeBestChainState(serializedData []byte) (bestChainState, error) {
// Ensure the serialized data has enough bytes to deserialize the work
// sum.
if uint32(len(serializedData[offset:])) < workSumBytesLen {
return bestChainState{}, database.Error{
ErrorCode: database.ErrCorruption,
Description: fmt.Sprintf("corrupt work sum size; want %v "+
"got %v", workSumBytesLen, uint32(len(serializedData[offset:]))),
}
str := fmt.Sprintf("corrupt work sum size; want %v got %v",
workSumBytesLen, uint32(len(serializedData[offset:])))
return bestChainState{}, database.MakeError(database.ErrCorruption, str)
}
workSumBytes := serializedData[offset : offset+workSumBytesLen]
state.workSum = new(big.Int).SetBytes(workSumBytes)
Expand Down
27 changes: 11 additions & 16 deletions blockchain/chainio_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1470,44 +1470,39 @@ func TestBestChainStateDeserializeErrors(t *testing.T) {
tests := []struct {
name string
serialized []byte
errType error
errKind database.ErrorKind
}{
{
name: "nothing serialized",
serialized: hexToBytes(""),
errType: database.Error{ErrorCode: database.ErrCorruption},
errKind: database.ErrCorruption,
},
{
name: "short data in hash",
serialized: hexToBytes("0000"),
errType: database.Error{ErrorCode: database.ErrCorruption},
errKind: database.ErrCorruption,
},
{
name: "short data in work sum",
serialized: hexToBytes("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000001000000000000000500000001000100"),
errType: database.Error{ErrorCode: database.ErrCorruption},
errKind: database.ErrCorruption,
},
}

for _, test := range tests {
// Ensure the expected error type and code is returned.
_, err := deserializeBestChainState(test.serialized)
if !errors.As(err, &test.errType) {
var derr database.Error
if !errors.As(err, &derr) {
t.Errorf("deserializeBestChainState (%s): expected "+
"error type does not match - got %T, want %T",
test.name, err, test.errType)
test.name, err, test.errKind)
continue
}
var derr database.Error
if errors.As(err, &derr) {
var tderr database.Error
if !errors.As(test.errType, &tderr) || derr.ErrorCode != tderr.ErrorCode {
t.Errorf("deserializeBestChainState (%s): "+
"wrong error code got: %v, want: %v",
test.name, derr.ErrorCode,
tderr.ErrorCode)
continue
}
if !errors.Is(derr, test.errKind) {
t.Errorf("deserializeBestChainState (%s): wrong error code "+
"got: %v, want: %v", test.name, derr, test.errKind)
continue
}
}
}
9 changes: 3 additions & 6 deletions blockchain/indexers/addrindex.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,12 +325,9 @@ func dbFetchAddrIndexEntries(bucket internalBucket, addrKey [addrKeySize]byte, n
// Ensure any deserialization errors are returned as
// database corruption errors.
if isDeserializeErr(err) {
err = database.Error{
ErrorCode: database.ErrCorruption,
Description: fmt.Sprintf("failed to "+
"deserialized address index "+
"for key %x: %v", addrKey, err),
}
str := fmt.Sprintf("failed to deserialized address index "+
"for key %x: %v", addrKey, err)
err = database.MakeError(database.ErrCorruption, str)
}

return nil, 0, err
Expand Down
19 changes: 8 additions & 11 deletions blockchain/indexers/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package indexers

import (
"context"
"errors"
"fmt"

"github.com/decred/dcrd/blockchain/v3/internal/progresslog"
Expand Down Expand Up @@ -60,11 +61,9 @@ func dbFetchIndexerTip(dbTx database.Tx, idxKey []byte) (*chainhash.Hash, int32,
indexesBucket := dbTx.Metadata().Bucket(indexTipsBucketName)
serialized := indexesBucket.Get(idxKey)
if len(serialized) < chainhash.HashSize+4 {
return nil, 0, database.Error{
ErrorCode: database.ErrCorruption,
Description: fmt.Sprintf("unexpected end of data for "+
"index %q tip", string(idxKey)),
}
str := fmt.Sprintf("unexpected end of data for index %q tip",
string(idxKey))
return nil, 0, database.MakeError(database.ErrCorruption, str)
}

var hash chainhash.Hash
Expand Down Expand Up @@ -103,11 +102,9 @@ func dbFetchIndexerVersion(dbTx database.Tx, idxKey []byte) (uint32, error) {
}

if len(serialized) < 4 {
return 0, database.Error{
ErrorCode: database.ErrCorruption,
Description: fmt.Sprintf("unexpected end of data for "+
"index %q version", string(idxKey)),
}
str := fmt.Sprintf("unexpected end of data for index %q version",
string(idxKey))
return 0, database.MakeError(database.ErrCorruption, str)
}

version := byteOrder.Uint32(serialized)
Expand Down Expand Up @@ -760,7 +757,7 @@ func dropIndexMetadata(db database.DB, idxKey []byte, idxName string) error {
}

err = meta.DeleteBucket(idxKey)
if err != nil && !database.IsError(err, database.ErrBucketNotFound) {
if err != nil && !errors.Is(err, database.ErrBucketNotFound) {
return err
}

Expand Down
15 changes: 5 additions & 10 deletions blockchain/indexers/txindex.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,21 +217,16 @@ func dbFetchTxIndexEntry(dbTx database.Tx, txHash *chainhash.Hash) (*TxIndexEntr

// Ensure the serialized data has enough bytes to properly deserialize.
if len(serializedData) < txEntrySize {
return nil, database.Error{
ErrorCode: database.ErrCorruption,
Description: fmt.Sprintf("corrupt transaction index "+
"entry for %s", txHash),
}
str := fmt.Sprintf("corrupt transaction index entry for %s", txHash)
return nil, database.MakeError(database.ErrCorruption, str)
}

// Load the block hash associated with the block ID.
hash, err := dbFetchBlockHashBySerializedID(dbTx, serializedData[0:4])
if err != nil {
return nil, database.Error{
ErrorCode: database.ErrCorruption,
Description: fmt.Sprintf("corrupt transaction index "+
"entry for %s: %v", txHash, err),
}
str := fmt.Sprintf("corrupt transaction index entry for %s: %v",
txHash, err)
return nil, database.MakeError(database.ErrCorruption, str)
}

// Deserialize the final entry.
Expand Down
7 changes: 2 additions & 5 deletions blockmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -1069,8 +1069,7 @@ func (b *blockManager) handleBlockMsg(bmsg *blockMsg) {
blockHash, err)
}
var dbErr database.Error
if errors.As(err, &dbErr) && dbErr.ErrorCode ==
database.ErrCorruption {
if errors.As(err, &dbErr) && errors.Is(dbErr, database.ErrCorruption) {
bmgrLog.Errorf("Critical failure: %v", dbErr.Error())
}

Expand Down Expand Up @@ -2586,9 +2585,7 @@ func loadBlockDB(params *chaincfg.Params) (database.DB, error) {
// Return the error if it's not because the database doesn't
// exist.
var dbErr database.Error
if !errors.As(err, &dbErr) || dbErr.ErrorCode !=
database.ErrDbDoesNotExist {

if !errors.As(err, &dbErr) || !errors.Is(dbErr, database.ErrDbDoesNotExist) {
return nil, err
}

Expand Down
6 changes: 3 additions & 3 deletions cmd/addblock/addblock.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package main

import (
"errors"
"os"
"path/filepath"
"runtime"
Expand Down Expand Up @@ -38,9 +39,8 @@ func loadBlockDB() (database.DB, error) {
if err != nil {
// Return the error if it's not because the database doesn't
// exist.
if dbErr, ok := err.(database.Error); !ok || dbErr.ErrorCode !=
database.ErrDbDoesNotExist {

var dbErr database.Error
if !errors.As(err, &dbErr) || !errors.Is(dbErr, database.ErrDbDoesNotExist) {
return nil, err
}

Expand Down
5 changes: 3 additions & 2 deletions database/cmd/dbtool/insecureimport.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package main

import (
"encoding/binary"
"errors"
"fmt"
"io"
"os"
Expand Down Expand Up @@ -376,8 +377,8 @@ func (cmd *importCmd) Execute(args []string) error {
resultsChan := importer.Import()
results := <-resultsChan
if results.err != nil {
dbErr, ok := results.err.(database.Error)
if !ok || ok && dbErr.ErrorCode != database.ErrDbNotOpen {
var dbErr database.Error
if !errors.As(results.err, &dbErr) || !errors.Is(dbErr, database.ErrDbNotOpen) {
shutdownChannel <- results.err
return
}
Expand Down
6 changes: 3 additions & 3 deletions database/cmd/dbtool/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package main

import (
"errors"
"os"
"path/filepath"
"runtime"
Expand Down Expand Up @@ -37,9 +38,8 @@ func loadBlockDB() (database.DB, error) {
if err != nil {
// Return the error if it's not because the database doesn't
// exist.
if dbErr, ok := err.(database.Error); !ok || dbErr.ErrorCode !=
database.ErrDbDoesNotExist {

var dbErr database.Error
if !errors.As(err, &dbErr) || !errors.Is(dbErr, database.ErrDbDoesNotExist) {
return nil, err
}

Expand Down
6 changes: 3 additions & 3 deletions database/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func RegisterDriver(driver Driver) error {
if _, exists := drivers[driver.DbType]; exists {
str := fmt.Sprintf("driver %q is already registered",
driver.DbType)
return makeError(ErrDbTypeRegistered, str, nil)
return MakeError(ErrDbTypeRegistered, str)
}

drivers[driver.DbType] = &driver
Expand All @@ -68,7 +68,7 @@ func Create(dbType string, args ...interface{}) (DB, error) {
drv, exists := drivers[dbType]
if !exists {
str := fmt.Sprintf("driver %q is not registered", dbType)
return nil, makeError(ErrDbUnknownType, str, nil)
return nil, MakeError(ErrDbUnknownType, str)
}

return drv.Create(args...)
Expand All @@ -83,7 +83,7 @@ func Open(dbType string, args ...interface{}) (DB, error) {
drv, exists := drivers[dbType]
if !exists {
str := fmt.Sprintf("driver %q is not registered", dbType)
return nil, makeError(ErrDbUnknownType, str, nil)
return nil, MakeError(ErrDbUnknownType, str)
}

return drv.Open(args...)
Expand Down
20 changes: 10 additions & 10 deletions database/driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,26 @@
package database_test

import (
"errors"
"fmt"
"testing"

"github.com/decred/dcrd/database/v2"
_ "github.com/decred/dcrd/database/v2/ffldb"
)

// checkDbError ensures the passed error is a database.Error with an error code
// that matches the passed error code.
func checkDbError(t *testing.T, testName string, gotErr error, wantErrCode database.ErrorCode) bool {
dbErr, ok := gotErr.(database.Error)
if !ok {
// checkDbError ensures the passed error is a database.Error that matches
// the passed error kind.
func checkDbError(t *testing.T, testName string, gotErr error, wantErr database.ErrorKind) bool {
var dbErr database.Error
if !errors.As(gotErr, &dbErr) {
t.Errorf("%s: unexpected error type - got %T, want %T",
testName, gotErr, database.Error{})
testName, gotErr, dbErr)
return false
}
if dbErr.ErrorCode != wantErrCode {
t.Errorf("%s: unexpected error code - got %s (%s), want %s",
testName, dbErr.ErrorCode, dbErr.Description,
wantErrCode)
if !errors.Is(dbErr, wantErr) {
t.Errorf("%s: unexpected error - got %s (%s), want %s",
testName, dbErr, dbErr.Description, wantErr)
return false
}

Expand Down
Loading

0 comments on commit ebe1cf9

Please sign in to comment.