// Copyright (c) 2014-2016 The btcsuite developers
// Copyright (c) 2015-2023 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package mining

import (
	"container/heap"
	"encoding/binary"
	"fmt"
	"math"
	"sort"
	"time"

	"github.com/decred/dcrd/blockchain/stake/v5"
	"github.com/decred/dcrd/blockchain/standalone/v2"
	"github.com/decred/dcrd/chaincfg/chainhash"
	"github.com/decred/dcrd/chaincfg/v3"
	"github.com/decred/dcrd/dcrutil/v4"
	"github.com/decred/dcrd/gcs/v4/blockcf2"
	"github.com/decred/dcrd/internal/blockchain"
	"github.com/decred/dcrd/txscript/v4"
	"github.com/decred/dcrd/txscript/v4/stdaddr"
	"github.com/decred/dcrd/txscript/v4/stdscript"
	"github.com/decred/dcrd/wire"
)

var (
	// zeroHash is the zero value hash (all zeros).  It is defined as a
	// convenience.
	zeroHash chainhash.Hash

	// opTrueScript is a simple public key script that contains the OP_TRUE
	// opcode.  It is defined here to reduce garbage creation.
	opTrueScript = []byte{txscript.OP_TRUE}
)

// Config is a descriptor containing the mining configuration.
type Config struct {
	// Policy houses the policy (configuration parameters) which is used to control
	// the generation of block templates.
	Policy *Policy

	// TxSource represents a source of transactions to consider for inclusion in
	// new blocks.
	TxSource TxSource

	// TimeSource defines the median time source which is used to retrieve the
	// current time adjusted by the median time offset.  This is used when setting
	// the timestamp in the header of new blocks.
	TimeSource blockchain.MedianTimeSource

	// SubsidyCache defines a subsidy cache to use when calculating and validating
	// block and vote subsidies.
	SubsidyCache *standalone.SubsidyCache

	// ChainParams identifies which chain parameters should be used while
	// generating block templates.
	ChainParams *chaincfg.Params

	// MiningTimeOffset defines the number of seconds to offset the mining
	// timestamp of a block by (positive values are in the past).
	MiningTimeOffset int

	// BestSnapshot defines the function to use to access information about the
	// current best block.  The returned instance should be treated as immutable.
	BestSnapshot func() *blockchain.BestState

	// BlockByHash defines the function to use to search the internal chain block
	// stores and the database in an attempt to find the requested block and return
	// it.  This function should return blocks regardless of whether or not they
	// are part of the main chain.
	BlockByHash func(hash *chainhash.Hash) (*dcrutil.Block, error)

	// CalcNextRequiredDifficulty defines the function to use to calculate the
	// required difficulty for the block after the given block based on the
	// difficulty retarget rules.
	CalcNextRequiredDifficulty func(hash *chainhash.Hash, timestamp time.Time) (uint32, error)

	// CalcStakeVersionByHash defines the function to use to calculate the expected
	// stake version for the block AFTER the provided block hash.
	CalcStakeVersionByHash func(hash *chainhash.Hash) (uint32, error)

	// CheckConnectBlockTemplate defines the function to use to fully validate that
	// connecting the passed block to either the tip of the main chain or its
	// parent does not violate any consensus rules, aside from the proof of work
	// requirement.
	CheckConnectBlockTemplate func(block *dcrutil.Block) error

	// CheckTicketExhaustion defines the function to use to ensure that extending
	// the block associated with the provided hash with a block that contains the
	// specified number of ticket purchases will not result in a chain that is
	// unrecoverable due to inevitable ticket exhaustion.  This scenario happens
	// when the number of live tickets drops below the number of tickets that is
	// needed to reach the next block at which any outstanding immature ticket
	// purchases that would provide the necessary live tickets mature.
	CheckTicketExhaustion func(hash *chainhash.Hash, ticketPurchases uint8) error

	// CheckTransactionInputs defines the function to use to perform a series of
	// checks on the inputs to a transaction to ensure they are valid.
	CheckTransactionInputs func(tx *dcrutil.Tx, txHeight int64,
		view *blockchain.UtxoViewpoint, checkFraudProof bool,
		prevHeader *wire.BlockHeader, isTreasuryEnabled,
		isAutoRevocationsEnabled bool,
		subsidySplitVariant standalone.SubsidySplitVariant) (int64, error)

	// CheckTSpendHasVotes defines the function to use to check whether the given
	// tspend has enough votes to be included in a block AFTER the specified block.
	CheckTSpendHasVotes func(prevHash chainhash.Hash, tspend *dcrutil.Tx) error

	// CountSigOps defines the function to use to count the number of signature
	// operations for all transaction input and output scripts in the provided
	// transaction.
	CountSigOps func(tx *dcrutil.Tx, isCoinBaseTx bool, isSSGen bool, isTreasuryEnabled bool) int

	// FetchUtxoEntry defines the function to use to load and return the requested
	// unspent transaction output from the point of view of the main chain tip.
	//
	// NOTE: Requesting an output for which there is no data will NOT return an
	// error.  Instead both the entry and the error will be nil.  This is done to
	// allow pruning of spent transaction outputs.  In practice this means the
	// caller must check if the returned entry is nil before invoking methods on
	// it.
	//
	// This function is safe for concurrent access however the returned entry (if
	// any) is NOT.
	FetchUtxoEntry func(outpoint wire.OutPoint) (*blockchain.UtxoEntry, error)

	// FetchUtxoView defines the function to use to fetch unspent transaction
	// output information.  The returned instance should be treated as immutable.
	FetchUtxoView func(tx *dcrutil.Tx, includeRegularTxns bool) (*blockchain.UtxoViewpoint, error)

	// FetchUtxoViewParentTemplate defines the function to use to fetch unspent
	// transaction output information from the point of view of just having
	// connected the given block, which must be a block template that connects to
	// the parent of the tip of the main chain.  In other words, the given block
	// must be a sibling of the current tip of the main chain.
	//
	// This should typically only be used by mining code when it is unable to
	// generate a template that extends the current tip due to being unable to
	// acquire the minimum required number of votes to extend it.
	//
	// The returned instance should be treated as immutable.
	FetchUtxoViewParentTemplate func(block *wire.MsgBlock) (*blockchain.UtxoViewpoint, error)

	// ForceHeadReorganization defines the function to use to force a
	// reorganization of the block chain to the block hash requested, so long as
	// it matches up with the current organization of the best chain.
	ForceHeadReorganization func(formerBest chainhash.Hash, newBest chainhash.Hash) error

	// HeaderByHash returns the block header identified by the given hash or an
	// error if it doesn't exist.  Note that this will return headers from both
	// the main chain and any side chains.
	HeaderByHash func(hash *chainhash.Hash) (wire.BlockHeader, error)

	// IsFinalizedTransaction defines the function to use to determine whether or
	// not a transaction is finalized.
	IsFinalizedTransaction func(tx *dcrutil.Tx, blockHeight int64, blockTime time.Time) bool

	// IsHeaderCommitmentsAgendaActive defines the function to use to determine
	// whether or not the header commitments agenda is active or not for the block
	// AFTER the given block.
	IsHeaderCommitmentsAgendaActive func(prevHash *chainhash.Hash) (bool, error)

	// IsTreasuryAgendaActive defines the function to use to determine if the
	// treasury agenda is active or not for the block AFTER the given block.
	IsTreasuryAgendaActive func(prevHash *chainhash.Hash) (bool, error)

	// IsAutoRevocationsAgendaActive defines the function to use to determine if
	// the automatic ticket revocations agenda is active or not for the block
	// AFTER the given block.
	IsAutoRevocationsAgendaActive func(prevHash *chainhash.Hash) (bool, error)

	// IsSubsidySplitAgendaActive defines the function to use to determine if
	// the modified subsidy split agenda is active or not for the block AFTER
	// the given block.
	IsSubsidySplitAgendaActive func(prevHash *chainhash.Hash) (bool, error)

	// IsSubsidySplitR2AgendaActive defines the function to use to determine if
	// the modified subsidy split round 2 agenda is active or not for the block
	// AFTER the given block.
	IsSubsidySplitR2AgendaActive func(prevHash *chainhash.Hash) (bool, error)

	// MaxTreasuryExpenditure defines the function to use to get the maximum amount
	// of funds that can be spent from the treasury by a set of TSpends for a block
	// that extends the given block hash.  The function should return 0 if it is
	// called on an invalid TVI.
	MaxTreasuryExpenditure func(preTVIBlock *chainhash.Hash) (int64, error)

	// NewUtxoViewpoint defines the function to use to create a new empty unspent
	// transaction output view.
	NewUtxoViewpoint func() *blockchain.UtxoViewpoint

	// TipGeneration defines the function to use to get the entire generation of
	// blocks stemming from the parent of the current tip.
	TipGeneration func() []chainhash.Hash

	// ValidateTransactionScripts defines the function to use to validate the
	// scripts for the passed transaction.
	ValidateTransactionScripts func(tx *dcrutil.Tx,
		utxoView *blockchain.UtxoViewpoint, flags txscript.ScriptFlags,
		isAutoRevocationsEnabled bool) error
}

// TxDesc is a descriptor about a transaction in a transaction source along with
// additional metadata.
type TxDesc struct {
	// Tx is the transaction associated with the entry.
	Tx *dcrutil.Tx

	// Type is the type of the transaction associated with the entry.
	Type stake.TxType

	// Added is the time when the entry was added to the source pool.
	Added time.Time

	// Height is the block height when the entry was added to the source
	// pool.
	Height int64

	// Fee is the total fee the transaction associated with the entry pays.
	Fee int64

	// TotalSigOps is the total signature operations for this transaction.
	TotalSigOps int

	// TxSize is the size of the transaction.
	TxSize int64
}

// TxAncestorStats is a descriptor that stores aggregated statistics for the
// unconfirmed ancestors of a transaction.
type TxAncestorStats struct {
	// Fees is the sum of all fees of unconfirmed ancestors.
	Fees int64

	// SizeBytes is the total size of all unconfirmed ancestors.
	SizeBytes int64

	// TotalSigOps is the total number of signature operations of all ancestors.
	TotalSigOps int

	// NumAncestors is the total number of ancestors for a given transaction.
	NumAncestors int

	// NumDescendants is the total number of descendants that have ancestor
	// statistics tracked for a given transaction.
	NumDescendants int
}

// VoteDesc is a descriptor about a vote transaction in a transaction source
// along with additional metadata.
type VoteDesc struct {
	VoteHash       chainhash.Hash
	TicketHash     chainhash.Hash
	ApprovesParent bool
}

const (
	// generatedBlockVersion is the version of the block being generated for
	// the main network.  It is defined as a constant here rather than using
	// the wire.BlockVersion constant since a change in the block version
	// will require changes to the generated block.  Using the wire constant
	// for generated block version could allow creation of invalid blocks
	// for the updated version.
	generatedBlockVersion = 10

	// generatedBlockVersionTest is the version of the block being generated
	// for networks other than the main network.
	generatedBlockVersionTest = 11

	// blockHeaderOverhead is the max number of bytes it takes to serialize
	// a block header and max possible transaction count.
	blockHeaderOverhead = wire.MaxBlockHeaderPayload + wire.MaxVarIntPayload

	// coinbaseFlags is some extra data appended to the coinbase script
	// sig.
	coinbaseFlags = "/dcrd/"

	// kilobyte is the size of a kilobyte.
	kilobyte = 1000
)

