Repository: bitcoinjs/bitcoinjs-lib
Pull request #1232 (2018-09-26 06:05:01)

P2SH/P2WSH payments .network should use .redeem.network if undefined
The default `network` now favours that which is defined...


Patch:
diff --git a/src/classify.js b/src/classify.js
index 8350e07e..0b98fa6c 100644
--- a/src/classify.js
+++ b/src/classify.js
@@ -9,7 +9,7 @@ const witnessScriptHash = require('./templates/witnessscripthash')
 const witnessCommitment = require('./templates/witnesscommitment')
 
 const types = {
-  P2MS: 'multisig',
+  MULTISIG: 'multisig',
   NONSTANDARD: 'nonstandard',
   NULLDATA: 'nulldata',
   P2PK: 'pubkey',
@@ -30,7 +30,7 @@ function classifyOutput (script) {
   const chunks = decompile(script)
   if (!chunks) throw new TypeError('Invalid script')
 
-  if (multisig.output.check(chunks)) return types.P2MS
+  if (multisig.output.check(chunks)) return types.MULTISIG
   if (pubKey.output.check(chunks)) return types.P2PK
   if (witnessCommitment.output.check(chunks)) return types.WITNESS_COMMITMENT
   if (nullData.output.check(chunks)) return types.NULLDATA
@@ -45,7 +45,7 @@ function classifyInput (script, allowIncomplete) {
 
   if (pubKeyHash.input.check(chunks)) return types.P2PKH
   if (scriptHash.input.check(chunks, allowIncomplete)) return types.P2SH
-  if (multisig.input.check(chunks, allowIncomplete)) return types.P2MS
+  if (multisig.input.check(chunks, allowIncomplete)) return types.MULTISIG
   if (pubKey.input.check(chunks)) return types.P2PK
 
   return types.NONSTANDARD
diff --git a/src/payments/p2sh.js b/src/payments/p2sh.js
index 47419369..0729c8bd 100644
--- a/src/payments/p2sh.js
+++ b/src/payments/p2sh.js
@@ -45,7 +45,11 @@ function p2sh (a, opts) {
     witness: typef.maybe(typef.arrayOf(typef.Buffer))
   }, a)
 
-  const network = a.network || BITCOIN_NETWORK
+  let network = a.network
+  if (!network) {
+    network = (a.redeem && a.redeem.network) || BITCOIN_NETWORK
+  }
+
   const o = { network }
 
   const _address = lazy.value(function () {
diff --git a/src/payments/p2wsh.js b/src/payments/p2wsh.js
index a26e7069..d8e6e8af 100644
--- a/src/payments/p2wsh.js
+++ b/src/payments/p2wsh.js
@@ -59,7 +59,11 @@ function p2wsh (a, opts) {
   })
   const _rchunks = lazy.value(function () { return bscript.decompile(a.redeem.input) })
 
-  const network = a.network || BITCOIN_NETWORK
+  let network = a.network
+  if (!network) {
+    network = (a.redeem && a.redeem.network) || BITCOIN_NETWORK
+  }
+
   const o = { network }
 
   lazy.prop(o, 'address', function () {
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index bea1ded5..87068419 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -56,17 +56,16 @@ function expandInput (scriptSig, witnessStack, type, scriptPubKey) {
       }
     }
 
-    case SCRIPT_TYPES.P2MS: {
-      const { m, pubkeys, signatures } = payments.p2ms({
+    case SCRIPT_TYPES.MULTISIG: {
+      const { pubkeys, signatures } = payments.p2ms({
         input: scriptSig,
         output: scriptPubKey
       }, { allowIncomplete: true })
 
       return {
-        prevOutType: SCRIPT_TYPES.P2MS,
+        prevOutType: SCRIPT_TYPES.MULTISIG,
         pubkeys: pubkeys,
-        signatures: signatures,
-        maxSignatures: m
+        signatures: signatures
       }
     }
   }
@@ -127,7 +126,7 @@ function expandInput (scriptSig, witnessStack, type, scriptPubKey) {
 
 // could be done in expandInput, but requires the original Transaction for hashForSignature
 function fixMultisigOrder (input, transaction, vin) {
-  if (input.redeemScriptType !== SCRIPT_TYPES.P2MS || !input.redeemScript) return
+  if (input.redeemScriptType !== SCRIPT_TYPES.MULTISIG || !input.redeemScript) return
   if (input.pubkeys.length === input.signatures.length) return
 
   const unmatched = input.signatures.concat()
@@ -203,13 +202,12 @@ function expandOutput (script, ourPubKey) {
       }
     }
 
-    case SCRIPT_TYPES.P2MS: {
+    case SCRIPT_TYPES.MULTISIG: {
       const p2ms = payments.p2ms({ output: script })
       return {
         type,
         pubkeys: p2ms.pubkeys,
-        signatures: p2ms.pubkeys.map(() => undefined),
-        maxSignatures: p2ms.m
+        signatures: p2ms.pubkeys.map(() => undefined)
       }
     }
   }
@@ -252,8 +250,7 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri
       signType: expanded.type,
 
       pubkeys: expanded.pubkeys,
-      signatures: expanded.signatures,
-      maxSignatures: expanded.maxSignatures
+      signatures: expanded.signatures
     }
   }
 
@@ -291,8 +288,7 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri
       signType: expanded.type,
 
       pubkeys: expanded.pubkeys,
-      signatures: expanded.signatures,
-      maxSignatures: expanded.maxSignatures
+      signatures: expanded.signatures
     }
   }
 
@@ -325,8 +321,7 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri
       signType: expanded.type,
 
       pubkeys: expanded.pubkeys,
-      signatures: expanded.signatures,
-      maxSignatures: expanded.maxSignatures
+      signatures: expanded.signatures
     }
   }
 
@@ -356,8 +351,7 @@ function prepareInput (input, ourPubKey, redeemScript, witnessValue, witnessScri
       signType: expanded.type,
 
       pubkeys: expanded.pubkeys,
-      signatures: expanded.signatures,
-      maxSignatures: expanded.maxSignatures
+      signatures: expanded.signatures
     }
   }
 
