From 1aab317dad208959446b2b9e1ef9a949e309c6cf Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 28 Sep 2016 16:46:35 +1000 Subject: [PATCH] TransactionBuilder: extract internal signature invalidation functions for individual testing --- src/transaction_builder.js | 59 ++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/src/transaction_builder.js b/src/transaction_builder.js index 75f53c5..efdaae0 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -322,14 +322,7 @@ TransactionBuilder.fromTransaction = function (transaction, network) { } TransactionBuilder.prototype.addInput = function (txHash, vout, sequence, prevOutScript) { - // if signatures exist, adding inputs is only acceptable if SIGHASH_ANYONECANPAY is used - // throw if any signatures *didn't* use SIGHASH_ANYONECANPAY - if (!this.inputs.every(function (otherInput) { - // no signature - if (otherInput.hashType === undefined) return true - - return otherInput.hashType & Transaction.SIGHASH_ANYONECANPAY - })) { + if (!this.__canModifyInputs()) { throw new Error('No, this would invalidate signatures') } @@ -387,23 +380,7 @@ TransactionBuilder.prototype.__addInputUnsafe = function (txHash, vout, sequence } TransactionBuilder.prototype.addOutput = function (scriptPubKey, value) { - var nOutputs = this.tx.outs.length - - // if signatures exist, adding outputs is only acceptable if SIGHASH_NONE or SIGHASH_SINGLE is used - // throws if any signatures didn't use SIGHASH_NONE|SIGHASH_SINGLE - if (!this.inputs.every(function (input, i) { - // no signature - if (input.hashType === undefined) return true - - var hashTypeMod = input.hashType & 0x1f - if (hashTypeMod === Transaction.SIGHASH_NONE) return true - if (hashTypeMod === Transaction.SIGHASH_SINGLE) { - // account for SIGHASH_SINGLE signing of a non-existing output, aka the "SIGHASH_SINGLE" bug - return i < nOutputs - } - - return false - })) { + if (!this.__canModifyOutputs()) { throw new Error('No, this would invalidate signatures') } @@ -501,4 +478,36 @@ TransactionBuilder.prototype.sign = function (vin, keyPair, redeemScript, hashTy if (!valid) throw new Error('Key pair cannot sign for this input') } +TransactionBuilder.prototype.__canModifyInputs = function () { + return this.inputs.every(function (otherInput) { + // no signature + if (otherInput.hashType === undefined) return true + + // if SIGHASH_ANYONECANPAY is set, signatures would not + // be invalidated by more inputs + return otherInput.hashType & Transaction.SIGHASH_ANYONECANPAY + }) +} + +TransactionBuilder.prototype.__canModifyOutputs = function () { + var nInputs = this.tx.ins.length + var nOutputs = this.tx.outs.length + + return this.inputs.every(function (input, i) { + // any signatures? + if (input.hashType === undefined) return true + + var hashTypeMod = input.hashType & 0x1f + if (hashTypeMod === Transaction.SIGHASH_NONE) return true + if (hashTypeMod === Transaction.SIGHASH_SINGLE) { + // if SIGHASH_SINGLE is set, and nInputs > nOutputs + // some signatures would be invalidated by the addition + // of more outputs + return nInputs <= nOutputs + } + + return false + }) +} + module.exports = TransactionBuilder