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