_policy_test.go raw
1 package mining
2
3 import (
4 "encoding/hex"
5 "testing"
6
7 blockchain "github.com/p9c/p9/pkg/chain"
8 chainhash "github.com/p9c/p9/pkg/chain/hash"
9 "github.com/p9c/p9/pkg/chain/wire"
10 "github.com/p9c/p9/pkg/util"
11 )
12
13 // newHashFromStr converts the passed big-endian hex string into a chainhash.Hash. It only differs from the one available in chainhash in that it panics on an error since it will only (and must only) be called with hard-coded, and therefore known good, hashes.
14 func newHashFromStr( hexStr string) *chainhash.Hash {
15 hash, e := chainhash.NewHashFromStr(hexStr)
16 if e != nil {
17 L.panic("invalid hash in source file: " + hexStr)
18 }
19 return hash
20 }
21
22 // hexToBytes converts the passed hex string into bytes and will panic if there is an error. This is only provided for the hard-coded constants so errors in the source code can be detected. It will only (and must only) be called with hard-coded values.
23 func hexToBytes( s string) []byte {
24 b, e := hex.DecodeString(s)
25 if e != nil {
26 L.panic("invalid hex in source file: " + s)
27 }
28 return b
29 }
30
31 // newUtxoViewpoint returns a new utxo view populated with outputs of the provided source transactions as if there were available at the respective block height specified in the heights slice. The length of the source txns and source tx heights must match or it will panic.
32 func newUtxoViewpoint( sourceTxns []*wire.MsgTx, sourceTxHeights []int32) *blockchain.UtxoViewpoint {
33 if len(sourceTxns) != len(sourceTxHeights) {
34 panic("each transaction must have its block height specified")
35 }
36 view := blockchain.NewUtxoViewpoint()
37 for i, tx := range sourceTxns {
38 view.AddTxOuts(util.NewTx(tx), sourceTxHeights[i])
39 }
40 return view
41 }
42
43 // TestCalcPriority ensures the priority calculations work as intended.
44 func TestCalcPriority( t *testing.T) {
45 // commonSourceTx1 is a valid transaction used in the tests below as an input to transactions that are having their priority calculated.
46 // From block 7 in main blockchain.
47 // tx 0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9
48 commonSourceTx1 := &wire.MsgTx{
49 Version: 1,
50 TxIn: []*wire.TxIn{{
51 PreviousOutPoint: wire.OutPoint{
52 Hash: chainhash.Hash{},
53 Index: wire.MaxPrevOutIndex,
54 },
55 SignatureScript: hexToBytes("04ffff001d0134"),
56 Sequence: 0xffffffff,
57 }},
58 TxOut: []*wire.TxOut{{
59 Value: 5000000000,
60 PkScript: hexToBytes("410411db93e1dcdb8a016b49840f8c5" +
61 "3bc1eb68a382e97b1482ecad7b148a6909a5cb2e0ead" +
62 "dfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8" +
63 "643f656b412a3ac"),
64 }},
65 LockTime: 0,
66 }
67 // commonRedeemTx1 is a valid transaction used in the tests below as the transaction to calculate the priority for.
68 // It originally came from block 170 in main blockchain.
69 commonRedeemTx1 := &wire.MsgTx{
70 Version: 1,
71 TxIn: []*wire.TxIn{{
72 PreviousOutPoint: wire.OutPoint{
73 Hash: *newHashFromStr("0437cd7f8525ceed232435" +
74 "9c2d0ba26006d92d856a9c20fa0241106ee5" +
75 "a597c9"),
76 Index: 0,
77 },
78 SignatureScript: hexToBytes("47304402204e45e16932b8af" +
79 "514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5f" +
80 "b8cd410220181522ec8eca07de4860a4acdd12909d83" +
81 "1cc56cbbac4622082221a8768d1d0901"),
82 Sequence: 0xffffffff,
83 }},
84 TxOut: []*wire.TxOut{{
85 Value: 1000000000,
86 PkScript: hexToBytes("4104ae1a62fe09c5f51b13905f07f06" +
87 "b99a2f7159b2225f374cd378d71302fa28414e7aab37" +
88 "397f554a7df5f142c21c1b7303b8a0626f1baded5c72" +
89 "a704f7e6cd84cac"),
90 }, {
91 Value: 4000000000,
92 PkScript: hexToBytes("410411db93e1dcdb8a016b49840f8c5" +
93 "3bc1eb68a382e97b1482ecad7b148a6909a5cb2e0ead" +
94 "dfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8" +
95 "643f656b412a3ac"),
96 }},
97 LockTime: 0,
98 }
99 tests := []struct {
100 name string // test description
101 tx *wire.MsgTx // tx to calc priority for
102 utxoView *blockchain.UtxoViewpoint // inputs to tx
103 nextHeight int32 // height for priority calc
104 want float64 // expected priority
105 }{
106 {
107 name: "one height 7 input, prio tx height 169",
108 tx: commonRedeemTx1,
109 utxoView: newUtxoViewpoint([]*wire.MsgTx{commonSourceTx1},
110 []int32{7}),
111 nextHeight: 169,
112 want: 5e9,
113 },
114 {
115 name: "one height 100 input, prio tx height 169",
116 tx: commonRedeemTx1,
117 utxoView: newUtxoViewpoint([]*wire.MsgTx{commonSourceTx1},
118 []int32{100}),
119 nextHeight: 169,
120 want: 2129629629.6296296,
121 },
122 {
123 name: "one height 7 input, prio tx height 100000",
124 tx: commonRedeemTx1,
125 utxoView: newUtxoViewpoint([]*wire.MsgTx{commonSourceTx1},
126 []int32{7}),
127 nextHeight: 100000,
128 want: 3086203703703.7036,
129 },
130 {
131 name: "one height 100 input, prio tx height 100000",
132 tx: commonRedeemTx1,
133 utxoView: newUtxoViewpoint([]*wire.MsgTx{commonSourceTx1},
134 []int32{100}),
135 nextHeight: 100000,
136 want: 3083333333333.3335,
137 },
138 }
139 for i, test := range tests {
140 got := CalcPriority(test.tx, test.utxoView, test.nextHeight)
141 if got != test.want {
142 t.Errorf("CalcPriority #%d (%q): unexpected priority "+
143 "got %v want %v", i, test.name, got, test.want)
144 continue
145 }
146 }
147 }
148