2014-03-11 06:12:54 +01:00
|
|
|
// 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"
|
2014-03-20 08:06:10 +01:00
|
|
|
"fmt"
|
2014-03-11 06:12:54 +01:00
|
|
|
"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
|
|
|
|
}
|
2014-03-20 08:06:10 +01:00
|
|
|
|
|
|
|
// 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 *btcwire.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)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
msgBlock.Header.Timestamp = newTimestamp
|
|
|
|
|
|
|
|
// Recalculate the required difficulty for the test networks since it
|
|
|
|
// can change based on time.
|
|
|
|
if activeNetParams.btcnet == btcwire.TestNet ||
|
|
|
|
activeNetParams.btcnet == btcwire.TestNet3 {
|
|
|
|
|
|
|
|
difficulty, err := bManager.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 the results
|
|
|
|
// from changing the coinbase script.
|
|
|
|
func UpdateExtraNonce(msgBlock *btcwire.MsgBlock, blockHeight int64, extraNonce uint64) error {
|
|
|
|
coinbaseScript := standardCoinbaseScript(blockHeight, extraNonce)
|
|
|
|
if len(coinbaseScript) > btcchain.MaxCoinbaseScriptLen {
|
|
|
|
return fmt.Errorf("coinbase transaction script length "+
|
|
|
|
"of %d is out of range (min: %d, max: %d)",
|
|
|
|
len(coinbaseScript), btcchain.MinCoinbaseScriptLen,
|
|
|
|
btcchain.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 := btcchain.BuildMerkleTreeStore(block.Transactions())
|
|
|
|
msgBlock.Header.MerkleRoot = *merkles[len(merkles)-1]
|
|
|
|
return nil
|
|
|
|
}
|