@@ -398,18 +392,14 @@ function build (type, input, allowIncomplete) {
 
       return payments.p2pk({ signature: signatures[0] })
     }
-    case SCRIPT_TYPES.P2MS: {
-      const m = input.maxSignatures
+    case SCRIPT_TYPES.MULTISIG: {
       if (allowIncomplete) {
         signatures = signatures.map(x => x || ops.OP_0)
       } else {
         signatures = signatures.filter(x => x)
       }
 
-      // if the transaction is not not complete (complete), or if signatures.length === m, validate
-      // otherwise, the number of OP_0's may be >= m, so don't validate (boo)
-      const validate = !allowIncomplete || (m === signatures.length)
-      return payments.p2ms({ m, pubkeys, signatures }, { allowIncomplete, validate })
+      return payments.p2ms({ signatures }, { allowIncomplete })
     }
     case SCRIPT_TYPES.P2SH: {
       const redeem = build(input.redeemScriptType, input, allowIncomplete)
@@ -643,9 +633,7 @@ TransactionBuilder.prototype.sign = function (vin, keyPair, redeemScript, hashTy
   // TODO: remove keyPair.network matching in 4.0.0
   if (keyPair.network && keyPair.network !== this.network) throw new TypeError('Inconsistent network')
   if (!this.__inputs[vin]) throw new Error('No input at index: ' + vin)
-
   hashType = hashType || Transaction.SIGHASH_ALL
-  if (this.__needsOutputs(hashType)) throw new Error('Transaction needs outputs')
 
   const input = this.__inputs[vin]
 
@@ -706,7 +694,8 @@ function signatureHashType (buffer) {
 
 TransactionBuilder.prototype.__canModifyInputs = function () {
   return this.__inputs.every(function (input) {
-    if (!input.signatures) return true
+    // any signatures?
+    if (input.signatures === undefined) return true
 
     return input.signatures.every(function (signature) {
       if (!signature) return true
@@ -719,25 +708,6 @@ TransactionBuilder.prototype.__canModifyInputs = function () {
   })
 }
 
-TransactionBuilder.prototype.__needsOutputs = function (signingHashType) {
-  if (signingHashType === Transaction.SIGHASH_ALL) {
-    return this.__tx.outs.length === 0
-  }
-
-  // if inputs are being signed with SIGHASH_NONE, we don't strictly need outputs
-  // .build() will fail, but .buildIncomplete() is OK
-  return (this.__tx.outs.length === 0) && this.__inputs.some((input) => {
-    if (!input.signatures) return false
-
-    return input.signatures.some((signature) => {
-      if (!signature) return false // no signature, no issue
-      const hashType = signatureHashType(signature)
-      if (hashType & Transaction.SIGHASH_NONE) return false // SIGHASH_NONE doesn't care about outputs
-      return true // SIGHASH_* does care
-    })
-  })
-}
-
 TransactionBuilder.prototype.__canModifyOutputs = function () {
   const nInputs = this.__tx.ins.length
   const nOutputs = this.__tx.outs.length


Test patch:
diff --git a/test/fixtures/p2sh.json b/test/fixtures/p2sh.json
index e6fe2aeb..595b85ea 100644
--- a/test/fixtures/p2sh.json
+++ b/test/fixtures/p2sh.json
@@ -166,6 +166,24 @@
           ]
         }
       }
+    },
+    {
+      "description": "p2sh-p2pkh, out (network derived from redeem)",
+      "arguments": {
+        "redeem": {
+          "address": "this is P2PKH context, unknown and ignored by P2SH",
+          "output": "OP_DUP OP_HASH160 c30afa58ae0673b00a45b5c17dff4633780f1400 OP_EQUALVERIFY OP_CHECKSIG",
+          "network": "testnet"
+        }
+      },
+      "expected": {
+        "address": "2N7nfc7zeWuADtpdR4MrR7Wq3dzr7LxTCgS",
+        "hash": "9f840a5fc02407ef0ad499c2ec0eb0b942fb0086",
+        "output": "OP_HASH160 9f840a5fc02407ef0ad499c2ec0eb0b942fb0086 OP_EQUAL",
+        "input": null,
+        "witness": null,
+        "network": "testnet"
+      }
     }
   ],
   "invalid": [
@@ -325,6 +343,24 @@
         }
       }
     },
+    {
+      "exception": "Network mismatch",
+      "arguments": {
+        "network": "bitcoin",
+        "redeem": {
+          "network": "testnet"
+        }
+      }
+    },
+    {
+      "exception": "Network mismatch",
+      "arguments": {
+        "network": "testnet",
+        "redeem": {
+          "network": "bitcoin"
+        }
+      }
+    },
     {
       "exception": "Empty input",
       "arguments": {
diff --git a/test/fixtures/p2wsh.json b/test/fixtures/p2wsh.json
index 0870278c..e5ce0e0c 100644
--- a/test/fixtures/p2wsh.json
+++ b/test/fixtures/p2wsh.json
@@ -179,6 +179,24 @@
           ]
         }
       }
