-// Copyright (c) 2014-2016 The btcsuite developers\r
-// Use of this source code is governed by an ISC\r
-// license that can be found in the LICENSE file.\r
-\r
-package mining\r
-\r
-import (\r
- "container/heap"\r
- "fmt"\r
- "time"\r
-\r
- "github.com/btcsuite/btcd/blockchain"\r
- "github.com/btcsuite/btcd/chaincfg"\r
- "github.com/btcsuite/btcd/chaincfg/chainhash"\r
- "github.com/btcsuite/btcd/txscript"\r
- "github.com/btcsuite/btcd/wire"\r
- "github.com/btcsuite/btcutil"\r
-)\r
-\r
-const (\r
- // MinHighPriority is the minimum priority value that allows a\r
- // transaction to be considered high priority.\r
- MinHighPriority = btcutil.SatoshiPerBitcoin * 144.0 / 250\r
-\r
- // blockHeaderOverhead is the max number of bytes it takes to serialize\r
- // a block header and max possible transaction count.\r
- blockHeaderOverhead = wire.MaxBlockHeaderPayload + wire.MaxVarIntPayload\r
-\r
- // CoinbaseFlags is added to the coinbase script of a generated block\r
- // and is used to monitor BIP16 support as well as blocks that are\r
- // generated via btcd.\r
- CoinbaseFlags = "/P2SH/btcd/"\r
-)\r
-\r
-// TxDesc is a descriptor about a transaction in a transaction source along with\r
-// additional metadata.\r
-type TxDesc struct {\r
- // Tx is the transaction associated with the entry.\r
- Tx *btcutil.Tx\r
-\r
- // Added is the time when the entry was added to the source pool.\r
- Added time.Time\r
-\r
- // Height is the block height when the entry was added to the the source\r
- // pool.\r
- Height int32\r
-\r
- // Fee is the total fee the transaction associated with the entry pays.\r
- Fee int64\r
-\r
- // FeePerKB is the fee the transaction pays in Satoshi per 1000 bytes.\r
- FeePerKB int64\r
-}\r
-\r
-// TxSource represents a source of transactions to consider for inclusion in\r
-// new blocks.\r
-//\r
-// The interface contract requires that all of these methods are safe for\r
-// concurrent access with respect to the source.\r
-type TxSource interface {\r
- // LastUpdated returns the last time a transaction was added to or\r
- // removed from the source pool.\r
- LastUpdated() time.Time\r
-\r
- // MiningDescs returns a slice of mining descriptors for all the\r
- // transactions in the source pool.\r
- MiningDescs() []*TxDesc\r
-\r
- // HaveTransaction returns whether or not the passed transaction hash\r
- // exists in the source pool.\r
- HaveTransaction(hash *chainhash.Hash) bool\r
-}\r
-\r
-// txPrioItem houses a transaction along with extra information that allows the\r
-// transaction to be prioritized and track dependencies on other transactions\r
-// which have not been mined into a block yet.\r
-type txPrioItem struct {\r
- tx *btcutil.Tx\r
- fee int64\r
- priority float64\r
- feePerKB int64\r
-\r
- // dependsOn holds a map of transaction hashes which this one depends\r
- // on. It will only be set when the transaction references other\r
- // transactions in the source pool and hence must come after them in\r
- // a block.\r
- dependsOn map[chainhash.Hash]struct{}\r
-}\r
-\r
-// txPriorityQueueLessFunc describes a function that can be used as a compare\r
-// function for a transaction priority queue (txPriorityQueue).\r
-type txPriorityQueueLessFunc func(*txPriorityQueue, int, int) bool\r
-\r
-// txPriorityQueue implements a priority queue of txPrioItem elements that\r
-// supports an arbitrary compare function as defined by txPriorityQueueLessFunc.\r
-type txPriorityQueue struct {\r
- lessFunc txPriorityQueueLessFunc\r
- items []*txPrioItem\r
-}\r
-\r
-// Len returns the number of items in the priority queue. It is part of the\r
-// heap.Interface implementation.\r
-func (pq *txPriorityQueue) Len() int {\r
- return len(pq.items)\r
-}\r
-\r
-// Less returns whether the item in the priority queue with index i should sort\r
-// before the item with index j by deferring to the assigned less function. It\r
-// is part of the heap.Interface implementation.\r
-func (pq *txPriorityQueue) Less(i, j int) bool {\r
- return pq.lessFunc(pq, i, j)\r
-}\r
-\r
-// Swap swaps the items at the passed indices in the priority queue. It is\r
-// part of the heap.Interface implementation.\r
-func (pq *txPriorityQueue) Swap(i, j int) {\r
- pq.items[i], pq.items[j] = pq.items[j], pq.items[i]\r
-}\r
-\r
-// Push pushes the passed item onto the priority queue. It is part of the\r
-// heap.Interface implementation.\r
-func (pq *txPriorityQueue) Push(x interface{}) {\r
- pq.items = append(pq.items, x.(*txPrioItem))\r
-}\r
-\r
-// Pop removes the highest priority item (according to Less) from the priority\r
-// queue and returns it. It is part of the heap.Interface implementation.\r
-func (pq *txPriorityQueue) Pop() interface{} {\r
- n := len(pq.items)\r
- item := pq.items[n-1]\r
- pq.items[n-1] = nil\r
- pq.items = pq.items[0 : n-1]\r
- return item\r
-}\r
-\r
-// SetLessFunc sets the compare function for the priority queue to the provided\r
-// function. It also invokes heap.Init on the priority queue using the new\r
-// function so it can immediately be used with heap.Push/Pop.\r
-func (pq *txPriorityQueue) SetLessFunc(lessFunc txPriorityQueueLessFunc) {\r
- pq.lessFunc = lessFunc\r
- heap.Init(pq)\r
-}\r
-\r
-// txPQByPriority sorts a txPriorityQueue by transaction priority and then fees\r
-// per kilobyte.\r
-func txPQByPriority(pq *txPriorityQueue, i, j int) bool {\r
- // Using > here so that pop gives the highest priority item as opposed\r
- // to the lowest. Sort by priority first, then fee.\r
- if pq.items[i].priority == pq.items[j].priority {\r
- return pq.items[i].feePerKB > pq.items[j].feePerKB\r
- }\r
- return pq.items[i].priority > pq.items[j].priority\r
-\r
-}\r
-\r
-// txPQByFee sorts a txPriorityQueue by fees per kilobyte and then transaction\r
-// priority.\r
-func txPQByFee(pq *txPriorityQueue, i, j int) bool {\r
- // Using > here so that pop gives the highest fee item as opposed\r
- // to the lowest. Sort by fee first, then priority.\r
- if pq.items[i].feePerKB == pq.items[j].feePerKB {\r
- return pq.items[i].priority > pq.items[j].priority\r
- }\r
- return pq.items[i].feePerKB > pq.items[j].feePerKB\r
-}\r
-\r
-// newTxPriorityQueue returns a new transaction priority queue that reserves the\r
-// passed amount of space for the elements. The new priority queue uses either\r
-// the txPQByPriority or the txPQByFee compare function depending on the\r
-// sortByFee parameter and is already initialized for use with heap.Push/Pop.\r
-// The priority queue can grow larger than the reserved space, but extra copies\r
-// of the underlying array can be avoided by reserving a sane value.\r
-func newTxPriorityQueue(reserve int, sortByFee bool) *txPriorityQueue {\r
- pq := &txPriorityQueue{\r
- items: make([]*txPrioItem, 0, reserve),\r
- }\r
- if sortByFee {\r
- pq.SetLessFunc(txPQByFee)\r
- } else {\r
- pq.SetLessFunc(txPQByPriority)\r
- }\r
- return pq\r
-}\r
-\r
-// BlockTemplate houses a block that has yet to be solved along with additional\r
-// details about the fees and the number of signature operations for each\r
-// transaction in the block.\r
-type BlockTemplate struct {\r
- // Block is a block that is ready to be solved by miners. Thus, it is\r
- // completely valid with the exception of satisfying the proof-of-work\r
- // requirement.\r
- Block *wire.MsgBlock\r
-\r
- // Fees contains the amount of fees each transaction in the generated\r
- // template pays in base units. Since the first transaction is the\r
- // coinbase, the first entry (offset 0) will contain the negative of the\r
- // sum of the fees of all other transactions.\r
- Fees []int64\r
-\r
- // SigOpCounts contains the number of signature operations each\r
- // transaction in the generated template performs.\r
- SigOpCounts []int64\r
-\r
- // Height is the height at which the block template connects to the main\r
- // chain.\r
- Height int32\r
-\r
- // ValidPayAddress indicates whether or not the template coinbase pays\r
- // to an address or is redeemable by anyone. See the documentation on\r
- // NewBlockTemplate for details on which this can be useful to generate\r
- // templates without a coinbase payment address.\r
- ValidPayAddress bool\r
-}\r
-\r
-// mergeUtxoView adds all of the entries in view to viewA. The result is that\r
-// viewA will contain all of its original entries plus all of the entries\r
-// in viewB. It will replace any entries in viewB which also exist in viewA\r
-// if the entry in viewA is fully spent.\r
-func mergeUtxoView(viewA *blockchain.UtxoViewpoint, viewB *blockchain.UtxoViewpoint) {\r
- viewAEntries := viewA.Entries()\r
- for hash, entryB := range viewB.Entries() {\r
- if entryA, exists := viewAEntries[hash]; !exists ||\r
- entryA == nil || entryA.IsFullySpent() {\r
-\r
- viewAEntries[hash] = entryB\r
- }\r
- }\r
-}\r
-\r
-// standardCoinbaseScript returns a standard script suitable for use as the\r
-// signature script of the coinbase transaction of a new block. In particular,\r
-// it starts with the block height that is required by version 2 blocks and adds\r
-// the extra nonce as well as additional coinbase flags.\r
-func standardCoinbaseScript(nextBlockHeight int32, extraNonce uint64) ([]byte, error) {\r
- return txscript.NewScriptBuilder().AddInt64(int64(nextBlockHeight)).\r
- AddInt64(int64(extraNonce)).AddData([]byte(CoinbaseFlags)).\r
- Script()\r
-}\r
-\r
-// createCoinbaseTx returns a coinbase transaction paying an appropriate subsidy\r
-// based on the passed block height to the provided address. When the address\r
-// is nil, the coinbase transaction will instead be redeemable by anyone.\r
-//\r
-// See the comment for NewBlockTemplate for more information about why the nil\r
-// address handling is useful.\r
-func createCoinbaseTx(params *chaincfg.Params, coinbaseScript []byte, nextBlockHeight int32, addr btcutil.Address) (*btcutil.Tx, error) {\r
- // Create the script to pay to the provided payment address if one was\r
- // specified. Otherwise create a script that allows the coinbase to be\r
- // redeemable by anyone.\r
- var pkScript []byte\r
- if addr != nil {\r
- var err error\r
- pkScript, err = txscript.PayToAddrScript(addr)\r
- if err != nil {\r
- return nil, err\r
- }\r
- } else {\r
- var err error\r
- scriptBuilder := txscript.NewScriptBuilder()\r
- pkScript, err = scriptBuilder.AddOp(txscript.OP_TRUE).Script()\r
- if err != nil {\r
- return nil, err\r
- }\r
- }\r
-\r
- tx := wire.NewMsgTx(wire.TxVersion)\r
- tx.AddTxIn(&wire.TxIn{\r
- // Coinbase transactions have no inputs, so previous outpoint is\r
- // zero hash and max index.\r
- PreviousOutPoint: *wire.NewOutPoint(&chainhash.Hash{},\r
- wire.MaxPrevOutIndex),\r
- SignatureScript: coinbaseScript,\r
- Sequence: wire.MaxTxInSequenceNum,\r
- })\r
- tx.AddTxOut(&wire.TxOut{\r
- Value: blockchain.CalcBlockSubsidy(nextBlockHeight, params),\r
- PkScript: pkScript,\r
- })\r
- return btcutil.NewTx(tx), nil\r
-}\r
-\r
-// spendTransaction updates the passed view by marking the inputs to the passed\r
-// transaction as spent. It also adds all outputs in the passed transaction\r
-// which are not provably unspendable as available unspent transaction outputs.\r
-func spendTransaction(utxoView *blockchain.UtxoViewpoint, tx *btcutil.Tx, height int32) error {\r
- for _, txIn := range tx.MsgTx().TxIn {\r
- originHash := &txIn.PreviousOutPoint.Hash\r
- originIndex := txIn.PreviousOutPoint.Index\r
- entry := utxoView.LookupEntry(originHash)\r
- if entry != nil {\r
- entry.SpendOutput(originIndex)\r
- }\r
- }\r
-\r
- utxoView.AddTxOuts(tx, height)\r
- return nil\r
-}\r
-\r
-// logSkippedDeps logs any dependencies which are also skipped as a result of\r
-// skipping a transaction while generating a block template at the trace level.\r
-func logSkippedDeps(tx *btcutil.Tx, deps map[chainhash.Hash]*txPrioItem) {\r
- if deps == nil {\r
- return\r
- }\r
-\r
- for _, item := range deps {\r
- log.Tracef("Skipping tx %s since it depends on %s\n",\r
- item.tx.Hash(), tx.Hash())\r
- }\r
-}\r
-\r
-// MinimumMedianTime returns the minimum allowed timestamp for a block building\r
-// on the end of the provided best chain. In particular, it is one second after\r
-// the median timestamp of the last several blocks per the chain consensus\r
-// rules.\r
-func MinimumMedianTime(chainState *blockchain.BestState) time.Time {\r
- return chainState.MedianTime.Add(time.Second)\r
-}\r
-\r
-// medianAdjustedTime returns the current time adjusted to ensure it is at least\r
-// one second after the median timestamp of the last several blocks per the\r
-// chain consensus rules.\r
-func medianAdjustedTime(chainState *blockchain.BestState, timeSource blockchain.MedianTimeSource) time.Time {\r
- // The timestamp for the block must not be before the median timestamp\r
- // of the last several blocks. Thus, choose the maximum between the\r
- // current time and one second after the past median time. The current\r
- // timestamp is truncated to a second boundary before comparison since a\r
- // block timestamp does not supported a precision greater than one\r
- // second.\r
- newTimestamp := timeSource.AdjustedTime()\r
- minTimestamp := MinimumMedianTime(chainState)\r
- if newTimestamp.Before(minTimestamp) {\r
- newTimestamp = minTimestamp\r
- }\r
-\r
- return newTimestamp\r
-}\r
-\r
-// BlkTmplGenerator provides a type that can be used to generate block templates\r
-// based on a given mining policy and source of transactions to choose from.\r
-// It also houses additional state required in order to ensure the templates\r
-// are built on top of the current best chain and adhere to the consensus rules.\r
-type BlkTmplGenerator struct {\r
- policy *Policy\r
- chainParams *chaincfg.Params\r
- txSource TxSource\r
- chain *blockchain.BlockChain\r
- timeSource blockchain.MedianTimeSource\r
- sigCache *txscript.SigCache\r
-}\r
-\r
-// NewBlkTmplGenerator returns a new block template generator for the given\r
-// policy using transactions from the provided transaction source.\r
-//\r
-// The additional state-related fields are required in order to ensure the\r
-// templates are built on top of the current best chain and adhere to the\r
-// consensus rules.\r
-func NewBlkTmplGenerator(policy *Policy, params *chaincfg.Params,\r
- txSource TxSource, chain *blockchain.BlockChain,\r
- timeSource blockchain.MedianTimeSource,\r
- sigCache *txscript.SigCache) *BlkTmplGenerator {\r
-\r
- return &BlkTmplGenerator{\r
- policy: policy,\r
- chainParams: params,\r
- txSource: txSource,\r
- chain: chain,\r
- timeSource: timeSource,\r
- sigCache: sigCache,\r
- }\r
-}\r
-\r
-// NewBlockTemplate returns a new block template that is ready to be solved\r
-// using the transactions from the passed transaction source pool and a coinbase\r
-// that either pays to the passed address if it is not nil, or a coinbase that\r
-// is redeemable by anyone if the passed address is nil. The nil address\r
-// functionality is useful since there are cases such as the getblocktemplate\r
-// RPC where external mining software is responsible for creating their own\r
-// coinbase which will replace the one generated for the block template. Thus\r
-// the need to have configured address can be avoided.\r
-//\r
-// The transactions selected and included are prioritized according to several\r
-// factors. First, each transaction has a priority calculated based on its\r
-// value, age of inputs, and size. Transactions which consist of larger\r
-// amounts, older inputs, and small sizes have the highest priority. Second, a\r
-// fee per kilobyte is calculated for each transaction. Transactions with a\r
-// higher fee per kilobyte are preferred. Finally, the block generation related\r
-// policy settings are all taken into account.\r
-//\r
-// Transactions which only spend outputs from other transactions already in the\r
-// block chain are immediately added to a priority queue which either\r
-// prioritizes based on the priority (then fee per kilobyte) or the fee per\r
-// kilobyte (then priority) depending on whether or not the BlockPrioritySize\r
-// policy setting allots space for high-priority transactions. Transactions\r
-// which spend outputs from other transactions in the source pool are added to a\r
-// dependency map so they can be added to the priority queue once the\r
-// transactions they depend on have been included.\r
-//\r
-// Once the high-priority area (if configured) has been filled with\r
-// transactions, or the priority falls below what is considered high-priority,\r
-// the priority queue is updated to prioritize by fees per kilobyte (then\r
-// priority).\r
-//\r
-// When the fees per kilobyte drop below the TxMinFreeFee policy setting, the\r
-// transaction will be skipped unless the BlockMinSize policy setting is\r
-// nonzero, in which case the block will be filled with the low-fee/free\r
-// transactions until the block size reaches that minimum size.\r
-//\r
-// Any transactions which would cause the block to exceed the BlockMaxSize\r
-// policy setting, exceed the maximum allowed signature operations per block, or\r
-// otherwise cause the block to be invalid are skipped.\r
-//\r
-// Given the above, a block generated by this function is of the following form:\r
-//\r
-// ----------------------------------- -- --\r
-// | Coinbase Transaction | | |\r
-// |-----------------------------------| | |\r
-// | | | | ----- policy.BlockPrioritySize\r
-// | High-priority Transactions | | |\r
-// | | | |\r
-// |-----------------------------------| | --\r
-// | | |\r
-// | | |\r
-// | | |--- policy.BlockMaxSize\r
-// | Transactions prioritized by fee | |\r
-// | until <= policy.TxMinFreeFee | |\r
-// | | |\r
-// | | |\r
-// | | |\r
-// |-----------------------------------| |\r
-// | Low-fee/Non high-priority (free) | |\r
-// | transactions (while block size | |\r
-// | <= policy.BlockMinSize) | |\r
-// ----------------------------------- --\r
-func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress btcutil.Address) (*BlockTemplate, error) {\r
- // Extend the most recently known best block.\r
- best := g.chain.BestSnapshot()\r
- prevHash := &best.Hash\r
- nextBlockHeight := best.Height + 1\r
-\r
- // Create a standard coinbase transaction paying to the provided\r
- // address. NOTE: The coinbase value will be updated to include the\r
- // fees from the selected transactions later after they have actually\r
- // been selected. It is created here to detect any errors early\r
- // before potentially doing a lot of work below. The extra nonce helps\r
- // ensure the transaction is not a duplicate transaction (paying the\r
- // same value to the same public key address would otherwise be an\r
- // identical transaction for block version 1).\r
- extraNonce := uint64(0)\r
- coinbaseScript, err := standardCoinbaseScript(nextBlockHeight, extraNonce)\r
- if err != nil {\r
- return nil, err\r
- }\r
- coinbaseTx, err := createCoinbaseTx(g.chainParams, coinbaseScript,\r
- nextBlockHeight, payToAddress)\r
- if err != nil {\r
- return nil, err\r
- }\r
- numCoinbaseSigOps := int64(blockchain.CountSigOps(coinbaseTx))\r
-\r
- // Get the current source transactions and create a priority queue to\r
- // hold the transactions which are ready for inclusion into a block\r
- // along with some priority related and fee metadata. Reserve the same\r
- // number of items that are available for the priority queue. Also,\r
- // choose the initial sort order for the priority queue based on whether\r
- // or not there is an area allocated for high-priority transactions.\r
- sourceTxns := g.txSource.MiningDescs()\r
- sortedByFee := g.policy.BlockPrioritySize == 0\r
- priorityQueue := newTxPriorityQueue(len(sourceTxns), sortedByFee)\r
-\r
- // Create a slice to hold the transactions to be included in the\r
- // generated block with reserved space. Also create a utxo view to\r
- // house all of the input transactions so multiple lookups can be\r
- // avoided.\r
- blockTxns := make([]*btcutil.Tx, 0, len(sourceTxns))\r
- blockTxns = append(blockTxns, coinbaseTx)\r
- blockUtxos := blockchain.NewUtxoViewpoint()\r
-\r
- // dependers is used to track transactions which depend on another\r
- // transaction in the source pool. This, in conjunction with the\r
- // dependsOn map kept with each dependent transaction helps quickly\r
- // determine which dependent transactions are now eligible for inclusion\r
- // in the block once each transaction has been included.\r
- dependers := make(map[chainhash.Hash]map[chainhash.Hash]*txPrioItem)\r
-\r
- // Create slices to hold the fees and number of signature operations\r
- // for each of the selected transactions and add an entry for the\r
- // coinbase. This allows the code below to simply append details about\r
- // a transaction as it is selected for inclusion in the final block.\r
- // However, since the total fees aren't known yet, use a dummy value for\r
- // the coinbase fee which will be updated later.\r
- txFees := make([]int64, 0, len(sourceTxns))\r
- txSigOpCounts := make([]int64, 0, len(sourceTxns))\r
- txFees = append(txFees, -1) // Updated once known\r
- txSigOpCounts = append(txSigOpCounts, numCoinbaseSigOps)\r
-\r
- log.Debugf("Considering %d transactions for inclusion to new block",\r
- len(sourceTxns))\r
-\r
-mempoolLoop:\r
- for _, txDesc := range sourceTxns {\r
- // A block can't have more than one coinbase or contain\r
- // non-finalized transactions.\r
- tx := txDesc.Tx\r
- if blockchain.IsCoinBase(tx) {\r
- log.Tracef("Skipping coinbase tx %s", tx.Hash())\r
- continue\r
- }\r
- if !blockchain.IsFinalizedTransaction(tx, nextBlockHeight,\r
- g.timeSource.AdjustedTime()) {\r
-\r
- log.Tracef("Skipping non-finalized tx %s", tx.Hash())\r
- continue\r
- }\r
-\r
- // Fetch all of the utxos referenced by the this transaction.\r
- // NOTE: This intentionally does not fetch inputs from the\r
- // mempool since a transaction which depends on other\r
- // transactions in the mempool must come after those\r
- // dependencies in the final generated block.\r
- utxos, err := g.chain.FetchUtxoView(tx)\r
- if err != nil {\r
- log.Warnf("Unable to fetch utxo view for tx %s: %v",\r
- tx.Hash(), err)\r
- continue\r
- }\r
-\r
- // Setup dependencies for any transactions which reference\r
- // other transactions in the mempool so they can be properly\r
- // ordered below.\r
- prioItem := &txPrioItem{tx: tx}\r
- for _, txIn := range tx.MsgTx().TxIn {\r
- originHash := &txIn.PreviousOutPoint.Hash\r
- originIndex := txIn.PreviousOutPoint.Index\r
- utxoEntry := utxos.LookupEntry(originHash)\r
- if utxoEntry == nil || utxoEntry.IsOutputSpent(originIndex) {\r
- if !g.txSource.HaveTransaction(originHash) {\r
- log.Tracef("Skipping tx %s because it "+\r
- "references unspent output %s "+\r
- "which is not available",\r
- tx.Hash(), txIn.PreviousOutPoint)\r
- continue mempoolLoop\r
- }\r
-\r
- // The transaction is referencing another\r
- // transaction in the source pool, so setup an\r
- // ordering dependency.\r
- deps, exists := dependers[*originHash]\r
- if !exists {\r
- deps = make(map[chainhash.Hash]*txPrioItem)\r
- dependers[*originHash] = deps\r
- }\r
- deps[*prioItem.tx.Hash()] = prioItem\r
- if prioItem.dependsOn == nil {\r
- prioItem.dependsOn = make(\r
- map[chainhash.Hash]struct{})\r
- }\r
- prioItem.dependsOn[*originHash] = struct{}{}\r
-\r
- // Skip the check below. We already know the\r
- // referenced transaction is available.\r
- continue\r
- }\r
- }\r
-\r
- // Calculate the final transaction priority using the input\r
- // value age sum as well as the adjusted transaction size. The\r
- // formula is: sum(inputValue * inputAge) / adjustedTxSize\r
- prioItem.priority = CalcPriority(tx.MsgTx(), utxos,\r
- nextBlockHeight)\r
-\r
- // Calculate the fee in Satoshi/kB.\r
- prioItem.feePerKB = txDesc.FeePerKB\r
- prioItem.fee = txDesc.Fee\r
-\r
- // Add the transaction to the priority queue to mark it ready\r
- // for inclusion in the block unless it has dependencies.\r
- if prioItem.dependsOn == nil {\r
- heap.Push(priorityQueue, prioItem)\r
- }\r
-\r
- // Merge the referenced outputs from the input transactions to\r
- // this transaction into the block utxo view. This allows the\r
- // code below to avoid a second lookup.\r
- mergeUtxoView(blockUtxos, utxos)\r
- }\r
-\r
- log.Tracef("Priority queue len %d, dependers len %d",\r
- priorityQueue.Len(), len(dependers))\r
-\r
- // The starting block size is the size of the block header plus the max\r
- // possible transaction count size, plus the size of the coinbase\r
- // transaction.\r
- blockSize := blockHeaderOverhead + uint32(coinbaseTx.MsgTx().SerializeSize())\r
- blockSigOps := numCoinbaseSigOps\r
- totalFees := int64(0)\r
-\r
- // Choose which transactions make it into the block.\r
- for priorityQueue.Len() > 0 {\r
- // Grab the highest priority (or highest fee per kilobyte\r
- // depending on the sort order) transaction.\r
- prioItem := heap.Pop(priorityQueue).(*txPrioItem)\r
- tx := prioItem.tx\r
-\r
- // Grab any transactions which depend on this one.\r
- deps := dependers[*tx.Hash()]\r
-\r
- // Enforce maximum block size. Also check for overflow.\r
- txSize := uint32(tx.MsgTx().SerializeSize())\r
- blockPlusTxSize := blockSize + txSize\r
- if blockPlusTxSize < blockSize ||\r
- blockPlusTxSize >= g.policy.BlockMaxSize {\r
-\r
- log.Tracef("Skipping tx %s because it would exceed "+\r
- "the max block size", tx.Hash())\r
- logSkippedDeps(tx, deps)\r
- continue\r
- }\r
-\r
- // Enforce maximum signature operations per block. Also check\r
- // for overflow.\r
- numSigOps := int64(blockchain.CountSigOps(tx))\r
- if blockSigOps+numSigOps < blockSigOps ||\r
- blockSigOps+numSigOps > blockchain.MaxSigOpsPerBlock {\r
- log.Tracef("Skipping tx %s because it would exceed "+\r
- "the maximum sigops per block", tx.Hash())\r
- logSkippedDeps(tx, deps)\r
- continue\r
- }\r
- numP2SHSigOps, err := blockchain.CountP2SHSigOps(tx, false,\r
- blockUtxos)\r
- if err != nil {\r
- log.Tracef("Skipping tx %s due to error in "+\r
- "CountP2SHSigOps: %v", tx.Hash(), err)\r
- logSkippedDeps(tx, deps)\r
- continue\r
- }\r
- numSigOps += int64(numP2SHSigOps)\r
- if blockSigOps+numSigOps < blockSigOps ||\r
- blockSigOps+numSigOps > blockchain.MaxSigOpsPerBlock {\r
- log.Tracef("Skipping tx %s because it would exceed "+\r
- "the maximum sigops per block (p2sh)",\r
- tx.Hash())\r
- logSkippedDeps(tx, deps)\r
- continue\r
- }\r
-\r
- // Skip free transactions once the block is larger than the\r
- // minimum block size.\r
- if sortedByFee &&\r
- prioItem.feePerKB < int64(g.policy.TxMinFreeFee) &&\r
- blockPlusTxSize >= g.policy.BlockMinSize {\r
-\r
- log.Tracef("Skipping tx %s with feePerKB %.2f "+\r
- "< TxMinFreeFee %d and block size %d >= "+\r
- "minBlockSize %d", tx.Hash(), prioItem.feePerKB,\r
- g.policy.TxMinFreeFee, blockPlusTxSize,\r
- g.policy.BlockMinSize)\r
- logSkippedDeps(tx, deps)\r
- continue\r
- }\r
-\r
- // Prioritize by fee per kilobyte once the block is larger than\r
- // the priority size or there are no more high-priority\r
- // transactions.\r
- if !sortedByFee && (blockPlusTxSize >= g.policy.BlockPrioritySize ||\r
- prioItem.priority <= MinHighPriority) {\r
-\r
- log.Tracef("Switching to sort by fees per kilobyte "+\r
- "blockSize %d >= BlockPrioritySize %d || "+\r
- "priority %.2f <= minHighPriority %.2f",\r
- blockPlusTxSize, g.policy.BlockPrioritySize,\r
- prioItem.priority, MinHighPriority)\r
-\r
- sortedByFee = true\r
- priorityQueue.SetLessFunc(txPQByFee)\r
-\r
- // Put the transaction back into the priority queue and\r
- // skip it so it is re-priortized by fees if it won't\r
- // fit into the high-priority section or the priority is\r
- // too low. Otherwise this transaction will be the\r
- // final one in the high-priority section, so just fall\r
- // though to the code below so it is added now.\r
- if blockPlusTxSize > g.policy.BlockPrioritySize ||\r
- prioItem.priority < MinHighPriority {\r
-\r
- heap.Push(priorityQueue, prioItem)\r
- continue\r
- }\r
- }\r
-\r
- // Ensure the transaction inputs pass all of the necessary\r
- // preconditions before allowing it to be added to the block.\r
- _, err = blockchain.CheckTransactionInputs(tx, nextBlockHeight,\r
- blockUtxos, g.chainParams)\r
- if err != nil {\r
- log.Tracef("Skipping tx %s due to error in "+\r
- "CheckTransactionInputs: %v", tx.Hash(), err)\r
- logSkippedDeps(tx, deps)\r
- continue\r
- }\r
- err = blockchain.ValidateTransactionScripts(tx, blockUtxos,\r
- txscript.StandardVerifyFlags, g.sigCache)\r
- if err != nil {\r
- log.Tracef("Skipping tx %s due to error in "+\r
- "ValidateTransactionScripts: %v", tx.Hash(),\r
- err)\r
- logSkippedDeps(tx, deps)\r
- continue\r
- }\r
-\r
- // Spend the transaction inputs in the block utxo view and add\r
- // an entry for it to ensure any transactions which reference\r
- // this one have it available as an input and can ensure they\r
- // aren't double spending.\r
- spendTransaction(blockUtxos, tx, nextBlockHeight)\r
-\r
- // Add the transaction to the block, increment counters, and\r
- // save the fees and signature operation counts to the block\r
- // template.\r
- blockTxns = append(blockTxns, tx)\r
- blockSize += txSize\r
- blockSigOps += numSigOps\r
- totalFees += prioItem.fee\r
- txFees = append(txFees, prioItem.fee)\r
- txSigOpCounts = append(txSigOpCounts, numSigOps)\r
-\r
- log.Tracef("Adding tx %s (priority %.2f, feePerKB %.2f)",\r
- prioItem.tx.Hash(), prioItem.priority, prioItem.feePerKB)\r
-\r
- // Add transactions which depend on this one (and also do not\r
- // have any other unsatisified dependencies) to the priority\r
- // queue.\r
- for _, item := range deps {\r
- // Add the transaction to the priority queue if there\r
- // are no more dependencies after this one.\r
- delete(item.dependsOn, *tx.Hash())\r
- if len(item.dependsOn) == 0 {\r
- heap.Push(priorityQueue, item)\r
- }\r
- }\r
- }\r
-\r
- // Now that the actual transactions have been selected, update the\r
- // block size for the real transaction count and coinbase value with\r
- // the total fees accordingly.\r
- blockSize -= wire.MaxVarIntPayload -\r
- uint32(wire.VarIntSerializeSize(uint64(len(blockTxns))))\r
- coinbaseTx.MsgTx().TxOut[0].Value += totalFees\r
- txFees[0] = -totalFees\r
-\r
- // Calculate the required difficulty for the block. The timestamp\r
- // is potentially adjusted to ensure it comes after the median time of\r
- // the last several blocks per the chain consensus rules.\r
- ts := medianAdjustedTime(best, g.timeSource)\r
- reqDifficulty, err := g.chain.CalcNextRequiredDifficulty(ts)\r
- if err != nil {\r
- return nil, err\r
- }\r
-\r
- // Calculate the next expected block version based on the state of the\r
- // rule change deployments.\r
- nextBlockVersion, err := g.chain.CalcNextBlockVersion()\r
- if err != nil {\r
- return nil, err\r
- }\r
-\r
- // Create a new block ready to be solved.\r
- merkles := blockchain.BuildMerkleTreeStore(blockTxns)\r
- var msgBlock wire.MsgBlock\r
- msgBlock.Header = wire.BlockHeader{\r
- Version: nextBlockVersion,\r
- PrevBlock: *prevHash,\r
- MerkleRoot: *merkles[len(merkles)-1],\r
- Timestamp: ts,\r
- Bits: reqDifficulty,\r
- }\r
- for _, tx := range blockTxns {\r
- if err := msgBlock.AddTransaction(tx.MsgTx()); err != nil {\r
- return nil, err\r
- }\r
- }\r
-\r
- // Finally, perform a full check on the created block against the chain\r
- // consensus rules to ensure it properly connects to the current best\r
- // chain with no issues.\r
- block := btcutil.NewBlock(&msgBlock)\r
- block.SetHeight(nextBlockHeight)\r
- if err := g.chain.CheckConnectBlock(block); err != nil {\r
- return nil, err\r
- }\r
-\r
- log.Debugf("Created new block template (%d transactions, %d in fees, "+\r
- "%d signature operations, %d bytes, target difficulty %064x)",\r
- len(msgBlock.Transactions), totalFees, blockSigOps, blockSize,\r
- blockchain.CompactToBig(msgBlock.Header.Bits))\r
-\r
- return &BlockTemplate{\r
- Block: &msgBlock,\r
- Fees: txFees,\r
- SigOpCounts: txSigOpCounts,\r
- Height: nextBlockHeight,\r
- ValidPayAddress: payToAddress != nil,\r
- }, nil\r
-}\r
-\r
-// UpdateBlockTime updates the timestamp in the header of the passed block to\r
-// the current time while taking into account the median time of the last\r
-// several blocks to ensure the new time is after that time per the chain\r
-// consensus rules. Finally, it will update the target difficulty if needed\r
-// based on the new time for the test networks since their target difficulty can\r
-// change based upon time.\r
-func (g *BlkTmplGenerator) UpdateBlockTime(msgBlock *wire.MsgBlock) error {\r
- // The new timestamp is potentially adjusted to ensure it comes after\r
- // the median time of the last several blocks per the chain consensus\r
- // rules.\r
- newTime := medianAdjustedTime(g.chain.BestSnapshot(), g.timeSource)\r
- msgBlock.Header.Timestamp = newTime\r
-\r
- // Recalculate the difficulty if running on a network that requires it.\r
- if g.chainParams.ReduceMinDifficulty {\r
- difficulty, err := g.chain.CalcNextRequiredDifficulty(newTime)\r
- if err != nil {\r
- return err\r
- }\r
- msgBlock.Header.Bits = difficulty\r
- }\r
-\r
- return nil\r
-}\r
-\r
-// UpdateExtraNonce updates the extra nonce in the coinbase script of the passed\r
-// block by regenerating the coinbase script with the passed value and block\r
-// height. It also recalculates and updates the new merkle root that results\r
-// from changing the coinbase script.\r
-func (g *BlkTmplGenerator) UpdateExtraNonce(msgBlock *wire.MsgBlock, blockHeight int32, extraNonce uint64) error {\r
- coinbaseScript, err := standardCoinbaseScript(blockHeight, extraNonce)\r
- if err != nil {\r
- return err\r
- }\r
- if len(coinbaseScript) > blockchain.MaxCoinbaseScriptLen {\r
- return fmt.Errorf("coinbase transaction script length "+\r
- "of %d is out of range (min: %d, max: %d)",\r
- len(coinbaseScript), blockchain.MinCoinbaseScriptLen,\r
- blockchain.MaxCoinbaseScriptLen)\r
- }\r
- msgBlock.Transactions[0].TxIn[0].SignatureScript = coinbaseScript\r
-\r
- // TODO(davec): A btcutil.Block should use saved in the state to avoid\r
- // recalculating all of the other transaction hashes.\r
- // block.Transactions[0].InvalidateCache()\r
-\r
- // Recalculate the merkle root with the updated extra nonce.\r
- block := btcutil.NewBlock(msgBlock)\r
- merkles := blockchain.BuildMerkleTreeStore(block.Transactions())\r
- msgBlock.Header.MerkleRoot = *merkles[len(merkles)-1]\r
- return nil\r
-}\r
-\r
-// BestSnapshot returns information about the current best chain block and\r
-// related state as of the current point in time using the chain instance\r
-// associated with the block template generator. The returned state must be\r
-// treated as immutable since it is shared by all callers.\r
-//\r
-// This function is safe for concurrent access.\r
-func (g *BlkTmplGenerator) BestSnapshot() *blockchain.BestState {\r
- return g.chain.BestSnapshot()\r
-}\r
-\r
-// TxSource returns the associated transaction source.\r
-//\r
-// This function is safe for concurrent access.\r
-func (g *BlkTmplGenerator) TxSource() TxSource {\r
- return g.txSource\r
-}\r
+package mining
+
+import (
+ "sort"
+ "strconv"
+ "time"
+
+ log "github.com/sirupsen/logrus"
+
+ "github.com/bytom/account"
+ "github.com/bytom/blockchain/txbuilder"
+ "github.com/bytom/consensus"
+ "github.com/bytom/errors"
+ "github.com/bytom/protocol"
+ "github.com/bytom/protocol/bc"
+ "github.com/bytom/protocol/bc/types"
+ "github.com/bytom/protocol/state"
+ "github.com/bytom/protocol/validation"
+ "github.com/bytom/protocol/vm/vmutil"
+)
+
+const logModule = "mining"
+
+// 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.
+func createCoinbaseTx(accountManager *account.Manager, amount uint64, blockHeight uint64) (tx *types.Tx, err error) {
+ amount += consensus.BlockSubsidy(blockHeight)
+ arbitrary := append([]byte{0x00}, []byte(strconv.FormatUint(blockHeight, 10))...)
+
+ var script []byte
+ if accountManager == nil {
+ script, err = vmutil.DefaultCoinbaseProgram()
+ } else {
+ script, err = accountManager.GetCoinbaseControlProgram()
+ arbitrary = append(arbitrary, accountManager.GetCoinbaseArbitrary()...)
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ if len(arbitrary) > consensus.CoinbaseArbitrarySizeLimit {
+ return nil, validation.ErrCoinbaseArbitraryOversize
+ }
+
+ builder := txbuilder.NewBuilder(time.Now())
+ if err = builder.AddInput(types.NewCoinbaseInput(arbitrary), &txbuilder.SigningInstruction{}); err != nil {
+ return nil, err
+ }
+ if err = builder.AddOutput(types.NewTxOutput(*consensus.BTMAssetID, amount, script)); err != nil {
+ return nil, err
+ }
+ _, txData, err := builder.Build()
+ if err != nil {
+ return nil, err
+ }
+
+ byteData, err := txData.MarshalText()
+ if err != nil {
+ return nil, err
+ }
+ txData.SerializedSize = uint64(len(byteData))
+
+ tx = &types.Tx{
+ TxData: *txData,
+ Tx: types.MapTx(txData),
+ }
+ return tx, nil
+}
+
+// NewBlockTemplate returns a new block template that is ready to be solved
+func NewBlockTemplate(c *protocol.Chain, txPool *protocol.TxPool, accountManager *account.Manager) (b *types.Block, err error) {
+ view := state.NewUtxoViewpoint()
+ txStatus := bc.NewTransactionStatus()
+ if err := txStatus.SetStatus(0, false); err != nil {
+ return nil, err
+ }
+ txEntries := []*bc.Tx{nil}
+ gasUsed := uint64(0)
+ txFee := uint64(0)
+
+ // get preblock info for generate next block
+ preBlockHeader := c.BestBlockHeader()
+ preBlockHash := preBlockHeader.Hash()
+ nextBlockHeight := preBlockHeader.Height + 1
+ nextBits, err := c.CalcNextBits(&preBlockHash)
+ if err != nil {
+ return nil, err
+ }
+
+ b = &types.Block{
+ BlockHeader: types.BlockHeader{
+ Version: 1,
+ Height: nextBlockHeight,
+ PreviousBlockHash: preBlockHash,
+ Timestamp: uint64(time.Now().Unix()),
+ BlockCommitment: types.BlockCommitment{},
+ Bits: nextBits,
+ },
+ }
+ bcBlock := &bc.Block{BlockHeader: &bc.BlockHeader{Height: nextBlockHeight}}
+ b.Transactions = []*types.Tx{nil}
+
+ txs := txPool.GetTransactions()
+ sort.Sort(byTime(txs))
+ for _, txDesc := range txs {
+ tx := txDesc.Tx.Tx
+ gasOnlyTx := false
+
+ if err := c.GetTransactionsUtxo(view, []*bc.Tx{tx}); err != nil {
+ blkGenSkipTxForErr(txPool, &tx.ID, err)
+ continue
+ }
+
+ gasStatus, err := validation.ValidateTx(tx, bcBlock)
+ if err != nil {
+ if !gasStatus.GasValid {
+ blkGenSkipTxForErr(txPool, &tx.ID, err)
+ continue
+ }
+ gasOnlyTx = true
+ }
+
+ if gasUsed+uint64(gasStatus.GasUsed) > consensus.MaxBlockGas {
+ break
+ }
+
+ if err := view.ApplyTransaction(bcBlock, tx, gasOnlyTx); err != nil {
+ blkGenSkipTxForErr(txPool, &tx.ID, err)
+ continue
+ }
+
+ if err := txStatus.SetStatus(len(b.Transactions), gasOnlyTx); err != nil {
+ return nil, err
+ }
+
+ b.Transactions = append(b.Transactions, txDesc.Tx)
+ txEntries = append(txEntries, tx)
+ gasUsed += uint64(gasStatus.GasUsed)
+ txFee += txDesc.Fee
+
+ if gasUsed == consensus.MaxBlockGas {
+ break
+ }
+ }
+
+ // creater coinbase transaction
+ b.Transactions[0], err = createCoinbaseTx(accountManager, txFee, nextBlockHeight)
+ if err != nil {
+ return nil, errors.Wrap(err, "fail on createCoinbaseTx")
+ }
+ txEntries[0] = b.Transactions[0].Tx
+
+ b.BlockHeader.BlockCommitment.TransactionsMerkleRoot, err = types.TxMerkleRoot(txEntries)
+ if err != nil {
+ return nil, err
+ }
+
+ b.BlockHeader.BlockCommitment.TransactionStatusHash, err = types.TxStatusMerkleRoot(txStatus.VerifyStatus)
+ return b, err
+}
+
+func blkGenSkipTxForErr(txPool *protocol.TxPool, txHash *bc.Hash, err error) {
+ log.WithFields(log.Fields{"module": logModule, "error": err}).Error("mining block generation: skip tx due to")
+ txPool.RemoveTransaction(txHash)
+}