decred.org/dcrwallet/v3@v3.1.0/wallet/txsizes/size.go (about)

     1  // Copyright (c) 2016 The btcsuite developers
     2  // Copyright (c) 2016-2019 The Decred developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  package txsizes
     7  
     8  import "github.com/decred/dcrd/wire"
     9  
    10  // Worst case script and input/output size estimates.
    11  const (
    12  	// RedeemP2PKSigScriptSize is the worst case (largest) serialize size
    13  	// of a transaction input script that redeems a compressed P2PK output.
    14  	// It is calculated as:
    15  	//
    16  	//   - OP_DATA_73
    17  	//   - 72 bytes DER signature + 1 byte sighash
    18  	RedeemP2PKSigScriptSize = 1 + 73
    19  
    20  	// RedeemP2PKHSigScriptSize is the worst case (largest) serialize size
    21  	// of a transaction input script that redeems a compressed P2PKH output.
    22  	// It is calculated as:
    23  	//
    24  	//   - OP_DATA_73
    25  	//   - 72 bytes DER signature + 1 byte sighash
    26  	//   - OP_DATA_33
    27  	//   - 33 bytes serialized compressed pubkey
    28  	RedeemP2PKHSigScriptSize = 1 + 73 + 1 + 33
    29  
    30  	// RedeemP2SHSigScriptSize is the worst case (largest) serialize size
    31  	// of a transaction input script that redeems a P2SH output.
    32  	// It is calculated as:
    33  	//
    34  	//  - OP_DATA_73
    35  	//  - 73-byte signature
    36  	//  - OP_DATA_35
    37  	//  - OP_DATA_33
    38  	//  - 33 bytes serialized compressed pubkey
    39  	//  - OP_CHECKSIG
    40  	RedeemP2SHSigScriptSize = 1 + 73 + 1 + 1 + 33 + 1
    41  
    42  	// RedeemP2PKHInputSize is the worst case (largest) serialize size of a
    43  	// transaction input redeeming a compressed P2PKH output.  It is
    44  	// calculated as:
    45  	//
    46  	//   - 32 bytes previous tx
    47  	//   - 4 bytes output index
    48  	//   - 1 byte tree
    49  	//   - 8 bytes amount
    50  	//   - 4 bytes block height
    51  	//   - 4 bytes block index
    52  	//   - 1 byte compact int encoding value 107
    53  	//   - 107 bytes signature script
    54  	//   - 4 bytes sequence
    55  	RedeemP2PKHInputSize = 32 + 4 + 1 + 8 + 4 + 4 + 1 + RedeemP2PKHSigScriptSize + 4
    56  
    57  	// P2PKHPkScriptSize is the size of a transaction output script that
    58  	// pays to a compressed pubkey hash.  It is calculated as:
    59  	//
    60  	//   - OP_DUP
    61  	//   - OP_HASH160
    62  	//   - OP_DATA_20
    63  	//   - 20 bytes pubkey hash
    64  	//   - OP_EQUALVERIFY
    65  	//   - OP_CHECKSIG
    66  	P2PKHPkScriptSize = 1 + 1 + 1 + 20 + 1 + 1
    67  
    68  	// P2PKHPkTreasruryScriptSize is the size of a transaction output
    69  	// script that pays stake change to a compressed pubkey hash.  This is
    70  	// used when a user sends coins to the treasury via OP_TADD.  It is
    71  	// calculated as:
    72  	//
    73  	//   - OP_SSTXCHANGE
    74  	//   - OP_DUP
    75  	//   - OP_HASH160
    76  	//   - OP_DATA_20
    77  	//   - 20 bytes pubkey hash
    78  	//   - OP_EQUALVERIFY
    79  	//   - OP_CHECKSIG
    80  	P2PKHPkTreasruryScriptSize = 1 + 1 + 1 + 1 + 20 + 1 + 1
    81  
    82  	// P2SHPkScriptSize is the size of a transaction output script that
    83  	// pays to a script hash.  It is calculated as:
    84  	//
    85  	//   - OP_HASH160
    86  	//   - OP_DATA_20
    87  	//   - 20 bytes script hash
    88  	//   - OP_EQUAL
    89  	P2SHPkScriptSize = 1 + 1 + 20 + 1
    90  
    91  	// TicketCommitmentScriptSize is the size of a ticket purchase commitment
    92  	// script. It is calculated as:
    93  	//
    94  	//   - OP_RETURN
    95  	//   - OP_DATA_30
    96  	//   - 20 bytes P2SH/P2PKH
    97  	//   - 8 byte amount
    98  	//   - 2 byte fee range limits
    99  	TicketCommitmentScriptSize = 1 + 1 + 20 + 8 + 2
   100  
   101  	// P2PKHOutputSize is the serialize size of a transaction output with a
   102  	// P2PKH output script.  It is calculated as:
   103  	//
   104  	//   - 8 bytes output value
   105  	//   - 2 bytes version
   106  	//   - 1 byte compact int encoding value 25
   107  	//   - 25 bytes P2PKH output script
   108  	P2PKHOutputSize = 8 + 2 + 1 + 25
   109  
   110  	// TSPENDInputSize
   111  	//
   112  	//   - OP_DATA_73
   113  	//   - 73 bytes signature
   114  	//   - OP_DATA_33
   115  	//   - 33 bytes serialized compressed pubkey
   116  	//   - 1 byte OP_TSPEND
   117  	TSPENDInputSize = 1 + 73 + 1 + 33 + 1
   118  )
   119  
   120  func sumOutputSerializeSizes(outputs []*wire.TxOut) (serializeSize int) {
   121  	for _, txOut := range outputs {
   122  		serializeSize += txOut.SerializeSize()
   123  	}
   124  	return serializeSize
   125  }
   126  
   127  // EstimateSerializeSize returns a worst case serialize size estimate for a
   128  // signed transaction that spends a number of outputs and contains each
   129  // transaction output from txOuts. The estimated size is incremented for an
   130  // additional change output if changeScriptSize is greater than 0. Passing 0
   131  // does not add a change output.
   132  func EstimateSerializeSize(scriptSizes []int, txOuts []*wire.TxOut, changeScriptSize int) int {
   133  	// Generate and sum up the estimated sizes of the inputs.
   134  	txInsSize := 0
   135  	for _, size := range scriptSizes {
   136  		txInsSize += EstimateInputSize(size)
   137  	}
   138  
   139  	inputCount := len(scriptSizes)
   140  	outputCount := len(txOuts)
   141  	changeSize := 0
   142  	if changeScriptSize > 0 {
   143  		changeSize = EstimateOutputSize(changeScriptSize)
   144  		outputCount++
   145  	}
   146  
   147  	// 12 additional bytes are for version, locktime and expiry.
   148  	return 12 + (2 * wire.VarIntSerializeSize(uint64(inputCount))) +
   149  		wire.VarIntSerializeSize(uint64(outputCount)) +
   150  		txInsSize +
   151  		sumOutputSerializeSizes(txOuts) +
   152  		changeSize
   153  }
   154  
   155  // EstimateSerializeSizeFromScriptSizes returns a worst case serialize size
   156  // estimate for a signed transaction that spends len(inputSizes) previous
   157  // outputs and pays to len(outputSizes) outputs with scripts of the provided
   158  // worst-case sizes. The estimated size is incremented for an additional
   159  // change output if changeScriptSize is greater than 0. Passing 0 does not
   160  // add a change output.
   161  func EstimateSerializeSizeFromScriptSizes(inputSizes []int, outputSizes []int, changeScriptSize int) int {
   162  	// Generate and sum up the estimated sizes of the inputs.
   163  	txInsSize := 0
   164  	for _, inputSize := range inputSizes {
   165  		txInsSize += EstimateInputSize(inputSize)
   166  	}
   167  
   168  	// Generate and sum up the estimated sizes of the outputs.
   169  	txOutsSize := 0
   170  	for _, outputSize := range outputSizes {
   171  		txOutsSize += EstimateOutputSize(outputSize)
   172  	}
   173  
   174  	inputCount := len(inputSizes)
   175  	outputCount := len(outputSizes)
   176  	changeSize := 0
   177  	if changeScriptSize > 0 {
   178  		changeSize = EstimateOutputSize(changeScriptSize)
   179  		outputCount++
   180  	}
   181  
   182  	// 12 additional bytes are for version, locktime and expiry.
   183  	return 12 + (2 * wire.VarIntSerializeSize(uint64(inputCount))) +
   184  		wire.VarIntSerializeSize(uint64(outputCount)) +
   185  		txInsSize + txOutsSize + changeSize
   186  }
   187  
   188  // EstimateInputSize returns the worst case serialize size estimate for a tx input
   189  //   - 32 bytes previous tx
   190  //   - 4 bytes output index
   191  //   - 1 byte tree
   192  //   - 8 bytes amount
   193  //   - 4 bytes block height
   194  //   - 4 bytes block index
   195  //   - the compact int representation of the script size
   196  //   - the supplied script size
   197  //   - 4 bytes sequence
   198  func EstimateInputSize(scriptSize int) int {
   199  	return 32 + 4 + 1 + 8 + 4 + 4 + wire.VarIntSerializeSize(uint64(scriptSize)) + scriptSize + 4
   200  }
   201  
   202  // EstimateOutputSize returns the worst case serialize size estimate for a tx output
   203  //   - 8 bytes amount
   204  //   - 2 bytes version
   205  //   - the compact int representation of the script size
   206  //   - the supplied script size
   207  func EstimateOutputSize(scriptSize int) int {
   208  	return 8 + 2 + wire.VarIntSerializeSize(uint64(scriptSize)) + scriptSize
   209  }