+    },
+    {
+      "description": "p2wsh-p2pkh, out (network derived from redeem)",
+      "arguments": {
+        "redeem": {
+          "address": "this is P2PKH context, unknown and ignored by p2wsh",
+          "output": "OP_DUP OP_HASH160 c30afa58ae0673b00a45b5c17dff4633780f1400 OP_EQUALVERIFY OP_CHECKSIG",
+          "network": "testnet"
+        }
+      },
+      "expected": {
+        "address": "tb1qusxlgq9quu27ucxs7a2fg8nv0pycdzvxsjk9npyupupxw3y892ssaskm8v",
+        "hash": "e40df400a0e715ee60d0f754941e6c784986898684ac59849c0f026744872aa1",
+        "output": "OP_0 e40df400a0e715ee60d0f754941e6c784986898684ac59849c0f026744872aa1",
+        "input": null,
+        "witness": null,
+        "network": "testnet"
+      }
     }
   ],
   "invalid": [
@@ -306,6 +324,15 @@
         }
       }
     },
+    {
+      "exception": "Network mismatch",
+      "arguments": {
+        "network": "testnet",
+        "redeem": {
+          "network": "bitcoin"
+        }
+      }
+    },
     {
       "exception": "Invalid prefix or Network mismatch",
       "arguments": {
diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json
index a2ca5d7e..4ddc5cbc 100644
--- a/test/fixtures/transaction_builder.json
+++ b/test/fixtures/transaction_builder.json
@@ -443,7 +443,7 @@
         ]
       },
       {
-        "description": "SIGHASH SINGLE (random)",
+        "description": "Sighash: SINGLE (random)",
         "txHex": "01000000012ffb29d53528ad30c37c267fbbeda3c6fce08f5f6f5d3b1eab22193599a3612a010000006b483045022100f963f1d9564075a934d7c3cfa333bd1378859b84cba947e149926fc9ec89b5ae02202b5b912e507bae65002aff972f9752e2aeb2e22c5fdbaaad672090378184df37032102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff0260a62f01000000001976a9140de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b888ac80969800000000001976a91454d0e925d5ee0ee26768a237067dee793d01a70688ac00000000",
         "version": 1,
         "inputs": [
@@ -473,7 +473,7 @@
         ]
       },
       {
-        "description": "SIGHASH ALL",
+        "description": "Sighash: ALL",
         "txHex": "01000000037db7f0b2a345ded6ddf28da3211a7d7a95a2943e9a879493d6481b7d69613f04010000006a47304402206abb0622b8b6ca83f1f4de84830cf38bf4615dc9e47a7dcdcc489905f26aa9cb02201d2d8a7815242b88e4cd66390ca46da802238f9b1395e0d118213d30dad38184012102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff652c491e5a781a6a3c547fa8d980741acbe4623ae52907278f10e1f064f67e05000000006b483045022100de13b42804f87a09bb46def12ab4608108d8c2db41db4bc09064f9c46fcf493102205e5c759ab7b2895c9b0447e56029f6895ff7bb20e0847c564a88a3cfcf080c4f012102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffffb9fa270fa3e4dd8c79f9cbfe5f1953cba071ed081f7c277a49c33466c695db35000000006b4830450221009100a3f5b30182d1cb0172792af6947b6d8d42badb0539f2c209aece5a0628f002200ae91702ca63347e344c85fcb536f30ee97b75cdf4900de534ed5e040e71a548012102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff03204e0000000000001976a9149ed1f577c60e4be1dbf35318ec12f51d25e8577388ac30750000000000001976a914fb407e88c48921d5547d899e18a7c0a36919f54d88ac50c30000000000001976a91404ccb4eed8cfa9f6e394e945178960f5ccddb38788ac00000000",
         "version": 1,
         "inputs": [
@@ -533,7 +533,7 @@
         ]
       },
       {
-        "description": "SIGHASH ALL | ANYONECANPAY",
+        "description": "Sighash: ALL | ANYONECANPAY",
         "txHex": "01000000037db7f0b2a345ded6ddf28da3211a7d7a95a2943e9a879493d6481b7d69613f04010000006b483045022100bd2829550e9b3a081747281029b5f5a96bbd83bb6a92fa2f8310f1bd0d53abc90220071b469417c55cdb3b04171fd7900d2768981b7ab011553d84d24ea85d277079812102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff652c491e5a781a6a3c547fa8d980741acbe4623ae52907278f10e1f064f67e05000000006a47304402206295e17c45c6356ffb20365b696bcbb869db7e8697f4b8a684098ee2bff85feb02202905c441abe39ec9c480749236b84fdd3ebd91ecd25b559136370aacfcf2815c812102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffffb9fa270fa3e4dd8c79f9cbfe5f1953cba071ed081f7c277a49c33466c695db35000000006b483045022100f58e7c98ac8412944d575bcdece0e5966d4018f05988b5b60b6f46b8cb7a543102201c5854d3361e29b58123f34218cec2c722f5ec7a08235ebd007ec637b07c193a812102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff03204e0000000000001976a9149ed1f577c60e4be1dbf35318ec12f51d25e8577388ac30750000000000001976a914fb407e88c48921d5547d899e18a7c0a36919f54d88ac50c30000000000001976a91404ccb4eed8cfa9f6e394e945178960f5ccddb38788ac00000000",
         "version": 1,
         "inputs": [
@@ -593,7 +593,7 @@
         ]
       },
       {
-        "description": "SIGHASH SINGLE",
+        "description": "Sighash: SINGLE",
         "txHex": "01000000037db7f0b2a345ded6ddf28da3211a7d7a95a2943e9a879493d6481b7d69613f04010000006b483045022100e822f152bb15a1d623b91913cd0fb915e9f85a8dc6c26d51948208bbc0218e800220255f78549d9614c88eac9551429bc00224f22cdcb41a3af70d52138f7e98d333032102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff652c491e5a781a6a3c547fa8d980741acbe4623ae52907278f10e1f064f67e05000000006a47304402206f37f79adeb86e0e2da679f79ff5c3ba206c6d35cd9a21433f0de34ee83ddbc00220118cabbac5d83b3aa4c2dc01b061e4b2fe83750d85a72ae6a1752300ee5d9aff032102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffffb9fa270fa3e4dd8c79f9cbfe5f1953cba071ed081f7c277a49c33466c695db35000000006a473044022042ac843d220a56b3de05f24c85a63e71efa7e5fc7c2ec766a2ffae82a88572b0022051a816b317313ea8d90010a77c3e02d41da4a500e67e6a5347674f836f528d82032102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff03204e0000000000001976a9149ed1f577c60e4be1dbf35318ec12f51d25e8577388ac30750000000000001976a914fb407e88c48921d5547d899e18a7c0a36919f54d88ac50c30000000000001976a91404ccb4eed8cfa9f6e394e945178960f5ccddb38788ac00000000",
         "version": 1,
         "inputs": [
@@ -653,7 +653,7 @@
         ]
       },
       {
-        "description": "SIGHASH SINGLE|ANYONECANPAY",
+        "description": "Sighash: SINGLE|ANYONECANPAY",
         "txHex": "01000000037db7f0b2a345ded6ddf28da3211a7d7a95a2943e9a879493d6481b7d69613f04010000006b483045022100d05a3b6cf2f0301000b0e45c09054f2c61570ce8798ebf571eef72da3b1c94a1022016d7ef3c133fa703bae2c75158ea08d335ac698506f99b3c369c37a9e8fc4beb832102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff652c491e5a781a6a3c547fa8d980741acbe4623ae52907278f10e1f064f67e05000000006b483045022100ee6bf07b051001dcbfa062692a40adddd070303286b714825b3fb4693dd8fcdb022056610885e5053e5d47f2be3433051305abe7978ead8f7cf2d0368947aff6b307832102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffffb9fa270fa3e4dd8c79f9cbfe5f1953cba071ed081f7c277a49c33466c695db35000000006b483045022100cfc930d5b5272d0220d9da98fabec97b9e66306f735efa837f43f6adc675cad902202f9dff76b8b9ec8f613d46094f17f64d875804292d8804aa59fd295b6fc1416b832102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff03204e0000000000001976a9149ed1f577c60e4be1dbf35318ec12f51d25e8577388ac30750000000000001976a914fb407e88c48921d5547d899e18a7c0a36919f54d88ac50c30000000000001976a91404ccb4eed8cfa9f6e394e945178960f5ccddb38788ac00000000",
         "version": 1,
         "inputs": [
@@ -713,7 +713,7 @@
         ]
       },
       {
-        "description": "SIGHASH NONE",
+        "description": "Sighash: NONE",
         "txHex": "01000000037db7f0b2a345ded6ddf28da3211a7d7a95a2943e9a879493d6481b7d69613f04010000006b483045022100e7f0a1ddd2c0b81e093e029b8a503afa27fe43549b0668d2141abf35eb3a63be022037f12d12cd50fc94a135f933406a8937557de9b9566a8841ff1548c1b6984531022102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff652c491e5a781a6a3c547fa8d980741acbe4623ae52907278f10e1f064f67e05000000006a473044022008451123ec2535dab545ade9d697519e63b28df5e311ea05e0ce28d39877a7c8022061ce5dbfb7ab478dd9e05b0acfd959ac3eb2641f61958f5d352f37621073d7c0022102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffffb9fa270fa3e4dd8c79f9cbfe5f1953cba071ed081f7c277a49c33466c695db35000000006a47304402205c001bcdfb35c70d8aa3bdbc75399afb72eb7cf1926ca7c1dfcddcb4d4d3e0f8022028992fffdcd4e9f34ab726f97c24157917641c2ef99361f588e3d4147d46eea5022102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff03204e0000000000001976a9149ed1f577c60e4be1dbf35318ec12f51d25e8577388ac30750000000000001976a914fb407e88c48921d5547d899e18a7c0a36919f54d88ac50c30000000000001976a91404ccb4eed8cfa9f6e394e945178960f5ccddb38788ac00000000",
         "version": 1,
         "inputs": [
@@ -773,7 +773,7 @@
         ]
       },
       {
-        "description": "SIGHASH NONE | ANYONECANPAY",
+        "description": "Sighash: NONE | ANYONECANPAY",
         "txHex": "01000000037db7f0b2a345ded6ddf28da3211a7d7a95a2943e9a879493d6481b7d69613f04010000006a47304402204ed272952177aaa5a1b171c2ca5a7a3d300ffcd7e04b040c0baaa4e3561862a502207e65a5b8f99c8a632b186c8a60496a12bf3116f51909b7497413aefdc3be7bf6822102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff652c491e5a781a6a3c547fa8d980741acbe4623ae52907278f10e1f064f67e05000000006a47304402203ec365300cc67602f4cc5be027959d3667b48db34c6c87d267c94a7e210d5c1f02204843350311c0a9711cad1960b17ce9e323a1ce6f37deefc3ffe63082d480be92822102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffffb9fa270fa3e4dd8c79f9cbfe5f1953cba071ed081f7c277a49c33466c695db35000000006b48304502210084f86f905c36372eff9c54ccd509a519a3325bcace8abfeed7ed3f0d579979e902201ff330dd2402e5ca9989a8a294fa36d6cf3a093edb18d29c9d9644186a3efeb4822102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff03204e0000000000001976a9149ed1f577c60e4be1dbf35318ec12f51d25e8577388ac30750000000000001976a914fb407e88c48921d5547d899e18a7c0a36919f54d88ac50c30000000000001976a91404ccb4eed8cfa9f6e394e945178960f5ccddb38788ac00000000",
         "version": 1,
         "inputs": [
@@ -1917,29 +1917,6 @@
           }
         ]
       },
