_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