|
|
@ -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') |
|
|
|
} |
|
|
|
} |
|
|
|