-      {
-        "description": "Incomplete Transaction P2SH(P2MS 2/3), missing signature",
-        "exception": "Not enough signatures provided",
-        "network": "testnet",
-        "inputs": [
-          {
-            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
-            "vout": 0,
-            "signs": [
-              {
-                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
-                "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG"
-              }
-            ]
-          }
-        ],
-        "outputs": [
-          {
-            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
-            "value": 1000
-          }
-        ]
-      },
       {
         "description": "Duplicate transaction outs",
         "exception": "Duplicate TxOut: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff:0",
@@ -2380,50 +2357,6 @@
             "value": 1000
           }
         ]
-      },
-      {
-        "description": "Transaction w/ no outputs (but 1 SIGHASH_NONE)",
-        "exception": "Transaction needs outputs",
-        "inputs": [
-          {
-            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
-            "vout": 0,
-            "signs": [
-              {
-                "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
-                "hashType": 2
-              }
-            ]
-          },
-          {
-            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
-            "vout": 1,
-            "signs": [
-              {
-                "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
-                "throws": true
-              }
-            ]
-          }
-        ],
-        "outputs": []
-      },
-      {
-        "description": "Transaction w/ no outputs",
-        "exception": "Transaction needs outputs",
-        "inputs": [
-          {
-            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
-            "vout": 0,
-            "signs": [
-              {
-                "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
-                "throws": true
-              }
-            ]
-          }
-        ],
-        "outputs": []
       }
     ],
     "fromTransaction": [
diff --git a/test/payments.utils.js b/test/payments.utils.js
index 219d086e..485bf038 100644
--- a/test/payments.utils.js
+++ b/test/payments.utils.js
@@ -1,6 +1,6 @@
 const t = require('assert')
 const bscript = require('../src/script')
-const bnetworks = require('../src/networks')
+const BNETWORKS = require('../src/networks')
 
 function tryHex (x) {
   if (Buffer.isBuffer(x)) return x.toString('hex')
@@ -58,7 +58,7 @@ function equate (a, b, args) {
 
   equateBase(a, b, '')
   if (b.redeem) equateBase(a.redeem, b.redeem, 'redeem.')
-  if (b.network) t.deepEqual(a.network, b.network, 'Inequal *.network')
+  if (b.network) t.deepEqual(a.network, BNETWORKS[b.network], 'Inequal *.network')
 
   // contextual
   if (b.signature === null) b.signature = undefined
@@ -76,7 +76,7 @@ function equate (a, b, args) {
 function preform (x) {
   x = Object.assign({}, x)
 
-  if (x.network) x.network = bnetworks[x.network]
+  if (x.network) x.network = BNETWORKS[x.network]
   if (typeof x.inputHex === 'string') {
     x.input = Buffer.from(x.inputHex, 'hex')
     delete x.inputHex
@@ -96,10 +96,11 @@ function preform (x) {
   if (x.pubkeys) x.pubkeys = x.pubkeys.map(fromHex)
   if (x.signatures) x.signatures = x.signatures.map(function (y) { return Number.isFinite(y) ? y : Buffer.from(y, 'hex') })
   if (x.redeem) {
+    x.redeem = Object.assign({}, x.redeem)
     if (typeof x.redeem.input === 'string') x.redeem.input = asmToBuffer(x.redeem.input)
     if (typeof x.redeem.output === 'string') x.redeem.output = asmToBuffer(x.redeem.output)
     if (Array.isArray(x.redeem.witness)) x.redeem.witness = x.redeem.witness.map(fromHex)
-    if (x.redeem.network) x.redeem.network = bnetworks[x.redeem.network]
+    if (x.redeem.network) x.redeem.network = BNETWORKS[x.redeem.network]
   }
 
   return x
diff --git a/test/transaction_builder.js b/test/transaction_builder.js
index 85adcff4..4911cbb5 100644
--- a/test/transaction_builder.js
+++ b/test/transaction_builder.js
@@ -1,8 +1,8 @@
 const { describe, it, beforeEach } = require('mocha')
 const assert = require('assert')
 const baddress = require('../src/address')
+const bcrypto = require('../src/crypto')
 const bscript = require('../src/script')
-const payments = require('../src/payments')
 
 const ECPair = require('../src/ecpair')
 const Transaction = require('../src/transaction')
@@ -11,6 +11,11 @@ const NETWORKS = require('../src/networks')
 
 const fixtures = require('./fixtures/transaction_builder')
 
+// TODO: remove
+function getAddress (node) {
+  return baddress.toBase58Check(bcrypto.hash160(node.publicKey), NETWORKS.bitcoin.pubKeyHash)
+}
+
 function constructSign (f, txb) {
   const network = NETWORKS[f.network]
   const stages = f.stages && f.stages.concat()
@@ -231,7 +236,6 @@ describe('TransactionBuilder', function () {
 
     it('throws if SIGHASH_ALL has been used to sign any existing scriptSigs', function () {
       txb.addInput(txHash, 0)
-      txb.addOutput(scripts[0], 1000)
       txb.sign(0, keyPair)
 
       assert.throws(function () {
@@ -247,7 +251,7 @@ describe('TransactionBuilder', function () {
     })
 
     it('accepts an address string and value', function () {
-      const { address } = payments.p2pkh({ pubkey: keyPair.publicKey })
+      const address = getAddress(keyPair)
       const vout = txb.addOutput(address, 1000)
       assert.strictEqual(vout, 0)
 
@@ -314,7 +318,6 @@ describe('TransactionBuilder', function () {
     it('throws if if there exist any scriptSigs', function () {
       const txb = new TransactionBuilder()
       txb.addInput(txHash, 0)
-      txb.addOutput(scripts[0], 100)
       txb.sign(0, keyPair)
 
       assert.throws(function () {
@@ -342,7 +345,6 @@ describe('TransactionBuilder', function () {
       it('throws ' + f.exception + (f.description ? ' (' + f.description + ')' : ''), function () {
         const txb = construct(f, true)
 
-        let threw = false
         f.inputs.forEach(function (input, index) {
           input.signs.forEach(function (sign) {
             const keyPairNetwork = NETWORKS[sign.network || f.network]
@@ -358,18 +360,15 @@ describe('TransactionBuilder', function () {
               witnessScript = bscript.fromASM(sign.witnessScript)
             }
 
-            if (sign.throws) {
+            if (!sign.throws) {
+              txb.sign(index, keyPair2, redeemScript, sign.hashType, sign.value, witnessScript)
+            } else {
               assert.throws(function () {
                 txb.sign(index, keyPair2, redeemScript, sign.hashType, sign.value, witnessScript)
               }, new RegExp(f.exception))
-              threw = true
-            } else {
-              txb.sign(index, keyPair2, redeemScript, sign.hashType, sign.value, witnessScript)
             }
           })
         })
-
-        assert.equal(threw, true)
       })
     })
   })