size_test.go raw

   1  package txsizes_test
   2  
   3  import (
   4  	"bytes"
   5  	"encoding/hex"
   6  	"testing"
   7  	
   8  	. "github.com/p9c/p9/pkg/txsizes"
   9  	"github.com/p9c/p9/pkg/wire"
  10  )
  11  
  12  const (
  13  	p2pkhScriptSize = P2PKHPkScriptSize
  14  	p2shScriptSize  = 23
  15  )
  16  
  17  func makeInts(value int, n int) []int {
  18  	v := make([]int, n)
  19  	for i := range v {
  20  		v[i] = value
  21  	}
  22  	return v
  23  }
  24  func TestEstimateSerializeSize(t *testing.T) {
  25  	tests := []struct {
  26  		InputCount           int
  27  		OutputScriptLengths  []int
  28  		AddChangeOutput      bool
  29  		ExpectedSizeEstimate int
  30  	}{
  31  		0:  {1, []int{}, false, 159},
  32  		1:  {1, []int{p2pkhScriptSize}, false, 193},
  33  		2:  {1, []int{}, true, 193},
  34  		3:  {1, []int{p2pkhScriptSize}, true, 227},
  35  		4:  {1, []int{p2shScriptSize}, false, 191},
  36  		5:  {1, []int{p2shScriptSize}, true, 225},
  37  		6:  {2, []int{}, false, 308},
  38  		7:  {2, []int{p2pkhScriptSize}, false, 342},
  39  		8:  {2, []int{}, true, 342},
  40  		9:  {2, []int{p2pkhScriptSize}, true, 376},
  41  		10: {2, []int{p2shScriptSize}, false, 340},
  42  		11: {2, []int{p2shScriptSize}, true, 374},
  43  		// 0xfd is discriminant for 16-bit compact ints, compact int
  44  		// total size increases from 1 byte to 3.
  45  		12: {1, makeInts(p2pkhScriptSize, 0xfc), false, 8727},
  46  		13: {1, makeInts(p2pkhScriptSize, 0xfd), false, 8727 + P2PKHOutputSize + 2},
  47  		14: {1, makeInts(p2pkhScriptSize, 0xfc), true, 8727 + P2PKHOutputSize + 2},
  48  		15: {0xfc, []int{}, false, 37558},
  49  		16: {0xfd, []int{}, false, 37558 + RedeemP2PKHInputSize + 2},
  50  	}
  51  	for i, test := range tests {
  52  		outputs := make([]*wire.TxOut, 0, len(test.OutputScriptLengths))
  53  		for _, l := range test.OutputScriptLengths {
  54  			outputs = append(outputs, &wire.TxOut{PkScript: make([]byte, l)})
  55  		}
  56  		actualEstimate := EstimateSerializeSize(test.InputCount, outputs, test.AddChangeOutput)
  57  		if actualEstimate != test.ExpectedSizeEstimate {
  58  			t.Errorf("Test %d: Got %v: Expected %v", i, actualEstimate, test.ExpectedSizeEstimate)
  59  		}
  60  	}
  61  }
  62  func TestEstimateVirtualSize(t *testing.T) {
  63  	type estimateVSizeTest struct {
  64  		tx              func() (*wire.MsgTx, error)
  65  		p2wpkhIns       int
  66  		nestedp2wpkhIns int
  67  		p2pkhIns        int
  68  		change          bool
  69  		result          int
  70  	}
  71  	// TODO(halseth): add tests for more combination out inputs/outputs.
  72  	tests := []estimateVSizeTest{
  73  		// Spending P2WPKH to two outputs. Example adapted from example in BIP-143.
  74  		{
  75  			tx: func() (*wire.MsgTx, error) {
  76  				txHex := "01000000000101ef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac0247304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee0121025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee635711000000"
  77  				b, e := hex.DecodeString(txHex)
  78  				if e != nil {
  79  					return nil, e
  80  				}
  81  				tx := &wire.MsgTx{}
  82  				e = tx.Deserialize(bytes.NewReader(b))
  83  				if e != nil {
  84  					return nil, e
  85  				}
  86  				return tx, nil
  87  			},
  88  			p2wpkhIns: 1,
  89  			result:    147,
  90  		},
  91  		{
  92  			// Spending P2SH-P2WPKH to two outputs. Example adapted from example in BIP-143.
  93  			tx: func() (*wire.MsgTx, error) {
  94  				txHex := "01000000000101db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a5477010000001716001479091972186c449eb1ded22b78e40d009bdf0089feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac02473044022047ac8e878352d3ebbde1c94ce3a10d057c24175747116f8288e5d794d12d482f0220217f36a485cae903c713331d877c1f64677e3622ad4010726870540656fe9dcb012103ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a2687392040000"
  95  				b, e := hex.DecodeString(txHex)
  96  				if e != nil {
  97  					return nil, e
  98  				}
  99  				tx := &wire.MsgTx{}
 100  				e = tx.Deserialize(bytes.NewReader(b))
 101  				if e != nil {
 102  					return nil, e
 103  				}
 104  				return tx, nil
 105  			},
 106  			nestedp2wpkhIns: 1,
 107  			result:          170,
 108  		},
 109  		{
 110  			// Spendin P2WPKH to on output, adding one change output. We reuse
 111  			// the transaction spending to two outputs, removing one of them.
 112  			tx: func() (*wire.MsgTx, error) {
 113  				txHex := "01000000000101ef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac0247304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee0121025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee635711000000"
 114  				b, e := hex.DecodeString(txHex)
 115  				if e != nil {
 116  					return nil, e
 117  				}
 118  				tx := &wire.MsgTx{}
 119  				e = tx.Deserialize(bytes.NewReader(b))
 120  				if e != nil {
 121  					return nil, e
 122  				}
 123  				// Only keep the first output.
 124  				tx.TxOut = []*wire.TxOut{tx.TxOut[0]}
 125  				return tx, nil
 126  			},
 127  			p2wpkhIns: 1,
 128  			change:    true,
 129  			result:    144,
 130  		},
 131  		{
 132  			// Spending one P2PKH to two P2PKH outputs (no witness data).
 133  			tx: func() (*wire.MsgTx, error) {
 134  				txHex := "0100000001a4c91c9720157a5ee582a7966471d9c70d0a860fa7757b4c42a535a12054a4c9000000006c493046022100d49c452a00e5b1213ac84d92269510a05a584a4d0949bd7d0ad4e3408ac8e80a022100bf98707ffaf1eb9dff146f7da54e68651c0a27e3653ec3882b7a95202328579c01210332d98672a4246fe917b9c724c339e757d46b1ffde3fb27fdc680b4bb29b6ad59ffffffff02a0860100000000001976a9144fb55ee0524076acd4c14e7773561e4c298c8e2788ac20688a0b000000001976a914cb7f6bb8e95a2cd06423932cfbbce73d16a18df088ac00000000"
 135  				b, e := hex.DecodeString(txHex)
 136  				if e != nil {
 137  					return nil, e
 138  				}
 139  				tx := &wire.MsgTx{}
 140  				e = tx.Deserialize(bytes.NewReader(b))
 141  				if e != nil {
 142  					return nil, e
 143  				}
 144  				return tx, nil
 145  			},
 146  			p2pkhIns: 1,
 147  			result:   227,
 148  		},
 149  	}
 150  	for _, test := range tests {
 151  		tx, e := test.tx()
 152  		if e != nil {
 153  			t.Fatalf("unable to get test tx: %v", e)
 154  		}
 155  		est := EstimateVirtualSize(test.p2pkhIns, test.p2wpkhIns,
 156  			test.nestedp2wpkhIns, tx.TxOut, test.change,
 157  		)
 158  		if est != test.result {
 159  			t.Fatalf("expected estimated vsize to be %d, "+
 160  				"instead got %d", test.result, est,
 161  			)
 162  		}
 163  	}
 164  }
 165