// containsTx is a helper function that checks to see if a list of transactions
// contains any of the TxIns of some transaction.
func containsTxIns(txs []*dcrutil.Tx, tx *dcrutil.Tx) bool {
	for _, txToCheck := range txs {
		for _, txIn := range tx.MsgTx().TxIn {
			if txIn.PreviousOutPoint.Hash.IsEqual(txToCheck.Hash()) {
				return true
			}
		}
	}

	return false
}

// blockWithNumVotes is a block with the number of votes currently present
// for that block. Just used for sorting.
type blockWithNumVotes struct {
	Hash     chainhash.Hash
	NumVotes uint16
}

// byNumberOfVotes implements sort.Interface to sort a slice of blocks by their
// number of votes.
type byNumberOfVotes []*blockWithNumVotes

// Len returns the number of elements in the slice.  It is part of the
// sort.Interface implementation.
func (b byNumberOfVotes) Len() int {
	return len(b)
}

// Swap swaps the elements at the passed indices.  It is part of the
// sort.Interface implementation.
func (b byNumberOfVotes) Swap(i, j int) {
	b[i], b[j] = b[j], b[i]
}

// Less returns whether the block with index i should sort before the block with
// index j.  It is part of the sort.Interface implementation.
func (b byNumberOfVotes) Less(i, j int) bool {
	return b[i].NumVotes < b[j].NumVotes
}

// SortParentsByVotes takes a list of block header hashes and sorts them
// by the number of votes currently available for them in the votes map of
// mempool.  It then returns all blocks that are eligible to be used (have
// at least a majority number of votes) sorted by number of votes, descending.
//
// This function is safe for concurrent access.
func SortParentsByVotes(txSource TxSource, currentTopBlock chainhash.Hash, blocks []chainhash.Hash, params *chaincfg.Params) []chainhash.Hash {
	// Return now when no blocks were provided.
	lenBlocks := len(blocks)
	if lenBlocks == 0 {
		return nil
	}

	// Fetch the vote metadata for the provided block hashes from the
	// mempool and filter out any blocks that do not have the minimum
	// required number of votes.
	minVotesRequired := (params.TicketsPerBlock / 2) + 1
	voteMetadata := txSource.VotesForBlocks(blocks)
	filtered := make([]*blockWithNumVotes, 0, lenBlocks)
	for i := range blocks {
		numVotes := uint16(len(voteMetadata[i]))
		if numVotes >= minVotesRequired {
			filtered = append(filtered, &blockWithNumVotes{
				Hash:     blocks[i],
				NumVotes: numVotes,
			})
		}
	}

	// Return now if there are no blocks with enough votes to be eligible to
	// build on top of.
	if len(filtered) == 0 {
		return nil
	}

	// Blocks with the most votes appear at the top of the list.
	sort.Sort(sort.Reverse(byNumberOfVotes(filtered)))
	sortedUsefulBlocks := make([]chainhash.Hash, 0, len(filtered))
	for _, bwnv := range filtered {
		sortedUsefulBlocks = append(sortedUsefulBlocks, bwnv.Hash)
	}

	// Make sure we don't reorganize the chain needlessly if the top block has
	// the same amount of votes as the current leader after the sort. After this
	// point, all blocks listed in sortedUsefulBlocks definitely also have the
	// minimum number of votes required.
	curVoteMetadata := txSource.VotesForBlocks([]chainhash.Hash{currentTopBlock})
	var numTopBlockVotes uint16
	if len(curVoteMetadata) > 0 {
		numTopBlockVotes = uint16(len(curVoteMetadata[0]))
	}
	if filtered[0].NumVotes == numTopBlockVotes && filtered[0].Hash !=
		currentTopBlock {

		// Attempt to find the position of the current block being built
		// from in the list.
		pos := 0
		for i, bwnv := range filtered {
			if bwnv.Hash == currentTopBlock {
				pos = i
				break
			}
		}

		// Swap the top block into the first position. We directly access
		// sortedUsefulBlocks useful blocks here with the assumption that
		// since the values were accumulated from filtered, they should be
		// in the same positions and we shouldn't be able to access anything
		// out of bounds.
		if pos != 0 {
			sortedUsefulBlocks[0], sortedUsefulBlocks[pos] =
				sortedUsefulBlocks[pos], sortedUsefulBlocks[0]
		}
	}

	return sortedUsefulBlocks
}

// BlockTemplate houses a block that has yet to be solved along with additional
// details about the fees and the number of signature operations for each
// transaction in the block.
type BlockTemplate struct {
	// Block is a block that is ready to be solved by miners.  Thus, it is
	// completely valid with the exception of satisfying the proof-of-work
	// requirement.
	Block *wire.MsgBlock

	// Fees contains the amount of fees each transaction in the generated
	// template pays in base units.  Since the first transaction is the
	// coinbase, the first entry (offset 0) will contain the negative of the
	// sum of the fees of all other transactions.
	Fees []int64

	// SigOpCounts contains the number of signature operations each
	// transaction in the generated template performs.
	SigOpCounts []int64

	// Height is the height at which the block template connects to the main
	// chain.
	Height int64

	// ValidPayAddress indicates whether or not the template coinbase pays
	// to an address or is redeemable by anyone.  See the documentation on
	// NewBlockTemplate for details on which this can be useful to generate
	// templates without a coinbase payment address.
	ValidPayAddress bool
}

// mergeUtxoView adds all of the entries in viewB to viewA.  The result is that
// viewA will contain all of its original entries plus all of the entries
// in viewB.  It will replace any entries in viewB which also exist in viewA
// if the entry in viewA is spent.
func mergeUtxoView(viewA *blockchain.UtxoViewpoint, viewB *blockchain.UtxoViewpoint) {
	viewAEntries := viewA.Entries()
	for outpoint, entryB := range viewB.Entries() {
		if entryA, exists := viewAEntries[outpoint]; !exists ||
			entryA == nil || entryA.IsSpent() {
			viewAEntries[outpoint] = entryB
		}
	}
}

// hashExistsInList checks if a hash exists in a list of hash pointers.
func hashInSlice(h chainhash.Hash, list []chainhash.Hash) bool {
	for i := range list {
		if h == list[i] {
			return true
		}
	}

	return false
}

// txIndexFromTxList returns a transaction's index in a list, or -1 if it
// can not be found.
func txIndexFromTxList(hash chainhash.Hash, list []*dcrutil.Tx) int {
	for i, tx := range list {
		h := tx.Hash()
		if hash == *h {
			return i
		}
	}

	return -1
}

// standardCoinbaseOpReturn creates a standard OP_RETURN output to insert into
// coinbase. This function autogenerates the extranonce. The OP_RETURN pushes
// 12 bytes.
func standardCoinbaseOpReturn(height uint32) ([]byte, error) {
	extraNonce, err := wire.RandomUint64()
	if err != nil {
		return nil, err
	}

	enData := make([]byte, 12)
	binary.LittleEndian.PutUint32(enData[0:4], height)
	binary.LittleEndian.PutUint64(enData[4:12], extraNonce)
	extraNonceScript, err := stdscript.ProvablyPruneableScriptV0(enData)
	if err != nil {
		return nil, err
	}

	return extraNonceScript, nil
}

// standardTreasurybaseOpReturn creates a standard OP_RETURN output to insert
// into a treasurybase. This function autogenerates the extranonce. The
// OP_RETURN pushes 12 bytes.
func standardTreasurybaseOpReturn(height uint32) ([]byte, error) {
	extraNonce, err := wire.RandomUint64()
	if err != nil {
		return nil, err
	}

	enData := make([]byte, 12)
	binary.LittleEndian.PutUint32(enData[0:4], height)
	binary.LittleEndian.PutUint64(enData[4:12], extraNonce)
	extraNonceScript, err := stdscript.ProvablyPruneableScriptV0(enData)
	if err != nil {
		return nil, err
	}

	return extraNonceScript, nil
}

// calcBlockMerkleRoot calculates and returns a merkle root depending on the
// result of the header commitments agenda vote.  In particular, before the
// agenda is active, it returns the merkle root of the regular transaction tree.
// Once the agenda is active, it returns the combined merkle root for the
// regular and stake transaction trees in accordance with DCP0005.
func calcBlockMerkleRoot(regularTxns, stakeTxns []*wire.MsgTx, hdrCmtActive bool) chainhash.Hash {
	if !hdrCmtActive {
		return standalone.CalcTxTreeMerkleRoot(regularTxns)
	}

	return standalone.CalcCombinedTxTreeMerkleRoot(regularTxns, stakeTxns)
}

// calcBlockCommitmentRootV1 calculates and returns the required v1 block and
// the previous output scripts it references as inputs.
func calcBlockCommitmentRootV1(block *wire.MsgBlock, prevScripts blockcf2.PrevScripter) (chainhash.Hash, error) {
	filter, err := blockcf2.Regular(block, prevScripts)
	if err != nil {
		return chainhash.Hash{}, err
	}
	return blockchain.CalcCommitmentRootV1(filter.Hash()), nil
}

// createCoinbaseTx returns a coinbase transaction paying an appropriate subsidy
// based on the passed block height to the provided address.  When the address
// is nil, the coinbase transaction will instead be redeemable by anyone.
//
// See the comment for NewBlockTemplate for more information about why the nil
// address handling is useful.
func createCoinbaseTx(subsidyCache *standalone.SubsidyCache,
	coinbaseScript []byte, opReturnPkScript []byte, nextBlockHeight int64,
	addr stdaddr.Address, voters uint16, params *chaincfg.Params,
	isTreasuryEnabled bool,
	subsidySplitVariant standalone.SubsidySplitVariant) *dcrutil.Tx {

	// Coinbase transactions have no inputs, so previous outpoint is zero hash
	// and max index.
	coinbaseInput := &wire.TxIn{
		PreviousOutPoint: *wire.NewOutPoint(&chainhash.Hash{},
			wire.MaxPrevOutIndex, wire.TxTreeRegular),
		Sequence:        wire.MaxTxInSequenceNum,
		BlockHeight:     wire.NullBlockHeight,
		BlockIndex:      wire.NullBlockIndex,
		SignatureScript: coinbaseScript,
	}

	// Block one is a special block that might pay out tokens to a ledger.
	if nextBlockHeight == 1 && len(params.BlockOneLedger) != 0 {
		tx := wire.NewMsgTx()
		tx.Version = 1
		tx.AddTxIn(coinbaseInput)
		tx.TxIn[0].ValueIn = params.BlockOneSubsidy()

		for _, payout := range params.BlockOneLedger {
			tx.AddTxOut(&wire.TxOut{
				Value:    payout.Amount,
				Version:  payout.ScriptVersion,
				PkScript: payout.Script,
			})
		}

		return dcrutil.NewTx(tx)
	}

	// Prior to the decentralized treasury agenda, the transaction version must
	// be 1 and there is an additional output that either pays to organization
	// associated with the treasury or a provably pruneable zero-value output
	// script when it is disabled.
	//
	// Once the decentralized treasury agenda is active, the transaction version
	// must be the new expected version and there is no treasury output since it
	// is included in the stake tree instead.
	var txVersion = uint16(1)
	var treasuryOutput *wire.TxOut
	var treasurySubsidy int64
	if !isTreasuryEnabled {
		if params.BlockTaxProportion > 0 {
			// Create the treasury output with the correct subsidy and public
			// key script for the organization associated with the treasury.
			treasurySubsidy = subsidyCache.CalcTreasurySubsidy(nextBlockHeight,
				voters, isTreasuryEnabled)
			treasuryOutput = &wire.TxOut{
				Value:    treasurySubsidy,
				PkScript: params.OrganizationPkScript,
			}
		} else {
			// Treasury disabled.
			treasuryOutput = &wire.TxOut{
				Value:    0,
				PkScript: opTrueScript,
			}
		}
	} else {
		// Set the transaction version to the new version required by the
		// decentralized treasury agenda.
		txVersion = wire.TxVersionTreasury
	}

	// Create the script to pay to the provided payment address if one was
	// specified.  Otherwise create a script that allows the coinbase to be
	// redeemable by anyone.
	workSubsidyScriptVer := uint16(0)
	workSubsidyScript := opTrueScript
	if addr != nil {
		workSubsidyScriptVer, workSubsidyScript = addr.PaymentScript()
	}

	// Create a coinbase with expected inputs and outputs.
	//
	// Inputs:
	//  - A single input with input value set to the total payout amount.
	//
	// Outputs:
	//  - Potential treasury output prior to the decentralized treasury agenda
	//  - Output that includes the block height and potential extra nonce used
	//    to ensure a unique hash
	//  - Output that pays the work subsidy to the miner
	workSubsidy := subsidyCache.CalcWorkSubsidyV3(nextBlockHeight, voters,
		subsidySplitVariant)
	tx := wire.NewMsgTx()
	tx.Version = txVersion
	tx.AddTxIn(coinbaseInput)
	tx.TxIn[0].ValueIn = workSubsidy + treasurySubsidy
	if treasuryOutput != nil {
		tx.AddTxOut(treasuryOutput)
	}
	tx.AddTxOut(&wire.TxOut{
		Value:    0,
		PkScript: opReturnPkScript,
	})
	tx.AddTxOut(&wire.TxOut{
		Value:    workSubsidy,
		Version:  workSubsidyScriptVer,
		PkScript: workSubsidyScript,
	})
	return dcrutil.NewTx(tx)
}

