diff --git a/src/transaction_builder.js b/src/transaction_builder.js index 5c94ce6..73fd12b 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -208,13 +208,16 @@ TransactionBuilder.prototype.addInput = function (txHash, vout, sequence, prevOu input.prevOutType = prevOutType } - var valid = this.inputs.every(function (input2) { - if (input2.hashType === undefined) return true - - return input2.hashType & Transaction.SIGHASH_ANYONECANPAY - }) - - if (!valid) throw new Error('No, this would invalidate signatures') + // 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 + })) { + throw new Error('No, this would invalidate signatures') + } var prevOut = txHash.toString('hex') + ':' + vout if (this.prevTxMap[prevOut]) throw new Error('Transaction is already an input') @@ -228,15 +231,24 @@ TransactionBuilder.prototype.addInput = function (txHash, vout, sequence, prevOu TransactionBuilder.prototype.addOutput = function (scriptPubKey, value) { var nOutputs = this.tx.outs.length - var valid = this.inputs.every(function (input, index) { + + // 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, index) { + // no signature if (input.hashType === undefined) return true var hashTypeMod = input.hashType & 0x1f - return (hashTypeMod === Transaction.SIGHASH_NONE) || - (hashTypeMod === Transaction.SIGHASH_SINGLE && index < nOutputs) - }) + 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 index < nOutputs + } - if (!valid) throw new Error('No, this would invalidate signatures') + return false + })) { + throw new Error('No, this would invalidate signatures') + } // Attempt to get a script if it's a base58 address string if (typeof scriptPubKey === 'string') {