func (g *BlkTmplGenerator) UpdateExtraNonce(msgBlock *wire.MsgBlock, blockHeight int32, extraNonce uint64) error {
	coinbaseScript, err := standardCoinbaseScript(blockHeight, extraNonce)
	if err != nil {
		return err
	}
	if len(coinbaseScript) > blockdag.MaxCoinbaseScriptLen {
		return fmt.Errorf("coinbase transaction script length "+
			"of %d is out of range (min: %d, max: %d)",
			len(coinbaseScript), blockdag.MinCoinbaseScriptLen,
			blockdag.MaxCoinbaseScriptLen)
	}
	msgBlock.Transactions[0].TxIn[0].SignatureScript = coinbaseScript
	block := soterutil.NewBlock(msgBlock)
	merkles := blockdag.BuildMerkleTreeStore(block.Transactions(), false)
	msgBlock.Header.MerkleRoot = *merkles[len(merkles)-1]
	return nil
}
UpdateExtraNonce updates the extra nonce in the coinbase script of the passed
block by regenerating the coinbase script with the passed value and block
height.  It also recalculates and updates the new merkle root that results
from changing the coinbase script.
package miningdag
import (
	"bytes"
	"container/heap"
	"fmt"
	"time"
	"github.com/soteria-dag/soterd/blockdag"
	"github.com/soteria-dag/soterd/chaincfg"
	"github.com/soteria-dag/soterd/chaincfg/chainhash"
	"github.com/soteria-dag/soterd/soterutil"
	"github.com/soteria-dag/soterd/txscript"
	"github.com/soteria-dag/soterd/wire"
)
const (
	MinHighPriority = soterutil.NanoSoterPerSoter * 144.0 / 250
	blockHeaderOverhead = wire.MaxBlockHeaderPayload + wire.MaxParentSubHeaderPayload + wire.MaxVarIntPayload
	CoinbaseFlags = "/P2SH/soterd/"
)
type TxDesc struct {
	Tx *soterutil.Tx
	Added time.Time
	Height int32
	Fee int64
	FeePerKB int64
}
type TxSource interface {
	LastUpdated() time.Time
	MiningDescs() []*TxDesc
	HaveTransaction(hash *chainhash.Hash) bool
}
type txPrioItem struct {
	tx       *soterutil.Tx
	fee      int64
	priority float64
	feePerKB int64
	dependsOn map[chainhash.Hash]struct{}
}
type txPriorityQueueLessFunc func(*txPriorityQueue, int, int) bool
type txPriorityQueue struct {
	lessFunc txPriorityQueueLessFunc
	items    []*txPrioItem
}
func (pq *txPriorityQueue) Len() int {
	return len(pq.items)
}
func (pq *txPriorityQueue) Less(i, j int) bool {
	return pq.lessFunc(pq, i, j)
}
func (pq *txPriorityQueue) Swap(i, j int) {
	pq.items[i], pq.items[j] = pq.items[j], pq.items[i]
}
func (pq *txPriorityQueue) Push(x interface{}) {
	pq.items = append(pq.items, x.(*txPrioItem))
}
func (pq *txPriorityQueue) Pop() interface{} {
	n := len(pq.items)
	item := pq.items[n-1]
	pq.items[n-1] = nil
	pq.items = pq.items[0 : n-1]
	return item
}
func (pq *txPriorityQueue) SetLessFunc(lessFunc txPriorityQueueLessFunc) {
	pq.lessFunc = lessFunc
	heap.Init(pq)
}
func txPQByPriority(pq *txPriorityQueue, i, j int) bool {
	if pq.items[i].priority == pq.items[j].priority {
		return pq.items[i].feePerKB > pq.items[j].feePerKB
	}
	return pq.items[i].priority > pq.items[j].priority
}
func txPQByFee(pq *txPriorityQueue, i, j int) bool {
	if pq.items[i].feePerKB == pq.items[j].feePerKB {
		return pq.items[i].priority > pq.items[j].priority
	}
	return pq.items[i].feePerKB > pq.items[j].feePerKB
}
func newTxPriorityQueue(reserve int, sortByFee bool) *txPriorityQueue {
	pq := &txPriorityQueue{
		items: make([]*txPrioItem, 0, reserve),
	}
	if sortByFee {
		pq.SetLessFunc(txPQByFee)
	} else {
		pq.SetLessFunc(txPQByPriority)
	}
	return pq
}
type BlockTemplate struct {
	Block *wire.MsgBlock
	Fees []int64
	SigOpCosts []int64
	Height int32
	ValidPayAddress bool
	WitnessCommitment []byte
}
func mergeUtxoView(viewA *blockdag.UtxoViewpoint, viewB *blockdag.UtxoViewpoint) {
	viewAEntries := viewA.Entries()
	for outpoint, entryB := range viewB.Entries() {
		if entryA, exists := viewAEntries[outpoint]; !exists ||
			entryA == nil || entryA.IsSpent() {
			viewAEntries[outpoint] = entryB
		}
	}
}
func standardCoinbaseScript(nextBlockHeight int32, extraNonce uint64) ([]byte, error) {
	return txscript.NewScriptBuilder().AddInt64(int64(nextBlockHeight)).
		AddInt64(int64(extraNonce)).AddData([]byte(CoinbaseFlags)).
		Script()
}
func createCoinbaseTx(params *chaincfg.Params, coinbaseScript []byte, nextBlockHeight int32, addr soterutil.Address) (*soterutil.Tx, error) {
	var pkScript []byte
	if addr != nil {
		var err error
		pkScript, err = txscript.PayToAddrScript(addr)
		if err != nil {
			return nil, err
		}
	} else {
		var err error
		scriptBuilder := txscript.NewScriptBuilder()
		pkScript, err = scriptBuilder.AddOp(txscript.OP_TRUE).Script()
		if err != nil {
			return nil, err
		}
	}
	tx := wire.NewMsgTx(wire.TxVersion)
	tx.AddTxIn(&wire.TxIn{
		PreviousOutPoint: *wire.NewOutPoint(&chainhash.Hash{},
			wire.MaxPrevOutIndex),
		SignatureScript: coinbaseScript,
		Sequence:        wire.MaxTxInSequenceNum,
	})
	tx.AddTxOut(&wire.TxOut{
		Value:    blockdag.CalcBlockSubsidy(nextBlockHeight, params),
		PkScript: pkScript,
	})
	return soterutil.NewTx(tx), nil
}
func spendTransaction(utxoView *blockdag.UtxoViewpoint, tx *soterutil.Tx, height int32) error {
	for _, txIn := range tx.MsgTx().TxIn {
		entry := utxoView.LookupEntry(txIn.PreviousOutPoint)
		if entry != nil {
			entry.Spend()
		}
	}
	utxoView.AddTxOuts(tx, height)
	return nil
}
func logSkippedDeps(tx *soterutil.Tx, deps map[chainhash.Hash]*txPrioItem) {
	if deps == nil {
		return
	}
	for _, item := range deps {
		log.Tracef("Skipping tx %s since it depends on %s\n",
			item.tx.Hash(), tx.Hash())
	}
}
func MinimumMedianTime(chainState *blockdag.BestState) time.Time {
	return chainState.MedianTime.Add(time.Second)
}
func medianAdjustedTime(chainState *blockdag.BestState, timeSource blockdag.MedianTimeSource) time.Time {
	newTimestamp := timeSource.AdjustedTime()
	minTimestamp := MinimumMedianTime(chainState)
	if newTimestamp.Before(minTimestamp) {
		newTimestamp = minTimestamp
	}
	return newTimestamp
}
type BlkTmplGenerator struct {
	policy      *Policy
	chainParams *chaincfg.Params
	txSource    TxSource
	chain       *blockdag.BlockDAG
	timeSource  blockdag.MedianTimeSource
	sigCache    *txscript.SigCache
	hashCache   *txscript.HashCache
}
func NewBlkTmplGenerator(policy *Policy, params *chaincfg.Params,
	txSource TxSource, chain *blockdag.BlockDAG,
	timeSource blockdag.MedianTimeSource,
	sigCache *txscript.SigCache,
	hashCache *txscript.HashCache) *BlkTmplGenerator {
	return &BlkTmplGenerator{
		policy:      policy,
		chainParams: params,
		txSource:    txSource,
		chain:       chain,
		timeSource:  timeSource,
		sigCache:    sigCache,
		hashCache:   hashCache,
	}
}
func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress soterutil.Address) (*BlockTemplate, error) {
	best := g.chain.BestSnapshot()
	snapshot := g.chain.DAGSnapshot()
	nextBlockHeight := snapshot.MaxHeight + 1
	extraNonce := uint64(0)
	coinbaseScript, err := standardCoinbaseScript(nextBlockHeight, extraNonce)
	if err != nil {
		return nil, err
	}
	coinbaseTx, err := createCoinbaseTx(g.chainParams, coinbaseScript,
		nextBlockHeight, payToAddress)
	if err != nil {
		return nil, err
	}
	coinbaseSigOpCost := int64(blockdag.CountSigOps(coinbaseTx)) * blockdag.WitnessScaleFactor
	sourceTxns := g.txSource.MiningDescs()
	sortedByFee := g.policy.BlockPrioritySize == 0
	priorityQueue := newTxPriorityQueue(len(sourceTxns), sortedByFee)
	blockTxns := make([]*soterutil.Tx, 0, len(sourceTxns))
	blockTxns = append(blockTxns, coinbaseTx)
	blockUtxos := blockdag.NewUtxoViewpoint()
	dependers := make(map[chainhash.Hash]map[chainhash.Hash]*txPrioItem)
	txFees := make([]int64, 0, len(sourceTxns))
	txSigOpCosts := make([]int64, 0, len(sourceTxns))
	txFees = append(txFees, -1)  
	txSigOpCosts = append(txSigOpCosts, coinbaseSigOpCost)
	log.Debugf("Considering %d transactions for inclusion to new block",
		len(sourceTxns))
mempoolLoop:
	for _, txDesc := range sourceTxns {
		tx := txDesc.Tx
		if blockdag.IsCoinBase(tx) {
			log.Tracef("Skipping coinbase tx %s", tx.Hash())
			continue
		}
		if !blockdag.IsFinalizedTransaction(tx, nextBlockHeight,
			g.timeSource.AdjustedTime()) {
			log.Tracef("Skipping non-finalized tx %s", tx.Hash())
			continue
		}
		utxos, err := g.chain.FetchUtxoView(tx)
		if err != nil {
			log.Warnf("Unable to fetch utxo view for tx %s: %v",
				tx.Hash(), err)
			continue
		}
		prioItem := &txPrioItem{tx: tx}
		for _, txIn := range tx.MsgTx().TxIn {
			originHash := &txIn.PreviousOutPoint.Hash
			entry := utxos.LookupEntry(txIn.PreviousOutPoint)
			if entry == nil || entry.IsSpent() {
				if !g.txSource.HaveTransaction(originHash) {
					log.Tracef("Skipping tx %s because it "+
						"references unspent output %s "+
						"which is not available",
						tx.Hash(), txIn.PreviousOutPoint)
					continue mempoolLoop
				}
				deps, exists := dependers[*originHash]
				if !exists {
					deps = make(map[chainhash.Hash]*txPrioItem)
					dependers[*originHash] = deps
				}
				deps[*prioItem.tx.Hash()] = prioItem
				if prioItem.dependsOn == nil {
					prioItem.dependsOn = make(
						map[chainhash.Hash]struct{})
				}
				prioItem.dependsOn[*originHash] = struct{}{}
				continue
			}
		}
		prioItem.priority = CalcPriority(tx.MsgTx(), utxos,
			nextBlockHeight)
		prioItem.feePerKB = txDesc.FeePerKB
		prioItem.fee = txDesc.Fee
		if prioItem.dependsOn == nil {
			heap.Push(priorityQueue, prioItem)
		}
		mergeUtxoView(blockUtxos, utxos)
	}
	log.Tracef("Priority queue len %d, dependers len %d",
		priorityQueue.Len(), len(dependers))
	blockWeight := uint32((blockHeaderOverhead * blockdag.WitnessScaleFactor) +
		blockdag.GetTransactionWeight(coinbaseTx))
	blockSigOpCost := coinbaseSigOpCost
	totalFees := int64(0)
	segwitStates, err := g.chain.ThresholdStates(chaincfg.DeploymentSegwit)
	if err != nil {
		return nil, err
	}
	segwitActiveCount := 0
	for _, segwitState := range segwitStates {
		if segwitState == blockdag.ThresholdActive {
			segwitActiveCount++
		}
	}
	segwitActive := segwitActiveCount == len(segwitStates)
	witnessIncluded := false
	for priorityQueue.Len() > 0 {
		prioItem := heap.Pop(priorityQueue).(*txPrioItem)
		tx := prioItem.tx
		switch {
		case !segwitActive && tx.HasWitness():
			continue
		case segwitActive && !witnessIncluded && tx.HasWitness():
			coinbaseCopy := soterutil.NewTx(coinbaseTx.MsgTx().Copy())
			coinbaseCopy.MsgTx().TxIn[0].Witness = [][]byte{
				bytes.Repeat([]byte("a"),
					blockdag.CoinbaseWitnessDataLen),
			}
			coinbaseCopy.MsgTx().AddTxOut(&wire.TxOut{
				PkScript: bytes.Repeat([]byte("a"),
					blockdag.CoinbaseWitnessPkScriptLength),
			})
			weightDiff := blockdag.GetTransactionWeight(coinbaseCopy) -
				blockdag.GetTransactionWeight(coinbaseTx)
			blockWeight += uint32(weightDiff)
			witnessIncluded = true
		}
		deps := dependers[*tx.Hash()]
		txWeight := uint32(blockdag.GetTransactionWeight(tx))
		blockPlusTxWeight := blockWeight + txWeight
		if blockPlusTxWeight < blockWeight ||
			blockPlusTxWeight >= g.policy.BlockMaxWeight {
			log.Tracef("Skipping tx %s because it would exceed "+
				"the max block weight", tx.Hash())
			logSkippedDeps(tx, deps)
			continue
		}
		sigOpCost, err := blockdag.GetSigOpCost(tx, false,
			blockUtxos, true, segwitActive)
		if err != nil {
			log.Tracef("Skipping tx %s due to error in "+
				"GetSigOpCost: %v", tx.Hash(), err)
			logSkippedDeps(tx, deps)
			continue
		}
		if blockSigOpCost+int64(sigOpCost) < blockSigOpCost ||
			blockSigOpCost+int64(sigOpCost) > blockdag.MaxBlockSigOpsCost {
			log.Tracef("Skipping tx %s because it would "+
				"exceed the maximum sigops per block", tx.Hash())
			logSkippedDeps(tx, deps)
			continue
		}
		if sortedByFee &&
			prioItem.feePerKB < int64(g.policy.TxMinFreeFee) &&
			blockPlusTxWeight >= g.policy.BlockMinWeight {
			log.Tracef("Skipping tx %s with feePerKB %d "+
				"< TxMinFreeFee %d and block weight %d >= "+
				"minBlockWeight %d", tx.Hash(), prioItem.feePerKB,
				g.policy.TxMinFreeFee, blockPlusTxWeight,
				g.policy.BlockMinWeight)
			logSkippedDeps(tx, deps)
			continue
		}
		if !sortedByFee && (blockPlusTxWeight >= g.policy.BlockPrioritySize ||
			prioItem.priority <= MinHighPriority) {
			log.Tracef("Switching to sort by fees per "+
				"kilobyte blockSize %d >= BlockPrioritySize "+
				"%d || priority %.2f <= minHighPriority %.2f",
				blockPlusTxWeight, g.policy.BlockPrioritySize,
				prioItem.priority, MinHighPriority)
			sortedByFee = true
			priorityQueue.SetLessFunc(txPQByFee)
			if blockPlusTxWeight > g.policy.BlockPrioritySize ||
				prioItem.priority < MinHighPriority {
				heap.Push(priorityQueue, prioItem)
				continue
			}
		}
		_, err = blockdag.CheckTransactionInputs(tx, nextBlockHeight, blockUtxos, g.chainParams, false)
		if err != nil {
			log.Tracef("Skipping tx %s due to error in "+
				"CheckTransactionInputs: %v", tx.Hash(), err)
			logSkippedDeps(tx, deps)
			continue
		}
		err = blockdag.ValidateTransactionScripts(tx, blockUtxos,
			txscript.StandardVerifyFlags, g.sigCache,
			g.hashCache)
		if err != nil {
			log.Tracef("Skipping tx %s due to error in "+
				"ValidateTransactionScripts: %v", tx.Hash(), err)
			logSkippedDeps(tx, deps)
			continue
		}
		spendTransaction(blockUtxos, tx, nextBlockHeight)
		blockTxns = append(blockTxns, tx)
		blockWeight += txWeight
		blockSigOpCost += int64(sigOpCost)
		totalFees += prioItem.fee
		txFees = append(txFees, prioItem.fee)
		txSigOpCosts = append(txSigOpCosts, int64(sigOpCost))
		log.Tracef("Adding tx %s (priority %.2f, feePerKB %.2f)",
			prioItem.tx.Hash(), prioItem.priority, prioItem.feePerKB)
		for _, item := range deps {
			delete(item.dependsOn, *tx.Hash())
			if len(item.dependsOn) == 0 {
				heap.Push(priorityQueue, item)
			}
		}
	}
	blockWeight -= wire.MaxVarIntPayload -
		(uint32(wire.VarIntSerializeSize(uint64(len(blockTxns)))) *
			blockdag.WitnessScaleFactor)
	coinbaseTx.MsgTx().TxOut[0].Value += totalFees
	txFees[0] = -totalFees
	var witnessCommitment []byte
	if witnessIncluded {
		var witnessNonce [blockdag.CoinbaseWitnessDataLen]byte
		coinbaseTx.MsgTx().TxIn[0].Witness = wire.TxWitness{witnessNonce[:]}
		witnessMerkleTree := blockdag.BuildMerkleTreeStore(blockTxns,
			true)
		witnessMerkleRoot := witnessMerkleTree[len(witnessMerkleTree)-1]
		var witnessPreimage [64]byte
		copy(witnessPreimage[:32], witnessMerkleRoot[:])
		copy(witnessPreimage[32:], witnessNonce[:])
		witnessCommitment = chainhash.DoubleHashB(witnessPreimage[:])
		witnessScript := append(blockdag.WitnessMagicBytes, witnessCommitment...)
		commitmentOutput := &wire.TxOut{
			Value:    0,
			PkScript: witnessScript,
		}
		coinbaseTx.MsgTx().TxOut = append(coinbaseTx.MsgTx().TxOut,
			commitmentOutput)
	}
	ts := medianAdjustedTime(best, g.timeSource)
	targetDifficulty, err := g.chain.TargetDifficulty(snapshot.MaxHeight)
	if err != nil {
		return nil, err
	}
	reqDifficulty := blockdag.BigToCompact(targetDifficulty)
	nextBlockVersion, err := g.chain.CalcNextBlockVersion()
	if err != nil {
		return nil, err
	}
	prevHash := snapshot.Hash
	merkles := blockdag.BuildMerkleTreeStore(blockTxns, false)
	var msgBlock wire.MsgBlock
	msgBlock.Header = wire.BlockHeader{
		Version:    nextBlockVersion,
		PrevBlock:  prevHash,
		MerkleRoot: *merkles[len(merkles)-1],
		Timestamp:  ts,
		Bits:       reqDifficulty,
	}
	nextParentVersion, err := g.chain.CalcNextParentVersion()
	if err != nil {
		return nil, err
	}
	var parents []*wire.Parent
	for _, hash := range snapshot.Tips {
		parents = append(parents, &wire.Parent{
			Hash: hash,
		})
	}
	msgBlock.Parents = wire.ParentSubHeader{
		Version: nextParentVersion,
		Size: int32(len(snapshot.Tips)),
		Parents: parents,
	}
	msgBlock.Verification = wire.VerificationSubHeader{}
	for _, tx := range blockTxns {
		if err := msgBlock.AddTransaction(tx.MsgTx()); err != nil {
			return nil, err
		}
	}
	block := soterutil.NewBlock(&msgBlock)
	block.SetHeight(nextBlockHeight)
	if err := g.chain.CheckConnectBlockTemplate(block); err != nil {
		return nil, err
	}
	log.Debugf("Created new block template (%d transactions, %d in "+
		"fees, %d signature operations cost, %d weight, target difficulty "+
		"%064x)", len(msgBlock.Transactions), totalFees, blockSigOpCost,
		blockWeight, blockdag.CompactToBig(msgBlock.Header.Bits))
	return &BlockTemplate{
		Block:             &msgBlock,
		Fees:              txFees,
		SigOpCosts:        txSigOpCosts,
		Height:            nextBlockHeight,
		ValidPayAddress:   payToAddress != nil,
		WitnessCommitment: witnessCommitment,
	}, nil
}
func (g *BlkTmplGenerator) UpdateBlockTime(msgBlock *wire.MsgBlock) error {
	newTime := medianAdjustedTime(g.chain.BestSnapshot(), g.timeSource)
	msgBlock.Header.Timestamp = newTime
	if g.chainParams.ReduceMinDifficulty {
		difficulty, err := g.chain.TargetDifficulty(g.chain.DAGSnapshot().MaxHeight)
		if err != nil {
			return err
		}
		msgBlock.Header.Bits = blockdag.BigToCompact(difficulty)
	}
	return nil
}