diff --git a/lib/bcoin/tx.js b/lib/bcoin/tx.js index 10b38d17..4ece67b6 100644 --- a/lib/bcoin/tx.js +++ b/lib/bcoin/tx.js @@ -626,71 +626,88 @@ TX.prototype.isCoinbase = function isCoinbase() { }; TX.prototype.maxSize = function maxSize() { - // Create copy with 0-script inputs var copy = this.clone(); - var size; + var i, input, total, size, s, m, n; - copy.inputs.forEach(function(input) { - input.script = []; - }); + // Create copy with 0-script inputs + for (i = 0; i < copy.inputs.length; i++) + copy.inputs[i].script = []; - size = copy.render().length; + total = copy.render().length; // Add size for signatures and public keys - copy.inputs.forEach(function(input, i) { - var s, m, n; + for (i = 0; i < copy.inputs.length; i++) { + input = copy.inputs[i]; + size = 0; // Get the previous output's subscript s = input.out.tx.getSubscript(input.out.index); if (bcoin.script.isPubkey(s)) { - // Signature + len - size += 74; - return; - } - - if (bcoin.script.isPubkeyhash(s)) { - // Signature + len - size += 74; - // Pub key + len - size += 34; - return; - } - - if (bcoin.script.isMultisig(s)) { - // Multisig - // Empty byte - size += 1; - // Signature + len + // P2PK + // OP_PUSHDATA0 [signature] + size += 1 + 73; + } else if (bcoin.script.isPubkeyhash(s)) { + // P2PKH + // OP_PUSHDATA0 [signature] + size += 1 + 73; + // OP_PUSHDATA0 [key] + size += 1 + 65; + } else if (bcoin.script.isMultisig(s)) { + // Bare Multisig + // Get the previous m value: m = s[0]; - // If using pushdata instead of OP_1-16: if (Array.isArray(m)) m = m[0] || 0; assert(m >= 1 && m <= 3); - size += 74 * m; - return; + // OP_0 + size += 1; + // OP_PUSHDATA0 [signature] ... + size += (1 + 73) * m; + } else if (bcoin.script.isScripthash(s)) { + // P2SH Multisig + // This technically won't work well for other + // kinds of P2SH. It will also over-estimate + // the fee by a lot (at least 10000 satoshis + // since we don't have access to the m and n + // values), which will be recalculated later. + // If fee turns out to be smaller later, we + // simply add more of the fee to the change + // output. + // m value + m = 15; + // n value + n = 15; + // OP_0 + size += 1; + // OP_PUSHDATA0 [signature] ... + size += (1 + 73) * m; + // OP_PUSHDATA2 [redeem] + size += 3; + // m value + size += 1; + // OP_PUSHDATA0 [key] ... + size += (1 + 65) * n; + // n value + size += 1; + // OP_CHECKMULTISIG + size += 1; } - if (bcoin.script.isScripthash(s)) { - // Multisig - // Empty byte - size += 1; - // Signature + len - size += 74 * 15; - // Redeem script - // m byte - size += 1; - // 1 byte length + 65 byte pubkey - size += 66 * 15; - // n byte - size += 1; - // checkmultisig byte - size += 1; - return; - } - }, this); + // Byte for varint size of input script + if (size < 0xfd) + size += 0; + else if (size <= 0xffff) + size += 2; + else if (size <= 0xffffffff) + size += 4; + else + size += 8; - return size; + total += size; + } + + return total; }; TX.prototype.getUnspent = function getUnspent(unspent) {