2cfc6478ce
This moves the priority-related code from the mempool package to the mining package and also exports a new constant named UnminedHeight which takes the place of the old unexported mempoolHeight. Even though the mempool makes use of the priority code to make decisions about what it will accept, priority really has to do with mining since it influences which transactions will end up into a block. This change also has the side effect of being a step towards enabling separation of the mining code into its own package which, as previously mentioned, needs access to the priority calculation code as well. Finally, the mempoolHeight variable was poorly named since what it really represents is a transaction that has not been mined into a block yet. Renaming the variable to more accurately reflect its purpose makes it clear that it belongs in the mining package which also needs the definition now as well since the priority calculation code relies on it. This will also benefit an outstanding PR which needs access to the same value.
125 lines
4.7 KiB
Go
125 lines
4.7 KiB
Go
// Copyright (c) 2014-2016 The btcsuite developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package mining
|
|
|
|
import (
|
|
"github.com/btcsuite/btcd/blockchain"
|
|
"github.com/btcsuite/btcd/wire"
|
|
"github.com/btcsuite/btcutil"
|
|
)
|
|
|
|
const (
|
|
// UnminedHeight is the height used for the "block" height field of the
|
|
// contextual transaction information provided in a transaction store
|
|
// when it has not yet been mined into a block.
|
|
UnminedHeight = 0x7fffffff
|
|
)
|
|
|
|
// Policy houses the policy (configuration parameters) which is used to control
|
|
// the generation of block templates. See the documentation for
|
|
// NewBlockTemplate for more details on each of these parameters are used.
|
|
type Policy struct {
|
|
// BlockMinSize is the minimum block size in bytes to be used when
|
|
// generating a block template.
|
|
BlockMinSize uint32
|
|
|
|
// BlockMaxSize is the maximum block size in bytes to be used when
|
|
// generating a block template.
|
|
BlockMaxSize uint32
|
|
|
|
// BlockPrioritySize is the size in bytes for high-priority / low-fee
|
|
// transactions to be used when generating a block template.
|
|
BlockPrioritySize uint32
|
|
|
|
// TxMinFreeFee is the minimum fee in Satoshi/1000 bytes that is
|
|
// required for a transaction to be treated as free for mining purposes
|
|
// (block template generation).
|
|
TxMinFreeFee btcutil.Amount
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// calcInputValueAge is a helper function used to calculate the input age of
|
|
// a transaction. The input age for a txin is the number of confirmations
|
|
// since the referenced txout multiplied by its output value. The total input
|
|
// age is the sum of this value for each txin. Any inputs to the transaction
|
|
// which are currently in the mempool and hence not mined into a block yet,
|
|
// contribute no additional input age to the transaction.
|
|
func calcInputValueAge(tx *wire.MsgTx, utxoView *blockchain.UtxoViewpoint, nextBlockHeight int32) float64 {
|
|
var totalInputAge float64
|
|
for _, txIn := range tx.TxIn {
|
|
// Don't attempt to accumulate the total input age if the
|
|
// referenced transaction output doesn't exist.
|
|
originHash := &txIn.PreviousOutPoint.Hash
|
|
originIndex := txIn.PreviousOutPoint.Index
|
|
txEntry := utxoView.LookupEntry(originHash)
|
|
if txEntry != nil && !txEntry.IsOutputSpent(originIndex) {
|
|
// Inputs with dependencies currently in the mempool
|
|
// have their block height set to a special constant.
|
|
// Their input age should computed as zero since their
|
|
// parent hasn't made it into a block yet.
|
|
var inputAge int32
|
|
originHeight := txEntry.BlockHeight()
|
|
if originHeight == UnminedHeight {
|
|
inputAge = 0
|
|
} else {
|
|
inputAge = nextBlockHeight - originHeight
|
|
}
|
|
|
|
// Sum the input value times age.
|
|
inputValue := txEntry.AmountByIndex(originIndex)
|
|
totalInputAge += float64(inputValue * int64(inputAge))
|
|
}
|
|
}
|
|
|
|
return totalInputAge
|
|
}
|
|
|
|
// 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 *wire.MsgTx, utxoView *blockchain.UtxoViewpoint, nextBlockHeight int32) 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.TxIn {
|
|
// Max inputs + size can't possibly overflow here.
|
|
overhead += 41 + minInt(110, len(txIn.SignatureScript))
|
|
}
|
|
|
|
serializedTxSize := tx.SerializeSize()
|
|
if overhead >= serializedTxSize {
|
|
return 0.0
|
|
}
|
|
|
|
inputValueAge := calcInputValueAge(tx, utxoView, nextBlockHeight)
|
|
return inputValueAge / float64(serializedTxSize-overhead)
|
|
}
|