func (db *BoltDB) fetchCSRFSecret() ([]byte, error) {
	var secret []byte
	err := db.DB.View(func(tx *bolt.Tx) error {
		pbkt := tx.Bucket(poolBkt)
		if pbkt == nil {
			desc := fmt.Sprintf("bucket %s not found", string(poolBkt))
			return errs.DBError(errs.StorageNotFound, desc)
		}
		v := pbkt.Get(csrfSecret)
		if v == nil {
			return errs.DBError(errs.ValueNotFound, "No csrf secret found")
		}
		secret = make([]byte, len(v))
		copy(secret, v)
		return nil
	})
	if err != nil {
		return nil, err
	}
	return secret, nil
}
fetchCSRFSecret retrieves the bytes used for the CSRF secret from the database.
package pool
import (
	"bytes"
	"encoding/binary"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"net/http"
	"path/filepath"
	"strconv"
	"time"
	bolt "go.etcd.io/bbolt"
	errs "github.com/decred/dcrpool/errors"
)
var (
	poolBkt = []byte("poolbkt")
	accountBkt = []byte("accountbkt")
	shareBkt = []byte("sharebkt")
	jobBkt = []byte("jobbkt")
	workBkt = []byte("workbkt")
	paymentBkt = []byte("paymentbkt")
	paymentArchiveBkt = []byte("paymentarchivebkt")
	hashDataBkt = []byte("hashdatabkt")
	versionK = []byte("version")
	lastPaymentCreatedOn = []byte("lastpaymentcreatedon")
	lastPaymentPaidOn = []byte("lastpaymentpaidon")
	lastPaymentHeight = []byte("lastpaymentheight")
	soloPool = []byte("solopool")
	csrfSecret = []byte("csrfsecret")
	PoolFeesK = "fees"
	BoltBackupFile = "backup.kv"
)
func openBoltDB(storage string) (*BoltDB, error) {
	const funcName = "openBoltDB"
	db, err := bolt.Open(storage, 0600,
		&bolt.Options{Timeout: 1 * time.Second})
	if err != nil {
		desc := fmt.Sprintf("%s: unable to open db file: %v", funcName, err)
		return nil, errs.DBError(errs.DBOpen, desc)
	}
	return &BoltDB{db}, nil
}
func createNestedBucket(parent *bolt.Bucket, child []byte) error {
	const funcName = "createNestedBucket"
	_, err := parent.CreateBucketIfNotExists(child)
	if err != nil {
		desc := fmt.Sprintf("%s: unable to create %s bucket: %v",
			funcName, string(child), err)
		return errs.DBError(errs.CreateStorage, desc)
	}
	return nil
}
func createBuckets(db *BoltDB) error {
	const funcName = "createBuckets"
	err := db.DB.Update(func(tx *bolt.Tx) error {
		var err error
		pbkt := tx.Bucket(poolBkt)
		if pbkt == nil {
			pbkt, err = tx.CreateBucketIfNotExists(poolBkt)
			if err != nil {
				desc := fmt.Sprintf("%s: unable to create %s bucket: %v",
					funcName, string(poolBkt), err)
				return errs.DBError(errs.CreateStorage, desc)
			}
			vbytes := make([]byte, 4)
			binary.LittleEndian.PutUint32(vbytes, BoltDBVersion)
			err = pbkt.Put(versionK, vbytes)
			if err != nil {
				desc := fmt.Sprintf("%s: unable to persist version: %v",
					funcName, err)
				return errs.DBError(errs.PersistEntry, desc)
			}
		}
		err = createNestedBucket(pbkt, accountBkt)
		if err != nil {
			return err
		}
		err = createNestedBucket(pbkt, shareBkt)
		if err != nil {
			return err
		}
		err = createNestedBucket(pbkt, workBkt)
		if err != nil {
			return err
		}
		err = createNestedBucket(pbkt, jobBkt)
		if err != nil {
			return err
		}
		err = createNestedBucket(pbkt, paymentBkt)
		if err != nil {
			return err
		}
		err = createNestedBucket(pbkt, paymentArchiveBkt)
		if err != nil {
			return err
		}
		return createNestedBucket(pbkt, hashDataBkt)
	})
	return err
}
func (db *BoltDB) Backup(backupFileName string) error {
	backupPath := filepath.Join(filepath.Dir(db.DB.Path()), backupFileName)
	return db.DB.View(func(tx *bolt.Tx) error {
		err := tx.CopyFile(backupPath, 0600)
		if err != nil {
			desc := fmt.Sprintf("unable to backup db: %v", err)
			return errs.PoolError(errs.Backup, desc)
		}
		return nil
	})
}
func InitBoltDB(dbFile string) (*BoltDB, error) {
	db, err := openBoltDB(dbFile)
	if err != nil {
		return nil, err
	}
	err = createBuckets(db)
	if err != nil {
		return nil, err
	}
	err = upgradeDB(db)
	if err != nil {
		return nil, err
	}
	return db, nil
}
func deleteEntry(db *BoltDB, bucket []byte, key string) error {
	const funcName = "deleteEntry"
	return db.DB.Update(func(tx *bolt.Tx) error {
		pbkt := tx.Bucket(poolBkt)
		if pbkt == nil {
			desc := fmt.Sprintf("%s: bucket %s not found", funcName,
				string(poolBkt))
			return errs.DBError(errs.StorageNotFound, desc)
		}
		b := pbkt.Bucket(bucket)
		err := b.Delete([]byte(key))
		if err != nil {
			desc := fmt.Sprintf("%s: unable to delete entry with "+
				"key %s from bucket %s", funcName, key, string(poolBkt))
			return errs.DBError(errs.DeleteEntry, desc)
		}
		return nil
	})
}
func fetchBucket(tx *bolt.Tx, bucketID []byte) (*bolt.Bucket, error) {
	const funcName = "fetchBucket"
	pbkt, err := fetchPoolBucket(tx)
	if err != nil {
		return nil, err
	}
	bkt := pbkt.Bucket(bucketID)
	if bkt == nil {
		desc := fmt.Sprintf("%s: bucket %s not found", funcName,
			string(bucketID))
		return nil, errs.DBError(errs.StorageNotFound, desc)
	}
	return bkt, nil
}
func fetchPoolBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
	funcName := "fetchPoolBucket"
	pbkt := tx.Bucket(poolBkt)
	if pbkt == nil {
		desc := fmt.Sprintf("%s: bucket %s not found", funcName,
			string(poolBkt))
		return nil, errs.DBError(errs.StorageNotFound, desc)
	}
	return pbkt, nil
}
func bigEndianBytesToNano(b []byte) uint64 {
	return binary.BigEndian.Uint64(b)
}
func nanoToBigEndianBytes(nano int64) []byte {
	b := make([]byte, 8)
	binary.BigEndian.PutUint64(b, uint64(nano))
	return b
}
func (db *BoltDB) fetchPoolMode() (uint32, error) {
	var mode uint32
	err := db.DB.View(func(tx *bolt.Tx) error {
		pbkt, err := fetchPoolBucket(tx)
		if err != nil {
			return err
		}
		b := pbkt.Get(soloPool)
		if b == nil {
			return errs.DBError(errs.ValueNotFound, "no pool mode found")
		}
		mode = binary.LittleEndian.Uint32(b)
		return nil
	})
	if err != nil {
		return 0, err
	}
	return mode, nil
}
func (db *BoltDB) persistPoolMode(mode uint32) error {
	return db.DB.Update(func(tx *bolt.Tx) error {
		pbkt := tx.Bucket(poolBkt)
		b := make([]byte, 4)
		binary.LittleEndian.PutUint32(b, mode)
		return pbkt.Put(soloPool, b)
	})
}