Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Chore] Guard against nil buckets to prevent panics #473

Merged
merged 2 commits into from
May 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion bchrpc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2929,7 +2929,6 @@ func (s *GrpcServer) getSlpToken(hash *chainhash.Hash, vout uint32, scriptPubKey
// NOTE: this is launched as a goroutine and does not return errors!
//
func (s *GrpcServer) slpEventHandler() {

if s.slpIndex == nil {
return
}
Expand Down
9 changes: 9 additions & 0 deletions blockchain/indexers/addrindex.go
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,9 @@ func (idx *AddrIndex) ConnectBlock(dbTx database.Tx, block *bchutil.Block,

// Add all of the index entries for each address.
addrIdxBucket := dbTx.Metadata().Bucket(addrIndexKey)
if addrIdxBucket == nil {
return fmt.Errorf("bucket nil for key: %s", addrIndexKey)
}
for addrKey, txIdxs := range addrsToTxns {
for _, txIdx := range txIdxs {
err := dbPutAddrIndexEntry(addrIdxBucket, addrKey,
Expand Down Expand Up @@ -762,6 +765,9 @@ func (idx *AddrIndex) DisconnectBlock(dbTx database.Tx, block *bchutil.Block,

// Remove all of the index entries for each address.
bucket := dbTx.Metadata().Bucket(addrIndexKey)
if bucket == nil {
return fmt.Errorf("bucket nil for key: %s", addrIndexKey)
}
for addrKey, txIdxs := range addrsToTxns {
err := dbRemoveAddrIndexEntries(bucket, addrKey, len(txIdxs))
if err != nil {
Expand Down Expand Up @@ -801,6 +807,9 @@ func (idx *AddrIndex) TxRegionsForAddress(dbTx database.Tx, addr bchutil.Address

var err error
addrIdxBucket := dbTx.Metadata().Bucket(addrIndexKey)
if addrIdxBucket == nil {
return fmt.Errorf("bucket nil for key: %s", addrIndexKey)
}
regions, skipped, err = dbFetchAddrIndexEntries(addrIdxBucket,
addrKey, numToSkip, numRequested, reverse,
fetchBlockHash)
Expand Down
34 changes: 31 additions & 3 deletions blockchain/indexers/cfindex.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package indexers
import (
"encoding/binary"
"errors"
"fmt"

"github.com/gcash/bchd/blockchain"
"github.com/gcash/bchd/chaincfg"
Expand Down Expand Up @@ -66,25 +67,49 @@ var (
// dbFetchFilterIdxEntry retrieves a data blob from the filter index database.
// An entry's absence is not considered an error.
func dbFetchFilterIdxEntry(dbTx database.Tx, key []byte, h *chainhash.Hash) ([]byte, error) {
idx := dbTx.Metadata().Bucket(cfIndexParentBucketKey).Bucket(key)
parentIdx := dbTx.Metadata().Bucket(cfIndexParentBucketKey)
if parentIdx == nil {
return []byte{}, fmt.Errorf("bucket nil for key: %s", cfIndexParentBucketKey)
}
idx := parentIdx.Bucket(key)
if idx == nil {
return []byte{}, fmt.Errorf("bucket nil for key: %s", key)
}
return idx.Get(h[:]), nil
}

// dbStoreFilterIdxEntry stores a data blob in the filter index database.
func dbStoreFilterIdxEntry(dbTx database.Tx, key []byte, h *chainhash.Hash, f []byte) error {
idx := dbTx.Metadata().Bucket(cfIndexParentBucketKey).Bucket(key)
parentIdx := dbTx.Metadata().Bucket(cfIndexParentBucketKey)
if parentIdx == nil {
return fmt.Errorf("bucket nil for key: %s", cfIndexParentBucketKey)
}
idx := parentIdx.Bucket(key)
if idx == nil {
return fmt.Errorf("bucket nil for key: %s", key)
}
return idx.Put(h[:], f)
}

// dbDeleteFilterIdxEntry deletes a data blob from the filter index database.
func dbDeleteFilterIdxEntry(dbTx database.Tx, key []byte, h *chainhash.Hash) error {
idx := dbTx.Metadata().Bucket(cfIndexParentBucketKey).Bucket(key)
parentIdx := dbTx.Metadata().Bucket(cfIndexParentBucketKey)
if parentIdx == nil {
return fmt.Errorf("bucket nil for key: %s", cfIndexParentBucketKey)
}
idx := parentIdx.Bucket(key)
if idx == nil {
return fmt.Errorf("bucket nil for key: %s", key)
}
return idx.Delete(h[:])
}

// dbFetchMigrationVersion retrieves the migration version from the bucket.
func dbFetchMigrationVersion(dbTx database.Tx) (uint32, error) {
bucket := dbTx.Metadata().Bucket(cfIndexParentBucketKey)
if bucket == nil {
return 0, fmt.Errorf("bucket nil for key: %s", cfIndexParentBucketKey)
}
versionBytes := bucket.Get(cfIndexMigrationVersionKey)
version := uint32(0)
if len(versionBytes) == 4 {
Expand All @@ -96,6 +121,9 @@ func dbFetchMigrationVersion(dbTx database.Tx) (uint32, error) {
// dbStoreMigrationVersion stores the migration version in the bucket.
func dbStoreMigrationVersion(dbTx database.Tx, version uint32) error {
bucket := dbTx.Metadata().Bucket(cfIndexParentBucketKey)
if bucket == nil {
return fmt.Errorf("bucket nil for key: %s", cfIndexParentBucketKey)
}
versionBytes := make([]byte, 4)
binary.BigEndian.PutUint32(versionBytes, version)
return bucket.Put(cfIndexMigrationVersionKey, versionBytes)
Expand Down
22 changes: 20 additions & 2 deletions blockchain/indexers/slpindex.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@ func dbPutTokenIDIndexEntry(dbTx database.Tx, id uint32, metadata *TokenMetadata
// token id for the provided hash from the index.
func dbFetchTokenIDByHash(dbTx database.Tx, hash *chainhash.Hash) (uint32, error) {
hashIndex := dbTx.Metadata().Bucket(tokenIDByHashIndexBucketName)
if hashIndex == nil {
return 0, fmt.Errorf("bucket nil for key: %s", tokenIDByHashIndexBucketName)
}
serializedID := hashIndex.Get(hash[:])
if serializedID == nil {
return 0, errNoTokenIDHashEntry
Expand All @@ -177,6 +180,9 @@ func dbFetchTokenIDByHash(dbTx database.Tx, hash *chainhash.Hash) (uint32, error
// retrieve the hash for the provided serialized token id from the index.
func dbFetchTokenMetadataBySerializedID(dbTx database.Tx, serializedID []byte) (*TokenMetadata, error) {
idIndex := dbTx.Metadata().Bucket(tokenMetadataByIDIndexBucketName)
if idIndex == nil {
return nil, fmt.Errorf("bucket nil for key: %s", tokenMetadataByIDIndexBucketName)
}
serializedData := idIndex.Get(serializedID)
if serializedData == nil {
return nil, errNoTokenMetadataEntry
Expand Down Expand Up @@ -316,6 +322,9 @@ func dbPutSlpIndexEntry(idx *SlpIndex, dbTx database.Tx, entryInfo *dbSlpIndexEn
byteOrder.PutUint16(target[4:], uint16(entryInfo.slpMsg.TokenType()))
copy(target[6:], entryInfo.slpMsgPkScript)
slpIndex := dbTx.Metadata().Bucket(slpIndexKey)
if slpIndex == nil {
return fmt.Errorf("bucket nil for key: %s", slpIndexKey)
}
return slpIndex.Put(txHash[:], target)
}

Expand All @@ -332,8 +341,11 @@ type SlpTxEntry struct {
// nil will be returned for the both the entry and the error.
func dbFetchSlpIndexEntry(dbTx database.Tx, txHash *chainhash.Hash) (*SlpTxEntry, error) {
// Load the record from the database and return now if it doesn't exist.
SlpIndex := dbTx.Metadata().Bucket(slpIndexKey)
serializedData := SlpIndex.Get(txHash[:])
slpIndex := dbTx.Metadata().Bucket(slpIndexKey)
if slpIndex == nil {
return nil, fmt.Errorf("bucket nil for key: %s", slpIndexKey)
}
serializedData := slpIndex.Get(txHash[:])
if len(serializedData) == 0 {
return nil, fmt.Errorf("slp entry does not exist %v", txHash)
}
Expand Down Expand Up @@ -376,6 +388,9 @@ func dbRemoveSlpIndexEntries(dbTx database.Tx, block *bchutil.Block) error {
// this method should only be called after a topological sort
dbRemoveSlpIndexEntry := func(dbTx database.Tx, txHash *chainhash.Hash) error {
slpIndex := dbTx.Metadata().Bucket(slpIndexKey)
if slpIndex == nil {
return fmt.Errorf("bucket nil for key: %s", slpIndexKey)
}
serializedData := slpIndex.Get(txHash[:])
if len(serializedData) == 0 {
return nil
Expand Down Expand Up @@ -1154,6 +1169,9 @@ func (idx *SlpIndex) buildGraphSearchTokenMap() (*map[chainhash.Hash]*chainhash.

err := idx.db.View(func(dbTx database.Tx) error {
idxBucket := dbTx.Metadata().Bucket(slpIndexKey)
if idxBucket == nil {
return fmt.Errorf("bucket nil for key: %s", slpIndexKey)
}

// loop through all of the valid slp txn items stored in the db
err := idxBucket.ForEach(func(k []byte, v []byte) error {
Expand Down
15 changes: 15 additions & 0 deletions blockchain/indexers/txindex.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ func dbRemoveBlockIDIndexEntry(dbTx database.Tx, hash *chainhash.Hash) error {
// block id for the provided hash from the index.
func dbFetchBlockIDByHash(dbTx database.Tx, hash *chainhash.Hash) (uint32, error) {
hashIndex := dbTx.Metadata().Bucket(idByHashIndexBucketName)
if hashIndex == nil {
return 0, fmt.Errorf("bucket nil for key: %s", idByHashIndexBucketName)
}
serializedID := hashIndex.Get(hash[:])
if serializedID == nil {
return 0, errNoBlockIDEntry
Expand All @@ -146,6 +149,9 @@ func dbFetchBlockIDByHash(dbTx database.Tx, hash *chainhash.Hash) (uint32, error
// retrieve the hash for the provided serialized block id from the index.
func dbFetchBlockHashBySerializedID(dbTx database.Tx, serializedID []byte) (*chainhash.Hash, error) {
idIndex := dbTx.Metadata().Bucket(hashByIDIndexBucketName)
if idIndex == nil {
return nil, fmt.Errorf("bucket nil for key: %s", hashByIDIndexBucketName)
}
hashBytes := idIndex.Get(serializedID)
if hashBytes == nil {
return nil, errNoBlockIDEntry
Expand Down Expand Up @@ -179,6 +185,9 @@ func putTxIndexEntry(target []byte, blockID uint32, txLoc wire.TxLoc) {
// been serialized putTxIndexEntry.
func dbPutTxIndexEntry(dbTx database.Tx, txHash *chainhash.Hash, serializedData []byte) error {
txIndex := dbTx.Metadata().Bucket(txIndexKey)
if txIndex == nil {
return fmt.Errorf("bucket nil for key: %s", txIndexKey)
}
return txIndex.Put(txHash[:], serializedData)
}

Expand All @@ -189,6 +198,9 @@ func dbPutTxIndexEntry(dbTx database.Tx, txHash *chainhash.Hash, serializedData
func dbFetchTxIndexEntry(dbTx database.Tx, txHash *chainhash.Hash) (*database.BlockRegion, error) {
// Load the record from the database and return now if it doesn't exist.
txIndex := dbTx.Metadata().Bucket(txIndexKey)
if txIndex == nil {
return nil, fmt.Errorf("bucket nil for key: %s", txIndexKey)
}
serializedData := txIndex.Get(txHash[:])
if len(serializedData) == 0 {
return nil, nil
Expand Down Expand Up @@ -257,6 +269,9 @@ func dbAddTxIndexEntries(dbTx database.Tx, block *bchutil.Block, blockID uint32)
// recent transaction index entry for the given hash.
func dbRemoveTxIndexEntry(dbTx database.Tx, txHash *chainhash.Hash) error {
txIndex := dbTx.Metadata().Bucket(txIndexKey)
if txIndex == nil {
return fmt.Errorf("bucket nil for key: %s", txIndexKey)
}
serializedData := txIndex.Get(txHash[:])
if len(serializedData) == 0 {
return fmt.Errorf("can't remove non-existent transaction %s "+
Expand Down