diff --git a/src/address.js b/src/address.js index 508b6ba..221f85a 100644 --- a/src/address.js +++ b/src/address.js @@ -2,6 +2,7 @@ var Buffer = require('safe-buffer').Buffer var bech32 = require('bech32') var bs58check = require('bs58check') var bscript = require('./script') +var btemplates = require('./templates') var networks = require('./networks') var typeforce = require('typeforce') var types = require('./types') @@ -50,10 +51,10 @@ function toBech32 (data, version, prefix) { function fromOutputScript (outputScript, network) { network = network || networks.bitcoin - if (bscript.pubKeyHash.output.check(outputScript)) return toBase58Check(bscript.compile(outputScript).slice(3, 23), network.pubKeyHash) - if (bscript.scriptHash.output.check(outputScript)) return toBase58Check(bscript.compile(outputScript).slice(2, 22), network.scriptHash) - if (bscript.witnessPubKeyHash.output.check(outputScript)) return toBech32(bscript.compile(outputScript).slice(2, 22), 0, network.bech32) - if (bscript.witnessScriptHash.output.check(outputScript)) return toBech32(bscript.compile(outputScript).slice(2, 34), 0, network.bech32) + if (btemplates.pubKeyHash.output.check(outputScript)) return toBase58Check(bscript.compile(outputScript).slice(3, 23), network.pubKeyHash) + if (btemplates.scriptHash.output.check(outputScript)) return toBase58Check(bscript.compile(outputScript).slice(2, 22), network.scriptHash) + if (btemplates.witnessPubKeyHash.output.check(outputScript)) return toBech32(bscript.compile(outputScript).slice(2, 22), 0, network.bech32) + if (btemplates.witnessScriptHash.output.check(outputScript)) return toBech32(bscript.compile(outputScript).slice(2, 34), 0, network.bech32) throw new Error(bscript.toASM(outputScript) + ' has no matching Address') } @@ -67,8 +68,8 @@ function toOutputScript (address, network) { } catch (e) {} if (decode) { - if (decode.version === network.pubKeyHash) return bscript.pubKeyHash.output.encode(decode.hash) - if (decode.version === network.scriptHash) return bscript.scriptHash.output.encode(decode.hash) + if (decode.version === network.pubKeyHash) return btemplates.pubKeyHash.output.encode(decode.hash) + if (decode.version === network.scriptHash) return btemplates.scriptHash.output.encode(decode.hash) } else { try { decode = fromBech32(address) @@ -77,8 +78,8 @@ function toOutputScript (address, network) { if (decode) { if (decode.prefix !== network.bech32) throw new Error(address + ' has an invalid prefix') if (decode.version === 0) { - if (decode.data.length === 20) return bscript.witnessPubKeyHash.output.encode(decode.data) - if (decode.data.length === 32) return bscript.witnessScriptHash.output.encode(decode.data) + if (decode.data.length === 20) return btemplates.witnessPubKeyHash.output.encode(decode.data) + if (decode.data.length === 32) return btemplates.witnessScriptHash.output.encode(decode.data) } } } diff --git a/src/transaction_builder.js b/src/transaction_builder.js index 94d3037..90e5e65 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -2,13 +2,14 @@ var Buffer = require('safe-buffer').Buffer var baddress = require('./address') var bcrypto = require('./crypto') var bscript = require('./script') +var btemplates = require('./templates') var networks = require('./networks') var ops = require('bitcoin-ops') var typeforce = require('typeforce') var types = require('./types') -var scriptTypes = bscript.types -var SIGNABLE = [bscript.types.P2PKH, bscript.types.P2PK, bscript.types.MULTISIG] -var P2SH = SIGNABLE.concat([bscript.types.P2WPKH, bscript.types.P2WSH]) +var scriptTypes = btemplates.types +var SIGNABLE = [btemplates.types.P2PKH, btemplates.types.P2PK, btemplates.types.MULTISIG] +var P2SH = SIGNABLE.concat([btemplates.types.P2WPKH, btemplates.types.P2WSH]) var ECPair = require('./ecpair') var ECSignature = require('./ecsignature') @@ -33,13 +34,13 @@ function extractChunks (type, chunks, script) { break case scriptTypes.P2PK: - pubKeys[0] = script ? bscript.pubKey.output.decode(script) : undefined + pubKeys[0] = script ? btemplates.pubKey.output.decode(script) : undefined signatures = chunks.slice(0, 1) break case scriptTypes.MULTISIG: if (script) { - var multisig = bscript.multisig.output.decode(script) + var multisig = btemplates.multisig.output.decode(script) pubKeys = multisig.pubKeys } @@ -72,24 +73,24 @@ function expandInput (scriptSig, witnessStack) { var chunks var scriptSigChunks = bscript.decompile(scriptSig) - var sigType = bscript.classifyInput(scriptSigChunks, true) + var sigType = btemplates.classifyInput(scriptSigChunks, true) if (sigType === scriptTypes.P2SH) { p2sh = true redeemScript = scriptSigChunks[scriptSigChunks.length - 1] - redeemScriptType = bscript.classifyOutput(redeemScript) - prevOutScript = bscript.scriptHash.output.encode(bcrypto.hash160(redeemScript)) + redeemScriptType = btemplates.classifyOutput(redeemScript) + prevOutScript = btemplates.scriptHash.output.encode(bcrypto.hash160(redeemScript)) prevOutType = scriptTypes.P2SH script = redeemScript } - var classifyWitness = bscript.classifyWitness(witnessStack, true) + var classifyWitness = btemplates.classifyWitness(witnessStack, true) if (classifyWitness === scriptTypes.P2WSH) { witnessScript = witnessStack[witnessStack.length - 1] - witnessScriptType = bscript.classifyOutput(witnessScript) + witnessScriptType = btemplates.classifyOutput(witnessScript) p2wsh = true witness = true if (scriptSig.length === 0) { - prevOutScript = bscript.witnessScriptHash.output.encode(bcrypto.sha256(witnessScript)) + prevOutScript = btemplates.witnessScriptHash.output.encode(bcrypto.sha256(witnessScript)) prevOutType = scriptTypes.P2WSH if (redeemScript !== undefined) { throw new Error('Redeem script given when unnecessary') @@ -99,13 +100,13 @@ function expandInput (scriptSig, witnessStack) { if (!redeemScript) { throw new Error('No redeemScript provided for P2WSH, but scriptSig non-empty') } - witnessProgram = bscript.witnessScriptHash.output.encode(bcrypto.sha256(witnessScript)) + witnessProgram = btemplates.witnessScriptHash.output.encode(bcrypto.sha256(witnessScript)) if (!redeemScript.equals(witnessProgram)) { throw new Error('Redeem script didn\'t match witnessScript') } } - if (!supportedType(bscript.classifyOutput(witnessScript))) { + if (!supportedType(btemplates.classifyOutput(witnessScript))) { throw new Error('unsupported witness script') } @@ -117,7 +118,7 @@ function expandInput (scriptSig, witnessStack) { var key = witnessStack[witnessStack.length - 1] var keyHash = bcrypto.hash160(key) if (scriptSig.length === 0) { - prevOutScript = bscript.witnessPubKeyHash.output.encode(keyHash) + prevOutScript = btemplates.witnessPubKeyHash.output.encode(keyHash) prevOutType = scriptTypes.P2WPKH if (typeof redeemScript !== 'undefined') { throw new Error('Redeem script given when unnecessary') @@ -126,7 +127,7 @@ function expandInput (scriptSig, witnessStack) { if (!redeemScript) { throw new Error('No redeemScript provided for P2WPKH, but scriptSig wasn\'t empty') } - witnessProgram = bscript.witnessPubKeyHash.output.encode(keyHash) + witnessProgram = btemplates.witnessPubKeyHash.output.encode(keyHash) if (!redeemScript.equals(witnessProgram)) { throw new Error('Redeem script did not have the right witness program') } @@ -143,7 +144,7 @@ function expandInput (scriptSig, witnessStack) { scriptType = redeemScriptType chunks = scriptSigChunks.slice(0, -1) } else { - prevOutType = scriptType = bscript.classifyInput(scriptSig) + prevOutType = scriptType = btemplates.classifyInput(scriptSig) chunks = scriptSigChunks } @@ -211,7 +212,7 @@ function expandOutput (script, scriptType, ourPubKey) { var scriptChunks = bscript.decompile(script) if (!scriptType) { - scriptType = bscript.classifyOutput(script) + scriptType = btemplates.classifyOutput(script) } var pubKeys = [] @@ -293,14 +294,14 @@ function prepareInput (input, kpPubKey, redeemScript, witnessValue, witnessScrip witnessScriptHash = bcrypto.sha256(witnessScript) checkP2shInput(input, redeemScriptHash) - if (!redeemScript.equals(bscript.witnessScriptHash.output.encode(witnessScriptHash))) throw new Error('Witness script inconsistent with redeem script') + if (!redeemScript.equals(btemplates.witnessScriptHash.output.encode(witnessScriptHash))) throw new Error('Witness script inconsistent with redeem script') expanded = expandOutput(witnessScript, undefined, kpPubKey) if (!expanded.pubKeys) throw new Error('WitnessScript not supported "' + bscript.toASM(redeemScript) + '"') - prevOutType = bscript.types.P2SH - prevOutScript = bscript.scriptHash.output.encode(redeemScriptHash) + prevOutType = btemplates.types.P2SH + prevOutScript = btemplates.scriptHash.output.encode(redeemScriptHash) p2sh = witness = p2wsh = true - p2shType = bscript.types.P2WSH + p2shType = btemplates.types.P2WSH signType = witnessType = expanded.scriptType signScript = witnessScript } else if (redeemScript) { @@ -310,12 +311,12 @@ function prepareInput (input, kpPubKey, redeemScript, witnessValue, witnessScrip expanded = expandOutput(redeemScript, undefined, kpPubKey) if (!expanded.pubKeys) throw new Error('RedeemScript not supported "' + bscript.toASM(redeemScript) + '"') - prevOutType = bscript.types.P2SH - prevOutScript = bscript.scriptHash.output.encode(redeemScriptHash) + prevOutType = btemplates.types.P2SH + prevOutScript = btemplates.scriptHash.output.encode(redeemScriptHash) p2sh = true signType = p2shType = expanded.scriptType signScript = redeemScript - witness = signType === bscript.types.P2WPKH + witness = signType === btemplates.types.P2WPKH } else if (witnessScript) { witnessScriptHash = bcrypto.sha256(witnessScript) checkP2WSHInput(input, witnessScriptHash) @@ -323,8 +324,8 @@ function prepareInput (input, kpPubKey, redeemScript, witnessValue, witnessScrip expanded = expandOutput(witnessScript, undefined, kpPubKey) if (!expanded.pubKeys) throw new Error('WitnessScript not supported "' + bscript.toASM(redeemScript) + '"') - prevOutType = bscript.types.P2WSH - prevOutScript = bscript.witnessScriptHash.output.encode(witnessScriptHash) + prevOutType = btemplates.types.P2WSH + prevOutScript = btemplates.witnessScriptHash.output.encode(witnessScriptHash) witness = p2wsh = true signType = witnessType = expanded.scriptType signScript = witnessScript @@ -344,7 +345,7 @@ function prepareInput (input, kpPubKey, redeemScript, witnessValue, witnessScrip signType = prevOutType signScript = prevOutScript } else { - prevOutScript = bscript.pubKeyHash.output.encode(bcrypto.hash160(kpPubKey)) + prevOutScript = btemplates.pubKeyHash.output.encode(bcrypto.hash160(kpPubKey)) expanded = expandOutput(prevOutScript, scriptTypes.P2PKH, kpPubKey) prevOutType = scriptTypes.P2PKH witness = false @@ -359,7 +360,7 @@ function prepareInput (input, kpPubKey, redeemScript, witnessValue, witnessScrip } if (signType === scriptTypes.P2WPKH) { - signScript = bscript.pubKeyHash.output.encode(bscript.witnessPubKeyHash.output.decode(signScript)) + signScript = btemplates.pubKeyHash.output.encode(btemplates.witnessPubKeyHash.output.decode(signScript)) } if (p2sh) { @@ -383,9 +384,9 @@ function prepareInput (input, kpPubKey, redeemScript, witnessValue, witnessScrip function buildStack (type, signatures, pubKeys, allowIncomplete) { if (type === scriptTypes.P2PKH) { - if (signatures.length === 1 && Buffer.isBuffer(signatures[0]) && pubKeys.length === 1) return bscript.pubKeyHash.input.encodeStack(signatures[0], pubKeys[0]) + if (signatures.length === 1 && Buffer.isBuffer(signatures[0]) && pubKeys.length === 1) return btemplates.pubKeyHash.input.encodeStack(signatures[0], pubKeys[0]) } else if (type === scriptTypes.P2PK) { - if (signatures.length === 1 && Buffer.isBuffer(signatures[0])) return bscript.pubKey.input.encodeStack(signatures[0]) + if (signatures.length === 1 && Buffer.isBuffer(signatures[0])) return btemplates.pubKey.input.encodeStack(signatures[0]) } else if (type === scriptTypes.MULTISIG) { if (signatures.length > 0) { signatures = signatures.map(function (signature) { @@ -396,7 +397,7 @@ function buildStack (type, signatures, pubKeys, allowIncomplete) { signatures = signatures.filter(function (x) { return x !== ops.OP_0 }) } - return bscript.multisig.input.encodeStack(signatures) + return btemplates.multisig.input.encodeStack(signatures) } } else { throw new Error('Not yet supported') @@ -416,7 +417,7 @@ function buildInput (input, allowIncomplete) { } var p2sh = false - if (scriptType === bscript.types.P2SH) { + if (scriptType === btemplates.types.P2SH) { // We can remove this error later when we have a guarantee prepareInput // rejects unsignable scripts - it MUST be signable at this point. if (!allowIncomplete && !supportedP2SHType(input.redeemScriptType)) { @@ -436,11 +437,11 @@ function buildInput (input, allowIncomplete) { switch (scriptType) { // P2WPKH is a special case of P2PKH - case bscript.types.P2WPKH: - witness = buildStack(bscript.types.P2PKH, input.signatures, input.pubKeys, allowIncomplete) + case btemplates.types.P2WPKH: + witness = buildStack(btemplates.types.P2PKH, input.signatures, input.pubKeys, allowIncomplete) break - case bscript.types.P2WSH: + case btemplates.types.P2WSH: // We can remove this check later if (!allowIncomplete && !supportedType(input.witnessScriptType)) { throw new Error('Impossible to sign this type') @@ -593,7 +594,7 @@ TransactionBuilder.prototype.__addInputUnsafe = function (txHash, vout, options) } input.prevOutScript = options.prevOutScript - input.prevOutType = prevOutType || bscript.classifyOutput(options.prevOutScript) + input.prevOutType = prevOutType || btemplates.classifyOutput(options.prevOutScript) } var vin = this.tx.addInput(txHash, vout, options.sequence, options.scriptSig) @@ -637,7 +638,7 @@ TransactionBuilder.prototype.__build = function (allowIncomplete) { // skip if no result if (!allowIncomplete) { - if (!supportedType(result.type) && result.type !== bscript.types.P2WPKH) { + if (!supportedType(result.type) && result.type !== btemplates.types.P2WPKH) { throw new Error(result.type + ' not supported') } } diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 2ad4c93..b98273a 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -3,6 +3,7 @@ var assert = require('assert') var baddress = require('../src/address') var bscript = require('../src/script') +var btemplates = require('../src/templates') var ops = require('bitcoin-ops') var BigInteger = require('bigi') @@ -434,7 +435,7 @@ describe('TransactionBuilder', function () { var signatures = bscript.decompile(scriptSig).slice(1, -1).filter(function (x) { return x !== ops.OP_0 }) // rebuild/replace the scriptSig without them - var replacement = bscript.scriptHash.input.encode(bscript.multisig.input.encode(signatures), redeemScript) + var replacement = btemplates.scriptHash.input.encode(btemplates.multisig.input.encode(signatures), redeemScript) assert.strictEqual(bscript.toASM(replacement), sign.scriptSigFiltered) tx.ins[i].script = replacement