Source: p2wsh.js

  1. import {encoding} from 'bufio';
  2. /**
  3. * This module provides functions and constants for the P2WSH address type.
  4. *
  5. * @module p2wsh
  6. */
  7. /**
  8. * Address type constant for "pay-to-witness-script-hash" or (P2WSH)
  9. * addresses.
  10. *
  11. * @constant
  12. * @type {string}
  13. * @default P2WSH
  14. */
  15. export const P2WSH = "P2WSH";
  16. /**
  17. * @description provides the size of single tx input for a segwit tx (i.e. empty script)
  18. * Each input field will look like:
  19. * prevhash (32 bytes) + prevIndex (4) + scriptsig (1) + sequence bytes (4)
  20. * @returns {Number} 41 (always 41 for segwit inputs since script sig is in witness)
  21. */
  22. function txinSize() {
  23. const PREVHASH_BYTES = 32;
  24. const PREV_INDEX_BYTES = 4;
  25. const SCRIPT_LENGTH_BYTES = 1
  26. const SEQUENCE_BYTES = 4
  27. return (PREVHASH_BYTES +
  28. PREV_INDEX_BYTES +
  29. SEQUENCE_BYTES +
  30. SCRIPT_LENGTH_BYTES
  31. )
  32. }
  33. /**
  34. * @description Returns the approximate size of outputs in tx.
  35. * Calculated by adding value field (8 bytes), field providing length
  36. * scriptPubkey and the script pubkey itself
  37. * @param {Number} [scriptPubkeySize = 34] size of script pubkey.
  38. * Defaults to 34 which is the size of a P2WSH script pubkey and the
  39. * largest possible standard
  40. * @returns {Number} size of tx output (default: 43)
  41. */
  42. function txoutSize(scriptPubkeySize = 34) {
  43. // per_output: value (8) + script length (1) +
  44. const VAL_BYTES = 8;
  45. const scriptLengthBytes = encoding.sizeVarint(scriptPubkeySize);
  46. // for P2WSH Locking script which is largest possible(34)
  47. return VAL_BYTES + scriptLengthBytes + scriptPubkeySize;
  48. }
  49. /**
  50. * @description calculates size of redeem script given n pubkeys.
  51. * Calculation looks like:
  52. * OP_M (1 byte) + size of each pubkey in redeem script (OP_DATA= 1 byte * N) +
  53. * pubkey size (33 bytes * N) + OP_N (1 byte) + OP_CHECKMULTISIG (1 byte)
  54. * => 1 + (1 * N) + (33 * N) + 1 + 1
  55. * @param {Number} n - value of n in m-of-n for multisig script
  56. * @returns {Number} 3 + 34 * N
  57. */
  58. export function getRedeemScriptSize(n) {
  59. const OP_M_BYTES = 1;
  60. const OP_N_BYTES = 1;
  61. const opDataBytes = n; // 1 byte per pubkey in redeem script
  62. const pubkeyBytes = 33 * n;
  63. const OP_CHECKMULTISIG_BYTES = 1;
  64. return OP_M_BYTES + opDataBytes + pubkeyBytes + OP_N_BYTES + OP_CHECKMULTISIG_BYTES;
  65. }
  66. /**
  67. * @description Calculates the value of a multisig witness given m-of-n values
  68. * Calculation is of the following form:
  69. * witness_items count (varint 1+) + null_data (1 byte) + size of each signature (1 byte * OP_M) + signatures (73 * M) +
  70. * redeem script length (1 byte) + redeem script size (4 + 34 * N bytes)
  71. * @param {Number} m - value of m in m-of-n for multisig script
  72. * @param {Number} n - value of n in m-of-n for multisig script
  73. * @returns {Number} 6 + (74 * M) + (34 * N)
  74. */
  75. export function getWitnessSize(m, n) {
  76. const OP_NULL_BYTES = 1; // needs to be added b/c of bug in multisig implementation
  77. const opDataBytes = m;
  78. // assumes largest possible signature size which could be 71, 72, or 73
  79. const signaturesSize = 73 * m;
  80. const REDEEM_SCRIPT_LENGTH = 1;
  81. const redeemScriptSize = getRedeemScriptSize(n);
  82. // total witness stack will be null bytes + each signature (m) + redeem script
  83. const WITNESS_ITEMS_COUNT = encoding.sizeVarint(1 + m + 1);
  84. return WITNESS_ITEMS_COUNT +
  85. OP_NULL_BYTES +
  86. opDataBytes +
  87. signaturesSize +
  88. REDEEM_SCRIPT_LENGTH +
  89. redeemScriptSize;
  90. }
  91. /**
  92. * @description Calculates the size of the fields in a transaction which DO NOT
  93. * get counted towards witness discount.
  94. * Calculated as: version bytes (4) + locktime bytes (4) + input_len (1+) + txins (41+) + output_len (1+) + outputs (9+)
  95. * @param {*} inputsCount - number of inputs in the tx
  96. * @param {*} outputsCount - number of outputs in the tx
  97. * @returns {Number} number of bytes in the tx without witness fields
  98. */
  99. export function calculateBase(inputsCount, outputsCount) {
  100. let total = 0;
  101. total += 4; // version
  102. total += 4 // locktime
  103. total += encoding.sizeVarint(inputsCount); // inputs length
  104. total += inputsCount * txinSize();
  105. total += encoding.sizeVarint(outputsCount);
  106. total += outputsCount * txoutSize();
  107. return total
  108. }
  109. export function calculateTotalWitnessSize({ numInputs, m, n }) {
  110. let total = 0;
  111. total += 1; // segwit marker
  112. total += 1; // segwit flag
  113. total += encoding.sizeVarint(numInputs) // bytes for number of witnesses
  114. total += numInputs * getWitnessSize(m, n) // add witness for each input
  115. return total;
  116. }
  117. /**
  118. * @description Calculate virtual bytes or "vsize".
  119. * vsize is equal three times "base size" of a tx w/o witness data, plus the
  120. * total size of all data, with the final result divided by scaling factor
  121. * of 4 and round up to the next integer. For example, if a transaction is
  122. * 200 bytes with new serialization, and becomes 99 bytes with marker, flag,
  123. * and witness removed, the vsize is (99 * 3 + 200) / 4 = 125 with round up.
  124. * @param {Number} baseSize - base size of transaction
  125. * @param {Number} witnessSize - size of witness fields
  126. * @returns {Number} virtual size of tx
  127. */
  128. function calculateVSize(baseSize, witnessSize) {
  129. const WITNESS_SCALE_FACTOR = 4;
  130. const totalSize = baseSize + witnessSize;
  131. const txWeight = baseSize * 3 + totalSize;
  132. return Math.ceil(txWeight / WITNESS_SCALE_FACTOR);
  133. }
  134. /**
  135. * Estimate the transaction virtual size (vsize) when spending inputs
  136. * from the same multisig P2WSH address.
  137. * @param {Object} config - configuration for the calculation
  138. * @param {number} config.numInputs - number of m-of-n multisig P2SH inputs
  139. * @param {number} config.numOutputs - number of outputs
  140. * @param {number} config.m - required signers
  141. * @param {number} config.n - total signers
  142. * @returns {number} estimated transaction virtual size in bytes
  143. */
  144. export function estimateMultisigP2WSHTransactionVSize(config) {
  145. // non-segwit discount fields
  146. const baseSize = calculateBase(config.numInputs, config.numOutputs);
  147. // these are the values that benefit from the segwit discount
  148. const witnessSize = calculateTotalWitnessSize(config);
  149. return calculateVSize(baseSize, witnessSize);
  150. }