Skip to content

Commit f4a83f8

Browse files
committed
address/txbuilder: require templates to prevent undefined exports
1 parent b6a6b0a commit f4a83f8

File tree

3 files changed

+49
-46
lines changed

3 files changed

+49
-46
lines changed

src/address.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ var Buffer = require('safe-buffer').Buffer
22
var bech32 = require('bech32')
33
var bs58check = require('bs58check')
44
var bscript = require('./script')
5+
var btemplates = require('./templates')
56
var networks = require('./networks')
67
var typeforce = require('typeforce')
78
var types = require('./types')
@@ -50,10 +51,10 @@ function toBech32 (data, version, prefix) {
5051
function fromOutputScript (outputScript, network) {
5152
network = network || networks.bitcoin
5253

53-
if (bscript.pubKeyHash.output.check(outputScript)) return toBase58Check(bscript.compile(outputScript).slice(3, 23), network.pubKeyHash)
54-
if (bscript.scriptHash.output.check(outputScript)) return toBase58Check(bscript.compile(outputScript).slice(2, 22), network.scriptHash)
55-
if (bscript.witnessPubKeyHash.output.check(outputScript)) return toBech32(bscript.compile(outputScript).slice(2, 22), 0, network.bech32)
56-
if (bscript.witnessScriptHash.output.check(outputScript)) return toBech32(bscript.compile(outputScript).slice(2, 34), 0, network.bech32)
54+
if (btemplates.pubKeyHash.output.check(outputScript)) return toBase58Check(bscript.compile(outputScript).slice(3, 23), network.pubKeyHash)
55+
if (btemplates.scriptHash.output.check(outputScript)) return toBase58Check(bscript.compile(outputScript).slice(2, 22), network.scriptHash)
56+
if (btemplates.witnessPubKeyHash.output.check(outputScript)) return toBech32(bscript.compile(outputScript).slice(2, 22), 0, network.bech32)
57+
if (btemplates.witnessScriptHash.output.check(outputScript)) return toBech32(bscript.compile(outputScript).slice(2, 34), 0, network.bech32)
5758

5859
throw new Error(bscript.toASM(outputScript) + ' has no matching Address')
5960
}
@@ -67,8 +68,8 @@ function toOutputScript (address, network) {
6768
} catch (e) {}
6869

6970
if (decode) {
70-
if (decode.version === network.pubKeyHash) return bscript.pubKeyHash.output.encode(decode.hash)
71-
if (decode.version === network.scriptHash) return bscript.scriptHash.output.encode(decode.hash)
71+
if (decode.version === network.pubKeyHash) return btemplates.pubKeyHash.output.encode(decode.hash)
72+
if (decode.version === network.scriptHash) return btemplates.scriptHash.output.encode(decode.hash)
7273
} else {
7374
try {
7475
decode = fromBech32(address)
@@ -77,8 +78,8 @@ function toOutputScript (address, network) {
7778
if (decode) {
7879
if (decode.prefix !== network.bech32) throw new Error(address + ' has an invalid prefix')
7980
if (decode.version === 0) {
80-
if (decode.data.length === 20) return bscript.witnessPubKeyHash.output.encode(decode.data)
81-
if (decode.data.length === 32) return bscript.witnessScriptHash.output.encode(decode.data)
81+
if (decode.data.length === 20) return btemplates.witnessPubKeyHash.output.encode(decode.data)
82+
if (decode.data.length === 32) return btemplates.witnessScriptHash.output.encode(decode.data)
8283
}
8384
}
8485
}

src/transaction_builder.js

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ var Buffer = require('safe-buffer').Buffer
22
var baddress = require('./address')
33
var bcrypto = require('./crypto')
44
var bscript = require('./script')
5+
var btemplates = require('./templates')
56
var networks = require('./networks')
67
var ops = require('bitcoin-ops')
78
var typeforce = require('typeforce')
89
var types = require('./types')
9-
var scriptTypes = bscript.types
10-
var SIGNABLE = [bscript.types.P2PKH, bscript.types.P2PK, bscript.types.MULTISIG]
11-
var P2SH = SIGNABLE.concat([bscript.types.P2WPKH, bscript.types.P2WSH])
10+
var scriptTypes = btemplates.types
11+
var SIGNABLE = [btemplates.types.P2PKH, btemplates.types.P2PK, btemplates.types.MULTISIG]
12+
var P2SH = SIGNABLE.concat([btemplates.types.P2WPKH, btemplates.types.P2WSH])
1213

1314
var ECPair = require('./ecpair')
1415
var ECSignature = require('./ecsignature')
@@ -33,13 +34,13 @@ function extractChunks (type, chunks, script) {
3334
break
3435

3536
case scriptTypes.P2PK:
36-
pubKeys[0] = script ? bscript.pubKey.output.decode(script) : undefined
37+
pubKeys[0] = script ? btemplates.pubKey.output.decode(script) : undefined
3738
signatures = chunks.slice(0, 1)
3839
break
3940

4041
case scriptTypes.MULTISIG:
4142
if (script) {
42-
var multisig = bscript.multisig.output.decode(script)
43+
var multisig = btemplates.multisig.output.decode(script)
4344
pubKeys = multisig.pubKeys
4445
}
4546

@@ -72,24 +73,24 @@ function expandInput (scriptSig, witnessStack) {
7273
var chunks
7374

7475
var scriptSigChunks = bscript.decompile(scriptSig)
75-
var sigType = bscript.classifyInput(scriptSigChunks, true)
76+
var sigType = btemplates.classifyInput(scriptSigChunks, true)
7677
if (sigType === scriptTypes.P2SH) {
7778
p2sh = true
7879
redeemScript = scriptSigChunks[scriptSigChunks.length - 1]
79-
redeemScriptType = bscript.classifyOutput(redeemScript)
80-
prevOutScript = bscript.scriptHash.output.encode(bcrypto.hash160(redeemScript))
80+
redeemScriptType = btemplates.classifyOutput(redeemScript)
81+
prevOutScript = btemplates.scriptHash.output.encode(bcrypto.hash160(redeemScript))
8182
prevOutType = scriptTypes.P2SH
8283
script = redeemScript
8384
}
8485

85-
var classifyWitness = bscript.classifyWitness(witnessStack, true)
86+
var classifyWitness = btemplates.classifyWitness(witnessStack, true)
8687
if (classifyWitness === scriptTypes.P2WSH) {
8788
witnessScript = witnessStack[witnessStack.length - 1]
88-
witnessScriptType = bscript.classifyOutput(witnessScript)
89+
witnessScriptType = btemplates.classifyOutput(witnessScript)
8990
p2wsh = true
9091
witness = true
9192
if (scriptSig.length === 0) {
92-
prevOutScript = bscript.witnessScriptHash.output.encode(bcrypto.sha256(witnessScript))
93+
prevOutScript = btemplates.witnessScriptHash.output.encode(bcrypto.sha256(witnessScript))
9394
prevOutType = scriptTypes.P2WSH
9495
if (redeemScript !== undefined) {
9596
throw new Error('Redeem script given when unnecessary')
@@ -99,13 +100,13 @@ function expandInput (scriptSig, witnessStack) {
99100
if (!redeemScript) {
100101
throw new Error('No redeemScript provided for P2WSH, but scriptSig non-empty')
101102
}
102-
witnessProgram = bscript.witnessScriptHash.output.encode(bcrypto.sha256(witnessScript))
103+
witnessProgram = btemplates.witnessScriptHash.output.encode(bcrypto.sha256(witnessScript))
103104
if (!redeemScript.equals(witnessProgram)) {
104105
throw new Error('Redeem script didn\'t match witnessScript')
105106
}
106107
}
107108

108-
if (!supportedType(bscript.classifyOutput(witnessScript))) {
109+
if (!supportedType(btemplates.classifyOutput(witnessScript))) {
109110
throw new Error('unsupported witness script')
110111
}
111112

@@ -117,7 +118,7 @@ function expandInput (scriptSig, witnessStack) {
117118
var key = witnessStack[witnessStack.length - 1]
118119
var keyHash = bcrypto.hash160(key)
119120
if (scriptSig.length === 0) {
120-
prevOutScript = bscript.witnessPubKeyHash.output.encode(keyHash)
121+
prevOutScript = btemplates.witnessPubKeyHash.output.encode(keyHash)
121122
prevOutType = scriptTypes.P2WPKH
122123
if (typeof redeemScript !== 'undefined') {
123124
throw new Error('Redeem script given when unnecessary')
@@ -126,7 +127,7 @@ function expandInput (scriptSig, witnessStack) {
126127
if (!redeemScript) {
127128
throw new Error('No redeemScript provided for P2WPKH, but scriptSig wasn\'t empty')
128129
}
129-
witnessProgram = bscript.witnessPubKeyHash.output.encode(keyHash)
130+
witnessProgram = btemplates.witnessPubKeyHash.output.encode(keyHash)
130131
if (!redeemScript.equals(witnessProgram)) {
131132
throw new Error('Redeem script did not have the right witness program')
132133
}
@@ -143,7 +144,7 @@ function expandInput (scriptSig, witnessStack) {
143144
scriptType = redeemScriptType
144145
chunks = scriptSigChunks.slice(0, -1)
145146
} else {
146-
prevOutType = scriptType = bscript.classifyInput(scriptSig)
147+
prevOutType = scriptType = btemplates.classifyInput(scriptSig)
147148
chunks = scriptSigChunks
148149
}
149150

@@ -211,7 +212,7 @@ function expandOutput (script, scriptType, ourPubKey) {
211212

212213
var scriptChunks = bscript.decompile(script)
213214
if (!scriptType) {
214-
scriptType = bscript.classifyOutput(script)
215+
scriptType = btemplates.classifyOutput(script)
215216
}
216217

217218
var pubKeys = []
@@ -293,14 +294,14 @@ function prepareInput (input, kpPubKey, redeemScript, witnessValue, witnessScrip
293294
witnessScriptHash = bcrypto.sha256(witnessScript)
294295
checkP2shInput(input, redeemScriptHash)
295296

296-
if (!redeemScript.equals(bscript.witnessScriptHash.output.encode(witnessScriptHash))) throw new Error('Witness script inconsistent with redeem script')
297+
if (!redeemScript.equals(btemplates.witnessScriptHash.output.encode(witnessScriptHash))) throw new Error('Witness script inconsistent with redeem script')
297298

298299
expanded = expandOutput(witnessScript, undefined, kpPubKey)
299300
if (!expanded.pubKeys) throw new Error('WitnessScript not supported "' + bscript.toASM(redeemScript) + '"')
300-
prevOutType = bscript.types.P2SH
301-
prevOutScript = bscript.scriptHash.output.encode(redeemScriptHash)
301+
prevOutType = btemplates.types.P2SH
302+
prevOutScript = btemplates.scriptHash.output.encode(redeemScriptHash)
302303
p2sh = witness = p2wsh = true
303-
p2shType = bscript.types.P2WSH
304+
p2shType = btemplates.types.P2WSH
304305
signType = witnessType = expanded.scriptType
305306
signScript = witnessScript
306307
} else if (redeemScript) {
@@ -310,21 +311,21 @@ function prepareInput (input, kpPubKey, redeemScript, witnessValue, witnessScrip
310311
expanded = expandOutput(redeemScript, undefined, kpPubKey)
311312
if (!expanded.pubKeys) throw new Error('RedeemScript not supported "' + bscript.toASM(redeemScript) + '"')
312313

313-
prevOutType = bscript.types.P2SH
314-
prevOutScript = bscript.scriptHash.output.encode(redeemScriptHash)
314+
prevOutType = btemplates.types.P2SH
315+
prevOutScript = btemplates.scriptHash.output.encode(redeemScriptHash)
315316
p2sh = true
316317
signType = p2shType = expanded.scriptType
317318
signScript = redeemScript
318-
witness = signType === bscript.types.P2WPKH
319+
witness = signType === btemplates.types.P2WPKH
319320
} else if (witnessScript) {
320321
witnessScriptHash = bcrypto.sha256(witnessScript)
321322
checkP2WSHInput(input, witnessScriptHash)
322323

323324
expanded = expandOutput(witnessScript, undefined, kpPubKey)
324325
if (!expanded.pubKeys) throw new Error('WitnessScript not supported "' + bscript.toASM(redeemScript) + '"')
325326

326-
prevOutType = bscript.types.P2WSH
327-
prevOutScript = bscript.witnessScriptHash.output.encode(witnessScriptHash)
327+
prevOutType = btemplates.types.P2WSH
328+
prevOutScript = btemplates.witnessScriptHash.output.encode(witnessScriptHash)
328329
witness = p2wsh = true
329330
signType = witnessType = expanded.scriptType
330331
signScript = witnessScript
@@ -344,7 +345,7 @@ function prepareInput (input, kpPubKey, redeemScript, witnessValue, witnessScrip
344345
signType = prevOutType
345346
signScript = prevOutScript
346347
} else {
347-
prevOutScript = bscript.pubKeyHash.output.encode(bcrypto.hash160(kpPubKey))
348+
prevOutScript = btemplates.pubKeyHash.output.encode(bcrypto.hash160(kpPubKey))
348349
expanded = expandOutput(prevOutScript, scriptTypes.P2PKH, kpPubKey)
349350
prevOutType = scriptTypes.P2PKH
350351
witness = false
@@ -359,7 +360,7 @@ function prepareInput (input, kpPubKey, redeemScript, witnessValue, witnessScrip
359360
}
360361

361362
if (signType === scriptTypes.P2WPKH) {
362-
signScript = bscript.pubKeyHash.output.encode(bscript.witnessPubKeyHash.output.decode(signScript))
363+
signScript = btemplates.pubKeyHash.output.encode(btemplates.witnessPubKeyHash.output.decode(signScript))
363364
}
364365

365366
if (p2sh) {
@@ -383,9 +384,9 @@ function prepareInput (input, kpPubKey, redeemScript, witnessValue, witnessScrip
383384

384385
function buildStack (type, signatures, pubKeys, allowIncomplete) {
385386
if (type === scriptTypes.P2PKH) {
386-
if (signatures.length === 1 && Buffer.isBuffer(signatures[0]) && pubKeys.length === 1) return bscript.pubKeyHash.input.encodeStack(signatures[0], pubKeys[0])
387+
if (signatures.length === 1 && Buffer.isBuffer(signatures[0]) && pubKeys.length === 1) return btemplates.pubKeyHash.input.encodeStack(signatures[0], pubKeys[0])
387388
} else if (type === scriptTypes.P2PK) {
388-
if (signatures.length === 1 && Buffer.isBuffer(signatures[0])) return bscript.pubKey.input.encodeStack(signatures[0])
389+
if (signatures.length === 1 && Buffer.isBuffer(signatures[0])) return btemplates.pubKey.input.encodeStack(signatures[0])
389390
} else if (type === scriptTypes.MULTISIG) {
390391
if (signatures.length > 0) {
391392
signatures = signatures.map(function (signature) {
@@ -396,7 +397,7 @@ function buildStack (type, signatures, pubKeys, allowIncomplete) {
396397
signatures = signatures.filter(function (x) { return x !== ops.OP_0 })
397398
}
398399

399-
return bscript.multisig.input.encodeStack(signatures)
400+
return btemplates.multisig.input.encodeStack(signatures)
400401
}
401402
} else {
402403
throw new Error('Not yet supported')
@@ -416,7 +417,7 @@ function buildInput (input, allowIncomplete) {
416417
}
417418

418419
var p2sh = false
419-
if (scriptType === bscript.types.P2SH) {
420+
if (scriptType === btemplates.types.P2SH) {
420421
// We can remove this error later when we have a guarantee prepareInput
421422
// rejects unsignable scripts - it MUST be signable at this point.
422423
if (!allowIncomplete && !supportedP2SHType(input.redeemScriptType)) {
@@ -436,11 +437,11 @@ function buildInput (input, allowIncomplete) {
436437

437438
switch (scriptType) {
438439
// P2WPKH is a special case of P2PKH
439-
case bscript.types.P2WPKH:
440-
witness = buildStack(bscript.types.P2PKH, input.signatures, input.pubKeys, allowIncomplete)
440+
case btemplates.types.P2WPKH:
441+
witness = buildStack(btemplates.types.P2PKH, input.signatures, input.pubKeys, allowIncomplete)
441442
break
442443

443-
case bscript.types.P2WSH:
444+
case btemplates.types.P2WSH:
444445
// We can remove this check later
445446
if (!allowIncomplete && !supportedType(input.witnessScriptType)) {
446447
throw new Error('Impossible to sign this type')
@@ -593,7 +594,7 @@ TransactionBuilder.prototype.__addInputUnsafe = function (txHash, vout, options)
593594
}
594595

595596
input.prevOutScript = options.prevOutScript
596-
input.prevOutType = prevOutType || bscript.classifyOutput(options.prevOutScript)
597+
input.prevOutType = prevOutType || btemplates.classifyOutput(options.prevOutScript)
597598
}
598599

599600
var vin = this.tx.addInput(txHash, vout, options.sequence, options.scriptSig)
@@ -637,7 +638,7 @@ TransactionBuilder.prototype.__build = function (allowIncomplete) {
637638

638639
// skip if no result
639640
if (!allowIncomplete) {
640-
if (!supportedType(result.type) && result.type !== bscript.types.P2WPKH) {
641+
if (!supportedType(result.type) && result.type !== btemplates.types.P2WPKH) {
641642
throw new Error(result.type + ' not supported')
642643
}
643644
}

test/transaction_builder.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
var assert = require('assert')
44
var baddress = require('../src/address')
55
var bscript = require('../src/script')
6+
var btemplates = require('../src/templates')
67
var ops = require('bitcoin-ops')
78

89
var BigInteger = require('bigi')
@@ -434,7 +435,7 @@ describe('TransactionBuilder', function () {
434435
var signatures = bscript.decompile(scriptSig).slice(1, -1).filter(function (x) { return x !== ops.OP_0 })
435436

436437
// rebuild/replace the scriptSig without them
437-
var replacement = bscript.scriptHash.input.encode(bscript.multisig.input.encode(signatures), redeemScript)
438+
var replacement = btemplates.scriptHash.input.encode(btemplates.multisig.input.encode(signatures), redeemScript)
438439
assert.strictEqual(bscript.toASM(replacement), sign.scriptSigFiltered)
439440

440441
tx.ins[i].script = replacement

0 commit comments

Comments
 (0)