btcd/mining.go
Dave Collins 7fac099bee mempool: Refactor mempool code to its own package. (#737)
This does the minimum work necessary to refactor the mempool code into
its own package.  The idea is that separating this code into its own
package will greatly improve its testability, allow independent
benchmarking and profiling, and open up some interesting opportunities
for future development related to the memory pool.

There are likely some areas related to policy that could be further
refactored, however it is better to do that in future commits in order
to keep the changeset as small as possible during this refactor.

Overview of the major changes:

- Create the new package
- Move several files into the new package:
  - mempool.go -> mempool/mempool.go
  - mempoolerror.go -> mempool/error.go
  - policy.go -> mempool/policy.go
  - policy_test.go -> mempool/policy_test.go
- Update mempool logging to use the new mempool package logger
- Rename mempoolPolicy to Policy (so it's now mempool.Policy)
- Rename mempoolConfig to Config (so it's now mempool.Config)
- Rename mempoolTxDesc to TxDesc (so it's now mempool.TxDesc)
- Rename txMemPool to TxPool (so it's now mempool.TxPool)
- Move defaultBlockPrioritySize to the new package and export it
- Export DefaultMinRelayTxFee from the mempool package
- Export the CalcPriority function from the mempool package
- Introduce a new RawMempoolVerbose function on the TxPool and update
  the RPC server to use it
- Update all references to the mempool to use the package.
- Add a skeleton README.md
2016-08-19 11:08:37 -05:00

820 lines
31 KiB
Go

// Copyright (c) 2014-2016 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package main
import (
"container/heap"
"container/list"
"fmt"
"time"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/mempool"
"github.com/btcsuite/btcd/mining"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)
const (
// generatedBlockVersion is the version of the block being generated.
// 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 = 4
// 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 added to the coinbase script of a generated block
// and is used to monitor BIP16 support as well as blocks that are
// generated via btcd.
coinbaseFlags = "/P2SH/btcd/"
)
// txPrioItem houses a transaction along with extra information that allows the
// transaction to be prioritized and track dependencies on other transactions
// which have not been mined into a block yet.
type txPrioItem struct {
tx *btcutil.Tx
fee int64
priority float64
feePerKB int64
// dependsOn holds a map of transaction hashes which this one depends
// on. It will only be set when the transaction references other
// transactions in the source pool and hence must come after them in
// a block.
dependsOn map[chainhash.Hash]struct{}
}
// txPriorityQueueLessFunc describes a function that can be used as a compare
// function for a transaction priority queue (txPriorityQueue).
type txPriorityQueueLessFunc func(*txPriorityQueue, int, int) bool
// txPriorityQueue implements a priority queue of txPrioItem elements that
// supports an arbitrary compare function as defined by txPriorityQueueLessFunc.
type txPriorityQueue struct {
lessFunc txPriorityQueueLessFunc
items []*txPrioItem
}
// Len returns the number of items in the priority queue. It is part of the
// heap.Interface implementation.
func (pq *txPriorityQueue) Len() int {
return len(pq.items)
}
// Less returns whether the item in the priority queue with index i should sort
// before the item with index j by deferring to the assigned less function. It
// is part of the heap.Interface implementation.
func (pq *txPriorityQueue) Less(i, j int) bool {
return pq.lessFunc(pq, i, j)
}
// Swap swaps the items at the passed indices in the priority queue. It is
// part of the heap.Interface implementation.
func (pq *txPriorityQueue) Swap(i, j int) {
pq.items[i], pq.items[j] = pq.items[j], pq.items[i]
}
// Push pushes the passed item onto the priority queue. It is part of the
// heap.Interface implementation.
func (pq *txPriorityQueue) Push(x interface{}) {
pq.items = append(pq.items, x.(*txPrioItem))
}
// Pop removes the highest priority item (according to Less) from the priority
// queue and returns it. It is part of the heap.Interface implementation.
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
}
// SetLessFunc sets the compare function for the priority queue to the provided
// function. It also invokes heap.Init on the priority queue using the new
// function so it can immediately be used with heap.Push/Pop.
func (pq *txPriorityQueue) SetLessFunc(lessFunc txPriorityQueueLessFunc) {
pq.lessFunc = lessFunc
heap.Init(pq)
}
// txPQByPriority sorts a txPriorityQueue by transaction priority and then fees
// per kilobyte.
func txPQByPriority(pq *txPriorityQueue, i, j int) bool {
// Using > here so that pop gives the highest priority item as opposed
// to the lowest. Sort by priority first, then fee.
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
}
// txPQByFee sorts a txPriorityQueue by fees per kilobyte and then transaction
// priority.
func txPQByFee(pq *txPriorityQueue, i, j int) bool {
// Using > here so that pop gives the highest fee item as opposed
// to the lowest. Sort by fee first, then priority.
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
}
// newTxPriorityQueue returns a new transaction priority queue that reserves the
// passed amount of space for the elements. The new priority queue uses either
// the txPQByPriority or the txPQByFee compare function depending on the
// sortByFee parameter and is already initialized for use with heap.Push/Pop.
// The priority queue can grow larger than the reserved space, but extra copies
// of the underlying array can be avoided by reserving a sane value.
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
}
// 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 int32
// 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 view 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 fully spent.
func mergeUtxoView(viewA *blockchain.UtxoViewpoint, viewB *blockchain.UtxoViewpoint) {
viewAEntries := viewA.Entries()
for hash, entryB := range viewB.Entries() {
if entryA, exists := viewAEntries[hash]; !exists ||
entryA == nil || entryA.IsFullySpent() {
viewAEntries[hash] = entryB
}
}
}
// standardCoinbaseScript returns a standard script suitable for use as the
// signature script of the coinbase transaction of a new block. In particular,
// it starts with the block height that is required by version 2 blocks and adds
// the extra nonce as well as additional coinbase flags.
func standardCoinbaseScript(nextBlockHeight int32, extraNonce uint64) ([]byte, error) {
return txscript.NewScriptBuilder().AddInt64(int64(nextBlockHeight)).
AddInt64(int64(extraNonce)).AddData([]byte(coinbaseFlags)).
Script()
}
// 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(coinbaseScript []byte, nextBlockHeight int32, addr btcutil.Address) (*btcutil.Tx, error) {
// 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.
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()
tx.AddTxIn(&wire.TxIn{
// Coinbase transactions have no inputs, so previous outpoint is
// zero hash and max index.
PreviousOutPoint: *wire.NewOutPoint(&chainhash.Hash{},
wire.MaxPrevOutIndex),
SignatureScript: coinbaseScript,
Sequence: wire.MaxTxInSequenceNum,
})
tx.AddTxOut(&wire.TxOut{
Value: blockchain.CalcBlockSubsidy(nextBlockHeight,
activeNetParams.Params),
PkScript: pkScript,
})
return btcutil.NewTx(tx), 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 *btcutil.Tx, height int32) error {
for _, txIn := range tx.MsgTx().TxIn {
originHash := &txIn.PreviousOutPoint.Hash
originIndex := txIn.PreviousOutPoint.Index
entry := utxoView.LookupEntry(originHash)
if entry != nil {
entry.SpendOutput(originIndex)
}
}
utxoView.AddTxOuts(tx, height)
return nil
}
// 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 *btcutil.Tx, deps *list.List) {
if deps == nil {
return
}
for e := deps.Front(); e != nil; e = e.Next() {
item := e.Value.(*txPrioItem)
minrLog.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(chainState *chainState) (time.Time, error) {
chainState.Lock()
defer chainState.Unlock()
if chainState.pastMedianTimeErr != nil {
return time.Time{}, chainState.pastMedianTimeErr
}
return chainState.pastMedianTime.Add(time.Second), nil
}
// 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 medianAdjustedTime(chainState *chainState, timeSource blockchain.MedianTimeSource) (time.Time, error) {
chainState.Lock()
defer chainState.Unlock()
if chainState.pastMedianTimeErr != nil {
return time.Time{}, chainState.pastMedianTimeErr
}
// 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 supported a precision greater than one
// second.
newTimestamp := timeSource.AdjustedTime()
minTimestamp := chainState.pastMedianTime.Add(time.Second)
if newTimestamp.Before(minTimestamp) {
newTimestamp = minTimestamp
}
return newTimestamp, nil
}
// 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 several
// factors. First, each transaction has a priority calculated based on its
// value, age of inputs, and size. Transactions which consist of larger
// amounts, older inputs, and small sizes have the highest priority. Second, a
// fee per kilobyte is calculated for each transaction. 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 either
// prioritizes based on the priority (then fee per kilobyte) or the fee per
// kilobyte (then priority) depending on whether or not the BlockPrioritySize
// policy setting allots space for high-priority transactions. 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.
//
// Once the high-priority area (if configured) has been filled with
// transactions, or the priority falls below what is considered high-priority,
// the priority queue is updated to prioritize by fees per kilobyte (then
// priority).
//
// When the fees per kilobyte drop below the TxMinFreeFee policy setting, the
// transaction will be skipped unless the BlockMinSize policy setting is
// nonzero, in which case the block will be filled with the low-fee/free
// transactions until the block size reaches that minimum size.
//
// 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.BlockPrioritySize
// | High-priority Transactions | | |
// | | | |
// |-----------------------------------| | --
// | | |
// | | |
// | | |--- policy.BlockMaxSize
// | Transactions prioritized by fee | |
// | until <= policy.TxMinFreeFee | |
// | | |
// | | |
// | | |
// |-----------------------------------| |
// | Low-fee/Non high-priority (free) | |
// | transactions (while block size | |
// | <= policy.BlockMinSize) | |
// ----------------------------------- --
func NewBlockTemplate(policy *mining.Policy, server *server, payToAddress btcutil.Address) (*BlockTemplate, error) {
var txSource mining.TxSource = server.txMemPool
blockManager := server.blockManager
timeSource := server.timeSource
chainState := &blockManager.chainState
// Extend the most recently known best block.
chainState.Lock()
prevHash := chainState.newestHash
nextBlockHeight := chainState.newestHeight + 1
chainState.Unlock()
// 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).
extraNonce := uint64(0)
coinbaseScript, err := standardCoinbaseScript(nextBlockHeight, extraNonce)
if err != nil {
return nil, err
}
coinbaseTx, err := createCoinbaseTx(coinbaseScript, nextBlockHeight,
payToAddress)
if err != nil {
return nil, err
}
numCoinbaseSigOps := int64(blockchain.CountSigOps(coinbaseTx))
// 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.
sourceTxns := txSource.MiningDescs()
sortedByFee := policy.BlockPrioritySize == 0
priorityQueue := newTxPriorityQueue(len(sourceTxns), sortedByFee)
// 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([]*btcutil.Tx, 0, len(sourceTxns))
blockTxns = append(blockTxns, coinbaseTx)
blockUtxos := blockchain.NewUtxoViewpoint()
// dependers is used to track transactions which depend on another
// transaction in the source pool. This, in conjunction with the
// dependsOn map kept with each dependent transaction helps quickly
// determine which dependent transactions are now eligible for inclusion
// in the block once each transaction has been included.
dependers := make(map[chainhash.Hash]*list.List)
// 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))
txSigOpCounts := make([]int64, 0, len(sourceTxns))
txFees = append(txFees, -1) // Updated once known
txSigOpCounts = append(txSigOpCounts, numCoinbaseSigOps)
minrLog.Debugf("Considering %d transactions for inclusion to new block",
len(sourceTxns))
mempoolLoop:
for _, txDesc := range sourceTxns {
// A block can't have more than one coinbase or contain
// non-finalized transactions.
tx := txDesc.Tx
if blockchain.IsCoinBase(tx) {
minrLog.Tracef("Skipping coinbase tx %s", tx.Hash())
continue
}
if !blockchain.IsFinalizedTransaction(tx, nextBlockHeight,
timeSource.AdjustedTime()) {
minrLog.Tracef("Skipping non-finalized tx %s", tx.Hash())
continue
}
// Fetch all of the utxos referenced by the this transaction.
// NOTE: This intentionally does not fetch inputs from the
// mempool since a transaction which depends on other
// transactions in the mempool must come after those
// dependencies in the final generated block.
utxos, err := blockManager.chain.FetchUtxoView(tx)
if err != nil {
minrLog.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{tx: tx}
for _, txIn := range tx.MsgTx().TxIn {
originHash := &txIn.PreviousOutPoint.Hash
originIndex := txIn.PreviousOutPoint.Index
utxoEntry := utxos.LookupEntry(originHash)
if utxoEntry == nil || utxoEntry.IsOutputSpent(originIndex) {
if !txSource.HaveTransaction(originHash) {
minrLog.Tracef("Skipping tx %s because "+
"it references unspent output "+
"%s which is not available",
tx.Hash(), txIn.PreviousOutPoint)
continue mempoolLoop
}
// The transaction is referencing another
// transaction in the source pool, so setup an
// ordering dependency.
depList, exists := dependers[*originHash]
if !exists {
depList = list.New()
dependers[*originHash] = depList
}
depList.PushBack(prioItem)
if prioItem.dependsOn == nil {
prioItem.dependsOn = make(
map[chainhash.Hash]struct{})
}
prioItem.dependsOn[*originHash] = struct{}{}
// Skip the check below. We already know the
// referenced transaction is available.
continue
}
}
// 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 = mempool.CalcPriority(tx.MsgTx(), utxos,
nextBlockHeight)
// Calculate the fee in Satoshi/kB.
txSize := tx.MsgTx().SerializeSize()
prioItem.feePerKB = (txDesc.Fee * 1000) / int64(txSize)
prioItem.fee = txDesc.Fee
// Add the transaction to the priority queue to mark it ready
// for inclusion in the block unless it has dependencies.
if prioItem.dependsOn == nil {
heap.Push(priorityQueue, prioItem)
}
// 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)
}
minrLog.Tracef("Priority queue len %d, dependers len %d",
priorityQueue.Len(), len(dependers))
// 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 := blockHeaderOverhead + uint32(coinbaseTx.MsgTx().SerializeSize())
blockSigOps := numCoinbaseSigOps
totalFees := int64(0)
// Choose which transactions make it into the block.
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.tx
// Grab the list of transactions which depend on this one (if
// any) and remove the entry for this transaction as it will
// either be included or skipped, but in either case the deps
// are no longer needed.
deps := dependers[*tx.Hash()]
delete(dependers, *tx.Hash())
// Enforce maximum block size. Also check for overflow.
txSize := uint32(tx.MsgTx().SerializeSize())
blockPlusTxSize := blockSize + txSize
if blockPlusTxSize < blockSize || blockPlusTxSize >= policy.BlockMaxSize {
minrLog.Tracef("Skipping tx %s because it would exceed "+
"the max block size", tx.Hash())
logSkippedDeps(tx, deps)
continue
}
// Enforce maximum signature operations per block. Also check
// for overflow.
numSigOps := int64(blockchain.CountSigOps(tx))
if blockSigOps+numSigOps < blockSigOps ||
blockSigOps+numSigOps > blockchain.MaxSigOpsPerBlock {
minrLog.Tracef("Skipping tx %s because it would "+
"exceed the maximum sigops per block", tx.Hash())
logSkippedDeps(tx, deps)
continue
}
numP2SHSigOps, err := blockchain.CountP2SHSigOps(tx, false,
blockUtxos)
if err != nil {
minrLog.Tracef("Skipping tx %s due to error in "+
"CountP2SHSigOps: %v", tx.Hash(), err)
logSkippedDeps(tx, deps)
continue
}
numSigOps += int64(numP2SHSigOps)
if blockSigOps+numSigOps < blockSigOps ||
blockSigOps+numSigOps > blockchain.MaxSigOpsPerBlock {
minrLog.Tracef("Skipping tx %s because it would "+
"exceed the maximum sigops per block (p2sh)",
tx.Hash())
logSkippedDeps(tx, deps)
continue
}
// Skip free transactions once the block is larger than the
// minimum block size.
if sortedByFee &&
prioItem.feePerKB < int64(policy.TxMinFreeFee) &&
blockPlusTxSize >= policy.BlockMinSize {
minrLog.Tracef("Skipping tx %s with feePerKB %d "+
"< TxMinFreeFee %d and block size %d >= "+
"minBlockSize %d", tx.Hash(), prioItem.feePerKB,
policy.TxMinFreeFee, blockPlusTxSize,
policy.BlockMinSize)
logSkippedDeps(tx, deps)
continue
}
// Prioritize by fee per kilobyte once the block is larger than
// the priority size or there are no more high-priority
// transactions.
if !sortedByFee && (blockPlusTxSize >= policy.BlockPrioritySize ||
prioItem.priority <= mempool.MinHighPriority) {
minrLog.Tracef("Switching to sort by fees per "+
"kilobyte blockSize %d >= BlockPrioritySize "+
"%d || priority %.2f <= minHighPriority %.2f",
blockPlusTxSize, policy.BlockPrioritySize,
prioItem.priority, mempool.MinHighPriority)
sortedByFee = true
priorityQueue.SetLessFunc(txPQByFee)
// Put the transaction back into the priority queue and
// skip it so it is re-priortized by fees if it won't
// fit into the high-priority section or the priority is
// too low. Otherwise this transaction will be the
// final one in the high-priority section, so just fall
// though to the code below so it is added now.
if blockPlusTxSize > policy.BlockPrioritySize ||
prioItem.priority < mempool.MinHighPriority {
heap.Push(priorityQueue, prioItem)
continue
}
}
// Ensure the transaction inputs pass all of the necessary
// preconditions before allowing it to be added to the block.
_, err = blockchain.CheckTransactionInputs(tx, nextBlockHeight,
blockUtxos, activeNetParams.Params)
if err != nil {
minrLog.Tracef("Skipping tx %s due to error in "+
"CheckTransactionInputs: %v", tx.Hash(), err)
logSkippedDeps(tx, deps)
continue
}
err = blockchain.ValidateTransactionScripts(tx, blockUtxos,
txscript.StandardVerifyFlags, server.sigCache)
if err != nil {
minrLog.Tracef("Skipping tx %s due to error in "+
"ValidateTransactionScripts: %v", tx.Hash(), err)
logSkippedDeps(tx, deps)
continue
}
// 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, tx, nextBlockHeight)
// Add the transaction to the block, increment counters, and
// save the fees and signature operation counts to the block
// template.
blockTxns = append(blockTxns, tx)
blockSize += txSize
blockSigOps += numSigOps
totalFees += prioItem.fee
txFees = append(txFees, prioItem.fee)
txSigOpCounts = append(txSigOpCounts, numSigOps)
minrLog.Tracef("Adding tx %s (priority %.2f, feePerKB %d)",
prioItem.tx.Hash(), prioItem.priority, prioItem.feePerKB)
// Add transactions which depend on this one (and also do not
// have any other unsatisified dependencies) to the priority
// queue.
if deps != nil {
for e := deps.Front(); e != nil; e = e.Next() {
// Add the transaction to the priority queue if
// there are no more dependencies after this
// one.
item := e.Value.(*txPrioItem)
delete(item.dependsOn, *tx.Hash())
if len(item.dependsOn) == 0 {
heap.Push(priorityQueue, item)
}
}
}
}
// 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.
blockSize -= wire.MaxVarIntPayload -
uint32(wire.VarIntSerializeSize(uint64(len(blockTxns))))
coinbaseTx.MsgTx().TxOut[0].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, err := medianAdjustedTime(chainState, timeSource)
if err != nil {
return nil, err
}
reqDifficulty, err := blockManager.chain.CalcNextRequiredDifficulty(ts)
if err != nil {
return nil, err
}
// Create a new block ready to be solved.
merkles := blockchain.BuildMerkleTreeStore(blockTxns)
var msgBlock wire.MsgBlock
msgBlock.Header = wire.BlockHeader{
Version: generatedBlockVersion,
PrevBlock: *prevHash,
MerkleRoot: *merkles[len(merkles)-1],
Timestamp: ts,
Bits: reqDifficulty,
}
for _, tx := range blockTxns {
if err := msgBlock.AddTransaction(tx.MsgTx()); err != nil {
return nil, err
}
}
// 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 := btcutil.NewBlock(&msgBlock)
block.SetHeight(nextBlockHeight)
if err := blockManager.chain.CheckConnectBlock(block); err != nil {
return nil, err
}
minrLog.Debugf("Created new block template (%d transactions, %d in "+
"fees, %d signature operations, %d bytes, target difficulty "+
"%064x)", len(msgBlock.Transactions), totalFees, blockSigOps,
blockSize, blockchain.CompactToBig(msgBlock.Header.Bits))
return &BlockTemplate{
Block: &msgBlock,
Fees: txFees,
SigOpCounts: txSigOpCounts,
Height: nextBlockHeight,
ValidPayAddress: payToAddress != nil,
}, nil
}
// UpdateBlockTime updates the timestamp in the header of the passed block 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. Finally, it will update the target difficulty if needed
// based on the new time for the test networks since their target difficulty can
// change based upon time.
func UpdateBlockTime(msgBlock *wire.MsgBlock, bManager *blockManager) error {
// 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, err := medianAdjustedTime(&bManager.chainState,
bManager.server.timeSource)
if err != nil {
return err
}
msgBlock.Header.Timestamp = newTimestamp
// If running on a network that requires recalculating the difficulty,
// do so now.
if activeNetParams.ReduceMinDifficulty {
difficulty, err := bManager.chain.CalcNextRequiredDifficulty(
newTimestamp)
if err != nil {
return err
}
msgBlock.Header.Bits = difficulty
}
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.
func UpdateExtraNonce(msgBlock *wire.MsgBlock, blockHeight int32, extraNonce uint64) error {
coinbaseScript, err := standardCoinbaseScript(blockHeight, extraNonce)
if err != nil {
return err
}
if len(coinbaseScript) > blockchain.MaxCoinbaseScriptLen {
return fmt.Errorf("coinbase transaction script length "+
"of %d is out of range (min: %d, max: %d)",
len(coinbaseScript), blockchain.MinCoinbaseScriptLen,
blockchain.MaxCoinbaseScriptLen)
}
msgBlock.Transactions[0].TxIn[0].SignatureScript = coinbaseScript
// TODO(davec): A btcutil.Block should use saved in the state to avoid
// recalculating all of the other transaction hashes.
// block.Transactions[0].InvalidateCache()
// Recalculate the merkle root with the updated extra nonce.
block := btcutil.NewBlock(msgBlock)
merkles := blockchain.BuildMerkleTreeStore(block.Transactions())
msgBlock.Header.MerkleRoot = *merkles[len(merkles)-1]
return nil
}