@trezor/utxo-lib
Version:
Client-side Bitcoin-like JavaScript library
126 lines (125 loc) • 4.17 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TxWeightCalculator = void 0;
const coinselectUtils_1 = require("./coinselect/coinselectUtils");
const _TXSIZE_HEADER = 4;
const _TXSIZE_FOOTER = 4;
const _TXSIZE_SEGWIT_OVERHEAD = 2;
const _TXSIZE_INPUT = 40;
const _TXSIZE_OUTPUT = 8;
const _TXSIZE_PUBKEY = 33;
const _TXSIZE_DER_SIGNATURE = 72;
const _TXSIZE_SCHNORR_SIGNATURE = 64;
const _TXSIZE_MULTISIGSCRIPT = 3;
const _TXSIZE_WITNESSPKHASH = 22;
const _TXSIZE_WITNESSSCRIPT = 34;
const SCRIPT_TYPES = {
p2pkh: 'SPENDADDRESS',
p2sh: 'SPENDP2SHWITNESS',
p2tr: 'SPENDTAPROOT',
p2wpkh: 'SPENDWITNESS'
};
const SEGWIT_INPUT_SCRIPT_TYPES = ['SPENDP2SHWITNESS', 'SPENDWITNESS', 'SPENDTAPROOT'];
const NONSEGWIT_INPUT_SCRIPT_TYPES = ['SPENDADDRESS', 'SPENDMULTISIG'];
function getVarIntSize(length) {
if (length < 253) return 1;
if (length < 65536) return 3;
return 5;
}
function getOpPushSize(length) {
if (length < 76) return 1;
if (length < 256) return 2;
if (length < 65536) return 3;
return 5;
}
class TxWeightCalculator {
inputs_count = 0;
outputs_count = 0;
counter = 4 * (_TXSIZE_HEADER + _TXSIZE_FOOTER);
segwit_inputs_count = 0;
inputs = [];
addInputByKey(type) {
this.addInput({
script_type: SCRIPT_TYPES[type]
});
}
addInput(input) {
this.inputs_count += 1;
let input_script_size = 0;
if (input.multisig) {
if (input.script_type === 'SPENDTAPROOT') {
throw new Error('Multisig not supported for Taproot yet');
}
const n = input.multisig.nodes ? input.multisig.nodes.length : input.multisig.pubkeys.length;
let multisig_script_size = _TXSIZE_MULTISIGSCRIPT + n * (1 + _TXSIZE_PUBKEY);
if (SEGWIT_INPUT_SCRIPT_TYPES.includes(input.script_type)) {
multisig_script_size += getVarIntSize(multisig_script_size);
} else {
multisig_script_size += getOpPushSize(multisig_script_size);
input_script_size = 1 + input.multisig.m * (1 + _TXSIZE_DER_SIGNATURE) + multisig_script_size;
}
} else if (input.script_type === 'SPENDTAPROOT') {
input_script_size = 1 + _TXSIZE_SCHNORR_SIGNATURE;
} else {
input_script_size = 1 + _TXSIZE_DER_SIGNATURE + 1 + _TXSIZE_PUBKEY;
}
this.counter += 4 * _TXSIZE_INPUT;
if (NONSEGWIT_INPUT_SCRIPT_TYPES.includes(input.script_type)) {
input_script_size += getVarIntSize(input_script_size);
this.counter += 4 * input_script_size;
} else if (SEGWIT_INPUT_SCRIPT_TYPES.includes(input.script_type)) {
this.segwit_inputs_count += 1;
if (input.script_type === 'SPENDP2SHWITNESS') {
if (input.multisig) {
this.counter += 4 * (2 + _TXSIZE_WITNESSSCRIPT);
} else {
this.counter += 4 * (2 + _TXSIZE_WITNESSPKHASH);
}
} else {
this.counter += 4;
}
this.counter += 1 + input_script_size;
} else if (input.script_type === 'EXTERNAL') {
const witness_size = 0;
const script_sig_size = 0;
if (input.ownership_proof) {} else {}
if (witness_size > 1) {
this.segwit_inputs_count += 1;
}
this.counter += 4 * (getVarIntSize(script_sig_size) + script_sig_size);
this.counter += witness_size;
} else {
throw new Error('unknown input script_type');
}
this.inputs.push({
length: input_script_size
});
}
addOutputByKey(key) {
this.addOutput({
length: coinselectUtils_1.OUTPUT_SCRIPT_LENGTH[key]
});
}
addOutput(script) {
this.outputs_count += 1;
const script_size = getVarIntSize(script.length) + script.length;
this.counter += 4 * (_TXSIZE_OUTPUT + script_size);
}
getTotal() {
let total = this.counter;
total += 4 * getVarIntSize(this.inputs_count);
total += 4 * getVarIntSize(this.outputs_count);
if (this.segwit_inputs_count) {
total += _TXSIZE_SEGWIT_OVERHEAD;
total += this.inputs_count - this.segwit_inputs_count;
}
return total;
}
getVirtualBytes() {
return Math.ceil(this.getTotal() / 4);
}
}
exports.TxWeightCalculator = TxWeightCalculator;
//# sourceMappingURL=txWeightCalculator.js.map