// createTreasuryBaseTx returns a treasurybase transaction paying an appropriate
// subsidy based on the passed block height to the treasury.
func createTreasuryBaseTx(subsidyCache *standalone.SubsidyCache, nextBlockHeight int64, voters uint16) (*dcrutil.Tx, error) {
	// Create provably pruneable script for the output that encodes the block
	// height used to ensure a unique overall transaction hash.  This is
	// necessary because neither the input nor the output that adds to the
	// treasury account balance are unique for a treasurybase.
	opReturnTreasury, err := standardTreasurybaseOpReturn(uint32(nextBlockHeight))
	if err != nil {
		return nil, err
	}

	// Create a treasurybase with expected inputs and outputs.
	//
	// Inputs:
	//  - A single input with input value set to the total payout amount.
	//
	// Outputs:
	//  - Treasury output that adds to the treasury account balance
	//  - Output that includes the block height to ensure a unique hash
	//
	// Note that all treasurybase transactions require TxVersionTreasury and
	// they must be in the stake transaction tree.
	const withTreasury = true
	trsySubsidy := subsidyCache.CalcTreasurySubsidy(nextBlockHeight, voters,
		withTreasury)
	tx := wire.NewMsgTx()
	tx.Version = wire.TxVersionTreasury
	tx.AddTxIn(&wire.TxIn{
		// Treasurybase transactions have no inputs, so previous outpoint
		// is zero hash and max index.
		PreviousOutPoint: *wire.NewOutPoint(&chainhash.Hash{},
			wire.MaxPrevOutIndex, wire.TxTreeRegular),
		Sequence:        wire.MaxTxInSequenceNum,
		BlockHeight:     wire.NullBlockHeight,
		BlockIndex:      wire.NullBlockIndex,
		SignatureScript: nil, // Must be nil by consensus.
	})
	tx.TxIn[0].ValueIn = trsySubsidy
	tx.AddTxOut(&wire.TxOut{
		Value:    trsySubsidy,
		Version:  0,
		PkScript: []byte{txscript.OP_TADD},
	})
	tx.AddTxOut(&wire.TxOut{
		Value:    0,
		PkScript: opReturnTreasury,
	})
	retTx := dcrutil.NewTx(tx)
	retTx.SetTree(wire.TxTreeStake)
	return retTx, nil
}

// spendTransaction updates the passed view by marking the inputs to the passed
// transaction as spent.  It also adds all outputs in the passed transaction
// which are not provably unspendable as available unspent transaction outputs.
func spendTransaction(utxoView *blockchain.UtxoViewpoint, tx *dcrutil.Tx,
	height int64, isTreasuryEnabled bool) {

	for _, txIn := range tx.MsgTx().TxIn {
		entry := utxoView.LookupEntry(txIn.PreviousOutPoint)
		if entry != nil {
			entry.Spend()
		}
	}

	utxoView.AddTxOuts(tx, height, wire.NullBlockIndex, isTreasuryEnabled)
}

// logSkippedDeps logs any dependencies which are also skipped as a result of
// skipping a transaction while generating a block template at the trace level.
func logSkippedDeps(tx *dcrutil.Tx, deps []*TxDesc) {
	if deps == nil {
		return
	}

	for _, item := range deps {
		log.Tracef("Skipping tx %s since it depends on %s\n",
			item.Tx.Hash(), tx.Hash())
	}
}

// minimumMedianTime returns the minimum allowed timestamp for a block building
// on the end of the current best chain.  In particular, it is one second after
// the median timestamp of the last several blocks per the chain consensus
// rules.
func minimumMedianTime(best *blockchain.BestState) time.Time {
	return best.MedianTime.Add(time.Second)
}

// medianAdjustedTime returns the current time adjusted to ensure it is at least
// one second after the median timestamp of the last several blocks per the
// chain consensus rules.
func (g *BlkTmplGenerator) medianAdjustedTime() time.Time {
	// The timestamp for the block must not be before the median timestamp
	// of the last several blocks.  Thus, choose the maximum between the
	// current time and one second after the past median time.  The current
	// timestamp is truncated to a second boundary before comparison since a
	// block timestamp does not support a precision greater than one second.
	best := g.cfg.BestSnapshot()
	newTimestamp := g.cfg.TimeSource.AdjustedTime()
	minTimestamp := minimumMedianTime(best)
	if newTimestamp.Before(minTimestamp) {
		newTimestamp = minTimestamp
	}

	// Adjust by the amount requested from the command line argument.
	newTimestamp = newTimestamp.Add(
		time.Duration(-g.cfg.MiningTimeOffset) * time.Second)

	return newTimestamp
}

// maybeInsertStakeTx checks to make sure that a stake tx is
// valid from the perspective of the mainchain (not necessarily
// the mempool or block) before inserting into a tx tree.
// If it fails the check, it returns false; otherwise true.
func (g *BlkTmplGenerator) maybeInsertStakeTx(stx *dcrutil.Tx, treeValid bool, isTreasuryEnabled bool) bool {
	missingInput := false

	view, err := g.cfg.FetchUtxoView(stx, treeValid)
	if err != nil {
		log.Warnf("Unable to fetch transaction store for "+
			"stx %s: %v", stx.Hash(), err)
		return false
	}
	mstx := stx.MsgTx()
	isSSGen := stake.IsSSGen(mstx)
	var isTSpend, isTreasuryBase bool
	if isTreasuryEnabled {
		isTSpend = stake.IsTSpend(mstx)
		isTreasuryBase = stake.IsTreasuryBase(mstx)
	}
	for i, txIn := range mstx.TxIn {
		// Evaluate if this is a stakebase or treasury base input or
		// not. If it is, continue without evaluation of the input.
		if (i == 0 && (isSSGen || isTreasuryBase)) || isTSpend {
			txIn.BlockHeight = wire.NullBlockHeight
			txIn.BlockIndex = wire.NullBlockIndex
			continue
		}

		entry := view.LookupEntry(txIn.PreviousOutPoint)
		if entry == nil {
			missingInput = true
			break
		} else {
			txIn.ValueIn = entry.Amount()
			txIn.BlockHeight = uint32(entry.BlockHeight())
			txIn.BlockIndex = entry.BlockIndex()
		}
	}
	return !missingInput
}

// handleTooFewVoters handles the situation in which there are too few voters on
// of the blockchain. If there are too few voters and a cached parent template to
// work off of is present, it will return a copy of that template to pass to the
// miner.
// Safe for concurrent access.
func (g *BlkTmplGenerator) handleTooFewVoters(nextHeight int64,
	miningAddress stdaddr.Address, isTreasuryEnabled bool,
	subsidySplitVariant standalone.SubsidySplitVariant) (*BlockTemplate, error) {

	stakeValidationHeight := g.cfg.ChainParams.StakeValidationHeight

	// Handle not enough voters being present if we're set to mine aggressively
	// (default behavior).
	best := g.cfg.BestSnapshot()
	if nextHeight >= stakeValidationHeight && g.cfg.Policy.AggressiveMining {
		// Fetch the latest block and head and begin working off of it with an
		// empty transaction tree regular and the contents of that stake tree.
		// In the future we should have the option of reading some transactions
		// from this block, too.
		topBlock, err := g.cfg.BlockByHash(&best.Hash)
		if err != nil {
			str := fmt.Sprintf("unable to get tip block %s", best.PrevHash)
			return nil, makeError(ErrGetTopBlock, str)
		}
		tipHeader := &topBlock.MsgBlock().Header

		// Start with a copy of the tip block header.
		var block wire.MsgBlock
		block.Header = *tipHeader

		// Create and populate a new coinbase.
		coinbaseScript := make([]byte, len(coinbaseFlags)+2)
		copy(coinbaseScript[2:], coinbaseFlags)
		opReturnPkScript, err := standardCoinbaseOpReturn(tipHeader.Height)
		if err != nil {
			return nil, err
		}
		coinbaseTx := createCoinbaseTx(g.cfg.SubsidyCache, coinbaseScript,
			opReturnPkScript, topBlock.Height(), miningAddress,
			tipHeader.Voters, g.cfg.ChainParams, isTreasuryEnabled,
			subsidySplitVariant)
		block.AddTransaction(coinbaseTx.MsgTx())

		if isTreasuryEnabled {
			treasuryBase, err := createTreasuryBaseTx(g.cfg.SubsidyCache,
				topBlock.Height(), tipHeader.Voters)
			if err != nil {
				return nil, err
			}
			block.AddSTransaction(treasuryBase.MsgTx())
		}

		// Copy all of the regular transactions over.
		for i, tx := range topBlock.Transactions() {
			if i == 0 {
				// Skip copying coinbase.
				continue
			}
			block.AddTransaction(tx.MsgTx())
		}

		// Copy all of the stake transactions over.
		for i, stx := range topBlock.STransactions() {
			if i == 0 && isTreasuryEnabled {
				// Skip copying treasurybase.
				continue
			}
			block.AddSTransaction(stx.MsgTx())
		}

		// Set a fresh timestamp.
		ts := g.medianAdjustedTime()
		block.Header.Timestamp = ts

		// Recalculate the size.
		block.Header.Size = uint32(block.SerializeSize())

		bt := &BlockTemplate{
			Block:           &block,
			Fees:            []int64{0},
			SigOpCounts:     []int64{0},
			Height:          int64(tipHeader.Height),
			ValidPayAddress: miningAddress != nil,
		}

		// Calculate the merkle root depending on the result of the header
		// commitments agenda vote.
		prevHash := &tipHeader.PrevBlock
		hdrCmtActive, err := g.cfg.IsHeaderCommitmentsAgendaActive(prevHash)
		if err != nil {
			return nil, err
		}
		header := &block.Header
		header.MerkleRoot = calcBlockMerkleRoot(block.Transactions, block.STransactions, hdrCmtActive)

		// Calculate the stake root or commitment root depending on the result
		// of the header commitments agenda vote.
		var cmtRoot chainhash.Hash
		if hdrCmtActive {
			// Load all of the previous output scripts the block references as
			// inputs since they are needed to create the filter commitment.
			blockUtxos, err := g.cfg.FetchUtxoViewParentTemplate(&block)
			if err != nil {
				str := fmt.Sprintf("failed to fetch inputs when making new "+
					"block template: %v", err)
				return nil, makeError(ErrFetchTxStore, str)
			}

			cmtRoot, err = calcBlockCommitmentRootV1(&block, blockUtxos)
			if err != nil {
				str := fmt.Sprintf("failed to calculate commitment root for "+
					"block when making new block template: %v", err)
				return nil, makeError(ErrCalcCommitmentRoot, str)
			}
		} else {
			cmtRoot = standalone.CalcTxTreeMerkleRoot(block.STransactions)
		}
		header.StakeRoot = cmtRoot

		// Make sure the block validates.
		btBlock := dcrutil.NewBlockDeepCopyCoinbase(&block)
		err = g.cfg.CheckConnectBlockTemplate(btBlock)
		if err != nil {
			str := fmt.Sprintf("failed to check template: %v while "+
				"constructing a new parent", err.Error())
			return nil, makeError(ErrCheckConnectBlock, str)
		}

		return bt, nil
	}

	log.Debugf("Not enough voters on top block to generate " +
		"new block template")

	return nil, nil
}

