size.go raw
1 // Package txsizes Copyright (c) 2016 The btcsuite developers
2 package txsizes
3
4 import (
5 "github.com/p9c/p9/pkg/blockchain"
6 h "github.com/p9c/p9/pkg/util/helpers"
7 "github.com/p9c/p9/pkg/wire"
8 )
9
10 // Worst case script and input/output size estimates.
11 const (
12 // RedeemP2PKHSigScriptSize is the worst case (largest) serialize size of a transaction input script that redeems a
13 // compressed P2PKH output. It is calculated as:
14 //
15 // - OP_DATA_73
16 // - 72 bytes DER signature + 1 byte sighash
17 // - OP_DATA_33
18 // - 33 bytes serialized compressed pubkey
19 RedeemP2PKHSigScriptSize = 1 + 73 + 1 + 33
20 // P2PKHPkScriptSize is the size of a transaction output script that pays to a compressed pubkey hash. It is
21 // calculated as:
22 //
23 // - OP_DUP
24 // - OP_HASH160
25 // - OP_DATA_20
26 // - 20 bytes pubkey hash
27 // - OP_EQUALVERIFY
28 // - OP_CHECKSIG
29 P2PKHPkScriptSize = 1 + 1 + 1 + 20 + 1 + 1
30 // RedeemP2PKHInputSize is the worst case (largest) serialize size of a transaction input redeeming a compressed
31 // P2PKH output. It is calculated as:
32 //
33 // - 32 bytes previous tx
34 // - 4 bytes output index
35 // - 1 byte compact int encoding value 107
36 // - 107 bytes signature script
37 // - 4 bytes sequence
38 RedeemP2PKHInputSize = 32 + 4 + 1 + RedeemP2PKHSigScriptSize + 4
39 // P2PKHOutputSize is the serialize size of a transaction output with a P2PKH output script. It is calculated as:
40 //
41 // - 8 bytes output value
42 // - 1 byte compact int encoding value 25
43 // - 25 bytes P2PKH output script
44 P2PKHOutputSize = 8 + 1 + P2PKHPkScriptSize
45 // // P2WPKHPkScriptSize is the size of a transaction output script that pays to a
46 // // witness pubkey hash. It is calculated as:
47 // //
48 // // - OP_0
49 // // - OP_DATA_20
50 // // - 20 bytes pubkey hash
51 // P2WPKHPkScriptSize = 1 + 1 + 20
52 // // P2WPKHOutputSize is the serialize size of a transaction output with a P2WPKH output script. It is calculated as:
53 // //
54 // // - 8 bytes output value
55 // // - 1 byte compact int encoding value 22
56 // // - 22 bytes P2PKH output script
57 // P2WPKHOutputSize = 8 + 1 + P2WPKHPkScriptSize
58 // // RedeemP2WPKHScriptSize is the size of a transaction input script that spends
59 // // a pay-to-witness-public-key hash (P2WPKH). The redeem script for P2WPKH
60 // // spends MUST be empty.
61 // RedeemP2WPKHScriptSize = 0
62 // // RedeemP2WPKHInputSize is the worst case size of a transaction input redeeming a P2WPKH output. It is calculated
63 // // as:
64 // //
65 // // - 32 bytes previous tx
66 // // - 4 bytes output index
67 // // - 1 byte encoding empty redeem script
68 // // - 0 bytes redeem script
69 // // - 4 bytes sequence
70 // RedeemP2WPKHInputSize = 32 + 4 + 1 + RedeemP2WPKHScriptSize + 4
71 // // RedeemNestedP2WPKHScriptSize is the worst case size of a transaction input
72 // // script that redeems a pay-to-witness-key hash nested in P2SH (P2SH-P2WPKH).
73 // // It is calculated as:
74 // //
75 // // - 1 byte compact int encoding value 22
76 // // - OP_0
77 // // - 1 byte compact int encoding value 20
78 // // - 20 byte key hash
79 // RedeemNestedP2WPKHScriptSize = 1 + 1 + 1 + 20
80 // // RedeemNestedP2WPKHInputSize is the worst case size of a transaction input redeeming a P2SH-P2WPKH output. It is
81 // // calculated as:
82 // //
83 // // - 32 bytes previous tx
84 // // - 4 bytes output index
85 // // - 1 byte compact int encoding value 23
86 // // - 23 bytes redeem script (scriptSig)
87 // // - 4 bytes sequence
88 // RedeemNestedP2WPKHInputSize = 32 + 4 + 1 + RedeemNestedP2WPKHScriptSize + 4
89 // // RedeemP2WPKHInputWitnessWeight is the worst case weight of a witness for
90 // // spending P2WPKH and nested P2WPKH outputs. It is calculated as:
91 // //
92 // // - 1 wu compact int encoding value 2 (number of items)
93 // // - 1 wu compact int encoding value 73
94 // // - 72 wu DER signature + 1 wu sighash
95 // // - 1 wu compact int encoding value 33
96 // // - 33 wu serialized compressed pubkey
97 // RedeemP2WPKHInputWitnessWeight = 1 + 1 + 73 + 1 + 33
98 )
99
100 // EstimateSerializeSize returns a worst case serialize size estimate for a signed transaction that spends inputCount
101 // number of compressed P2PKH outputs and contains each transaction output from txOuts. The estimated size is
102 // incremented for an additional P2PKH change output if addChangeOutput is true.
103 func EstimateSerializeSize(inputCount int, txOuts []*wire.TxOut, addChangeOutput bool) int {
104 changeSize := 0
105 outputCount := len(txOuts)
106 if addChangeOutput {
107 changeSize = P2PKHOutputSize
108 outputCount++
109 }
110 // 8 additional bytes are for version and locktime
111 return 8 + wire.VarIntSerializeSize(uint64(inputCount)) +
112 wire.VarIntSerializeSize(uint64(outputCount)) +
113 inputCount*RedeemP2PKHInputSize +
114 h.SumOutputSerializeSizes(txOuts) +
115 changeSize
116 }
117
118 // EstimateVirtualSize returns a worst case virtual size estimate for a signed transaction that spends the given number
119 // of P2PKH, P2WPKH and (nested) P2SH-P2WPKH outputs, and contains each transaction output from txOuts. The estimate is
120 // incremented for an additional P2PKH change output if addChangeOutput is true.
121 func EstimateVirtualSize(numP2PKHIns, numP2WPKHIns, numNestedP2WPKHIns int,
122 txOuts []*wire.TxOut, addChangeOutput bool,
123 ) int {
124 changeSize := 0
125 // outputCount := len(txOuts)
126 if addChangeOutput {
127 // We are always using P2WPKH as change output.
128 changeSize = P2PKHOutputSize
129 // outputCount++
130 }
131 // Version 4 bytes + LockTime 4 bytes + Serialized var int size for the number of transaction inputs and outputs +
132 // size of redeem scripts + the size out the serialized outputs and change.
133 baseSize := 8 +
134 wire.VarIntSerializeSize(
135 uint64(numP2PKHIns+numP2WPKHIns+numNestedP2WPKHIns),
136 ) +
137 wire.VarIntSerializeSize(uint64(len(txOuts))) +
138 numP2PKHIns*RedeemP2PKHInputSize +
139 // numP2WPKHIns*RedeemP2PKHInputSize +
140 // numNestedP2WPKHIns*RedeemNestedP2WPKHInputSize +
141 h.SumOutputSerializeSizes(txOuts) +
142 changeSize
143 // If this transaction has any witness inputs, we must count the witness data.
144 witnessWeight := 0
145 // if numP2WPKHIns+numNestedP2WPKHIns > 0 {
146 // // Additional 2 weight units for segwit marker + flag.
147 // witnessWeight = 2 +
148 // wire.VarIntSerializeSize(
149 // uint64(numP2WPKHIns+numNestedP2WPKHIns)) +
150 // numP2WPKHIns*RedeemP2WPKHInputWitnessWeight +
151 // numNestedP2WPKHIns*RedeemP2WPKHInputWitnessWeight
152 // }
153 // We add 3 to the witness weight to make sure the result is always rounded up.
154 return baseSize + (witnessWeight+3)/blockchain.WitnessScaleFactor
155 }
156