address/txbuilder: require templates to prevent undefined exports
This commit is contained in:
parent
b6a6b0a50a
commit
f4a83f8aed
3 changed files with 49 additions and 46 deletions
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue