func serializeVSPHost(record *VSPHost) []byte {
	buf := make([]byte, 4+len(record.Host))
	curPos := 0
	byteOrder.PutUint32(buf[curPos:curPos+4], uint32(len(record.Host)))
	curPos += 4
	copy(buf[curPos:curPos+len(record.Host)], record.Host[:])
	return buf
}
serializeVSPHost serializes a vsp host record into a byte array.
package udb
import (
	"bytes"
	"decred.org/dcrwallet/v2/errors"
	"decred.org/dcrwallet/v2/wallet/walletdb"
	"github.com/decred/dcrd/chaincfg/chainhash"
)
var (
	vspBucketKey       = []byte("vsp")
	vspHostBucketKey   = []byte("vsphost")
	vspPubKeyBucketKey = []byte("vsppubkey")
)
type FeeStatus int
const (
	VSPFeeProcessStarted FeeStatus = iota
	VSPFeeProcessPaid
	VSPFeeProcessErrored
	VSPFeeProcessConfirmed
)
type VSPTicket struct {
	FeeHash     chainhash.Hash
	FeeTxStatus uint32
	VSPHostID   uint32
	Host        string
	PubKey      []byte
}
func SetVSPTicket(dbtx walletdb.ReadWriteTx, ticketHash *chainhash.Hash, record *VSPTicket) error {
	pubkey, err := GetVSPPubKey(dbtx, []byte(record.Host))
	if err != nil && errors.Is(err, errors.NotExist) {
		vspHostBucket := dbtx.ReadWriteBucket(vspHostBucketKey)
		v := vspHostBucket.Get(rootVSPHostIndex)
		vspHostID := byteOrder.Uint32(v)
		vspHostID += 1  
		err = SetVSPHost(dbtx, vspHostID, &VSPHost{
			Host: []byte(record.Host),
		})
		if err != nil {
			return err
		}
		vspIndexBytes := make([]byte, 4)
		byteOrder.PutUint32(vspIndexBytes, vspHostID)
		err = vspHostBucket.Put(rootVSPHostIndex, vspIndexBytes)
		if err != nil {
			return errors.E(errors.IO, err)
		}
		pubkey = &VSPPubKey{
			ID:     vspHostID,
			PubKey: record.PubKey,
		}
		err = SetVSPPubKey(dbtx, []byte(record.Host), pubkey)
		if err != nil {
			return err
		}
		record.VSPHostID = vspHostID
	} else if err != nil {
		return err
	}
	if bytes.Compare(pubkey.PubKey, record.PubKey) != 0 {
		err = SetVSPPubKey(dbtx, []byte(record.Host), &VSPPubKey{
			ID:     pubkey.ID,
			PubKey: record.PubKey,
		})
		if err != nil {
			return err
		}
	}
	record.VSPHostID = pubkey.ID
	bucket := dbtx.ReadWriteBucket(vspBucketKey)
	serializedRecord := serializeVSPTicket(record)
	return bucket.Put(ticketHash[:], serializedRecord)
}
func GetVSPTicket(dbtx walletdb.ReadTx, tickethash chainhash.Hash) (*VSPTicket, error) {
	bucket := dbtx.ReadBucket(vspBucketKey)
	serializedTicket := bucket.Get(tickethash[:])
	if serializedTicket == nil {
		err := errors.Errorf("no VSP info for ticket %v", &tickethash)
		return nil, errors.E(errors.NotExist, err)
	}
	ticket := deserializeVSPTicket(serializedTicket)
	host, err := GetVSPHost(dbtx, ticket.VSPHostID)
	if err != nil && !errors.Is(err, errors.NotExist) {
		return nil, err
	}
	if host != nil && len(host.Host) > 0 {
		ticket.Host = string(host.Host)
		pubkey, err := GetVSPPubKey(dbtx, host.Host)
		if err != nil && !errors.Is(err, errors.NotExist) {
			return nil, err
		}
		if pubkey != nil {
			ticket.PubKey = pubkey.PubKey
		}
	}
	return ticket, nil
}
func GetVSPTicketsByFeeStatus(dbtx walletdb.ReadTx, feeStatus int) (map[chainhash.Hash]*VSPTicket, error) {
	bucket := dbtx.ReadBucket(vspBucketKey)
	tickets := make(map[chainhash.Hash]*VSPTicket)
	err := bucket.ForEach(func(k, v []byte) error {
		ticket := deserializeVSPTicket(v)
		if int(ticket.FeeTxStatus) == feeStatus {
			var hash chainhash.Hash
			hash.SetBytes(k)
			tickets[hash] = ticket
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	return tickets, nil
}
func deserializeVSPTicket(serializedTicket []byte) *VSPTicket {
	curPos := 0
	vspTicket := &VSPTicket{}
	copy(vspTicket.FeeHash[:], serializedTicket[curPos:hashSize])
	curPos += hashSize
	vspTicket.FeeTxStatus = byteOrder.Uint32(serializedTicket[curPos : curPos+4])
	curPos += 4
	vspTicket.VSPHostID = byteOrder.Uint32(serializedTicket[curPos : curPos+4])
	return vspTicket
}
func serializeVSPTicket(record *VSPTicket) []byte {
	buf := make([]byte, hashSize+4+4)
	curPos := 0
	copy(buf[curPos:curPos+hashSize], record.FeeHash[:])
	curPos += hashSize
	byteOrder.PutUint32(buf[curPos:curPos+4], record.FeeTxStatus)
	curPos += 4
	byteOrder.PutUint32(buf[curPos:curPos+4], record.VSPHostID)
	return buf
}
type VSPHost struct {
	Host []byte
}
func SetVSPHost(dbtx walletdb.ReadWriteTx, id uint32, record *VSPHost) error {
	bucket := dbtx.ReadWriteBucket(vspHostBucketKey)
	serializedRecord := serializeVSPHost(record)
	k := make([]byte, 4)
	byteOrder.PutUint32(k, id)
	return bucket.Put(k, serializedRecord)
}
func GetVSPHost(dbtx walletdb.ReadTx, id uint32) (*VSPHost, error) {
	k := make([]byte, 4)
	byteOrder.PutUint32(k, id)
	bucket := dbtx.ReadBucket(vspHostBucketKey)
	serializedHost := bucket.Get(k)
	if serializedHost == nil {
		err := errors.Errorf("no VSP host info for id %v", &id)
		return nil, errors.E(errors.NotExist, err)
	}
	host := deserializeVSPHost(serializedHost)
	return host, nil
}
func deserializeVSPHost(serializedHost []byte) *VSPHost {
	curPos := 0
	VSPHost := &VSPHost{}
	hostLength := byteOrder.Uint32(serializedHost[curPos : curPos+4])
	curPos += 4
	VSPHost.Host = serializedHost[curPos : curPos+int(hostLength)]
	return VSPHost
}