// createRevocationFromTicket creates a revocation transaction from the provided
// ticket hash.  It also adds any utxos used to create the transaction to the
// provided block utxos viewpoint so that they are available for lookup.
//
// Note: This should only be used if the automatic ticket revocations agenda is
// active.
func (g *BlkTmplGenerator) createRevocationFromTicket(ticketHash *chainhash.Hash,
	blockUtxos *blockchain.UtxoViewpoint, prevHeaderBytes []byte,
	isTreasuryEnabled bool) (*TxDesc, error) {

	// Fetch the utxo for the ticket submission to be revoked.
	const ticketSubmissionOutput = 0
	ticketSubmission := wire.OutPoint{
		Hash:  *ticketHash,
		Index: ticketSubmissionOutput,
		Tree:  wire.TxTreeStake,
	}
	ticketUtxo, err := g.cfg.FetchUtxoEntry(ticketSubmission)
	if err != nil {
		return nil, makeError(ErrGetTicketInfo, err.Error())
	}
	if ticketUtxo == nil || ticketUtxo.IsSpent() {
		str := fmt.Sprintf("ticket %v does not exist or is spent", ticketHash)
		return nil, makeError(ErrGetTicketInfo, str)
	}

	// Add the ticket submission utxo to the block utxos view so that it is
	// available for lookup later.
	blockUtxos.Entries()[ticketSubmission] = ticketUtxo

	// Get the minimal outputs for the ticket.
	ticketMinOuts := ticketUtxo.TicketMinimalOutputs()
	if ticketMinOuts == nil {
		str := fmt.Sprintf("ticket %v missing minimal outputs", ticketHash)
		return nil, makeError(ErrGetTicketInfo, str)
	}

	// Create a revocation transaction for the ticket.
	const isAutoRevocationsEnabled = true
	const revocationTxFee = dcrutil.Amount(0)
	revocationMsgTx, err := stake.CreateRevocationFromTicket(ticketHash,
		ticketMinOuts, revocationTxFee, stake.TxVersionAutoRevocations,
		g.cfg.ChainParams, prevHeaderBytes, isAutoRevocationsEnabled)
	if err != nil {
		return nil, err
	}
	revocationTx := dcrutil.NewTx(revocationMsgTx)
	revocationTx.SetTree(wire.TxTreeStake)
	txDesc := &TxDesc{
		Tx:   revocationTx,
		Type: stake.TxTypeSSRtx,
		TotalSigOps: g.cfg.CountSigOps(revocationTx, false, false,
			isTreasuryEnabled),
		TxSize: int64(revocationMsgTx.SerializeSize()),
	}

	return txDesc, nil
}

// addAutoRevocationsToQueue is a helper function that creates revocations for
// all tickets that will become missed or expired as of the block being created.
// It inserts the created revocations into the provided priority queue and maps.
//
// Note: This should only be used if the automatic ticket revocations agenda is
// active.
func (g *BlkTmplGenerator) addAutoRevocationsToQueue(winningTickets map[chainhash.Hash]bool,
	blockUtxos *blockchain.UtxoViewpoint, prevHeaderBytes []byte, numSSGen int,
	isTreasuryEnabled bool, priorityQueue *txPriorityQueue,
	prioritizedTxns map[chainhash.Hash]struct{},
	prioItemMap map[chainhash.Hash]*txPrioItem) error {

	// Return now if there are no tickets to revoke.
	best := g.cfg.BestSnapshot()
	missedCount := len(best.NextWinningTickets) - numSSGen
	expiredCount := len(best.NextExpiringTickets)
	if missedCount+expiredCount == 0 {
		return nil
	}

	// Create a slice of the ticket hashes that must be revoked due to
	// becoming missed or expired this block.
	revokeTickets := make([]chainhash.Hash, 0, missedCount+expiredCount)

	// Add tickets that will be missed to the slice of ticket hashes to
	// revoke.
	for ticketHash, hasVote := range winningTickets {
		// If a winning ticket does not have a vote in this block, it will be
		// missed.
		if !hasVote {
			revokeTickets = append(revokeTickets, ticketHash)
		}
	}

	// Add tickets that will be expired to the slice of ticket hashes to
	// revoke.
	revokeTickets = append(revokeTickets, best.NextExpiringTickets...)

	// Create revocation transactions for all tickets that will become missed
	// or expired as of this block.
	for i := range revokeTickets {
		// Create the revocation transaction.
		ticketHash := &revokeTickets[i]
		txDesc, err := g.createRevocationFromTicket(ticketHash, blockUtxos,
			prevHeaderBytes, isTreasuryEnabled)
		if err != nil {
			return err
		}

		// Add the revocation transaction to the priority queue.
		prioItem := &txPrioItem{
			txDesc:         txDesc,
			txType:         txDesc.Type,
			autoRevocation: true,
		}
		revocationTxHash := txDesc.Tx.Hash()
		prioritizedTxns[*revocationTxHash] = struct{}{}
		heap.Push(priorityQueue, prioItem)
		prioItemMap[*revocationTxHash] = prioItem
	}

	log.Debugf("Generated %d automatic revocations for the new block (num "+
		"missed this block: %d, num expired this block: %d)", len(revokeTickets),
		missedCount, expiredCount)

	return nil
}

// BlkTmplGenerator generates block templates based on a given mining policy
// and a transactions source. It also houses additional state required in
// order to ensure the templates adhere to the consensus rules and are built
// on top of the best chain tip or its parent if the best chain tip is
// unable to get enough votes.
//
// See the NewBlockTemplate method for a detailed description of how the block
// template is generated.
type BlkTmplGenerator struct {
	cfg *Config
}

// NewBlkTmplGenerator returns a new block template generator for the given
// policy using transactions from the provided transaction source.
func NewBlkTmplGenerator(cfg *Config) *BlkTmplGenerator {
	return &BlkTmplGenerator{cfg: cfg}
}

// calcFeePerKb returns an adjusted fee per kilobyte taking the provided
// transaction and its ancestors into account.
func calcFeePerKb(txDesc *TxDesc, ancestorStats *TxAncestorStats) float64 {
	txSize := txDesc.Tx.MsgTx().SerializeSize()
	if ancestorStats.Fees < 0 || ancestorStats.SizeBytes < 0 {
		return (float64(txDesc.Fee) * float64(kilobyte)) / float64(txSize)
	}
	return (float64(txDesc.Fee+ancestorStats.Fees) * float64(kilobyte)) /
		float64(int64(txSize)+ancestorStats.SizeBytes)
}

