func indexDropKey(idxKey []byte) []byte {
	dropKey := make([]byte, len(idxKey)+1)
	dropKey[0] = 'd'
	copy(dropKey[1:], idxKey)
	return dropKey
}
indexDropKey returns the key for an index which indicates it is in the
process of being dropped.
package indexers
import (
	"bytes"
	"fmt"
	"github.com/HcashOrg/hcashd/blockchain"
	"github.com/HcashOrg/hcashd/blockchain/internal/progresslog"
	"github.com/HcashOrg/hcashd/blockchain/stake"
	"github.com/HcashOrg/hcashd/chaincfg"
	"github.com/HcashOrg/hcashd/chaincfg/chainhash"
	"github.com/HcashOrg/hcashd/database"
	"github.com/HcashOrg/hcashd/wire"
	"github.com/HcashOrg/hcashutil"
)
var (
	indexTipsBucketName = []byte("idxtips")
)
func dbPutIndexerTip(dbTx database.Tx, idxKey []byte, hash *chainhash.Hash, height int32) error {
	serialized := make([]byte, chainhash.HashSize+4)
	copy(serialized, hash[:])
	byteOrder.PutUint32(serialized[chainhash.HashSize:], uint32(height))
	indexesBucket := dbTx.Metadata().Bucket(indexTipsBucketName)
	return indexesBucket.Put(idxKey, serialized)
}
func dbFetchIndexerTip(dbTx database.Tx, idxKey []byte) (*chainhash.Hash, int32, error) {
	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)),
		}
	}
	var hash chainhash.Hash
	copy(hash[:], serialized[:chainhash.HashSize])
	height := int32(byteOrder.Uint32(serialized[chainhash.HashSize:]))
	return &hash, height, nil
}
func dbIndexConnectBlock(dbTx database.Tx, indexer Indexer, block, parent *hcashutil.Block, view *blockchain.UtxoViewpoint) error {
	idxKey := indexer.Key()
	curTipHash, _, err := dbFetchIndexerTip(dbTx, idxKey)
	if err != nil {
		return err
	}
	if !curTipHash.IsEqual(&block.MsgBlock().Header.PrevBlock) {
		return AssertError(fmt.Sprintf("dbIndexConnectBlock must be "+
			"called with a block that extends the current index "+
			"tip (%s, tip %s, block %s)", indexer.Name(),
			curTipHash, block.Hash()))
	}
	if err := indexer.ConnectBlock(dbTx, block, parent, view); err != nil {
		return err
	}
	return dbPutIndexerTip(dbTx, idxKey, block.Hash(), int32(block.Height()))
}
func dbIndexDisconnectBlock(dbTx database.Tx, indexer Indexer, block, parent *hcashutil.Block, view *blockchain.UtxoViewpoint) error {
	idxKey := indexer.Key()
	curTipHash, _, err := dbFetchIndexerTip(dbTx, idxKey)
	if err != nil {
		return err
	}
	if !curTipHash.IsEqual(block.Hash()) {
		return AssertError(fmt.Sprintf("dbIndexDisconnectBlock must "+
			"be called with the block at the current index tip "+
			"(%s, tip %s, block %s)", indexer.Name(),
			curTipHash, block.Hash()))
	}
	if err := indexer.DisconnectBlock(dbTx, block, parent, view); err != nil {
		return err
	}
	prevHash := &block.MsgBlock().Header.PrevBlock
	return dbPutIndexerTip(dbTx, idxKey, prevHash, int32(block.Height()-1))
}
type Manager struct {
	params         *chaincfg.Params
	db             database.DB
	enabledIndexes []Indexer
}
var _ blockchain.IndexManager = (*Manager)(nil)