func (b *bucket) Bucket(key []byte) database.Bucket {
	if err := b.tx.checkClosed(); err != nil {
		return nil
	}
	childID := b.tx.fetchKey(bucketIndexKey(b.id, key))
	if childID == nil {
		return nil
	}
	childBucket := &bucket{tx: b.tx}
	copy(childBucket.id[:], childID)
	return childBucket
}
Bucket retrieves a nested bucket with the given key.  Returns nil if
the bucket does not exist.

This function is part of the database.Bucket interface implementation.
package ffldb
import (
	"bytes"
	"encoding/binary"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"sort"
	"sync"
	"github.com/soteria-dag/soterd/chaincfg/chainhash"
	"github.com/soteria-dag/soterd/database"
	"github.com/soteria-dag/soterd/database/internal/treap"
	"github.com/soteria-dag/soterd/wire"
	"github.com/soteria-dag/soterd/soterutil"
	"github.com/btcsuite/goleveldb/leveldb"
	"github.com/btcsuite/goleveldb/leveldb/comparer"
	ldberrors "github.com/btcsuite/goleveldb/leveldb/errors"
	"github.com/btcsuite/goleveldb/leveldb/filter"
	"github.com/btcsuite/goleveldb/leveldb/iterator"
	"github.com/btcsuite/goleveldb/leveldb/opt"
	"github.com/btcsuite/goleveldb/leveldb/util"
)
const (
	metadataDbName = "metadata"
	blockHdrSize = wire.MaxBlockHeaderPayload
	blockHdrOffset = blockLocSize
)
var (
	byteOrder = binary.LittleEndian
	bucketIndexPrefix = []byte("bidx")
	curBucketIDKeyName = []byte("bidx-cbid")
	metadataBucketID = [4]byte{}
	blockIdxBucketID = [4]byte{0x00, 0x00, 0x00, 0x01}
	blockIdxBucketName = []byte("ffldb-blockidx")
	writeLocKeyName = []byte("ffldb-writeloc")
)
const (
	errDbNotOpenStr = "database is not open"
	errTxClosedStr = "database tx is closed"
)
type bulkFetchData struct {
	*blockLocation
	replyIndex int
}
type bulkFetchDataSorter []bulkFetchData
func (s bulkFetchDataSorter) Len() int {
	return len(s)
}
func (s bulkFetchDataSorter) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}
func (s bulkFetchDataSorter) Less(i, j int) bool {
	if s[i].blockFileNum < s[j].blockFileNum {
		return true
	}
	if s[i].blockFileNum > s[j].blockFileNum {
		return false
	}
	return s[i].fileOffset < s[j].fileOffset
}
func makeDbErr(c database.ErrorCode, desc string, err error) database.Error {
	return database.Error{ErrorCode: c, Description: desc, Err: err}
}
func convertErr(desc string, ldbErr error) database.Error {
	var code = database.ErrDriverSpecific
	switch {
	case ldberrors.IsCorrupted(ldbErr):
		code = database.ErrCorruption
	case ldbErr == leveldb.ErrClosed:
		code = database.ErrDbNotOpen
	case ldbErr == leveldb.ErrSnapshotReleased:
		code = database.ErrTxClosed
	case ldbErr == leveldb.ErrIterReleased:
		code = database.ErrTxClosed
	}
	return database.Error{ErrorCode: code, Description: desc, Err: ldbErr}
}
func copySlice(slice []byte) []byte {
	ret := make([]byte, len(slice))
	copy(ret, slice)
	return ret
}
type cursor struct {
	bucket      *bucket
	dbIter      iterator.Iterator
	pendingIter iterator.Iterator
	currentIter iterator.Iterator
}
var _ database.Cursor = (*cursor)(nil)
func (c *cursor) Bucket() database.Bucket {
	if err := c.bucket.tx.checkClosed(); err != nil {
		return nil
	}
	return c.bucket
}
func (c *cursor) Delete() error {
	if err := c.bucket.tx.checkClosed(); err != nil {
		return err
	}
	if c.currentIter == nil {
		str := "cursor is exhausted"
		return makeDbErr(database.ErrIncompatibleValue, str, nil)
	}
	key := c.currentIter.Key()
	if bytes.HasPrefix(key, bucketIndexPrefix) {
		str := "buckets may not be deleted from a cursor"
		return makeDbErr(database.ErrIncompatibleValue, str, nil)
	}
	c.bucket.tx.deleteKey(copySlice(key), true)
	return nil
}
func (c *cursor) skipPendingUpdates(forwards bool) {
	for c.dbIter.Valid() {
		var skip bool
		key := c.dbIter.Key()
		if c.bucket.tx.pendingRemove.Has(key) {
			skip = true
		} else if c.bucket.tx.pendingKeys.Has(key) {
			skip = true
		}
		if !skip {
			break
		}
		if forwards {
			c.dbIter.Next()
		} else {
			c.dbIter.Prev()
		}
	}
}
func (c *cursor) chooseIterator(forwards bool) bool {
	c.skipPendingUpdates(forwards)
	if !c.dbIter.Valid() && !c.pendingIter.Valid() {
		c.currentIter = nil
		return false
	}
	if !c.pendingIter.Valid() {
		c.currentIter = c.dbIter
		return true
	}
	if !c.dbIter.Valid() {
		c.currentIter = c.pendingIter
		return true
	}
	compare := bytes.Compare(c.dbIter.Key(), c.pendingIter.Key())
	if (forwards && compare > 0) || (!forwards && compare < 0) {
		c.currentIter = c.pendingIter
	} else {
		c.currentIter = c.dbIter
	}
	return true
}
func (c *cursor) First() bool {
	if err := c.bucket.tx.checkClosed(); err != nil {
		return false
	}
	c.dbIter.First()
	c.pendingIter.First()
	return c.chooseIterator(true)
}
func (c *cursor) Last() bool {
	if err := c.bucket.tx.checkClosed(); err != nil {
		return false
	}
	c.dbIter.Last()
	c.pendingIter.Last()
	return c.chooseIterator(false)
}
func (c *cursor) Next() bool {
	if err := c.bucket.tx.checkClosed(); err != nil {
		return false
	}
	if c.currentIter == nil {
		return false
	}
	c.currentIter.Next()
	return c.chooseIterator(true)
}
func (c *cursor) Prev() bool {
	if err := c.bucket.tx.checkClosed(); err != nil {
		return false
	}
	if c.currentIter == nil {
		return false
	}
	c.currentIter.Prev()
	return c.chooseIterator(false)
}
func (c *cursor) Seek(seek []byte) bool {
	if err := c.bucket.tx.checkClosed(); err != nil {
		return false
	}
	seekKey := bucketizedKey(c.bucket.id, seek)
	c.dbIter.Seek(seekKey)
	c.pendingIter.Seek(seekKey)
	return c.chooseIterator(true)
}
func (c *cursor) rawKey() []byte {
	if c.currentIter == nil {
		return nil
	}
	return copySlice(c.currentIter.Key())
}
func (c *cursor) Key() []byte {
	if err := c.bucket.tx.checkClosed(); err != nil {
		return nil
	}
	if c.currentIter == nil {
		return nil
	}
	key := c.currentIter.Key()
	if bytes.HasPrefix(key, bucketIndexPrefix) {
		key = key[len(bucketIndexPrefix)+4:]
		return copySlice(key)
	}
	key = key[len(c.bucket.id):]
	return copySlice(key)
}
func (c *cursor) rawValue() []byte {
	if c.currentIter == nil {
		return nil
	}
	return copySlice(c.currentIter.Value())
}
func (c *cursor) Value() []byte {
	if err := c.bucket.tx.checkClosed(); err != nil {
		return nil
	}
	if c.currentIter == nil {
		return nil
	}
	if bytes.HasPrefix(c.currentIter.Key(), bucketIndexPrefix) {
		return nil
	}
	return copySlice(c.currentIter.Value())
}
type cursorType int
const (
	ctKeys cursorType = iota
	ctBuckets
	ctFull
)
func cursorFinalizer(c *cursor) {
	c.dbIter.Release()
	c.pendingIter.Release()
}
func newCursor(b *bucket, bucketID []byte, cursorTyp cursorType) *cursor {
	var dbIter, pendingIter iterator.Iterator
	switch cursorTyp {
	case ctKeys:
		keyRange := util.BytesPrefix(bucketID)
		dbIter = b.tx.snapshot.NewIterator(keyRange)
		pendingKeyIter := newLdbTreapIter(b.tx, keyRange)
		pendingIter = pendingKeyIter
	case ctBuckets:
		prefix := make([]byte, len(bucketIndexPrefix)+4)
		copy(prefix, bucketIndexPrefix)
		copy(prefix[len(bucketIndexPrefix):], bucketID)
		bucketRange := util.BytesPrefix(prefix)
		dbIter = b.tx.snapshot.NewIterator(bucketRange)
		pendingBucketIter := newLdbTreapIter(b.tx, bucketRange)
		pendingIter = pendingBucketIter
	case ctFull:
		fallthrough
	default:
		prefix := make([]byte, len(bucketIndexPrefix)+4)
		copy(prefix, bucketIndexPrefix)
		copy(prefix[len(bucketIndexPrefix):], bucketID)
		bucketRange := util.BytesPrefix(prefix)
		keyRange := util.BytesPrefix(bucketID)
		dbKeyIter := b.tx.snapshot.NewIterator(keyRange)
		dbBucketIter := b.tx.snapshot.NewIterator(bucketRange)
		iters := []iterator.Iterator{dbKeyIter, dbBucketIter}
		dbIter = iterator.NewMergedIterator(iters,
			comparer.DefaultComparer, true)
		pendingKeyIter := newLdbTreapIter(b.tx, keyRange)
		pendingBucketIter := newLdbTreapIter(b.tx, bucketRange)
		iters = []iterator.Iterator{pendingKeyIter, pendingBucketIter}
		pendingIter = iterator.NewMergedIterator(iters,
			comparer.DefaultComparer, true)
	}
	return &cursor{bucket: b, dbIter: dbIter, pendingIter: pendingIter}
}
type bucket struct {
	tx *transaction
	id [4]byte
}
var _ database.Bucket = (*bucket)(nil)
func bucketIndexKey(parentID [4]byte, key []byte) []byte {
	indexKey := make([]byte, len(bucketIndexPrefix)+4+len(key))
	copy(indexKey, bucketIndexPrefix)
	copy(indexKey[len(bucketIndexPrefix):], parentID[:])
	copy(indexKey[len(bucketIndexPrefix)+4:], key)
	return indexKey
}
func bucketizedKey(bucketID [4]byte, key []byte) []byte {
	bKey := make([]byte, 4+len(key))
	copy(bKey, bucketID[:])
	copy(bKey[4:], key)
	return bKey
}