// NewBlockTemplate returns a new block template that is ready to be solved
// using the transactions from the passed transaction source pool and a coinbase
// that either pays to the passed address if it is not nil, or a coinbase that
// is redeemable by anyone if the passed address is nil.  The nil address
// functionality is useful since there are cases such as the getblocktemplate
// RPC where external mining software is responsible for creating their own
// coinbase which will replace the one generated for the block template.  Thus
// the need to have configured address can be avoided.
//
// The transactions selected and included are prioritized according to whether
// or not they are stake transactions and their fee per kilobyte.  Transactions
// with a higher fee per kilobyte are preferred.  Finally, the block generation
// related policy settings are all taken into account.
//
// Transactions which only spend outputs from other transactions already in the
// block chain are immediately added to a priority queue which prioritizes based
// the fee per kilobyte.  Transactions which spend outputs from other
// transactions in the source pool are added to a dependency map so they can be
// added to the priority queue once the transactions they depend on have been
// included.
//
// When the fees per kilobyte drop below the TxMinFreeFee policy setting, the
// transaction will be skipped.
//
// Any transactions which would cause the block to exceed the BlockMaxSize
// policy setting, exceed the maximum allowed signature operations per block, or
// otherwise cause the block to be invalid are skipped.
//
// Given the above, a block generated by this function is of the following form:
//
//	 -----------------------------------  --
//	|      Coinbase Transaction         |   |
//	|-----------------------------------|   |
//	|                                   |   |
//	|                                   |   |--- (policy.BlockMaxSize) / 2
//	|  Transactions prioritized by fee  |   |
//	|  until <= policy.TxMinFreeFee     |   |
//	|                                   |   |
//	|                                   |   |
//	 -----------------------------------  --
//
// Which also includes a stake tree that looks like the following:
//
//	 -----------------------------------  --  --
//	|                                   |   |   |
//	|             Votes                 |   |   | --- >= (chaincfg.TicketsPerBlock/2) + 1
//	|                                   |   |   |
//	|-----------------------------------|   | --
//	|                                   |   |   |
//	|            Tickets                |   |   | --- <= chaincfg.MaxFreshStakePerBlock
//	|                                   |   |   |
//	|-----------------------------------|   | --
//	|                                   |   |
//	|          Revocations              |   |
//	|                                   |   |
//	 -----------------------------------  --
//
// This function returns nil when there are not enough voters on any of the
// current top blocks to create a new block template.
func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress stdaddr.Address) (*BlockTemplate, error) {
	// All transaction scripts are verified using the more strict standard
	// flags.
	scriptFlags, err := g.cfg.Policy.StandardVerifyFlags()
	if err != nil {
		return nil, err
	}

	// Extend the most recently known best block.
	// The most recently known best block is the top block that has the most
	// ssgen votes for it. We only need this after the height in which stake voting
	// has kicked in.
	// To figure out which block has the most ssgen votes, we need to run the
	// following algorithm:
	// 1. Acquire the HEAD block and all of its orphans. Record their block header
	// hashes.
	// 2. Create a map of [blockHeaderHash] --> [mempoolTxnList].
	// 3. for blockHeaderHash in candidateBlocks:
	//		if mempoolTx.StakeDesc == SSGen &&
	//			mempoolTx.SSGenParseBlockHeader() == blockHeaderHash:
	//			map[blockHeaderHash].append(mempoolTx)
	// 4. Check len of each map entry and store.
	// 5. Query the ticketdb and check how many eligible ticket holders there are
	//    for the given block you are voting on.
	// 6. Divide #ofvotes (len(map entry)) / totalPossibleVotes --> penalty ratio
	// 7. Store penalty ratios for all block candidates.
	// 8. Select the one with the largest penalty ratio (highest block reward).
	//    This block is then selected to build upon instead of the others, because
	//    it yields the greater amount of rewards.

	best := g.cfg.BestSnapshot()
	prevHash := best.Hash
	nextBlockHeight := best.Height + 1
	stakeValidationHeight := g.cfg.ChainParams.StakeValidationHeight

	isTreasuryEnabled, err := g.cfg.IsTreasuryAgendaActive(&prevHash)
	if err != nil {
		return nil, err
	}

	isAutoRevocationsEnabled, err := g.cfg.IsAutoRevocationsAgendaActive(&prevHash)
	if err != nil {
		return nil, err
	}

	isSubsidyEnabled, err := g.cfg.IsSubsidySplitAgendaActive(&prevHash)
	if err != nil {
		return nil, err
	}

	isSubsidyR2Enabled, err := g.cfg.IsSubsidySplitR2AgendaActive(&prevHash)
	if err != nil {
		return nil, err
	}

	// Determine which subsidy split variant to use depending on the active
	// agendas.
	subsidySplitVariant := standalone.SSVOriginal
	switch {
	case isSubsidyR2Enabled:
		subsidySplitVariant = standalone.SSVDCP0012
	case isSubsidyEnabled:
		subsidySplitVariant = standalone.SSVDCP0010
	}

	var (
		isTVI            bool
		maxTreasurySpend int64
	)
	if isTreasuryEnabled {
		isTVI = standalone.IsTreasuryVoteInterval(uint64(nextBlockHeight),
			g.cfg.ChainParams.TreasuryVoteInterval)
	}

	if nextBlockHeight >= stakeValidationHeight {
		// Obtain the entire generation of blocks stemming from this parent.
		children := g.cfg.TipGeneration()

		// Get the list of blocks that we can actually build on top of. If we're
		// not currently on the block that has the most votes, switch to that
		// block.
		eligibleParents := SortParentsByVotes(g.cfg.TxSource, prevHash, children,
			g.cfg.ChainParams)
		if len(eligibleParents) == 0 {
			log.Debugf("Too few voters found on any HEAD block, " +
				"recycling a parent block to mine on")
			return g.handleTooFewVoters(nextBlockHeight, payToAddress,
				isTreasuryEnabled, subsidySplitVariant)
		}

		log.Debugf("Found eligible parent %v with enough votes to build "+
			"block on, proceeding to create a new block template",
			eligibleParents[0])

		// Force a reorganization to the parent with the most votes if needed.
		for i := range eligibleParents {
			newHead := &eligibleParents[i]
			if *newHead == prevHash {
				break
			}

			err := g.cfg.ForceHeadReorganization(prevHash, *newHead)
			if err != nil {
				log.Debugf("failed to reorganize to new parent: %v", err)
				continue
			}

			// Ensure the needed votes are actually in the mempool.
			voteHashes := g.cfg.TxSource.VoteHashesForBlock(newHead)
			if len(voteHashes) == 0 {
				return nil, fmt.Errorf("no vote metadata for block %v",
					newHead)
			}
			haveAllVotes := g.cfg.TxSource.HaveAllTransactions(voteHashes)
			if !haveAllVotes {
				continue
			}

			prevHash = *newHead
			break
		}

		// Obtain the maximum allowed treasury expenditure.
		if isTreasuryEnabled && isTVI {
			maxTreasurySpend, err = g.cfg.MaxTreasuryExpenditure(&prevHash)
			if err != nil {
				return nil, err
			}
		}
	}

	// Get the current source transactions and create a priority queue to
	// hold the transactions which are ready for inclusion into a block
	// along with some priority related and fee metadata.  Reserve the same
	// number of items that are available for the priority queue.  Also,
	// choose the initial sort order for the priority queue based on whether
	// or not there is an area allocated for high-priority transactions.
	miningView := g.cfg.TxSource.MiningView()
	sourceTxns := miningView.TxDescs()
	priorityQueue := newTxPriorityQueue(len(sourceTxns), txPQByStakeAndFee)
	prioritizedTxns := make(map[chainhash.Hash]struct{}, len(sourceTxns))

	// Create a slice to hold the transactions to be included in the
	// generated block with reserved space.  Also create a utxo view to
	// house all of the input transactions so multiple lookups can be
	// avoided.
	blockTxns := make([]*dcrutil.Tx, 0, len(sourceTxns))
	blockUtxos := g.cfg.NewUtxoViewpoint()

	// Create slices to hold the fees and number of signature operations
	// for each of the selected transactions and add an entry for the
	// coinbase.  This allows the code below to simply append details about
	// a transaction as it is selected for inclusion in the final block.
	// However, since the total fees aren't known yet, use a dummy value for
	// the coinbase fee which will be updated later.
	txFees := make([]int64, 0, len(sourceTxns))
	txFeesMap := make(map[chainhash.Hash]int64)
	txSigOpCounts := make([]int64, 0, len(sourceTxns))
	txSigOpCountsMap := make(map[chainhash.Hash]int64)
	txFees = append(txFees, -1) // Updated once known

	log.Debugf("Considering %d transactions for inclusion to new block",
		len(sourceTxns))
	knownDisapproved := g.cfg.TxSource.IsRegTxTreeKnownDisapproved(&prevHash)

	// Tracks the total number of transactions that depend on another
	// from the tx source.
	totalDescendantTxns := 0
	prioItemMap := make(map[chainhash.Hash]*txPrioItem, len(sourceTxns))

mempoolLoop:
	for _, txDesc := range sourceTxns {
		// A block can't have more than one coinbase or contain
		// non-finalized transactions.
		tx := txDesc.Tx
		msgTx := tx.MsgTx()
		if standalone.IsCoinBaseTx(msgTx, isTreasuryEnabled) {
			log.Tracef("Skipping coinbase tx %s", tx.Hash())
			continue
		}
		if !g.cfg.IsFinalizedTransaction(tx, nextBlockHeight, best.MedianTime) {
			log.Tracef("Skipping non-finalized tx %s", tx.Hash())
			continue
		}

		// Need this for a check below for stake base input, and to check
		// the ticket number.
		isSSGen := txDesc.Type == stake.TxTypeSSGen
		if isSSGen {
			blockHash, blockHeight := stake.SSGenBlockVotedOn(msgTx)
			if !((blockHash == prevHash) &&
				(int64(blockHeight) == nextBlockHeight-1)) {
				log.Tracef("Skipping ssgen tx %s because it does "+
					"not vote on the correct block", tx.Hash())
				continue
			}
		}

		var isTSpend bool
		if isTreasuryEnabled {
			isTSpend = txDesc.Type == stake.TxTypeTSpend
		}

		// Fetch all of the utxos referenced by the this transaction.
		utxos, err := g.cfg.FetchUtxoView(tx, !knownDisapproved)
		if err != nil {
			log.Warnf("Unable to fetch utxo view for tx %s: "+
				"%v", tx.Hash(), err)
			continue
		}

		// Setup dependencies for any transactions which reference
		// other transactions in the mempool so they can be properly
		// ordered below.
		prioItem := &txPrioItem{txDesc: txDesc, txType: txDesc.Type}
		for i, txIn := range tx.MsgTx().TxIn {
			// Evaluate if this is a stakebase input or not. If it is, continue
			// without evaluation of the input.
			// if isStakeBase
			if (i == 0 && isSSGen) || isTSpend {
				continue
			}

			originHash := &txIn.PreviousOutPoint.Hash
			entry := utxos.LookupEntry(txIn.PreviousOutPoint)
			if entry == nil || entry.IsSpent() {
				if !g.cfg.TxSource.HaveTransaction(originHash) {
					log.Tracef("Skipping tx %s because "+
						"it references unspent output "+
						"%s which is not available",
						tx.Hash(), txIn.PreviousOutPoint)
					continue mempoolLoop
				}
			}
		}

		// Calculate the final transaction priority using the input
		// value age sum as well as the adjusted transaction size.  The
		// formula is: sum(inputValue * inputAge) / adjustedTxSize
		prioItem.priority = CalcPriority(tx.MsgTx(), utxos,
			nextBlockHeight)

		// Calculate the fee in Atoms/KB.
		// NOTE: This is a more precise value than the one calculated
		// during calcMinRelayFee which rounds up to the nearest full
		// kilobyte boundary.  This is beneficial since it provides an
		// incentive to create smaller transactions.
		ancestorStats, hasStats := miningView.AncestorStats(tx.Hash())
		prioItem.feePerKB = calcFeePerKb(txDesc, ancestorStats)
		prioItem.fee = txDesc.Fee + ancestorStats.Fees
		prioItemMap[*tx.Hash()] = prioItem
		hasParents := miningView.hasParents(tx.Hash())

		if !hasParents || hasStats {
			heap.Push(priorityQueue, prioItem)
			prioritizedTxns[*tx.Hash()] = struct{}{}
			blockUtxos.AddTxOuts(tx, nextBlockHeight, wire.NullBlockIndex,
				isTreasuryEnabled)
		}

		if hasParents {
			totalDescendantTxns++
		}

		// Merge the referenced outputs from the input transactions to
		// this transaction into the block utxo view.  This allows the
		// code below to avoid a second lookup.
		mergeUtxoView(blockUtxos, utxos)
	}

	log.Tracef("Priority queue len %d, dependers len %d",
		priorityQueue.Len(), totalDescendantTxns)

	// The starting block size is the size of the block header plus the max
	// possible transaction count size, plus the size of the coinbase
	// transaction.
	blockSize := uint32(blockHeaderOverhead)

	// Guesstimate for sigops based on valid txs in loop below. This number
	// tends to overestimate sigops because of the way the loop below is
	// coded and the fact that tx can sometimes be removed from the tx
	// trees if they fail one of the stake checks below the priorityQueue
	// pop loop. This is buggy, but not catastrophic behaviour. A future
	// release should fix it. TODO
	blockSigOps := int64(0)
	totalFees := int64(0)

	numSStx := 0
	numSSGen := 0
	numTAdds := 0

	foundWinningTickets := make(map[chainhash.Hash]bool, len(best.NextWinningTickets))
	for _, ticketHash := range best.NextWinningTickets {
		foundWinningTickets[ticketHash] = false
	}

	// Create a map of the ticket hashes that will become expired as of the block.
	numExpiring := len(best.NextExpiringTickets)
	expiringTicketHashes := make(map[chainhash.Hash]struct{}, numExpiring)
	for _, ticketHash := range best.NextExpiringTickets {
		expiringTicketHashes[ticketHash] = struct{}{}
	}

	// Maintain lookup of transactions that have been included in the block
	// template.
	templateTxnMap := make(map[chainhash.Hash]struct{})

	// Track if auto revocations have been added to the priority queue.
	addedAutoRevocations := false

	// Get the best block and header.
	bestHeader, err := g.cfg.HeaderByHash(&best.Hash)
	if err != nil {
		str := fmt.Sprintf("unable to get tip block header %v", best.Hash)
		return nil, makeError(ErrGetTopBlock, str)
	}
	bestHeaderBytes, err := bestHeader.Bytes()
	if err != nil {
		str := fmt.Sprintf("failed to serialize header for block %v: %v",
			best.Hash, err)
		return nil, makeError(ErrSerializeHeader, str)
	}

	// Choose which transactions make it into the block.
nextPriorityQueueItem:
	for priorityQueue.Len() > 0 {
		// Grab the highest priority (or highest fee per kilobyte
		// depending on the sort order) transaction.
		prioItem := heap.Pop(priorityQueue).(*txPrioItem)
		tx := prioItem.txDesc.Tx
		delete(prioritizedTxns, *tx.Hash())

		if _, exist := templateTxnMap[*tx.Hash()]; exist {
			continue
		}

		// Store if this is an SStx or not.
		isSStx := prioItem.txType == stake.TxTypeSStx

		// Store if this is an SSGen or not.
		isSSGen := prioItem.txType == stake.TxTypeSSGen

		// Store if this is an SSRtx or not.
		isSSRtx := prioItem.txType == stake.TxTypeSSRtx

		var isTSpend, isTAdd bool
		if isTreasuryEnabled {
			// Store if this is an TSpend or not.
			isTSpend = prioItem.txType == stake.TxTypeTSpend

			// Store if this is a TAdd or not
			isTAdd = prioItem.txType == stake.TxTypeTAdd
		}

		// If the transaction is not a vote, then we are done adding votes since
		// votes are the highest priority in the queue.
		doneAddingVotes := !isSSGen

		// If the automatic ticket revocations agenda is active, then the block MUST
		// contain version 2 revocation transactions for all tickets that will
		// become missed or expired as of this block.
		//
		// Create and insert these revocations into the priority queue AFTER votes
		// are done being added to ensure that revocations are added for votes that
		// fail validation checks or are otherwise not included into the block.
		if isAutoRevocationsEnabled && !addedAutoRevocations && doneAddingVotes {
			// Create revocations for all tickets that will become missed or expired
			// as of the block being created and add them to the priority queue and
			// maps.
			err = g.addAutoRevocationsToQueue(foundWinningTickets, blockUtxos,
				bestHeaderBytes, numSSGen, isTreasuryEnabled, priorityQueue,
				prioritizedTxns, prioItemMap)
			if err != nil {
				return nil, err
			}

			// Set the flag that auto revocations have been added so that they are
			// only added once.
			addedAutoRevocations = true

			// Requeue the current item now that the revocations have been added and
			// continue.
			heap.Push(priorityQueue, prioItem)
			prioritizedTxns[*tx.Hash()] = struct{}{}
			continue
		}

		// Grab the list of transactions which depend on this one (if any).
		deps := miningView.children(tx.Hash())

		// Skip TSpend if this block is not on a TVI or outside of the
		// Tspend window.
		if isTSpend {
			if !isTVI {
				log.Tracef("Skipping tspend %v because block "+
					"is not on a TVI: %v", tx.Hash(),
					nextBlockHeight)
				continue
			}

			// We are on a TVI, make sure this tspend is within the
			// window.
			exp := tx.MsgTx().Expiry
			if !standalone.InsideTSpendWindow(nextBlockHeight,
				exp, g.cfg.ChainParams.TreasuryVoteInterval,
				g.cfg.ChainParams.TreasuryVoteIntervalMultiplier) {

				log.Tracef("Skipping treasury spend %v at height %d because it "+
					"has an expiry of %d that is outside of the voting window",
					tx.Hash(), nextBlockHeight, exp)
				continue
			}

			// Ensure there are enough votes. Send in a fake block
			// with the proper height.
			err = g.cfg.CheckTSpendHasVotes(prevHash,
				dcrutil.NewTx(tx.MsgTx()))
			if err != nil {
				log.Tracef("Skipping tspend %v because it doesn't have enough "+
					"votes: height %v reason '%v'", tx.Hash(), nextBlockHeight, err)
				continue
			}

			// Ensure this TSpend won't overspend from the
			// treasury. This is currently considering between
			// TSpends by tx priority order, which might not be
			// ideal, but we don't expect this to be triggered for
			// mainnet. This could be improved by sorting approved
			// TSpends either by approval % or by expiry.
			tspendAmount := tx.MsgTx().TxIn[0].ValueIn
			if maxTreasurySpend-tspendAmount < 0 {
				log.Tracef("Skipping tspend %v because it spends "+
					"more than allowed: treasury %d tspend %d",
					tx.Hash(), maxTreasurySpend, tspendAmount)
				continue
			}
			maxTreasurySpend -= tspendAmount
		}

		// Skip if we already have too many TAdds.
		if isTAdd && numTAdds >= blockchain.MaxTAddsPerBlock {
			log.Tracef("Skipping tadd %s because it would exceed "+
				"the max number of tadds allowed in a block",
				tx.Hash())
			logSkippedDeps(tx, deps)
			continue
		}

		// Skip if we already have too many SStx.
		if isSStx && (numSStx >=
			int(g.cfg.ChainParams.MaxFreshStakePerBlock)) {
			log.Tracef("Skipping sstx %s because it would exceed "+
				"the max number of sstx allowed in a block", tx.Hash())
			logSkippedDeps(tx, deps)
			continue
		}

		// Skip if the SStx commit value is below the value required by the
		// stake diff.
		if isSStx && (tx.MsgTx().TxOut[0].Value < best.NextStakeDiff) {
			continue
		}

		// Skip revocation transactions if they are spending tickets that are not
		// eligible to be revoked.
		if isSSRtx {
			ticketHash := &tx.MsgTx().TxIn[0].PreviousOutPoint.Hash

			// Determine if the ticket being revoked will become missed or expired as
			// of this block.
			voted, winning := foundWinningTickets[*ticketHash]
			missedThisBlock := !voted && winning
			_, expiringThisBlock := expiringTicketHashes[*ticketHash]
			missedOrExpiredThisBlock := missedThisBlock || expiringThisBlock

			// Ensure the ticket being spent is actually eligible to be revoked in
			// this block.  If the automatic ticket revocations agenda is active, then
			// revocations are allowed if the ticket will become missed or expired as
			// of this block.
			eligible := (isAutoRevocationsEnabled && missedOrExpiredThisBlock) ||
				hashInSlice(*ticketHash, best.MissedTickets)

			if !eligible {
				continue
			}
		}

		if miningView.isRejected(tx.Hash()) {
			// If the transaction or any of its ancestors have been rejected,
			// discard the transaction.
			continue
		}

		ancestors := miningView.ancestors(tx.Hash())
		ancestorStats, _ := miningView.AncestorStats(tx.Hash())
		oldFee := prioItem.feePerKB
		prioItem.feePerKB = calcFeePerKb(prioItem.txDesc, ancestorStats)

		feeDecreased := oldFee > prioItem.feePerKB
		if feeDecreased && ancestorStats.NumAncestors == 0 {
			// If the fee decreased due to ancestors being included in the
			// template and the transaction has no parents, then enqueue it one
			// more time with an accurate feePerKb.
			heap.Push(priorityQueue, prioItem)
			prioritizedTxns[*tx.Hash()] = struct{}{}
			continue
		}

		if feeDecreased {
			// Skip the transaction if the total feePerKb decreased.
			// This addresses a vulnerability that would allow a low-fee
			// transaction to have an inflated and inaccurate feePerKb based on
			// ancestors that have already been included in the block template.
			// The transaction will be added back to the priority queue when all
			// parent transactions are included in the template.
			continue
		}

		// Enforce maximum block size.  Also check for overflow.
		txSize := uint32(tx.MsgTx().SerializeSize())
		blockPlusTxSize := blockSize + txSize + uint32(ancestorStats.SizeBytes)
		if blockPlusTxSize < blockSize ||
			blockPlusTxSize >= g.cfg.Policy.BlockMaxSize {
			log.Tracef("Skipping tx %s (size %v) because it "+
				"would exceed the max block size; cur block "+
				"size %v, cur num tx %v", tx.Hash(), txSize,
				blockSize, len(blockTxns))
			logSkippedDeps(tx, deps)
			miningView.reject(tx.Hash())
			continue
		}

		// Enforce maximum signature operations per block.  Also check
		// for overflow.
		numSigOps := int64(prioItem.txDesc.TotalSigOps)
		numSigOpsBundle := numSigOps + int64(ancestorStats.TotalSigOps)
		if blockSigOps+numSigOpsBundle < blockSigOps ||
			blockSigOps+numSigOpsBundle > blockchain.MaxSigOpsPerBlock {
			log.Tracef("Skipping tx %s because it would "+
				"exceed the maximum sigops per block", tx.Hash())
			logSkippedDeps(tx, deps)
			miningView.reject(tx.Hash())
			continue
		}

		// Check to see if the SSGen tx actually uses a ticket that is
		// valid for the next block.
		if isSSGen {
			if foundWinningTickets[tx.MsgTx().TxIn[1].PreviousOutPoint.Hash] {
				continue
			}
			msgTx := tx.MsgTx()
			isEligible := false
			for _, sstxHash := range best.NextWinningTickets {
				if sstxHash.IsEqual(&msgTx.TxIn[1].PreviousOutPoint.Hash) {
					isEligible = true
				}
			}

			if !isEligible {
				continue
			}
		}

		// Skip transactions that do not pay enough fee except for stake
		// transactions.
		if prioItem.feePerKB < float64(g.cfg.Policy.TxMinFreeFee) &&
			tx.Tree() != wire.TxTreeStake {

			log.Tracef("Skipping tx %s with feePerKB %.2f < TxMinFreeFee %d ",
				tx.Hash(), prioItem.feePerKB, g.cfg.Policy.TxMinFreeFee)
			logSkippedDeps(tx, deps)
			miningView.reject(tx.Hash())
			continue
		}

		txBundle := append(ancestors, prioItem.txDesc)
		for _, bundledTx := range txBundle {
			// Ensure the transaction inputs pass all of the necessary
			// preconditions before allowing it to be added to the block.
			// The fraud proof is not checked because it will be filled in
			// by the miner.
			_, err = g.cfg.CheckTransactionInputs(bundledTx.Tx, nextBlockHeight,
				blockUtxos, false, &bestHeader, isTreasuryEnabled,
				isAutoRevocationsEnabled, subsidySplitVariant)
			if err != nil {
				log.Tracef("Skipping tx %s due to error in "+
					"CheckTransactionInputs: %v", bundledTx.Tx.Hash(), err)
				logSkippedDeps(bundledTx.Tx, deps)
				miningView.reject(bundledTx.Tx.Hash())
				continue nextPriorityQueueItem
			}
			err = g.cfg.ValidateTransactionScripts(bundledTx.Tx, blockUtxos,
				scriptFlags, isAutoRevocationsEnabled)
			if err != nil {
				log.Tracef("Skipping tx %s due to error in "+
					"ValidateTransactionScripts: %v", bundledTx.Tx.Hash(), err)
				logSkippedDeps(bundledTx.Tx, deps)
				miningView.reject(bundledTx.Tx.Hash())
				continue nextPriorityQueueItem
			}
		}

		for _, bundledTxDesc := range txBundle {
			bundledTx := bundledTxDesc.Tx
			bundledTxHash := bundledTx.Hash()

			// Spend the transaction inputs in the block utxo view and add
			// an entry for it to ensure any transactions which reference
			// this one have it available as an input and can ensure they
			// aren't double spending.
			spendTransaction(blockUtxos, bundledTxDesc.Tx, nextBlockHeight,
				isTreasuryEnabled)

			// Add the transaction to the block, increment counters, and
			// save the fees and signature operation counts to the block
			// template.
			blockTxns = append(blockTxns, bundledTx)
			blockSize += uint32(bundledTx.MsgTx().SerializeSize())
			bundledTxSigOps := int64(bundledTxDesc.TotalSigOps)
			blockSigOps += bundledTxSigOps

			// Accumulate the SStxs in the block, because only a certain number
			// are allowed.
			if bundledTxDesc.Type == stake.TxTypeSStx {
				numSStx++
			}
			if bundledTxDesc.Type == stake.TxTypeSSGen {
				foundWinningTickets[bundledTx.MsgTx().TxIn[1].PreviousOutPoint.Hash] = true
				numSSGen++
			}
			if isTreasuryEnabled && bundledTxDesc.Type == stake.TxTypeTAdd {
				numTAdds++
			}

			templateTxnMap[*bundledTxHash] = struct{}{}
			txFeesMap[*bundledTxHash] = bundledTxDesc.Fee
			txSigOpCountsMap[*bundledTxHash] = bundledTxSigOps

			bundledPrioItem := prioItemMap[*bundledTxHash]
			log.Tracef("Adding tx %s (priority %.2f, feePerKB %.2f)",
				bundledTxHash, bundledPrioItem.priority,
				bundledPrioItem.feePerKB)

			// Remove transaction from mining view since it's been added to the
			// block template.
			bundledTxDeps := miningView.children(bundledTxHash)
			miningView.RemoveTransaction(bundledTxHash, false)

			// Add transactions which depend on this one (and also do not
			// have any other unsatisfied dependencies) to the priority
			// queue.
			for _, childTx := range bundledTxDeps {
				childTxHash := childTx.Tx.Hash()
				if _, exist := prioritizedTxns[*childTxHash]; exist {
					continue
				}

				// Add the transaction to the priority queue if there are no
				// more dependencies after this one and the priority item for it
				// already exists.
				if !miningView.hasParents(childTxHash) {
					childPrioItem := prioItemMap[*childTxHash]
					if childPrioItem != nil {
						heap.Push(priorityQueue, childPrioItem)
						prioritizedTxns[*childTxHash] = struct{}{}
					}
				}
			}
		}
	}

	// If we did not already add auto revocations above, attempt to add them now.
	// This case will be hit if the priority queue contained only vote
	// transactions.
	if isAutoRevocationsEnabled && !addedAutoRevocations {
		// Create revocations for all tickets that will become missed or expired
		// as of the block being created and add them to the priority queue and
		// maps.
		err = g.addAutoRevocationsToQueue(foundWinningTickets, blockUtxos,
			bestHeaderBytes, numSSGen, isTreasuryEnabled, priorityQueue,
			prioritizedTxns, prioItemMap)
		if err != nil {
			return nil, err
		}

		// Set the flag that auto revocations have been added so that they are
		// only added once.
		addedAutoRevocations = true

		// Continue to dequeue from the priority queue now that the revocations have
		// been added.
		goto nextPriorityQueueItem
	}

	// Build tx list for stake tx.
	blockTxnsStake := make([]*dcrutil.Tx, 0, len(blockTxns))

	// Create a standard coinbase transaction paying to the provided
	// address.  NOTE: The coinbase value will be updated to include the
	// fees from the selected transactions later after they have actually
	// been selected.  It is created here to detect any errors early
	// before potentially doing a lot of work below.  The extra nonce helps
	// ensure the transaction is not a duplicate transaction (paying the
	// same value to the same public key address would otherwise be an
	// identical transaction for block version 1).
	// Decred: We need to move this downwards because of the requirements
	// to incorporate voters and potential voters.
	//
	// NOTE: we have to do this early to deal with stakebase.
	coinbaseScript := []byte{0x00, 0x00}
	coinbaseScript = append(coinbaseScript, []byte(coinbaseFlags)...)

	// Add a random coinbase nonce to ensure that tx prefix hash
	// so that our merkle root is unique for lookups needed for
	// getwork, etc.
	opReturnPkScript, err := standardCoinbaseOpReturn(uint32(nextBlockHeight))
	if err != nil {
		return nil, err
	}

	// Stake tx ordering in stake tree:
	// 1. Stakebase
	// 2. SSGen (votes).
	// 3. SStx (fresh stake tickets).
	// 4. SSRtx (revocations for missed tickets).
	// 5. Stuff treasury payout in stake tree.

	// We have to figure out how many voters we have before adding the
	// stakebase transaction.
	//
	// We should only find at most TicketsPerBlock votes per block, so
	// initialize the slices using that as a hint to avoid reallocations.
	voters := 0
	voteBitsVoters := make([]uint16, 0, g.cfg.ChainParams.TicketsPerBlock)
	votes := make([]*dcrutil.Tx, 0, g.cfg.ChainParams.TicketsPerBlock)

	// After SVH, we should add SSGens (votes) to the stake tree. Since we
	// need to figure out the number of voters before creating the
	// treasuryBase, we add the votes to an aux slice to be processed
	// later.
	if nextBlockHeight >= stakeValidationHeight {
		for _, tx := range blockTxns {
			msgTx := tx.MsgTx()

			if stake.IsSSGen(msgTx) {
				txCopy := dcrutil.NewTxDeepTxIns(tx)
				if g.maybeInsertStakeTx(txCopy, !knownDisapproved,
					isTreasuryEnabled) {

					vb := stake.SSGenVoteBits(txCopy.MsgTx())
					voteBitsVoters = append(voteBitsVoters, vb)
					votes = append(votes, txCopy)
					voters++
				}
			}

			// Don't let this overflow, although probably it's impossible.
			if voters >= math.MaxUint16 {
				break
			}
		}
	}

	// If the treasury is enabled, it should be the first tx of the stake
	// tree.
	var treasuryBase *dcrutil.Tx
	if isTreasuryEnabled {
		treasuryBase, err = createTreasuryBaseTx(g.cfg.SubsidyCache,
			nextBlockHeight, uint16(voters))
		if err != nil {
			return nil, err
		}
		blockTxnsStake = append(blockTxnsStake, treasuryBase)
	}

	// Add the votes to blockTxnsStake since treasuryBase needs to come
	// first.
	blockTxnsStake = append(blockTxnsStake, votes...)

	// Set votebits, which determines whether the TxTreeRegular of the previous
	// block is valid or not.
	var votebits uint16
	if nextBlockHeight < stakeValidationHeight {
		votebits = uint16(0x0001) // TxTreeRegular enabled pre-staking
	} else {
		// Otherwise, we need to check the votes to determine if the tx tree was
		// validated or not.
		voteYea := 0
		totalVotes := 0

		for _, vb := range voteBitsVoters {
			if dcrutil.IsFlagSet16(vb, dcrutil.BlockValid) {
				voteYea++
			}
			totalVotes++
		}

		if voteYea == 0 { // Handle zero case for div by zero error prevention.
			votebits = uint16(0x0000) // TxTreeRegular disabled
		} else if (totalVotes / voteYea) <= 1 {
			votebits = uint16(0x0001) // TxTreeRegular enabled
		} else {
			votebits = uint16(0x0000) // TxTreeRegular disabled
		}
	}

	// Get the newly purchased tickets (SStx tx) and store them and their
	// number.
	freshStake := 0
	for _, tx := range blockTxns {
		msgTx := tx.MsgTx()
		if tx.Tree() == wire.TxTreeStake && stake.IsSStx(msgTx) {
			// A ticket can not spend an input from TxTreeRegular,
			// since it has not yet been validated.
			if containsTxIns(blockTxns, tx) {
				continue
			}

			// Quick check for difficulty here.
			if msgTx.TxOut[0].Value >= best.NextStakeDiff {
				txCopy := dcrutil.NewTxDeepTxIns(tx)
				if g.maybeInsertStakeTx(txCopy, !knownDisapproved,
					isTreasuryEnabled) {

					blockTxnsStake = append(blockTxnsStake, txCopy)
					freshStake++
				}
			}
		}

		// Don't let this overflow.
		if freshStake >= int(g.cfg.ChainParams.MaxFreshStakePerBlock) {
			break
		}
	}

	// Ensure that mining the block would not cause the chain to become
	// unrecoverable due to ticket exhaustion.
	err = g.cfg.CheckTicketExhaustion(&best.Hash, uint8(freshStake))
	if err != nil {
		log.Debug(err)
		return nil, makeError(ErrTicketExhaustion, err.Error())
	}

	// Get the ticket revocations (SSRtx tx) and store them and their
	// number.
	revocations := 0
	for _, tx := range blockTxns {
		if nextBlockHeight < stakeValidationHeight {
			break // No SSRtx should be present before this height.
		}

		msgTx := tx.MsgTx()
		if tx.Tree() == wire.TxTreeStake && stake.IsSSRtx(msgTx) {
			txCopy := dcrutil.NewTxDeepTxIns(tx)
			if g.maybeInsertStakeTx(txCopy, !knownDisapproved,
				isTreasuryEnabled) {

				blockTxnsStake = append(blockTxnsStake, txCopy)
				revocations++
			}
		}

		// Don't let this overflow.
		if revocations >= math.MaxUint8 {
			break
		}
	}

	// Insert TAdd/TSpend transactions.
	if isTreasuryEnabled {
		for _, tx := range blockTxns {
			msgTx := tx.MsgTx()
			if tx.Tree() == wire.TxTreeStake && stake.IsTAdd(msgTx) {
				txCopy := dcrutil.NewTxDeepTxIns(tx)
				if g.maybeInsertStakeTx(txCopy, !knownDisapproved,
					isTreasuryEnabled) {

					blockTxnsStake = append(blockTxnsStake, txCopy)
					log.Tracef("maybeInsertStakeTx TADD %v ", tx.Hash())
				}
			} else if tx.Tree() == wire.TxTreeStake && stake.IsTSpend(msgTx) {
				txCopy := dcrutil.NewTxDeepTxIns(tx)
				if g.maybeInsertStakeTx(txCopy, !knownDisapproved,
					isTreasuryEnabled) {

					blockTxnsStake = append(blockTxnsStake, txCopy)
					log.Tracef("maybeInsertStakeTx TSPEND %v ", tx.Hash())
				}
			}
		}
	}

	coinbaseTx := createCoinbaseTx(g.cfg.SubsidyCache, coinbaseScript,
		opReturnPkScript, nextBlockHeight, payToAddress, uint16(voters),
		g.cfg.ChainParams, isTreasuryEnabled, subsidySplitVariant)
	coinbaseTx.SetTree(wire.TxTreeRegular)

	numCoinbaseSigOps := int64(g.cfg.CountSigOps(coinbaseTx, true,
		false, isTreasuryEnabled))
	blockSize += uint32(coinbaseTx.MsgTx().SerializeSize())
	blockSigOps += numCoinbaseSigOps
	txFeesMap[*coinbaseTx.Hash()] = 0
	txSigOpCountsMap[*coinbaseTx.Hash()] = numCoinbaseSigOps
	if treasuryBase != nil {
		txFeesMap[*treasuryBase.Hash()] = 0
		n := int64(g.cfg.CountSigOps(treasuryBase, true, false, isTreasuryEnabled))
		txSigOpCountsMap[*treasuryBase.Hash()] = n
	}

	// Build tx lists for regular tx.
	blockTxnsRegular := make([]*dcrutil.Tx, 0, len(blockTxns)+1)

	// Append coinbase.
	blockTxnsRegular = append(blockTxnsRegular, coinbaseTx)

	// Assemble the two transaction trees.
	for _, tx := range blockTxns {
		if tx.Tree() == wire.TxTreeRegular {
			blockTxnsRegular = append(blockTxnsRegular, tx)
		} else if tx.Tree() == wire.TxTreeStake {
			continue
		} else {
			log.Tracef("Error adding tx %s to block; invalid tree", tx.Hash())
			continue
		}
	}

	for _, tx := range blockTxnsRegular {
		fee, ok := txFeesMap[*tx.Hash()]
		if !ok {
			return nil, fmt.Errorf("couldn't find fee for tx %v",
				*tx.Hash())
		}
		totalFees += fee
		txFees = append(txFees, fee)

		tsos, ok := txSigOpCountsMap[*tx.Hash()]
		if !ok {
			return nil, fmt.Errorf("couldn't find sig ops count for tx %v",
				*tx.Hash())
		}
		txSigOpCounts = append(txSigOpCounts, tsos)
	}

	for _, tx := range blockTxnsStake {
		fee, ok := txFeesMap[*tx.Hash()]
		if !ok {
			return nil, fmt.Errorf("couldn't find fee for stx %v",
				*tx.Hash())
		}
		totalFees += fee
		txFees = append(txFees, fee)

		tsos, ok := txSigOpCountsMap[*tx.Hash()]
		if !ok {
			return nil, fmt.Errorf("couldn't find sig ops count for stx %v",
				*tx.Hash())
		}
		txSigOpCounts = append(txSigOpCounts, tsos)
	}

	// Scale the fees according to the number of voters once stake validation
	// height is reached.
	if nextBlockHeight >= stakeValidationHeight {
		totalFees *= int64(voters)
		totalFees /= int64(g.cfg.ChainParams.TicketsPerBlock)
	}

	txSigOpCounts = append(txSigOpCounts, numCoinbaseSigOps)

	// Now that the actual transactions have been selected, update the
	// block size for the real transaction count and coinbase value with
	// the total fees accordingly.
	if nextBlockHeight > 1 {
		blockSize -= wire.MaxVarIntPayload -
			uint32(wire.VarIntSerializeSize(uint64(len(blockTxnsRegular))+
				uint64(len(blockTxnsStake))))
		powOutputIdx := 2
		if isTreasuryEnabled {
			powOutputIdx = 1
		}
		coinbaseTx.MsgTx().TxOut[powOutputIdx].Value += totalFees
		txFees[0] = -totalFees
	}

	// Calculate the required difficulty for the block.  The timestamp
	// is potentially adjusted to ensure it comes after the median time of
	// the last several blocks per the chain consensus rules.
	ts := g.medianAdjustedTime()
	reqDifficulty, err := g.cfg.CalcNextRequiredDifficulty(&prevHash, ts)
	if err != nil {
		return nil, makeError(ErrGettingDifficulty, err.Error())
	}

	// Return nil if we don't yet have enough voters; sometimes it takes a
	// bit for the mempool to sync with the votes map and we end up down
	// here despite having the relevant votes available in the votes map.
	minimumVotesRequired :=
		int((g.cfg.ChainParams.TicketsPerBlock / 2) + 1)
	if nextBlockHeight >= stakeValidationHeight &&
		voters < minimumVotesRequired {
		log.Warnf("incongruent number of voters in mempool " +
			"vs mempool.voters; not enough voters found")
		return g.handleTooFewVoters(nextBlockHeight, payToAddress,
			isTreasuryEnabled, subsidySplitVariant)
	}

	// Correct transaction index fraud proofs for any transactions that
	// are chains. maybeInsertStakeTx fills this in for stake transactions
	// already, so only do it for regular transactions.
	for i, tx := range blockTxnsRegular {
		// No need to check any of the transactions in the custom first
		// block.
		if nextBlockHeight == 1 {
			break
		}

		// Skip coinbase.
		if i == 0 {
			continue
		}

		view, err := g.cfg.FetchUtxoView(tx, !knownDisapproved)
		if err != nil {
			str := fmt.Sprintf("failed to fetch utxo view for tx %v: %s",
				tx.Hash(), err.Error())
			return nil, makeError(ErrFetchTxStore, str)
		}

		// Copy the transaction and swap the pointer.
		txCopy := dcrutil.NewTxDeepTxIns(tx)
		blockTxnsRegular[i] = txCopy
		tx = txCopy

		for _, txIn := range tx.MsgTx().TxIn {
			entry := view.LookupEntry(txIn.PreviousOutPoint)
			if entry == nil {
				// Set a flag with the index so we can properly set
				// the fraud proof below.
				txIn.BlockIndex = wire.NullBlockIndex
			} else {
				txIn.ValueIn = entry.Amount()
				txIn.BlockHeight = uint32(entry.BlockHeight())
				txIn.BlockIndex = entry.BlockIndex()
			}
		}
	}

	// Fill in locally referenced inputs.
	for i, tx := range blockTxnsRegular {
		// Skip coinbase.
		if i == 0 {
			continue
		}

		for _, txIn := range tx.MsgTx().TxIn {
			// This tx was at some point 0-conf and now requires the correct block
			// height and index.  Set it here.  It is safe to modify the transaction
			// directly since it has already been copied above.
			if txIn.BlockIndex == wire.NullBlockIndex {
				idx := txIndexFromTxList(txIn.PreviousOutPoint.Hash,
					blockTxnsRegular)

				// The input is in the block, set it accordingly.
				if idx != -1 {
					originIdx := txIn.PreviousOutPoint.Index
					amt := blockTxnsRegular[idx].MsgTx().TxOut[originIdx].Value
					txIn.ValueIn = amt
					txIn.BlockHeight = uint32(nextBlockHeight)
					txIn.BlockIndex = uint32(idx)
				} else {
					str := fmt.Sprintf("failed find hash in tx list "+
						"for fraud proof; tx in hash %v",
						txIn.PreviousOutPoint.Hash)
					return nil, makeError(ErrFraudProofIndex, str)
				}
			}
		}
	}

	// Choose the block version to generate based on the network.
	blockVersion := int32(generatedBlockVersion)
	if g.cfg.ChainParams.Net != wire.MainNet {
		blockVersion = generatedBlockVersionTest
	}

	// Figure out stake version.
	generatedStakeVersion, err := g.cfg.CalcStakeVersionByHash(&prevHash)
	if err != nil {
		return nil, err
	}

	// Create a new block ready to be solved.
	var msgBlock wire.MsgBlock
	msgBlock.Header = wire.BlockHeader{
		Version:   blockVersion,
		PrevBlock: prevHash,
		// MerkleRoot and StakeRoot set below.
		VoteBits:     votebits,
		FinalState:   best.NextFinalState,
		Voters:       uint16(voters),
		FreshStake:   uint8(freshStake),
		Revocations:  uint8(revocations),
		PoolSize:     best.NextPoolSize,
		Timestamp:    ts,
		SBits:        best.NextStakeDiff,
		Bits:         reqDifficulty,
		StakeVersion: generatedStakeVersion,
		Height:       uint32(nextBlockHeight),
		// Size declared below
	}

	for _, tx := range blockTxnsRegular {
		if err := msgBlock.AddTransaction(tx.MsgTx()); err != nil {
			return nil, makeError(ErrTransactionAppend, err.Error())
		}
	}

	totalTreasuryOps := 0
	for _, tx := range blockTxnsStake {
		if err := msgBlock.AddSTransaction(tx.MsgTx()); err != nil {
			return nil, makeError(ErrTransactionAppend, err.Error())
		}
		// While in this loop count treasury operations.
		if isTreasuryEnabled {
			if stake.IsTAdd(tx.MsgTx()) {
				totalTreasuryOps++
			} else if stake.IsTSpend(tx.MsgTx()) {
				totalTreasuryOps++
			}
		}
	}

	// Calculate the merkle root depending on the result of the header
	// commitments agenda vote.
	hdrCmtActive, err := g.cfg.IsHeaderCommitmentsAgendaActive(&prevHash)
	if err != nil {
		return nil, err
	}
	msgBlock.Header.MerkleRoot = calcBlockMerkleRoot(msgBlock.Transactions,
		msgBlock.STransactions, hdrCmtActive)

	// Calculate the stake root or commitment root depending on the result of
	// the header commitments agenda vote.
	var cmtRoot chainhash.Hash
	if hdrCmtActive {
		cmtRoot, err = calcBlockCommitmentRootV1(&msgBlock, blockUtxos)
		if err != nil {
			str := fmt.Sprintf("failed to calculate commitment root for block "+
				"when making new block template: %v", err)
			return nil, makeError(ErrCalcCommitmentRoot, str)
		}
	} else {
		cmtRoot = standalone.CalcTxTreeMerkleRoot(msgBlock.STransactions)
	}
	msgBlock.Header.StakeRoot = cmtRoot

	msgBlock.Header.Size = uint32(msgBlock.SerializeSize())

	// Finally, perform a full check on the created block against the chain
	// consensus rules to ensure it properly connects to the current best
	// chain with no issues.
	block := dcrutil.NewBlockDeepCopyCoinbase(&msgBlock)
	err = g.cfg.CheckConnectBlockTemplate(block)
	if err != nil {
		str := fmt.Sprintf("failed to do final check for check connect "+
			"block when making new block template: %v", err)
		return nil, makeError(ErrCheckConnectBlock, str)
	}

	log.Debugf("Created new block template (%d transactions, %d stake "+
		"transactions, %d treasury transactions, %d in fees, %d signature "+
		"operations, %d bytes, target difficulty %064x, stake difficulty %v)",
		len(msgBlock.Transactions), len(msgBlock.STransactions),
		totalTreasuryOps, totalFees, blockSigOps, blockSize,
		standalone.CompactToBig(msgBlock.Header.Bits),
		dcrutil.Amount(msgBlock.Header.SBits).ToCoin())

	blockTemplate := &BlockTemplate{
		Block:           &msgBlock,
		Fees:            txFees,
		SigOpCounts:     txSigOpCounts,
		Height:          nextBlockHeight,
		ValidPayAddress: payToAddress != nil,
	}

	return blockTemplate, nil
}

// UpdateBlockTime updates the timestamp in the passed header to the current
// time while taking into account the median time of the last several blocks to
// ensure the new time is after that time per the chain consensus rules.
func (g *BlkTmplGenerator) UpdateBlockTime(header *wire.BlockHeader) {
	// The new timestamp is potentially adjusted to ensure it comes after
	// the median time of the last several blocks per the chain consensus
	// rules.
	newTimestamp := g.medianAdjustedTime()
	header.Timestamp = newTimestamp
}
