diff --git a/blockmanager.go b/blockmanager.go index bcadd2fe..be2797ed 100644 --- a/blockmanager.go +++ b/blockmanager.go @@ -76,6 +76,28 @@ type getSyncPeerMsg struct { reply chan *peer } +// checkConnectBlockMsg is a message type to be sent across the message channel +// for requesting chain to check if a block connects to the end of the current +// main chain. +type checkConnectBlockMsg struct { + block *btcutil.Block + reply chan error +} + +// calcNextReqDifficultyResponse is a response sent to the reply channel of a +// calcNextReqDifficultyMsg query. +type calcNextReqDifficultyResponse struct { + difficulty uint32 + err error +} + +// calcNextReqDifficultyMsg is a message type to be sent across the message +// channel for requesting the required difficulty of the next block. +type calcNextReqDifficultyMsg struct { + timestamp time.Time + reply chan calcNextReqDifficultyResponse +} + // headerNode is used as a node in a list of headers that are linked together // between checkpoints. type headerNode struct { @@ -949,6 +971,18 @@ out: case getSyncPeerMsg: msg.reply <- b.syncPeer + case checkConnectBlockMsg: + err := b.blockChain.CheckConnectBlock(msg.block) + msg.reply <- err + + case calcNextReqDifficultyMsg: + difficulty, err := + b.blockChain.CalcNextRequiredDifficulty( + msg.timestamp) + msg.reply <- calcNextReqDifficultyResponse{ + difficulty: difficulty, + err: err, + } default: bmgrLog.Warnf("Invalid message type in block "+ "handler: %T", msg) @@ -1160,6 +1194,28 @@ func (b *blockManager) SyncPeer() *peer { return <-reply } +// CheckConnectBlock performs several checks to confirm connecting the passed +// block to the main chain does not violate any rules. This function makes use +// of CheckConnectBlock on an internal instance of a block chain. It is funneled +// through the block manager since btcchain is not safe for concurrent access. +func (b *blockManager) CheckConnectBlock(block *btcutil.Block) error { + reply := make(chan error) + b.msgChan <- checkConnectBlockMsg{block: block, reply: reply} + return <-reply +} + +// CalcNextRequiredDifficulty calculates the required difficulty for the next +// block after the current main chain. This function makes use of +// CalcNextRequiredDifficulty on an internal instance of a block chain. It is +// funneled through the block manager since btcchain is not safe for concurrent +// access. +func (b *blockManager) CalcNextRequiredDifficulty(timestamp time.Time) (uint32, error) { + reply := make(chan calcNextReqDifficultyResponse) + b.msgChan <- calcNextReqDifficultyMsg{timestamp: timestamp, reply: reply} + response := <-reply + return response.difficulty, response.err +} + // newBlockManager returns a new bitcoin block manager. // Use Start to begin processing asynchronous block and inv updates. func newBlockManager(s *server) (*blockManager, error) { diff --git a/mempool.go b/mempool.go index 5b14836b..ee8c9502 100644 --- a/mempool.go +++ b/mempool.go @@ -66,10 +66,10 @@ const ( maxStandardMultiSigKeys = 3 // minTxRelayFee is the minimum fee in satoshi that is required for a - // transaction to be treated as free for relay purposes. It is also - // used to help determine if a transaction is considered dust and as a - // base for calculating minimum required fees for larger transactions. - // This value is in Satoshi/KB (kilobyte, not kibibyte). + // transaction to be treated as free for relay and mining purposes. It + // is also used to help determine if a transaction is considered dust + // and as a base for calculating minimum required fees for larger + // transactions. This value is in Satoshi/1000 bytes. minTxRelayFee = 1000 ) @@ -94,7 +94,6 @@ type txMemPool struct { outpoints map[btcwire.OutPoint]*btcutil.Tx pennyTotal float64 // exponentially decaying total for penny spends. lastPennyUnix int64 // unix time of last ``penny spend'' - } // isDust returns whether or not the passed transaction output amount is @@ -148,8 +147,8 @@ func isDust(txOut *btcwire.TxOut) bool { // The output is considered dust if the cost to the network to spend the // coins is more than 1/3 of the minimum free transaction relay fee. - // minFreeTxRelayFee is in Satoshi/KB (kilobyte, not kibibyte), so - // multiply by 1000 to convert bytes. + // minFreeTxRelayFee is in Satoshi/KB, so multiply by 1000 to + // convert to bytes. // // Using the typical values for a pay-to-pubkey-hash transaction from // the breakdown above and the default minimum free transaction relay @@ -379,10 +378,10 @@ func calcMinRelayFee(tx *btcutil.Tx) int64 { // Calculate the minimum fee for a transaction to be allowed into the // mempool and relayed by scaling the base fee (which is the minimum - // free transaction relay fee). minTxRelayFee is in Satoshi/KB - // (kilobyte, not kibibyte), so divide the transaction size by 1000 to - // convert to kilobytes. Also, integer division is used so fees only - // increase on full kilobyte boundaries. + // free transaction relay fee). minTxRelayFee is in Satoshi/KB, so + // divide the transaction size by 1000 to convert to kilobytes. Also, + // integer division is used so fees only increase on full kilobyte + // boundaries. minFee := (1 + serializedLen/1000) * minTxRelayFee // Set the minimum fee to the maximum possible value if the calculated diff --git a/mining.go b/mining.go new file mode 100644 index 00000000..825d1108 --- /dev/null +++ b/mining.go @@ -0,0 +1,771 @@ +// Copyright (c) 2014 Conformal Systems LLC. +// 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" + "github.com/conformal/btcchain" + "github.com/conformal/btcdb" + "github.com/conformal/btcscript" + "github.com/conformal/btcutil" + "github.com/conformal/btcwire" + "time" +) + +const ( + // generatedBlockVersion is the version of the block being generated. + // It is defined as a constant here rather than using the + // btcwire.BlockVersion constant since a change in the block version + // will require changes to the generated block. Using the btcwire + // constant for generated block version could allow creation of invalid + // blocks for the updated version. + generatedBlockVersion = 2 + + // minHighPriority is the minimum priority value that allows a + // transaction to be considered high priority. + minHighPriority = btcutil.SatoshiPerBitcoin * 144 / 250 + + // blockHeaderOverhead is the max number of bytes it takes to serialize + // a block header and max possible transaction count. + blockHeaderOverhead = btcwire.MaxBlockHeaderPayload + btcwire.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 float64 + + // 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 memory pool and hence must come after them in + // a block. + dependsOn map[btcwire.ShaHash]struct{} +} + +// txPriorityQueueLessFunc describes a function that can be used as a compare +// function for a transation 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 *btcwire.MsgBlock + fees []int64 + sigOpCounts []int64 +} + +// minInt is a helper function to return the minimum of two ints. This avoids +// a math import and the need to cast to floats. +func minInt(a, b int) int { + if a < b { + return a + } + return b +} + +// mergeTxStore adds all of the transactions in txStoreB to txStoreA. The +// result is that txStoreA will contain all of its original transactions plus +// all of the transactions in txStoreB. +func mergeTxStore(txStoreA btcchain.TxStore, txStoreB btcchain.TxStore) { + for hash, txDataB := range txStoreB { + if txDataA, exists := txStoreA[hash]; !exists || + (txDataA.Err == btcdb.TxShaMissing && txDataB.Err != + btcdb.TxShaMissing) { + + txStoreA[hash] = txDataB + } + } +} + +// 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 int64, extraNonce uint64) []byte { + return btcscript.NewScriptBuilder().AddInt64(nextBlockHeight). + AddUint64(extraNonce).AddData([]byte(coinbaseFlags)).Script() +} + +// createCoinbaseTx returns a coinbase transaction paying an appropriate subsidy +// based on the passed block height to the passed public key. It also accepts +// an extra nonce value for the signature script. This 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). +func createCoinbaseTx(coinbaseScript []byte, nextBlockHeight int64, addr btcutil.Address) (*btcutil.Tx, error) { + // Create a script to pay to the specific address. + pkScript, err := btcscript.PayToAddrScript(addr) + if err != nil { + return nil, err + } + + tx := btcwire.NewMsgTx() + tx.AddTxIn(&btcwire.TxIn{ + // Coinbase transactions have no inputs, so previous outpoint is + // zero hash and max index. + PreviousOutpoint: *btcwire.NewOutPoint(&btcwire.ShaHash{}, + btcwire.MaxPrevOutIndex), + SignatureScript: coinbaseScript, + Sequence: btcwire.MaxTxInSequenceNum, + }) + tx.AddTxOut(&btcwire.TxOut{ + Value: btcchain.CalcBlockSubsidy(nextBlockHeight, + activeNetParams.btcnet), + PkScript: pkScript, + }) + return btcutil.NewTx(tx), nil +} + +// calcPriority returns a transaction priority given a transaction and the sum +// of each of its input values multiplied by their age (# of confirmations). +// Thus, the final formula for the priority is: +// sum(inputValue * inputAge) / adjustedTxSize +func calcPriority(tx *btcutil.Tx, serializedTxSize int, inputValueAge float64) float64 { + // In order to encourage spending multiple old unspent transaction + // outputs thereby reducing the total set, don't count the constant + // overhead for each input as well as enough bytes of the signature + // script to cover a pay-to-script-hash redemption with a compressed + // pubkey. This makes additional inputs free by boosting the priority + // of the transaction accordingly. No more incentive is given to avoid + // encouraging gaming future transactions through the use of junk + // outputs. This is the same logic used in the reference + // implementation. + // + // The constant overhead for a txin is 41 bytes since the previous + // outpoint is 36 bytes + 4 bytes for the sequence + 1 byte the + // signature script length. + // + // A compressed pubkey pay-to-script-hash redemption with a maximum len + // signature is of the form: + // [OP_DATA_73 <73-byte sig> + OP_DATA_35 + {OP_DATA_33 + // <33 byte compresed pubkey> + OP_CHECKSIG}] + // + // Thus 1 + 73 + 1 + 1 + 33 + 1 = 110 + overhead := 0 + for _, txIn := range tx.MsgTx().TxIn { + // Max inputs + size can't possibly overflow here. + overhead += 41 + minInt(110, len(txIn.SignatureScript)) + } + + if overhead >= serializedTxSize { + return 0.0 + } + + return inputValueAge / float64(serializedTxSize-overhead) +} + +// spendTransaction updates the passed transaction store by marking the inputs +// to the passed transaction as spent. It also adds the passed transaction to +// the store at the provided height. +func spendTransaction(txStore btcchain.TxStore, tx *btcutil.Tx, height int64) error { + for _, txIn := range tx.MsgTx().TxIn { + originHash := &txIn.PreviousOutpoint.Hash + originIndex := txIn.PreviousOutpoint.Index + if originTx, exists := txStore[*originHash]; exists { + originTx.Spent[originIndex] = true + } + } + + txStore[*tx.Sha()] = &btcchain.TxData{ + Tx: tx, + Hash: tx.Sha(), + BlockHeight: height, + Spent: make([]bool, len(tx.MsgTx().TxOut)), + Err: nil, + } + + 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.Sha(), tx.Sha()) + } +} + +// 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) (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 := time.Unix(time.Now().Unix(), 0) + minTimestamp := chainState.pastMedianTime.Add(time.Second) + if newTimestamp.Before(minTimestamp) { + newTimestamp = minTimestamp + } + + return newTimestamp, nil +} + +// NewBlockTemplate returns a new block template using the transactions from the +// passed transaction memory pool with a coinbase that pays to the passed +// address and is ready to be solved. 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 configuration options 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 +// configuration option allots space for high-priority transactions. +// Transactions which spend outputs from other transactions in the memory 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 configuration option, +// the transaction will be skipped unless there is a BlockMinSize set, 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 +// configuration option, 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 | | | +// |-----------------------------------| | | +// | | | | ----- cfg.BlockPrioritySize +// | High-priority Transactions | | | +// | | | | +// |-----------------------------------| | -- +// | | | +// | | | +// | | |--- cfg.BlockMaxSize +// | Transactions prioritized by fee | | +// | until <= cfg.TxMinFreeFee | | +// | | | +// | | | +// | | | +// |-----------------------------------| | +// | Low-fee/Non high-priority (free) | | +// | transactions (while block size | | +// | <= cfg.BlockMinSize) | | +// ----------------------------------- -- +func NewBlockTemplate(payToAddress btcutil.Address, mempool *txMemPool) (*BlockTemplate, error) { + blockManager := mempool.server.blockManager + chainState := &blockManager.chainState + chain := blockManager.blockChain + + // 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. + extraNonce := uint64(0) + coinbaseScript := standardCoinbaseScript(nextBlockHeight, extraNonce) + coinbaseTx, err := createCoinbaseTx(coinbaseScript, nextBlockHeight, + payToAddress) + if err != nil { + return nil, err + } + numCoinbaseSigOps := int64(btcchain.CountSigOps(coinbaseTx)) + + // Get the current memory pool 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 in the memory pool 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. + mempoolTxns := mempool.TxDescs() + sortedByFee := cfg.BlockPrioritySize == 0 + priorityQueue := newTxPriorityQueue(len(mempoolTxns), sortedByFee) + + // Create a slice to hold the transactions to be included in the + // generated block with reserved space. Also create a transaction + // store to house all of the input transactions so multiple lookups + // can be avoided. + blockTxns := make([]*btcutil.Tx, 0, len(mempoolTxns)) + blockTxns = append(blockTxns, coinbaseTx) + blockTxStore := make(btcchain.TxStore) + + // dependers is used to track transactions which depend on another + // transaction in the memory 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[btcwire.ShaHash]*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, len(mempoolTxns)) + txSigOpCounts := make([]int64, len(mempoolTxns)) + txFees = append(txFees, -1) // Updated once known + txSigOpCounts = append(txSigOpCounts, numCoinbaseSigOps) + + minrLog.Debugf("Considering %d mempool transactions for inclusion to "+ + "new block", len(mempoolTxns)) + +mempoolLoop: + for _, txDesc := range mempoolTxns { + // A block can't have more than one coinbase or contain + // non-finalized transactions. + tx := txDesc.Tx + if btcchain.IsCoinBase(tx) { + minrLog.Tracef("Skipping coinbase tx %s", tx.Sha()) + continue + } + if !btcchain.IsFinalizedTransaction(tx, nextBlockHeight, time.Now()) { + minrLog.Tracef("Skipping non-finalized tx %s", tx.Sha()) + continue + } + + // Fetch all of the transactions referenced by the inputs to + // 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. + txStore, err := chain.FetchTransactionStore(tx) + if err != nil { + minrLog.Warnf("Unable to fetch transaction store for "+ + "tx %s: %v", tx.Sha(), err) + continue + } + + // Calculate the input value age sum for the transaction. This + // is comprised of the sum all of input amounts multiplied by + // their respective age (number of confirmations since the + // referenced input transaction). While doing the above, also + // setup dependencies for any transactions which reference other + // transactions in the mempool so they can be properly ordered + // below. + prioItem := &txPrioItem{tx: txDesc.Tx} + inputValueAge := float64(0.0) + for _, txIn := range tx.MsgTx().TxIn { + originHash := &txIn.PreviousOutpoint.Hash + originIndex := txIn.PreviousOutpoint.Index + txData, exists := txStore[*originHash] + if !exists || txData.Err != nil || txData.Tx == nil { + if !mempool.HaveTransaction(originHash) { + minrLog.Tracef("Skipping tx %s because "+ + "it references tx %s which is "+ + "not available", tx.Sha, + originHash) + continue mempoolLoop + } + + // The transaction is referencing another + // transaction in the memory 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[btcwire.ShaHash]struct{}) + } + prioItem.dependsOn[*originHash] = struct{}{} + + // No need to calculate or sum input value age + // for this input since it's zero due to + // the input age multiplier of 0. + continue + } + + // Ensure the output index in the referenced transaction + // is available. + msgTx := txData.Tx.MsgTx() + if originIndex > uint32(len(msgTx.TxOut)) { + minrLog.Tracef("Skipping tx %s because "+ + "it references output %d of tx %s "+ + "which is out of bounds", tx.Sha, + originIndex, originHash) + continue mempoolLoop + } + + // Sum the input value times age. + originTxOut := txData.Tx.MsgTx().TxOut[originIndex] + inputValue := originTxOut.Value + inputAge := nextBlockHeight - txData.BlockHeight + inputValueAge += float64(inputValue * inputAge) + } + + // 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 + txSize := tx.MsgTx().SerializeSize() + prioItem.priority = calcPriority(tx, txSize, inputValueAge) + + // Calculate the fee in Satoshi/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. + prioItem.feePerKB = float64(txDesc.Fee) / (float64(txSize) / 1000) + 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 store which contains all of the input transactions + // for this transaction into the input transaction store. This + // allows the code below to avoid a second lookup. + mergeTxStore(blockTxStore, txStore) + } + + 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.Sha()] + delete(dependers, *tx.Sha()) + + // Enforce maximum block size. Also check for overflow. + txSize := uint32(tx.MsgTx().SerializeSize()) + blockPlusTxSize := blockSize + txSize + if blockPlusTxSize < blockSize || blockPlusTxSize >= cfg.BlockMaxSize { + minrLog.Tracef("Skipping tx %s because it would exceed "+ + "the max block size", tx.Sha()) + logSkippedDeps(tx, deps) + continue + } + + // Enforce maximum signature operations per block. Also check + // for overflow. + numSigOps := int64(btcchain.CountSigOps(tx)) + if blockSigOps+numSigOps < blockSigOps || + blockSigOps+numSigOps > btcchain.MaxSigOpsPerBlock { + minrLog.Tracef("Skipping tx %s because it would "+ + "exceed the maximum sigops per block", tx.Sha()) + logSkippedDeps(tx, deps) + continue + } + numP2SHSigOps, err := btcchain.CountP2SHSigOps(tx, false, + blockTxStore) + if err != nil { + minrLog.Tracef("Skipping tx %s due to error in "+ + "CountP2SHSigOps: %v", tx.Sha(), err) + logSkippedDeps(tx, deps) + continue + } + numSigOps += int64(numP2SHSigOps) + if blockSigOps+numSigOps < blockSigOps || + blockSigOps+numSigOps > btcchain.MaxSigOpsPerBlock { + minrLog.Tracef("Skipping tx %s because it would "+ + "exceed the maximum sigops per block (p2sh)", + tx.Sha()) + logSkippedDeps(tx, deps) + continue + } + + // Skip free transactions once the block is larger than the + // minimum block size. + if sortedByFee && prioItem.feePerKB < minTxRelayFee && + blockPlusTxSize >= cfg.BlockMinSize { + + minrLog.Tracef("Skipping tx %s with feePerKB %.2f "+ + "< minTxRelayFee %d and block size %d >= "+ + "minBlockSize %d", tx.Sha(), prioItem.feePerKB, + minTxRelayFee, blockPlusTxSize, + cfg.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 >= cfg.BlockPrioritySize || + prioItem.priority <= float64(minHighPriority)) { + + minrLog.Tracef("Switching to sort by fees per "+ + "kilobyte blockSize %d >= BlockPrioritySize "+ + "%d || priority %.2f <= minHighPriority %.2f", + blockPlusTxSize, cfg.BlockPrioritySize, + prioItem.priority, float64(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 > cfg.BlockPrioritySize || + prioItem.priority < float64(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 = btcchain.CheckTransactionInputs(tx, nextBlockHeight, + blockTxStore) + if err != nil { + minrLog.Tracef("Skipping tx %s due to error in "+ + "CheckTransactionInputs: %v", tx.Sha(), err) + logSkippedDeps(tx, deps) + continue + } + flags := btcscript.ScriptBip16 | btcscript.ScriptCanonicalSignatures + err = btcchain.ValidateTransactionScripts(tx, blockTxStore, flags) + if err != nil { + minrLog.Tracef("Skipping tx %s due to error in "+ + "ValidateTransactionScripts: %v", tx.Sha(), err) + logSkippedDeps(tx, deps) + continue + } + + // Spend the transaction inputs in the block transaction store + // 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(blockTxStore, 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 %.2f)", + prioItem.tx.Sha(), 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.Sha()) + 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 -= btcwire.MaxVarIntPayload - + uint32(btcwire.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) + if err != nil { + return nil, err + } + requiredDifficulty, err := blockManager.CalcNextRequiredDifficulty(ts) + if err != nil { + return nil, err + } + + // Create a new block ready to be solved. + merkles := btcchain.BuildMerkleTreeStore(blockTxns) + var msgBlock btcwire.MsgBlock + msgBlock.Header = btcwire.BlockHeader{ + Version: generatedBlockVersion, + PrevBlock: *prevHash, + MerkleRoot: *merkles[len(merkles)-1], + Timestamp: ts, + Bits: requiredDifficulty, + } + 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.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, btcchain.CompactToBig(msgBlock.Header.Bits)) + + return &BlockTemplate{ + block: &msgBlock, + fees: txFees, + sigOpCounts: txSigOpCounts, + }, nil +}