policy.go raw

   1  package mining
   2  
   3  import (
   4  	"github.com/p9c/p9/pkg/amt"
   5  	"github.com/p9c/p9/pkg/blockchain"
   6  	"github.com/p9c/p9/pkg/wire"
   7  )
   8  
   9  const (
  10  	// UnminedHeight is the height used for the "block" height field of the
  11  	// contextual transaction information provided in a transaction store when it
  12  	// has not yet been mined into a block.
  13  	UnminedHeight = 0x7fffffff
  14  )
  15  
  16  // Policy houses the policy (configuration parameters) which is used to control
  17  // the generation of block templates. See the documentation for NewBlockTemplate
  18  // for more details on each of these parameters are used.
  19  type Policy struct {
  20  	// BlockMinWeight is the minimum block weight to be used when generating a block
  21  	// template.
  22  	BlockMinWeight uint32
  23  	// BlockMaxWeight is the maximum block weight to be used when generating a block
  24  	// template.
  25  	BlockMaxWeight uint32
  26  	// BlockMinWeight is the minimum block size to be used when generating a block
  27  	// template.
  28  	BlockMinSize uint32
  29  	// BlockMaxSize is the maximum block size to be used when generating a block
  30  	// template.
  31  	BlockMaxSize uint32
  32  	// BlockPrioritySize is the size in bytes for high-priority / low-fee
  33  	// transactions to be used when generating a block template.
  34  	BlockPrioritySize uint32
  35  	// TxMinFreeFee is the minimum fee in Satoshi/1000 bytes that is required for a
  36  	// transaction to be treated as free for mining purposes (block template
  37  	// generation).
  38  	TxMinFreeFee amt.Amount
  39  }
  40  
  41  // minInt is a helper function to return the minimum of two ints. This avoids a
  42  // math import and the need to cast to floats.
  43  func minInt(a, b int) int {
  44  	if a < b {
  45  		return a
  46  	}
  47  	return b
  48  }
  49  
  50  // calcInputValueAge is a helper function used to calculate the input age of a
  51  // transaction. The input age for a txin is the number of confirmations since
  52  // the referenced txout multiplied by its output value. The total input age is
  53  // the sum of this value for each txin. Any inputs to the transaction which are
  54  // currently in the mempool and hence not mined into a block yet, contribute no
  55  // additional input age to the transaction.
  56  func calcInputValueAge(tx *wire.MsgTx, utxoView *blockchain.UtxoViewpoint, nextBlockHeight int32) float64 {
  57  	var totalInputAge float64
  58  	for _, txIn := range tx.TxIn {
  59  		// Don't attempt to accumulate the total input age if the referenced transaction
  60  		// output doesn't exist.
  61  		entry := utxoView.LookupEntry(txIn.PreviousOutPoint)
  62  		if entry != nil && !entry.IsSpent() {
  63  			// Inputs with dependencies currently in the mempool have their block height set
  64  			// to a special constant. Their input age should computed as zero since their
  65  			// parent hasn't made it into a block yet.
  66  			var inputAge int32
  67  			originHeight := entry.BlockHeight()
  68  			if originHeight == UnminedHeight {
  69  				inputAge = 0
  70  			} else {
  71  				inputAge = nextBlockHeight - originHeight
  72  			}
  73  			// Sum the input value times age.
  74  			inputValue := entry.Amount()
  75  			totalInputAge += float64(inputValue * int64(inputAge))
  76  		}
  77  	}
  78  	return totalInputAge
  79  }
  80  
  81  // CalcPriority returns a transaction priority given a transaction and the sum
  82  // of each of its input values multiplied by their age (# of confirmations).
  83  // Thus, the final formula for the priority is: sum(inputValue * inputAge) /
  84  // adjustedTxSize
  85  func CalcPriority(tx *wire.MsgTx, utxoView *blockchain.UtxoViewpoint, nextBlockHeight int32) float64 {
  86  	// In order to encourage spending multiple old unspent transaction outputs
  87  	// thereby reducing the total set, don't count the constant overhead for each
  88  	// input as well as enough bytes of the signature script to cover a
  89  	// pay-to-script-hash redemption with a compressed pubkey.
  90  	//
  91  	// This makes additional inputs free by boosting the priority of the transaction
  92  	// accordingly. No more incentive is given to avoid encouraging gaming future
  93  	// transactions through the use of junk outputs.
  94  	//
  95  	// This is the same logic used in the reference implementation.
  96  	//
  97  	// The constant overhead for a txin is 41 bytes since the previous outpoint is
  98  	// 36 bytes + 4 bytes for the sequence + 1 byte the signature script length. A
  99  	// compressed pubkey pay-to-script-hash redemption with a maximum len signature
 100  	// is of the form:
 101  	//
 102  	// [OP_DATA_73 <73-byte sig> + OP_DATA_35 + {OP_DATA_33 <33 byte compresed pubkey> + OP_CHECKSIG}] Thus 1 + 73 + 1 +
 103  	// 1 + 33 + 1 = 110
 104  	overhead := 0
 105  	for _, txIn := range tx.TxIn {
 106  		// Max inputs + size can't possibly overflow here.
 107  		overhead += 41 + minInt(110, len(txIn.SignatureScript))
 108  	}
 109  	serializedTxSize := tx.SerializeSize()
 110  	if overhead >= serializedTxSize {
 111  		return 0.0
 112  	}
 113  	inputValueAge := calcInputValueAge(tx, utxoView, nextBlockHeight)
 114  	return inputValueAge / float64(serializedTxSize-overhead)
 115  }
 116